首页 > 其他分享 >Spring Boot中使用Filter过滤器

Spring Boot中使用Filter过滤器

时间:2022-11-30 16:55:39浏览次数:56  
标签:Spring Boot Filter 过滤器 import servlet public out

Filter过滤器

一、引入

在和管理员有关的Controller中,接口都需要判断当前用户是否为管理员,如果是管理员,则可以操作目录;如果不是管理员,则不能操作;这一连串的身份验证代码都是固定的,并且在每一个接口中都需要编写,显然代码没有得到重复利用。为了解决这一问题,可以使用Servlet规范中的Filter过滤器来解决这个问题。

二、Filter介绍

  • Filter是过滤器(是一个Java程序)
  • Filter可以在Servlet这个目标程序执行之前添加代码。也可以在目标Servlet执行之后添加代码。之前之后都可以添加过滤规则。
  • 一般情况下,都是在过滤器当中编写公共代码。

三、Filter实现(原始实现方式)

  • 第一步:编写一个Java类实现一个接口:jarkata.servlet.Filter。并且实现这个接口当中所有的方法。

    • init方法:在Filter对象第一次被创建之后调用,并且只调用一次。
    • doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。
    • destroy方法:在Filter对象被释放/销毁之前调用,并且只调用一次。
  • 第二步:注册Filter

    • 在web.xml文件中对Filter进行配置。这个配置和Servlet很像。

      • <filter>
            <filter-name>filter2</filter-name>
            <filter-class>com.bjpowernode.javaweb.servlet.Filter2</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filter2</filter-name>
            <url-pattern>*.do</url-pattern>
        </filter-mapping>
        
    • 或者使用注解进行注册:@WebFilter({"*.do"})

      • // 访问这个/abc路径就会执行这个过滤器
        @WebFilter("/abc")
        public class AdminFilter implements Filter {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
        
            }
        
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                
            }
        
            @Override
            public void destroy() {
        
            }
        }
        

四、Filter相关知识点

  • 注意:

    • Servlet对象默认情况下,在服务器启动的时候是不会新建对象的。
    • Filter对象默认情况下,在服务器启动的时候会新建对象。
    • Servlet是单例的。Filter也是单例的。(单实例)
  • 目标Servlet是否执行,取决于两个条件:

    • 第一:在过滤器当中是否编写了:chain.doFilter(request, response); 代码。(放行)
    • 第二:用户发送的请求路径是否和Servlet的请求路径一致。
  • chain.doFilter(request, response); 这行代码的作用:

    • 执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet
  • 注意:Filter的优先级,天生的就比Servlet优先级高。

    • /a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。
  • 关于Filter的配置路径:

    • /a.do、/b.do、/dept/save。这些配置方式都是精确匹配
    • /* 匹配所有路径
    • *.do 后缀匹配。不要以 / 开始
    • /dept/* 前缀匹配
  • 在web.xml文件中进行配置的时候,Filter的执行顺序是什么?

    • 依靠filter-mapping标签的配置位置,越靠上优先级越高。
  • 过滤器的调用顺序,遵循数据结构。

  • 使用@WebFilter的时候,Filter的执行顺序是怎样的呢?

    • 执行顺序是:比较Filter这个类名。
    • 比如:FilterA和FilterB,则先执行FilterA。
    • 比如:Filter1和Filter2,则先执行Filter1。
  • Filter的生命周期?

    • 和Servlet对象生命周期一致。
    • 区别:Filter默认情况下,在服务器启动阶段就实例化。Servlet不会。
  • Filter过滤器这里有一个设计模式:

    • 责任链设计模式
    • 过滤器最大的优点:
      • 在程序编译阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。
    • 责任链设计模式最大的核心思想:
      • 在程序运行阶段,动态的组合程序的调用顺序。

五、Spring Boot项目中使用Filter过滤器

过滤器是AOP(面向切面编程)思想的具体实现。可以过滤浏览器发出的请求,并且决定放行请求还是中断请求。

机制简述
在浏览器对服务器发起请求或者服务器对浏览器响应,都会经过过滤器。

基于过滤器的机制,我们可以在过滤器中对请求和响应做一些处理,可以在过滤器中决定是否放行,例如:校验请求中有没有敏感字符串,校验有没有Session,实现URL级别的权限控制、压缩响应信息、编码格式等。

5.1 Spring Boot使用过滤器的两种方式

  1. 使用spring boot提供的FilterRegistrationBean注册Filter
  2. 使用原生servlet注解@WebServlet,并在启动类上面增加注解@ServletComponentScan注册Filter

两种方法的本质都是一样的,都是去FilterRegistrationBean注册Filter

总结:定义Filter + 注册Filter

5.2 方法一:使用SpringBoot配置类实现

  • 定义一个Filter类
  1. 定义一个Filter类实现Filter接口
  2. 重写三个方法:init、doFilter、destory

AdminFilter.java



package com.kyk.imoocmall.filter;

import com.kyk.imoocmall.common.Constant;
import com.kyk.imoocmall.pojo.User;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 管理员校验过滤器
 * @FileName imooc-mall
 * @Author keyongkang
 * @Create 2022-11-30-9:14
 */

public class AdminFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        request.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        servletResponse.setCharacterEncoding("utf-8");

        HttpSession session = request.getSession();

        // 对当前用户进行校验
        User currentUser = (User)session.getAttribute(Constant.IMOOC_MALL_USER);

        if (currentUser == null) {
            // 用户未登录
            //return R.error(ImoocMallExceptionEnum.USER_NOT_LOGIN);
            PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();
            out.write("{\n" +
                    "    \"status\": 10007,\n" +
                    "    \"msg\": 用户未登录,\n" +
                    "    \"data\": null\n" +
                    "}");
            out.flush();
            out.close();
            return;
        }

        if (currentUser.getRole() != 2) {
            // 非管理员操作
            PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();
            out.write("{\n" +
                    "    \"status\": 10009,\n" +
                    "    \"msg\": \"当前用户不是管理员,无操作权限\",\n" +
                    "    \"data\": null\n" +
                    "}");
            out.flush();
            out.close();
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

该过滤器是用来校验管理员登录的。

  • 注册Filter

AdminFilterConfig.java

package com.kyk.imoocmall.config;

import com.kyk.imoocmall.filter.AdminFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Admin过滤器的配置
 * @FileName imooc-mall
 * @Author keyongkang
 * @Create 2022-11-30-9:30
 */

@Configuration //定义此类为配置类,必须添加!
public class AdminFilterConfig {
    @Bean
    public AdminFilter adminFilter() {
        return new AdminFilter();
    }

    // 使用spring boot提供的FilterRegistrationBean注册Filter
    @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;
    }
}

总结:自定义一个Filter,然后自定义AdminFilterConfig类,使用spring boot提供的FilterRegistrationBean注册Filter

5.3 方法二:使用原生servlet注解@WebFilter + @ServletComponentScan

  • 定义一个Filter类

在filter类上使用@WebFilter注解

package com.kyk.imoocmall.filter;


import com.kyk.imoocmall.common.Constant;
import com.kyk.imoocmall.pojo.User;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 管理员校验过滤器
 * @FileName imooc-mall
 * @Author keyongkang
 * @Create 2022-11-30-9:14
 */

@WebFilter(urlPatterns = "/admin/category/*") // 注意
public class AdminFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        request.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        servletResponse.setCharacterEncoding("utf-8");

        HttpSession session = request.getSession();

        // 对当前用户进行校验
        User currentUser = (User)session.getAttribute(Constant.IMOOC_MALL_USER);

        if (currentUser == null) {
            // 用户未登录
            //return R.error(ImoocMallExceptionEnum.USER_NOT_LOGIN);
            PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();
            out.write("{\n" +
                    "    \"status\": 10007,\n" +
                    "    \"msg\": 用户未登录,\n" +
                    "    \"data\": null\n" +
                    "}");
            out.flush();
            out.close();
            return;
        }

        if (currentUser.getRole() != 2) {
            // 非管理员操作
            //return R.error(ImoocMallExceptionEnum.NOT_ADMIN);
            PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();
            out.write("{\n" +
                    "    \"status\": 10009,\n" +
                    "    \"msg\": \"当前用户不是管理员,无操作权限\",\n" +
                    "    \"data\": null\n" +
                    "}");
            out.flush();
            out.close();
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}
  • 在启动类上面增加注解@ServletComponentScan开启Servlet支持
package com.kyk.imoocmall;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import springfox.documentation.oas.annotations.EnableOpenApi;

@EnableOpenApi
@SpringBootApplication
@MapperScan("com.kyk.imoocmall.mapper")
@ServletComponentScan("com.kyk.imoocmall.filter")  //扫描指定指定的filter包
public class ImoocMallApplication {

    public static void main(String[] args) {
        SpringApplication.run(ImoocMallApplication.class, args);
    }

}

注意:这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们需在启动类中加注解:@ServletComponetScan,指定扫描的包。

标签:Spring,Boot,Filter,过滤器,import,servlet,public,out
From: https://www.cnblogs.com/keyongkang/p/16939006.html

相关文章

  • Spring Cloud Consul
    3.1.2该项目通过自动配置为SpringBoot应用程序提供Consul集成并绑定到Spring环境和其他Spring编程模型习语。与一些简单的注释,您可以快速启用和配置内部的常见模......
  • Sharding-JDBC 原理和spring boot 核心配置文件说明
    1、分库分表策略:如每个数据记录属于一个集团ID、属于一个店铺ID列,可以根据集团ID%数据库数量取余设置规则分片键,及设置用哪个数据库和哪个表。同现可以使用数据记录中的......
  • SpringBoot Mongodb实战整合
    目录找出数组中,具有qid=1并且reorderFlag=0的记录找出数组中,qid=1或者reorderFlag=0的记录新增数组数据修改数组数据,根据条件批量修改嵌套数组的字段值删除数组数据......
  • SpringBoot 如何实现异步编程
    https://blog.csdn.net/m0_60028455/article/details/121650608 首先我们来看看在Spring中为什么要使用异步编程,它能解决什么问题?为什么要用异步框架,它解决什么问题?在......
  • Spring的AOP简介和Spring中的通知使用方法以及异常
    AOP中关键性概念连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出.目标(Target):被通知(被代理)的对象注1:完成具体的业务逻辑通知(Advice):在某个特定的......
  • 基于SpringBoot+Layui的物业管理系统【完整项目源码】
    使用建议业务逻辑简略,需要细化业务,增加业务开发,如未交费提醒等技术架构数据库:MySQL8.X后端技术:SpringBoot2.3.0,MyBatisPlus数据连接池:Druid前端技术:La......
  • springboot整合quartz达到动态配置定时任务的效果
    如题:首先贴上maven的配置<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>......
  • SpringCloud之Config分布式配置文件中心
    分布式系统面临的配置问题:微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息......
  • 论项目中日志处理的正确操作(springboot案例)
    理论和日志的重要不需要重复,各位都明白,企业中甩锅 查询记录  必要的东西,直接贴上代码案例 maven<dependency><groupId>org.springframework.boot</groupI......
  • SpringBoot整合Swagger生成接口文档
    介绍:Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。本文简单介绍了在项目中集成swagger的方法和一些常见问题。如果想深入分析项目源码,了解更多内容,见......