1. 简介
在Spring框架中,拦截器是一种很重要的组件,它们允许在请求到达控制器之前或之后执行一些代码。拦截器在请求处理的特定点进行拦截,然后通过逻辑来决定是否将控制器的处理传递给下一个处理程序。
在Spring中,拦截器是由实现了HandlerInterceptor接口的类实现的。HandlerInterceptor接口暴露了三种拦截方法:preHandle(在请求处理之前被调用)、postHandle(在请求处理之后调用,渲染视图之前)和afterCompletion(在完成请求后执行,无论发生了什么)。
这里就和之前的过滤器Filter很相似,但是也有不同
拦截器和过滤器都可以用于在处理请求和响应过程中进行额外的处理,但它们之间还是有一些重要的区别的。
拦截器是Spring MVC的一部分,它基于Java反射机制,在请求到达控制器前后拦截并进行额外的处理。过滤器是Servlet规范中的一部分,用于在请求到达servlet之前或之后进行拦截,可以用来修改请求或响应。
过滤器可以用于处理Servlet规范之外的事物,例如对静态内容进行GZIP压缩等。而拦截器则仅针对请求到达Spring MVC控制器的场景进行处理。
需要通过代码来将拦截器添加到应用程序中,而过滤器则可以通过修改web.xml文件来添加。
拦截器只能拦截请求和响应,但过滤器可以拦截请求、响应,甚至是错误处理。
拦截器和过滤器的拦截范围不同。拦截器只会拦截到已经映射成功的路径,而过滤器则可以拦截到所有的请求。
通常情况下,如果是针对Spring MVC的请求或响应处理,应该使用拦截器,如果需要处理所有的请求和响应,包括静态内容,应该选择过滤器。
2. 入门案例
2.1 第一种
- 制作拦截器功能类
- 配置拦截器的执行位置
- 声明拦截器的bean,实现HanderInterceptor接口,并且要扫描加载bean,拦截器类最好放在controller目录下
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
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) throws Exception {
System.out.println("postHandle...");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
- 定义配置类
SpringMvcSupport
,实现WebMvcConfigurationSupport
接口,最后实现addInterceptor
方法;
第一个方法是对pages目录下的静态资源放行,避免被SpringMVC拦截;
第二个方法是设置拦截路径("/books","/books/*")
,路径可以通过可变参数设置多个;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}
2.2 第二种
直接将配置拦截器的操作写在
SpringMvcConfig
中;
实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性;
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置多拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}
3. 拦截器参数
主要是在preHandle方法中做校验,返回true还是false;
preHandle方法是一个拦截器的执行方法,在请求到达Controller时进行拦截操作;
preHandle方法中的handler参数是被拦截的请求的Controller对象,它有以下两个主要用处:
- 可以用handler来判断当前请求的Controller类和方法,从而进行特定的业务处理。例如,可以根据不同的Controller类或方法来设置响应头、重定向或转发请求等操作。
- 可以利用handler参数来访问Controller方法中定义的参数、注解或其他信息。例如,可以通过handler.getParameterAnnotations()方法获取方法参数上的注解并进行业务处理,或者通过handler.getMethodParameters()方法获取方法的参数信息进行业务逻辑操作。
这里给出大致原理:
实现上述功能的底层原理之一就是Java的反射机制。handler参数本质上是一个HandlerMethod对象,包含了被拦截的请求对应的Controller类和方法信息以及该方法的参数信息等细节。
在具体的业务实现中,可以利用反射机制来获取HandlerMethod对象中的各种信息进行业务逻辑的处理。例如,可以通过调用HandlerMethod对象的getMethod()方法获得被拦截方法的Method对象,这样就可以对原始方法进行操作。
下面给出示例代码:
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
System.out.println("preHandle..."+contentType);
System.out.println(hm.getMethod().getClass());
return true;
}
@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
控制台输出:
4. 拦截器链配置
了解即可,一般是单个拦截器