SpringMVC的处理器拦截器相似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者能够本身定义一些拦截器来实现特定的功能。css
1.【拦截器链】(Interceptor Chain): 将拦截器按必定的顺序链接成一条链。在访问被拦截的方法或者字段时,拦截器链中的拦截器就会按照以前定义的顺序被调用。html
2.过滤器与拦截器的区别java
拦截器是AOP思想的具体应用。web
过滤器 | 拦截器 |
---|---|
servlet规范中的一部分,任何java web工程均可以使用 | 拦截器是SpringMVC框架本身的,只有使用了SpringMVC框架的工程才能使用 |
在url-pattern中配置了/*以后,能够对全部要访问的资源进行拦截 | 拦截器只会拦截访问的控制器方法, 若是访问的是jsp/html/css/image/js是不会进行拦截的 |
想要自定义拦截器,必须实现 HandlerInterceptor 接口。redis
/** 自定义拦截器 */ public class HanderInterceptorOne implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle拦截器拦截了"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("postHandle方法执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("afterCompletion方法执行了"); } }
配置springMVC.xmlspring
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorOne" class="com.itheima.myInterceptor.HanderInterceptorOne"/> </mvc:interceptor> </mvc:interceptors>
1. 访问的index.jspsession
<%-- 测试拦截器 --%> <a href="${pageContext.request.contextPath}/interceptor/function">拦截器测试</a>
2. 控制器代码mvc
/** 测试拦截器的控制器 */ @Controller @RequestMapping("/interceptor") public class InterceptorController { @RequestMapping("/function") public String testFunction() { System.out.println("控制器中的方法执行了"); return "success"; } }
3. 运行结果app
preHandle拦截器拦截了 控制器中的方法执行了 postHandle方法执行了 afterCompletion方法执行了
1. 拦截器的放行框架
放行的含义是指,若是有下一个拦截器就执行下一个,若是该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
2. 拦截器中方法的说明
拦截器HandlerInterceptor接口中的三个方法详解。
2.1 boolean preHandle
方法
2.1.1 方法源码
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; }
2.1.2 如何调用:按照拦截器定义顺序调用
2.1.3 什么时候调用:只要配置了都会被调用
2.1.4 逻辑功能:若是开发者决定该拦截器对请求拦截处理后还要调用其余的拦截器,或者是业务处理器去进行处理,则返回true。若是开发者决定不须要再调用其余的组件去处理请求,则返回false。
2.2 void postHandle
方法
2.2.1 方法源码
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
2.2.2 如何调用:按照拦截器定义逆序调用
2.2.3 什么时候调用:拦截器链内全部拦截器返回成功时调用
2.2.4 逻辑功能:在业务处理器处理完请求后,可是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
2.3 void afterCompletion
方法
2.3.1 方法源码
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
2.3.2 如何调用:按拦截器定义逆序调用
2.3.3 什么时候调用:只有对应的preHandle返回true才会被调用
2.3.4 逻辑功能:在DispatcherServlet彻底处理完请求后被调用,能够在该方法中进行一些资源清理的操做。
3. 拦截器的做用路径
做用路径能够经过在配置文件中配置。能够配置多个
<!-- 配置拦截器的做用范围 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> -- 用于指定拦截的url,能够配置多个 <mvc:exclude-mapping path="/xxx"/> -- 用于指定排除的url,能够配置多个 <bean id="handlerInterceptorOne" class="com.itheima.myInterceptor.HanderInterceptorOne"/> </mvc:interceptor> </mvc:interceptors>
4. 多个拦截器的执行顺序
多个拦截器是按照配置的顺序决定的,下面以前后配置
HandlerInterceptorDemo1/HandlerInterceptorDemo2
为例:
1. 拦截器1代码
public class HandlerInterceptorDemo1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("拦截器1:preHandle拦截器拦截了"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("拦截器1:postHandle方法在DispatcherServlet响应前执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("拦截器1:afterCompletion方法在DispatcherServlet响应后执行了"); } }
2. 拦截器2代码
将拦截器中的输出语句中的拦截器1换成拦截器2,类名换成HandlerInterceptorDemo2
3. 配置文件
<!-- 正常执行的拦截器配置,按照配置的顺序执行 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorDemo1" class="com.itheima.myInterceptor.HandlerInterceptorDemo1"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorDemo2" class="com.itheima.myInterceptor.HandlerInterceptorDemo2"/> </mvc:interceptor> </mvc:interceptors>
4. 测试代码
访问的index.jsp代码和控制器代码同上【*】测试运行结果...
5. 执行结果
拦截器1:preHandle拦截器拦截了 拦截器2:preHandle拦截器拦截了 控制器中的方法执行了 拦截器2:postHandle方法在DispatcherServlet响应前执行了 拦截器1:postHandle方法在DispatcherServlet响应前执行了 拦截器2:afterCompletion方法在DispatcherServlet响应后执行了 拦截器1:afterCompletion方法在DispatcherServlet响应后执行了
1. 拦截器1代码
同上一个案例的拦截器1的代码
2. 拦截器2代码
public class HandlerInterceptorDemo2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("拦截器2:preHandle拦截器拦截了"); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("拦截器2:postHandle方法在DispatcherServlet响应前执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("拦截器2:afterCompletion方法在DispatcherServlet响应后执行了"); } }
3. 配置文件
同上一个案例的配置文件
4. 测试代码
访问的index.jsp代码和控制器代码同上【*】测试运行结果...
5. 执行结果
拦截器1:preHandle拦截器拦截了 拦截器2:preHandle拦截器拦截了 拦截器1:afterCompletion方法在DispatcherServlet响应后执行了
6、拦截器的简单案例
验证用户是否登陆(认证用户)
1. 实现思路
1.1 有一个登录页面,须要写一个controller访问页面。
1.2 登录页面有一提交表单的动做。须要在controller中处理。
1.2.1 判断用户名密码是否正确。
1.2.2 若是正确,向session(redis)中写入用户信息。
1.2.3 返回登录成功。
1.3 拦截用户请求,判断用户是否登录。
1.3.1 若是用户已经登录。放行 1.3.2 若是用户未登录,跳转到登录页面
2. 控制器代码
@Controller @RequestMapping("/user") public class UserController { /** 跳转到登录页面 */ @RequestMapping("/jumplogin") public String jumpLogin(Model model) throws Exception { return "login"; } /** 登录提交 */ @RequestMapping("/login") public String login(HttpSession session, String userid, String pwd) throws Exception { // 向session记录用户身份信息 session.setAttribute("user", userid); return "success"; } /** 退出登录 */ @RequestMapping("logout") public String logout(HttpSession session) throws Exception { // session 过时 session.invalidate(); return "login"; } }
3. 拦截器代码
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException { // 若是是登录页面则放行 System.out.println("uri: " + request.getRequestURI()); if (request.getRequestURI().contains("login")) { return true; } HttpSession session = request.getSession(); // 若是用户已登录也放行 if(session.getAttribute("user") != null) { return true; } // 用户没有登录跳转到登录页面 request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response); return false; } }
4. springMVC.xml配置
<!-- 登录案例的拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="loginInterceptor" class="com.itheima.myInterceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
5. 登录页面login.jsp
<form action="${pageContext.request.contextPath}/user/login"> 用户名:<input type="text" name="userid"> <br> 密码: <input type="password" name="pwd"> <br> <input type="submit" value="提交"> </form>