版本 | 时间 | 备注 |
---|---|---|
1.0 | 2019-04-28 | 创建笔记 |
本章介绍拦截器和过滤器的区别,如何配置拦截器
Interceptor
以及在拦截器中解决跨域问题
项目源码:https://gitee.com/fzyprojects/boot-test
一、拦截器和过滤器的区别
Spring的
Interceptor
和Servlet的Filter
有相似之处,比如二者都是AOP编程思想的提现,都能实现权限检查,日志记录等。不同的是:
- 使用范围不同。Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。
- 规范不同。Filter是Servlet规范规定的,拦截器是Spring定义的。
- 使用资源不同。同其它代码块一样,拦截器也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此可以使用Spring的所有资源、对象。例如Service对象、数据源和事务管理等,通过IOC注入到拦截器即可。而Filter无法做到这一点。
- 深度不同。Filter只在Servlet前后起作用。而拦截器可以深入到方法前后,异常抛出前后等,因此拦截器具有更大的弹性。所以在Spring构建的程序中,要优先使用拦截器。
二、拦截器的配置
- 创建
MyIntercepyor
实现HandlerInterceptor
- 重写
preHandle
,postHandle
,afterCompletion
方法 - 配置拦截器
preHandle
请求处理之前需要执行的方法
postHandle
请求处理之后执行的方法
afterCompletion
请求生命周期结束之后执行的方法
接口HandlerInterceptor
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 {
}
}
重写方法
public class AreaInterceptor implements HandlerInterceptor {
/**
* 请求开始处理之前
* @param request
* @param response
* @param handler
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("*** preHandle-postHandle***");
return true;
}
/**
* 请求处理之后
* @param request
* @param response
* @param handler
* @param modelAndView
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("*** AreaInterceptor-postHandle***");
}
/**
* 请求生命周期结束之后
* @param request
* @param response
* @param handler
* @param ex
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("*** AreaInterceptor-afterCompletion***");
}
}
配置拦截器
拦截器需要进行配置才能够使用。配置的目的是将拦截器交给
spring
的IOC
容器管理。并且配置拦截器的使用条件
- 配置拦截器实现
WebMvcConfigurer
,创建拦截器的Bean-
addInterceptor
(拦截器)--> 将拦截器注册进来 -
addPathPatterns
("url")--> 添加需要拦截的请求 -
excludePathPatterns
("url")-->添加放行的请求,即不拦截
-
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
private static final String ALL = "/**";
private static final String LOGIN = "/inter/login";
private static final String ERROR = "/error";
private static final String TH = "/th/**";
/**
* 解决跨域问题
* @return
*/
@Bean
public AreaInterceptor getAreaInterceptor() {
return new AreaInterceptor();
}
/**
* 返回单例对象
* @return
*/
@Bean
public TokenInterceptor getMyInterceptor() {
return new TokenInterceptor();
}
/**
* 拦截器2
* @return
*/
@Bean
public MyInterceptor2 getMyInterceptor2() {
return new MyInterceptor2();
}
/**
* addInterceptor(拦截器)--> 将拦截器注册进来
* addPathPatterns("url")--> 添加需要拦截的请求
* excludePathPatterns("url")-->添加放行的请求,即不拦截
* <p>
* 注意:如果要拦截所有请求,则拦截"/**"
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getAreaInterceptor()).addPathPatterns(ALL);
registry.addInterceptor(getMyInterceptor()).addPathPatterns(ALL).excludePathPatterns(ERROR, LOGIN, TH);
//registry.addInterceptor(getMyInterceptor2()).addPathPatterns("/**").excludePathPatterns("/inter/bbb","/inter/ccc");
}
}
三、解决跨域问题
请求发送端和接收端的
ip地址
以及端口号
不一致都可能导致跨域问题,想要解决跨域问题,可以在拦截器中进行如下设置
- 注意:需要禁止
OPTIONS
请求
/**
* 拦截器,解决跨域问题
*/
public class AreaInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
//浏览器会先发送一个试探请求OPTIONS,然后才会发送真正的请求,为了避免拦截器拦截两次请求,所以不能让OPTIONS请求通过
if ("OPTIONS".equals(request.getRequestURI())){
return false;
}
return true;
}
}
终极解决方式1
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("URI - [{}]",request.getRequestURI());
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
return true;
}
终极解决方式2
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter{
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("*");
}
}
网友评论