1、springmvc 执行流程 和 HandlerExecutionChain(handler 执行链,包含 handler 方法和拦截器)
2、开发拦截器
3、多个拦截器的执行顺序
4、拦截器的例子
5、spring mvc的 HandlerMethod 和 ResourceHttpRequestHandler
1、springmvc 执行流程 和 HandlerExecutionChain(handler 执行链,包含 handler 方法和拦截器) <--返回目录
springmvc 执行流程:
拦截器是 springmvc 中强大的控件,可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作。springmvc 会在启动期间就通过 @RequestMapping 的注解解析URI 和处理器的对应关系,在运行的时候通过请求找到对应的 HandlerMapping,然后构建 HandlerExecutionChain 对象,它是一个执行的责任链对象,这个对象指向了控制器所对应的方法和拦截器。
2、开发拦截器 <--返回目录
使用拦截器需要实现接口 org.springframework.web.servlet.HandlerInterceptor,这个接口定义了三个方法,源码:
package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; public interface HandlerInterceptor { /** * Intercept the execution of a handler. Called after HandlerMapping determined * an appropriate handler object, but before HandlerAdapter invokes the handler.*/ boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** * Intercept the execution of a handler. Called after HandlerAdapter actually * invoked the handler, but before the DispatcherServlet renders the view. * Can expose additional model objects to the view via the given ModelAndView.*/ void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; /** * Callback after completion of request processing, that is, after rendering * the view. Will be called on any outcome of handler execution, thus allows * for proper resource cleanup. * <p>Note: Will only be called if this interceptor's {@code preHandle} * method has successfully completed and returned {@code true}!*/ void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
1) PreHandle(request, response, handler):在处理器之前执行的前置方法,这样 springmvc 可以在进入 handler 方法前处理一些逻辑。注意,此方法返回一个 boolean 值,会影响后面 springmvc 的流程。返回 true,拦截。
2) PostHandle(request, response, handler, modelAndView): 在处理器之后执行的后置方法,此时 DispatcherServlet 还没开始渲染视图,可以在这个方法里面 通过 ModelAndView 添加一些数据得等等。
3) afterCompletion(request, response, handler, exception): 无论是否产生异常都会在渲染视图后执行的方法。
开发拦截器
1)可以通过实现 HandlerInterceptor 接口,但是这样要同时实现 HandlerInterceptor 接口的三个方法,通常开发中可以继承 HandlerInterceptorAdapter 类,然后重写相应的方法即可。
2)注册拦截器。
SSM项目里面,在springmvc配置文件里面配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**">
<bean class="com.oy.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
使用 JavaConfig 配置:
public class WebConfig extends WebMvcConfigurerAdapter { /** * 注册拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**"); } }
拦截器的执行流程:
3、多个拦截器的执行顺序 <--返回目录
首先拦截器执行顺序按照注册配置拦截器顺序前后执行。
4、拦截器的例子 <--返回目录
需求:实现功能:标注@IsLogin的方法,必须登录才能访问;没有登录重定向到login.jsp
步骤:
* spring自定义注解拦截器的配置 * 1)自定义注解IsLogin; * 2)自定义拦截器LoginInterceptor,映射路径"/**",拦截所有请求; * 3)注册拦截器; * 4)在contrller中测试LoginInterceptor + 注解@IsLogin的使用
自定义注解 IsLogin
package com.oy.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface IsLogin { }
拦截器(注册拦截器代码省略)
package com.oy.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.oy.Pojo.User; import com.oy.annotation.IsLogin; public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 请求的目标不是方法,放行 if (!(handler instanceof HandlerMethod)) { return true; } // 请求的目标是方法 HandlerMethod hm = (HandlerMethod) handler; Object o = hm.getMethodAnnotation(IsLogin.class); if (o == null) {// 没有这个注解 return true; // 放行 } // 有注解 User currentUser = (User) request.getSession().getAttribute("currentUser"); if (currentUser == null) {// 没有登录 response.sendRedirect("/login.jsp"); return false; } else { // 登录了 return true; // 放行 } } }
测试 controller
package com.oy.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.oy.Pojo.User; import com.oy.annotation.IsLogin; /** * spring自定义注解拦截器的配置 * 1)自定义注解IsLogin; * 2)自定义拦截器LoginInterceptor,映射路径"/**",拦截所有请求; * 3)注册拦截器; * 4)在本方法中测试LoginInterceptor + 注解@IsLogin的使用 * * 实现功能:标注@IsLogin的方法,必须登录才能访问;没有登录重定向到login.jsp; */ @Controller public class CustomerInterceptorController { /** * 登录 * @return */ @RequestMapping("/test/login") @ResponseBody public String login(HttpServletRequest request) { User user = new User(); user.setId(1); user.setUsername("xxx"); user.setPassword("123"); request.getSession().setAttribute("currentUser", user); return "<a href='/test/isLogin'>click,test is logged in or not</a>"; } /** * 此方法被@IsLogin标注,只有登录才能调用此方法 * @return */ @IsLogin @RequestMapping("/test/isLogin") @ResponseBody public String add() { return "hello, xxx, you are welcome!"; } }
5、spring mvc的 HandlerMethod 和 ResourceHttpRequestHandler <--返回目录
HandlerInterceptor 接口三个方法都有一个参数 handler, 如果请求目标是 controller 的方法,则 handler 类型是 org.springframework.web.method.HandlerMethod。HandlerMethod封装了很多属性,在访问请求方法的时候可以方便的访问到方法、方法参数、方法上的注解、所属类等并且对方法参数封装处理,也可以方便的访问到方法参数的注解等信息。如果请求目标是静态资,handler 类型是org.springframework.web.servlet.resource.ResourceHttpRequestHandler。
6、springboot 注册拦截器 <--返回目录
https://www.cnblogs.com/tiancai/p/11196667.html
参考:
1)《JavaEE互联网轻量级框架整合开发SSM框架(SpringMVC+Spring+MyBatis)和Redis实现》杨开振