前言
Spring MVC 提供了一个拦截器的机制,它专门用于拦截 controller层 的路由请求。
它的本质是:AOP面向切面的编程,也就是说符合横切关注点的功能都可以考虑使用拦截器实现。比如一些应用场景:
- 权限检查
例如:用户登录检查,访问项目的内部接口时,可以通过拦截器检测用户是否登录,如果登录,直接放回用户登录页面。
- 日志记录
更新推荐用原生的 AOP 机制会更好一点,粒度会更细,控制起来也更方便,如果你是针对某个接口或者某个请求,或者某个业务针对性的记录日志,其实也可以考虑用拦截器来完成。
- 性能监控
记录接口访问过程中的开始时间和结束时间的处理机制。
- 通用行为
比如获取 cookie信息,获取用户信息,并将用户信息存放到请求头中,方便后续业务的使用。
自定义拦截器
1.创建一个拦截器类实现一个接口HandlerInterceptor。
返回值类型 | 方法声明 | 描述 |
---|---|---|
boolean | preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) | 该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作 |
void | postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) | 该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改 |
void | afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) | 该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作 |
package com.example.canal.aop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器类 注意:MyInterceptor 中的方法执行顺序为 preHandle – Controller 方法 – postHandle – afterCompletion 所以拦截器实际上可以对 Controller
* 方法执行前后进行拦截监控。
*/
@Slf4j
public class MyInterceptor implements HandlerInterceptor {// 实现HandlerInterceptor接口
/**
* 访问控制器方法前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if (loginUser == null) {
// 未登录,返回登陆页
request.setAttribute("msg", "您没有权限进行此操作,请先登陆!");
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
} else {
// 放行
return true;
}
}
/**
* 访问控制器方法后执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("postHandle执行", modelAndView);
}
/**
* postHandle方法执行完成后执行,一般用于释放资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("afterCompletion执行异常", ex);
}
}
- 创建一个拦截器的配置类实现WebMvcConfigurer的接口,并且重写addInterceptors方法,注册拦截器类,并且为当前拦截器类定义规则。
package com.example.canal.aop;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 定义拦截器配置类
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 对所有访问路径,都通过MyInterceptor类型的拦截器进行拦截
// addPathPatterns:该方法用于指定拦截路径,例如拦截路径为“/**”,表示拦截所有请求,包括对静态资源的请求。
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/", "/login",
"/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**");
// 放行登录页,登陆操作,静态资源
// excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。
}
}
自定义注解实现拦截器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestOne {
String value();
}
public class TestOneInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
//获得注解信息
TestOne testOne = ((HandlerMethod) handler).getMethodAnnotation(TestOne.class);
if ("".equals(testOne.value())) { //条件根据需求判断
//内容
}
}
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
单拦截器和多拦截器流程