[拦截器]spring 中 HandlerInterceptor 与 javax.servlet.Filter区别及使用
Posted on 2021-03-28 11:14 海绵谷 阅读(221) 评论(0) 编辑 收藏 举报拦截器定义
1.Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并做相应的处理。例如通过拦截器可以进行权限验证、判断用户是否已登录等。
2. 执行先后顺序:Filter前处理 --> Interceptor前处理 --> controller--> Interceptor后处理 --> Filter后处理
3. HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前(preHandle)、request被响应之后(postHandle)、视图渲染之前以及request全部结束之后(afterCompletion)。
4. Filter 的 doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)—它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理
编写步骤
1.在spring中通过实现 HandlerInterceptor接口,然后重写preHandle(),postHandle(),afterCompletion(); preHandle()方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。 postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。 afterCompletion()方法:该方法在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作 2. 实现javax.servlet.Filter 接口,然后重写doFilter()方法,。例如实现记录请求url
public class LogFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("----项目启动----");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//拦截请求
String reqPath = ((HttpServletRequest)servletRequest).getServletPath();
if(!(reqPath.contains(".js") || reqPath.contains(".css"))){
logger.info("----请求url:"+reqPath+"----");
}
//拦截继续传递
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
logger.info("----项目关闭----");
}
}
例如判断用户是否登录,ThreadLocal 用来存储用户信息
思路:拦截所有请求(排除静态资源请求),然后获取登录信息是否有效,无效就重定向到登录页面,有效继续传递。
/**
* @author ngLee
* @version 1.0
* @Desc 如果用户信息存在,就不拦截请求
* @date 2021/3/25 22:05
*/
@Component
public class AuthIntercepteror implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取用户信息,session里面取
User user = UserContext.getUser();
if(user == null){
String target = URLEncoder.encode(request.getRequestURI(),"UTF-8");
String reqType = request.getMethod();
if("GET".equalsIgnoreCase(reqType)){
response.sendRedirect("/account/login.vw?target="+target);
}else {
response.sendRedirect("/account/login.vw");
}
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
/**
* @author ngLee
* @version 1.0
* @Desc 如果用户信息存在,就不拦截请求
* 用户信息不存在,重定向到登录页面
* @date 2021/3/25 22:05
*/
@Component
public class AuthIntercepteror implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = UserContext.getUser();
if(user == null){
String target = URLEncoder.encode(request.getRequestURI(),"UTF-8");
String reqType = request.getMethod();
if("GET".equalsIgnoreCase(reqType)){
response.sendRedirect("/account/login.vw?target="+target);
}else {
response.sendRedirect("/account/login.vw");
}
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
//存储用户信息 公用
public class UserContext {
public static ThreadLocal<User> USER_LOCAL = new ThreadLocal<>();
/**
* @desc 存储用户
* @author ngLee
* @date 2021/3/25 21:56
*/
public static void setUser(User user){
USER_LOCAL.set(user);
}
public static User getUser(){
return USER_LOCAL.get();
}
public static void remove(){
USER_LOCAL.remove();
}
}
将实现的拦截器 配置到项目中,才能起作用
注意:拦截器的执行是有一定顺序的,该顺序与我们拦截器的注册顺序有关,例如上问实现的两个拦截器,工作顺序应该是AuthIntercepter拦截请求,判断是否有用户信息,有信息则放到当前线程进行存储,然后存储的信息供AuthIntercepteror使用,然后根据请求的方式,进行重定向。流程图如下
将拦截器进行注册,实现WebMvcConfigurer 接口,重写addInterceptors()方法
/**
* @author ngLee
* @version 1.0
* @Desc
* @date 2021/3/25 22:17
*/
@Configuration
public class WebMvcConf implements WebMvcConfigurer {
@Autowired
private AuthIntercepter authIntercepter;
@Autowired
private AuthIntercepteror authIntercepteror;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//所有请求
registry.addInterceptor(authIntercepter).excludePathPatterns("/static").addPathPatterns("/**");
//涉及到个人信息需要登录
registry.addInterceptor(authIntercepteror).addPathPatterns("/account/profile**");
}
}