Springboot 过滤器

拦截器和过滤器的区别:

过滤器(Filter) :可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息。

拦截器(Interceptor):可以拿到你请求的控制器和方法,却拿不到请求方法的参数。

切片(Aspect): 可以拿到方法的参数,但是却拿不到http请求和响应的对象


1.过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。

2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。

3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射

4、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。

5、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。

6、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。



最简单明了的区别就是过滤器可以修改request,而拦截器不能
过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境
拦截器可以调用IOC容器中的各种依赖,而过滤器不能
过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

一、应用场景:

Springboot的过滤器,在web开发中可以过滤指定的url
比如过拦截掉我们不需要的接口请求,同时也可以修改request和response内容
过滤器的应用场景:
1)过滤敏感词汇(防止sql注入)
2)设置字符编码
3)URL级别的权限访问控制
4)压缩响应信息

二、实现方法:

 1、使用spring boot提供的FilterRegistrationBean注册Filter 
2、使用原生servlet注解定义Filter 
两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter

 方式一: (使用spring boot提供的FilterRegistrationBean注册Filter )

①、先定义Filter:

 
package com.corwien.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
Logger logger = LoggerFactory.getLogger(BaseFilter.class);

    static final String TOKEN = "20220423344556abac";
    
    //内部接口集合
    public static List<String> INSIDE_URLS = Lists.newArrayList("/index","/inside");
    //白名单接口集合
    public static List<String> WHITE_PATH = Lists.newArrayList("/white","/login");

    @Override public void init(FilterConfig filterConfig) throws ServletException {
 
    }
    @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // do something 处理request 或response
     // doFilter()方法中的servletRequest参数的类型是ServletRequest,需要转换为HttpServletRequest类型方便调用某些方法
      System.out.println("filter1"); // 调用filter链中的下一个filter
 
   HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
 
        String ip = request.getRemoteAddr();
      
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = new Date();
        String date = sdf.format(d);
 
        System.out.printf("%s %s 访问了 %s%n", date, ip, url);

        String requestURI = request.getRequestURI();
       if(INSIDE_URLS.contains(requestURI)){
            //内部接口,直接通过
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        if(WHITE_PATH.contains(requestURI)){
            //白名单接口,直接通过
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        //进行校验,如token校验
        String token = request.getHeader("token");
        if(TOKEN.equals(token)){
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            //token校验不通过,重定向到登录页面
            wrapper.sendRedirect("/login");
        }
    }
    @Override public void destroy() {
 
    }
}

过滤器需要实现Filter类,其中有三个默认的方法(init初始方法,doFilter核心过滤方法,destroy销毁方法) 

②、注册自定义Filter过滤器配置类

@Configuration
public class FilterConfig {
    /**
     * 基础过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean<Filter> baseFilter(){
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new BaseFilter());
        filterRegistrationBean.setUrlPatterns(Lists.newArrayList("/*"));
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }
}

新增controller方法和登录页login.html


@RestController
public class restController {

    @Autowired
    private AsynService asynService;
    /**
     * 白名单接口
     * @return
     */
    @GetMapping("/while")
    public String whileTest(){
        return "success";
    }

    /**
     * 非白名单接口
     * @return
     */
    @GetMapping("/no-while")
    public String noWhileTest(){
        return "success";
    }

    /**
     * 登录接口
     * @param username
     * @param password
     * @param mv
     * @param request
     * @param model
     * @return
     */
    @GetMapping("/login")
    public ModelAndView login(String username, String password, ModelAndView mv, HttpServletRequest request, Model model){
        if(StringUtils.hasLength(username)&&StringUtils.hasLength(password)){
            //TODO 登录逻辑
            System.out.println("成功!!");
            mv.setViewName("index");
        }else{
            System.out.println("失败!!");
            mv.setViewName("/login.html");
        }
        return mv;
    }
}

测试

项目启动后,访问下面两个接口(白名单接口PK非白名单接口)
接口一:http://localhost:8080/whileTest
接口二:http://localhost:8080/no-while

接口一为白名单范畴,过滤器直接通行,返回“success”

接口二在过滤器中需要校验token,在没有携带token的情况下,会重定向到登录页

### Spring Boot 中过滤器的实现与配置 #### 配置方式一:使用 `Filter` 接口 在 Spring Boot 中,可以通过实现标准的 Servlet API 的 `javax.servlet.Filter` 接口来创建一个过滤器。该接口提供了一个核心方法——`doFilter()` 方法,在此方法中可以编写逻辑以处理 HTTP 请求和响应。 以下是具体实现步骤: 1. 创建类并实现 `Filter` 接口。 2. 覆盖 `init(FilterConfig filterConfig)` 和 `destroy()` 方法(可选),用于初始化和销毁资源。 3. 编写 `doFilter(ServletRequest request, ServletResponse response, FilterChain chain)` 方法中的业务逻辑。 示例代码如下: ```java import javax.servlet.*; import java.io.IOException; public class MyCustomFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("MyCustomFilter 初始化"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("请求前操作..."); // 继续链式调用下一个过滤器或目标资源 chain.doFilter(request, response); System.out.println("响应后操作..."); } @Override public void destroy() { System.out.println("MyCustomFilter 销毁"); } } ``` 为了使上述过滤器生效,还需要将其注册到应用程序上下文中[^1]。 --- #### 注册过滤器的方式 ##### 方式二:通过 `@Component` 自动扫描 如果希望利用 Spring 容器管理过滤器实例,则可以直接将其实现标记为组件,并让其自动注入容器中。 修改上面的例子,添加注解即可完成注册: ```java import org.springframework.stereotype.Component; import javax.servlet.*; @Component public class MyCustomFilter implements Filter { ... } // 添加 @Component 注解 ``` 这种方式下,Spring Boot 会自动检测此类并将它作为一个 Bean 加入应用生命周期管理之中。 --- ##### 方式三:使用 `FilterRegistrationBean` 对于更复杂的场景或者需要指定特定属性的情况,比如设置 URL 映射规则、加载顺序等参数时,推荐采用 `FilterRegistrationBean` 来显式声明过滤器对象及其行为特征。 下面是一个例子展示如何定义这样的 bean 并对其进行个性化定制: ```java import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; @Configuration public class FilterConfiguration { @Bean public FilterRegistrationBean<MyCustomFilter> loggingFilter(){ FilterRegistrationBean<MyCustomFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MyCustomFilter()); registrationBean.addUrlPatterns("/api/*"); // 设置匹配路径 registrationBean.setOrder(1); // 设定优先级 return registrationBean; } } ``` 这里设置了 `/api/*` 下的所有访问都会触发这个过滤器工作,并且它的执行次序被安排得较早发生 (数值越低代表越先被执行)。 --- #### 日志记录注意事项 当涉及到日志功能扩展时,请注意遵循最佳实践建议 —— 使用专门的日志框架而非简单打印语句输出调试信息。例如 Logback 是非常流行的解决方案之一;按照官方文档指导调整项目结构有助于更好地控制消息流向及格式化样式[^3]。 最终效果应该是既满足功能性需求又能保持良好的维护性和性能表现。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值