拦截器是 Web 项目很重要和常用的功能,如对用户权限验证,判断用户是否已登录等。
SpringMVC 中的拦截器通过实现HanderInterceptor
接口来完成,或继承抽象类HandlerInterceptorAdapter
,重写里面的方法来完成。
HanderInterceptor
HanderInterceptor 接口中定义了三个方法,SpringMVC 通过这三个方法来对用户请求进行拦截处理。
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
本方法在请求处理之前执行,返回值是 Boolean
类型,返回值为 false
时,表示请求结束;返回 true
时就会继承调用下一个 interceptor 的 preHandle() 方法,如果是最后一个 Interceptor,就调用当前请求的 Controller 方法。SpringMVC 中的 Interceptor 是链式调用,即在一个应用中或一个请求中可以同时存在多个Interceptor, 调用的的顺序是根据声明的顺序依次执行;所以可以在该方法中对一些请求做一个预处理,或初始化操作。
handler 参数是目标处理方法,是 HandlerMethod 类型,即处理请求的具体方法。可以通过该参数获取目标方法对象,再根据目标方法对象获取方法上的注解,再根据注解进行业务处理。
1 2 3 4 5 6
| HandlerMethod handler1 = (HandlerMethod) handler; Method method1 = handler1.getMethod(); RequestMapping methodAnnotation = handler1.getMethodAnnotation(RequestMapping.class); if (null != methodAnnotation) { System.out.println("-----------------"); }
|
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
preHandle()
方法返回true
;,请求被处理之后,也就是 Controller 方法被调用之后执行,但是在DispatcherServlet 进行视图返回渲染之前被调用。
多个 Interceptor 时,该方法的调用顺序与 preHandle() 相反。
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
preHandle() 方法返回true
,整个请求结束之后,DispatcherServlet 进行视图返回渲染之后执行。该方法主要作用是进行资源清理。
接口源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true; }
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { }
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
|
拦截器链调用顺序
实现示例
登录认证拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
import com.anqi.entity.User;
public class LoginInterceptor implements HandlerInterceptor {
private static final String[] IGNORE_URI = { "/loginForm", "/login", "/register" };
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception { boolean flag = false; String servletPath = request.getServletPath(); for (String uri : IGNORE_URI) { if (servletPath.contains(uri)) { flag = true; break; } }
if (!flag) { HttpSession session = request.getSession(); User user = (User) session.getAttribute("user"); if (user == null || "".equals(user.toString())) { request.setAttribute("msg", "请先登录"); request.getRequestDispatcher("loginForm").forward(request, response);
return false; } else { flag = true; } } return flag; }
@Override public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object obj, ModelAndView exception) throws Exception {
}
@Override public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object obj, Exception exception) throws Exception {
}
}
|
登录Token认证拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired UserService userService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { String token = httpServletRequest.getHeader("token"); if(!(object instanceof HandlerMethod)){ return true; } HandlerMethod handlerMethod=(HandlerMethod)object; Method method=handlerMethod.getMethod(); if (method.isAnnotationPresent(PassToken.class)) { PassToken passToken = method.getAnnotation(PassToken.class); if (passToken.required()) { return true; } } if (method.isAnnotationPresent(UserLoginToken.class)) { UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class); if (userLoginToken.required()) { if (token == null) { throw new RuntimeException("无token,请重新登录"); } String userId; try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new RuntimeException("401"); } User user = userService.findUserById(userId); if (user == null) { throw new RuntimeException("用户不存在,请重新登录"); } JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); } catch (JWTVerificationException e) { throw new RuntimeException("401"); } return true; } } return true; }
@Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
} @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { }
|
装配拦截器
拦截/admin/
开头的所有请求。
1 2 3 4 5 6 7 8
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/admin/**" /> <bean class="com.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
|