Spring模块 | 拦截器如何实现

简介: Spring根据官方文档实现拦截器

拦截器

官方文档介绍

所有实现都支持处理程序拦截器,当您要将特定功能应用于某些请求(例如,检查主体)时,这些拦截器非常有用。拦截器必须使用三种方法从包中实现,这些方法应提供足够的灵活性来执行各种预处理和后处理:HandlerMappingHandlerInterceptororg.springframework.web.servlet

  • preHandle(..):在运行实际处理程序之前,
  • postHandle(..):运行处理程序后
  • afterCompletion(..):完成请求后

拦截器如何实现

实现一个自己的拦截器,需要实现HandlerInterceptor接口。接口内的三个核心方法如下:

1.preHandle():该方法在业务处理器处理请求之前调用。主要用来进行一些前置初始化操作或者是对当前请求的预处理,也可以进行一些判断来决定请求是否要继续下去,该方法的返回值类型位boolean值,如果返回位false,就表示当前请求结束,如果返回为true,那么就会继续调用下一个Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。

2.postHandle():这个方法在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView 对象进行操作。

3.afterCompletion():在postHandle执行之后执行,发生异常也会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

拦截器的代码实现

登陆拦截器

publicclassLogInterceptorextendsHandlerInterceptorAdapter {

 

   //在执行Controller方法之前来执行的

   //用于用户认证校验、用户权限校验

   @Override

   publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)

           throwsException {

       longstartTime=System.currentTimeMillis();

       System.out.println("\n-------- LogInterception.preHandle --- ");

       System.out.println("Request URL: "+request.getRequestURL());

       System.out.println("Start Time: "+System.currentTimeMillis());

 

       request.setAttribute("startTime", startTime);

 

       returntrue;

   }

   //在执行Controller方法之后返回modelAndView之前来执行

   //如果需要向页面提供一些公用的数据或配置一些视图信息,使用此方法实现从modelAndView入手

   @Override

   publicvoidpostHandle(HttpServletRequestrequest, HttpServletResponseresponse, //

                          Objecthandler, ModelAndViewmodelAndView) throwsException {

 

       System.out.println("\n-------- LogInterception.postHandle --- ");

       System.out.println("Request URL: "+request.getRequestURL());

 

       // You can add attributes in the modelAndView

       // and use that in the view page

   }

 

   //完成对页面的渲染之后执行此方法

   //作系统统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间       点的差就是执行时长

   //实现系统统一日志记录

   @Override

   publicvoidafterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, //

                               Objecthandler, Exceptionex) throwsException {

       System.out.println("\n-------- LogInterception.afterCompletion --- ");

 

       longstartTime= (Long) request.getAttribute("startTime");

       longendTime=System.currentTimeMillis();

       System.out.println("Request URL: "+request.getRequestURL());

       System.out.println("End Time: "+endTime);

 

       System.out.println("Time Taken: "+ (endTime-startTime));

   }

 

}

 

鉴权拦截器

publicclassAdminInterceptorextendsHandlerInterceptorAdapter {

 

   @Override

   publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)

           throwsException {

 

       System.out.println("\n-------- AdminInterceptor.preHandle --- ");

       returntrue;

   }

 

   @Override

   publicvoidpostHandle(HttpServletRequestrequest, HttpServletResponseresponse, //

                          Objecthandler, ModelAndViewmodelAndView) throwsException {

 

       System.out.println("\n-------- AdminInterceptor.postHandle --- ");

   }

 

   @Override

   publicvoidafterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, //

                               Objecthandler, Exceptionex) throwsException {

 

       System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");

   }

 

}

 

拦截器添加到拦截列表

@Configuration

publicclassWebConfigimplementsWebMvcConfigurer {

   @Override

   publicvoidaddInterceptors(InterceptorRegistryregistry) {

       // LogInterceptor apply to all URLs.

       // LogInterceptor应用于所有url。

       registry.addInterceptor(newLogInterceptor());

 

       

       // 这个拦截器应用于/admin/*这样的URL

       // Exclude /admin/oldLogin

       registry.addInterceptor(newAdminInterceptor())//

               .addPathPatterns("/admin/*");

   }

 

}

 

业务逻辑处理Controller

@Controller

publicclassInterceptorTestController {

 

   @RequestMapping(value= { "/", "/test" })

   publicStringtest(Modelmodel) {

 

       System.out.println("\n-------- MainController --- ");

 

       System.out.println(" ** You are in Controller ** ");

 

       return"test";

   }

 

   @RequestMapping(value= { "/admin/login" })

   publicStringlogin(Modelmodel) {

 

       System.out.println("\n-------- MainController.login --- ");

 

       System.out.println(" ** You are in Controller ** ");

 

       return"login";

   }

 

}

 

流程顺序

拦截器

模拟登陆拦截

配置登陆拦截器

publicclassLoginInterceptor2implements  HandlerInterceptor{

   @Override

   publicbooleanpreHandle(HttpServletRequestrequest,

                            HttpServletResponseresponse, Objecthandler) throwsException {

       System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");

       Stringuri=request.getRequestURI();

       //判断当前请求地址是否登录地址

       if(uri.contains("login") ||uri.contains("toLoginPage"))

       {

           //直接放行

           returntrue;

       }

       else

       {

           //判断用户是否登录

           if(request.getSession().getAttribute("userName")!=null)

               //说明已经登录,放行

               returntrue;          

           else

               //没有登录,重定向到登录界面

               response.sendRedirect(request.getContextPath() +"/toLoginPage");  

       }

 

       //默认拦截

       returnfalse;

   }

   @Override

   publicvoidpostHandle(HttpServletRequestrequest,

                          HttpServletResponseresponse, Objecthandler,

                          ModelAndViewmodelAndView) throwsException {

       System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");

   }

   @Override

   publicvoidafterCompletion(HttpServletRequestrequest,

                               HttpServletResponseresponse, Objecthandler, Exceptionex)

           throwsException {

       System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");

   }

}

 

添加登陆拦截器

@Configuration

publicclassWebConfigimplementsWebMvcConfigurer {

 

   @Override

   publicvoidaddViewControllers(ViewControllerRegistryregistry)

   {

       registry.addViewController("/toIndexPage").setViewName("/index");

       registry.addViewController("/").setViewName("/index");

   }

 

   @Override

   publicvoidaddInterceptors(InterceptorRegistryregistry) {

       registry.addInterceptor(newLoginInterceptor2())

           .addPathPatterns("/**") //所有路径都被拦截

           .excludePathPatterns( //添加不拦截路径

               "/toLoginPage", //登录页面

               "/login",       //登录请求

               "/**/*.html",   //html静态资源

               "/**/*.js",     //js静态资源

               "/**/*.css"     //css静态资源

       );

   }

}

controller层

@Controller

publicclassUserController {

 

   /**

    * 登录页面

    */

   @RequestMapping("/toLoginPage")

   publicStringtoLoginPage()

   {

       //跳转至登录页面

       return"login.html";

   }

   /**

    * 登录

    */

   @RequestMapping(value="/login", method=RequestMethod.POST)

   publicStringlogin(Modelmodel, HttpServletRequestrequest, StringuserName, Stringpassword)

   {

       //验证登录信息

       if (userName.equals("xiaoqi") &&password.equals("123456"))

       {

           //验证成功,记录Session信息

           request.getSession().setAttribute("userName", userName);

           //重定向到首页

           return"redirect:toIndexPage";

       }

       else

       {

           model.addAttribute("errorMsg", "账号或密码错误!");

       }

       //跳转至登录页面

       returntoLoginPage();

   }

 

   /**

    * 登出

    */

   @RequestMapping(value="/logout")

   publicStringlogout(HttpServletRequestrequest)

   {

       //销毁session对象

       request.getSession().invalidate();

       //重定向到登录页面

       return"redirect:toLoginPage";

   }

}

HTML页面

<!DOCTYPE html>

<htmllang="en"xmlns:th="http://www.thymeleaf.org">

<head>

   <metacharset="UTF-8">

   <title>用户登录</title>

</head>

<body>

<divalign="center">请输入登录信息

   <formname="Mfrom"method="post"action="/login"onsubmit="SubmitLogin()">

       <table>

           <tr>

               <td>用户姓名:</td>

               <td><inputtype="text"name="userName"value="xiaoqi"class="txtBox"/></td>

           </tr>

           <tr>

               <td>登录密码:</td>

               <td><inputtype="password"name="password"value="123456"class="txtBox"/></td>

           </tr>

           <!-- 以下是提交、取消按钮 -->

           <tr>

               <td>

                   <inputtype="submit"value="登录"/>

               </td>

               <td>

                   <inputtype="reset"value="取消"/>

               </td>

           </tr>

       </table>

       <pstyle="color:red"th:text="${errorMsg}"></p>

   </form>

</div>

</body>

<script>

   //提交登录

   functionSubmitLogin() {

       //判断用户名是否为空

       if (!Mfrom.userName.value) {

           alert("请输入用户姓名!");

           Mfrom.userName.focus();

           returnfalse;

       }

 

       //判断密码是否为空

       if (!Mfrom.password.value) {

           alert("请输入登录密码!");

           Mfrom.password.focus();

           returnfalse;

       }

       returntrue;

   }

</script>

</html>

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

   <meta charset="UTF-8">

   <title>首页</title>

   <meta name="author" content="pan_junbiao的博客">

</head>

<body>

<h1>首页</h1>

<p>当前Session中保存的登录人名称:<span th:text="${session.userName}"/></p>

<a href="logout" onclick="return confirm('确定注销吗?');">注销</a>

</body>

</html>


相关文章
|
2月前
|
Java Spring
Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行
【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。
44 1
|
2月前
|
缓存 Java Spring
Spring 源码阅读 66:基于 JDK 的 AOP 代理如何获取拦截器链(4)- 将 Advice 封装为拦截器
【1月更文挑战第1天】本文分析了 Advice 被封装成 MethodInterceptor 的过程,Spring AOP 用到的五种 Advice 中,有些本身就是 MethodInterceptor 的实现类,而有些需要通过适配器的封装。
52 0
|
19天前
|
监控 Java 关系型数据库
java版MES系统源码,后端采用 Spring Boot 多模块架构
MES系统采用Vue3的vue-element-plus-admin为后台,Spring Boot多模块架构,支持MySQL、Oracle等数据库,具备SaaS多租户功能。核心功能包括车间计划排程、工艺流程配置、生产质量管理、进度追踪、库存和排班管理等,全面覆盖生产运营关键环节。
java版MES系统源码,后端采用 Spring Boot 多模块架构
|
3天前
|
IDE Java 机器人
Spring Boot中的多模块项目构建
Spring Boot中的多模块项目构建
|
3天前
|
监控 前端开发 Java
Spring Boot中的拦截器配置
Spring Boot中的拦截器配置
|
10天前
|
前端开发 JavaScript Java
【Spring Boot】 深入理解Spring Boot拦截器:自定义设计与实现全攻略
【Spring Boot】 深入理解Spring Boot拦截器:自定义设计与实现全攻略
12 0
|
2月前
|
前端开发 Java 程序员
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
34 1
|
2月前
|
前端开发 Java Spring
[AIGC] Spring Interceptor 拦截器详解
[AIGC] Spring Interceptor 拦截器详解
|
2月前
|
Java Spring
如何创建spring 的web模块
如何创建spring 的web模块
20 6
|
2月前
|
缓存 Java Spring
单体项目中资源管理模块集成Spring Cache
该内容是关于将Spring Cache集成到资源管理模块以实现缓存同步的说明。主要策略包括:查询时添加到缓存,增删改时删除相关缓存。示例代码展示了@Service类中使用@Transactional和@Cacheable注解进行缓存操作,以及在RedisTemplate中处理缓存的示例。
28 5