过滤器和拦截器
Filter
- SpringBoot启动默认加载的Filter
characterEncodingFilter
hiddenHttpMethodFilter
httpPutFormContentFilter
requestContextFilter
- Filter 优先级
- Ordered.HIGHEST_PRECEDENCE
- Ordered.HIGHEST_PRECEDENCE
- 低位值意味着更高的优先级 Higher values are interpreted as lower priority
- 自定义Filter,避免和默认的Filter优先级一样,不然会冲突
- 自定义 Filter
- 新建一个 Filter 类,实现 javax.servlet.Filter 接口
public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 可以对 request 和 response 进行强转进行后续处理 System.out.println("coming in"); // 放行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("filter destroy"); } }
- 两种方式添加 Filter 进 Spring
- servlet 3.0 方式
- 在自定义 Filter 上添加注解
@WebFileter(urlPatterns={"/api/*"})
- 支持正则
- 在启动类添加扫描注解
@ServletComponentScan
- config 方式
- 在自定义 Filter 上添加注解
@Component
- 添加一个配置类
/** * 对原始 filter 进行配置 */ @Configuration public class WebConfig { @Bean public FilterRegistrationBean<MyFilter> myFilter(){ FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>(); MyFilter filter = new MyFilter(); filterRegistrationBean.setFilter(filter); // 可以设置不同的 url List<String> urls = new LinkedList<>(); urls.add("/api/*"); filterRegistrationBean.setUrlPatterns(urls); return filterRegistrationBean; } }
Servlet
原生
- 添加 servlet
@WebServlet(name = "userServlet",urlPatterns = "/test/customs")
public class UserServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("custom sevlet");
resp.getWriter().flush();
resp.getWriter().close();
}
}
- 启动类配置
@ServletComponentScan
Listener 监听器
- 常用的监听器
- servletContextListener
- httpSessionListener
- servletRequestListener
- 自定义Listener
@WebListener
public class RequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generated method stub
System.out.println("======requestDestroyed========");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("======requestInitialized========");
}
}
- 启动类配置
@ServletComponentScan
拦截器
- 新建配置类
- 1.x
- 继承
WebMvcConfigurationAdapter
- 继承
- 2.x
- 实现
WebMvcConfigurer
/** * 配置拦截器 */ @Configuration public class WebConfigTwo implements WebMvcConfigurer { @Autowired private TimeInterceptor timeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor) .addPathPatterns("/user/**") .excludePathPatterns("/user/all"); } }
- 实现
- 自定义拦截器 HandlerInterceptor
@Component
public class TimeInterceptor implements HandlerInterceptor {
/**
* 进入 controller 之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(" preHandle ");
request.setAttribute("start", LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
System.out.println(((HandlerMethod)handler).getMethod().getName());
return true;
}
/**
* controller 返回之前, 出现异常则不会执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(" postHandle ");
long start = (long) request.getAttribute("start");
System.out.println("花费了: " + (LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)-start));
}
/**
* 不管 controller 是正常返回还是异常,都会进入
* 会被 @ControllerHandler 中的 @ExceptionHandler 给吃掉
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(" afterCompletion ");
System.out.println("ex is : " + ex);
}
}
- 按照注册顺序进行拦截
- 先注册,先被拦截
拦截器不生效常见问题:
- 是否有加
@Configuration
- 拦截路径是否有问题 ** 和 *
- 拦截器最后路径一定要
"/**"
, 如果是目录的话则是"/*/"
Filter 和 Intercepter 区别
Filter | Interceptor |
---|---|
基于函数回调 doFilter() |
基于 AOP 思想 |
只在Servlet前后起作用 | 深入到方法前后、异常抛出前后等 |
依赖于 Servlet 容器即web应用中 | 不依赖于Servlet 容器所以可以运行在多种环境。 |
只能在容器初始化时调用一次 | 接口调用的生命周期里, 可以被多次调用 |
执行顺序
过滤前->拦截前->action执行->拦截后->过滤后