springboot中过滤器有三种注册方式,下面我们分别来看看这三个
1.@WebFilter
通过 @WebFilter 注解来标记一个过滤器,这种方式相信大家很容易想到。这是将 Servlet 中的那一套东西直接拿到 Spring Boot 上用。
具体做法就是通过 @WebFilter 注解来标记一个 Filter,如下:
1 2 3 4 5 6 7 8 9 10
| @WebFilter(urlPatterns = "/*") public class MyFilter implements Filter {
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
|
在 @WebFilter 注解中可以配置过滤器的拦截规则。这个注解要生效,还需要我们在项目启动类上配置 @ServletComponentScan 注解,如下:
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication @ServletComponentScan public class FilterdemoApplication {
public static void main(String[] args) { SpringApplication.run(FilterdemoApplication.class, args); }
}
|
@ServletComponentScan 注解虽然名字带了 Servlet,但是实际上它不仅仅可以扫描项目中的 Servlet 容器,也可以扫描 Filter 和 Listener。
这是我们在 Spring Boot 中使用过滤器的第一种方式,在实际项目中,这种方式使用较少,因为这种方式有一个很大的弊端就是无法指定 Filter 的优先级,如果存在多个 Filter 时,无法通过 @Order 指定优先级。
2.@Bean
第二种方式就是将过滤器配置成 Bean,注册到 Spring 容器中去。这种方法不再需要 @ServletComponentScan 注解,只要一个 Bean 即可,如下:
1 2 3 4 5 6 7 8 9 10
| @Component public class MyFilter implements Filter {
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
|
这种方式看起来很方便,一个注解将 Filter 纳入到 Spring 容器中即可。而且这种方式还有一个优势,就是如果存在多个 Filter,可以通过 @Order 注解指定多个 Filter 的优先级,像下面这样:
1 2 3 4 5 6 7 8 9 10 11
| @Component @Order(-1) public class MyFilter implements Filter {
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
|
虽然解决了优先级问题,但是发现这种方式好像没有办法设置 Filter 的拦截规则!是的,直接定义 Bean 的话,默认的拦截规则就是 /* 即拦截所有请求,开发者无法进行自定义配置。
所以第三种方式就出来了
3.FilterRegistrationBean
第三种方案还是将 Filter 封装成一个 Bean,但这个 Bean 是 FilterRegistrationBean,通过 FilterRegistrationBean 我们既可以配置 Filter 的优先级,也可以配置 Filter 的拦截规则
一般在项目中,我们都是使用 FilterRegistrationBean 来配置过滤器,看一个案例:
1.本次过滤器的案例是对登录是否为管理员身份进行校验,过滤器类AdminFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public class AdminFilter implements Filter { @Autowired UserService userService; @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; // HttpServletResponse response = (HttpServletResponse)servletResponse; // PrintWriter out = response.getWriter(); HttpSession session = request.getSession(); User currentUser = (User) session.getAttribute(Constant.IMOOC_MALL_USER); if (currentUser == null){ /*在Java Web开发中,咱们常常须要拦截http请求,去作一些转发或者是校验等事情。这类工做一般filter能够很轻松的搞定,但这通常都是拦截请求。而咱们有时候也会有一些需求,好比说是拦截服务器的返回(Response),但愿在数据流在服务器端处理完毕,且返回浏览器以前,在这中间作一些本身的事情。网上搜了搜,发现资源不多。因而本身实现了一版,跟你们分享一下。主要用到了HttpServletResponseWrapper获取到数据流,而后经过response.getWriter().write来回写数据。htm*/ /* * HttpServletResponseWrapper * Servlet规范中的filter引入了一个功能强大的拦截模式。Filter能在request到达servlet的服务方法之前拦截HttpServletRequest对象, * 而在服务方法转移控制后又能拦截HttpServletResponse对象。 * 但是HttpServletRequest中的参数是无法改变的, * 若是手动执行修改request中的参数,则会抛出异常。 * 且无法获取到HttpServletResponse中的输出流中的数据, * 因为HttpServletResponse中输出流的数据会写入到默认的输出端,你手动无法获取到数据。 * 我们可以利用HttpServletRequestWrapper包装HttpServletRequest, * 用HttpServletResponseWrapper包装HttpServletResponse, * 在Wrapper中实现参数的修改或者是response输出流的读取, * 然后用HttpServletRequestWrapper替换HttpServletRequest,HttpServletResponseWrapper替换HttpServletResponse。 * 这样就实现了参数的修改设置和输出流的读取。 * */ PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter(); out.write("{\n" + " \"status\": 10007,\n" + " \"msg\": \"NEED_LOGIN\",\n" + " \"data\": null\n" + "}"); out.flush(); out.close(); return;//方法执行到此处结束,不会进入controller } //校验是否是管理员 boolean adminRole = userService.checkAdminRole(currentUser); if (adminRole){ filterChain.doFilter(servletRequest,servletResponse); }else { PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter(); out.write("{\n" + " \"status\": 10009,\n" + " \"msg\": \"NEED_ADMIN\",\n" + " \"data\": null\n" + "}"); out.flush(); out.close(); } }
@Override public void destroy() { Filter.super.destroy(); } }
|
2.过滤器配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.imooc.mall.config;
import com.imooc.mall.filter.AdminFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter; import javax.servlet.FilterRegistration;
/* *描述: Admin过滤器的配置 * */ @Configuration public class AdminFilterConfig { @Bean public AdminFilter adminFilter(){ return new AdminFilter(); } @Bean(name = "adminFilterConf") public FilterRegistrationBean adminFilterConfig(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(adminFilter()); filterRegistrationBean.addUrlPatterns("/admin/category/*"); filterRegistrationBean.addUrlPatterns("/admin/product/*"); filterRegistrationBean.addUrlPatterns("/admin/order/*"); filterRegistrationBean.setName("adminFilterConf"); return filterRegistrationBean;
} }
|