springMVC 拦截器
Spring MVC 自定义拦截器
Spring MVC 自定义拦截器
一、拦截器
Interceptor 拦截功能基于 java 的动态代理实现。
SpringMVC中的Interceptor拦截器是链式的,可以同时存在。
在spring 框架之中,实现自定义拦截类,可以实现
第一种是实现HandlerInterceptor接口,
第二种是实现WebRequestInterceptor接口
(1)HandlerInterceptor 接口实现
@Slf4j //lombok @Component public class AuthorityIntercept implements HandlerInterceptor{ /** *在进入 Controller 之前调用 * * true : 调用当前请求的 Controller 中的方法 * 或 下一个拦截器 * false : 请求结束,不会进入到 Controller 层 * * handler : (HandlerMethod) 封装了请求控制层的 Bean 实例 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; //日志记录 String methodName = handlerMethod.getMethod().getName(); Class _class = handlerMethod.getBeanType(); String className = _class.getSimpleName(); Map<String,String[]> parameterMap = request.getParameterMap(); StringBuilder sb = new StringBuilder(); for (Map.Entry<String, String[]> entry: parameterMap.entrySet()) { // == "" 易精确的查找 String key = entry.getKey(); String [] parameter = entry.getValue(); String value = Arrays.asList(parameter).toString(); sb.append("key :").append(key).append(",").append("value : ").append(value); } log.info("request className :{} methodName :{}, parameter :{}",className,methodName,sb); //不拦截 user login 的方法,(无法登入) //也可以在 dispatcher-servlet.xml 进行配置 exclude if (methodName.equals("UserManageController") && className.equals("login")){ return true; } User user = null; String loginToken = LoginCookieUtil.readLoginCookieValue(request); if (StringUtils.isNotBlank(loginToken)){ user = JacksonUtil.stringToObject(SharedRedisPoolUtil.get(loginToken),User.class); } if (user == null || user.getRole() != Const.Role.ROLE_ADMIN) { //返回false.即不会调用controller里的方法 需要返回设置格式 // 这里要添加reset,否则报异常 getWriter() has already been called for this response. response.reset(); //这里要设置编码,否则会乱码 response.setCharacterEncoding("UTF-8"); // 这里要设置返回值的类型,因为全部是json接口。 response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); if (user == null){ out.print(JacksonUtil.objectToString(ServerResponse.createByErrorMessage("拦截器拦截,请登入"))); }else{ out.print(JacksonUtil.objectToString(ServerResponse.createByErrorMessage("拦截器拦截,用户无权限操作"))); } } return true; } /** * Controller 执行之后调用 */ @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } //DispatcherServlet 渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作。 @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception { System.out.println("afterCompletion"); } }
(2)dispatcher-servlet.xml 配置
<!-- 声明拦截器 --> <mvc:interceptors> <!-- 使用 bean 定义一个 Interceptor,直接定义在 mvc:interceptors 下面的 Interceptor 将拦截所有的请求 --> <mvc:interceptor> <!-- /manage/** 包含子路径 /manage/* 当前路径 / web 项目根路径 --> <mvc:mapping path="/manage/**" /> <!-- 对登入不拦截 --> <mvc:exclude-mapping path="/manage/user/login.do"/> <!-- 定义在 mvc:interceptor 下面的 Interceptor,表示对特定的请求进行拦截 --> <bean class="com.mmall.controller.Intercept.AuthorityIntercept"/> </mvc:interceptor> </mvc:interceptors>
(3)拦截器的执行顺序
<!-- 配置拦截器 --> <mvc:interceptors> <!-- 多个拦截器,按顺序执行 --> <mvc:interceptor> <mvc:mapping path="/**"/> <!-- 表示拦截所有的url包括子url路径 --> <bean class="ssm.interceptor.HandlerInterceptor1"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="ssm.interceptor.HandlerInterceptor2"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="ssm.interceptor.HandlerInterceptor3"/> </mvc:interceptor> </mvc:interceptors>
1、三个拦截器都可以通过 true
当所有拦截器都放行的时候,preHandle方法是按照配置的顺序执的;而另外两个方法按照配置的顺序逆向执行的。
2、最后一个拦截器不可以通过
1. 由于拦截器1和2放行,所以拦截器3的preHandle才能执行。也就是说前面的拦截器放行,后面的拦截器才能执行preHandle。
2. 拦截器3不放行,所以其另外两个方法没有被执行。即如果某个拦截器不放行,那么它的另外两个方法就不会背执行。
3. 只要有一个拦截器不放行,所有拦截器的postHandle方法都不会执行,但是只要执行过preHandle并且放行的,就会执行afterCompletion方法。
3、三个拦截器都不可以通过
只执行了第一个拦截器的preHandle方法,因为都不放行,所以没有一个执行postHandle方法和afterCompletion方法。
拦截器执行顺序总结:
拦截器放行的时候,会进入下一个拦截器的preHandle方法(按照配置的顺序执行)或者进入 controller 层方法执行 ,
preHandle 所有的方法执行完,另外两个方法得到执行的前提式 preHandle 返回图 true ,因此,
另外两个方法按照配置的顺序逆向执行的(根据实际 preHandle 执行情况)。