Spring Boot-Filter过滤器使用

零、本文纲要

  • 一、Filter作用
  • 二、Filter使用
    1、基础准备
    2、编写Filter
    3、扫描Filter
    4、测试
  • 三、使用总结
  • 补充:完整Filter实现类代码

一、Filter作用

  • ① 权限控制;

  • ② 对request、response拦截处理;

  • ③ 公共代码提取。

二、Filter使用

1、基础准备

  • ① 引入依赖


    org.springframework.boot
    spring-boot-starter



    org.springframework.boot
    spring-boot-starter-test
    test



    org.springframework.boot
    spring-boot-starter-web
    compile

  • ② 编写配置文件
server:
  port: 8080
  • ③ 编写启动类
@Slf4j // lombok 提供的日志注解,方便直接使用 log 输出指定日志
@SpringBootApplication
public class TemplateApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReggieApplication.class, args);
        log.info("项目启动成功!");
    }
}

2、编写Filter

  • 基础:Filter接口
public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; // 此处关注此方法

    default void destroy() {
    }
}

此处我们重点关注doFilter方法,编写实现类重写该方法。

  • ① 编写登录过滤器

Ⅰ 在自定义Filter实现类上使用@WebFilter注解;

Ⅱ 自定义filterName(随意,不要与其他Filter重复即可);

Ⅲ 定义urlPatterns此处设置为"/*",表示拦截所有请求;

/**
 * 检查用户是否已经登录的过滤器
 */
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
            ... ...
    }
}
  • ② 编写详细方法体

Ⅰ 将传入的requestresponse对象转换为Http类型

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;

Ⅱ 自定义不需要处理的URI数组

// 定义不需要处理的请求路径
String[] urls = new String[]{
        "/employee/login", // 员工登录
        "/employee/logout", // 员工登出
        "/backend/**", // 管理后台静态资源
        "/front/**", // 移动端静态资源
        "/common/**", // 通用部分
        "/user/sendMsg", // 移动端短信验证码
        "/user/login" // 移动端登录
};

Ⅲ 获取请求URI

// A. 获取本次请求的URI
String requestURI = request.getRequestURI();

Ⅳ 判断本次请求

// B. 判断本次请求, 是否需要登录, 才可以访问
boolean check = checkURI(urls, requestURI);

封装checkURI方法,如下:

a、注入PATH_MATCHER,用于路径比较,如下:

// Spring 框架提供的用于路径比较的类:路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

b、方法体,如下:

/**
 * 路径匹配,检查本次请求是否需要放行
 * @param urls 需放行的 urls
 * @param requestURI 请求进来的 URI
 * @return 放回结果
 */
public boolean checkURI(String[] urls, String requestURI){
    for (String url : urls) {
        boolean match = PATH_MATCHER.match(url, requestURI);
        if (match) return true;
    }
    return false;
}

Ⅴ 不需要拦截,则直接放行

// C. 如果不需要拦截,则直接放行
if (check){
    log.info("本次{}请求不需要处理!", requestURI);
    filterChain.doFilter(request, response);
    return;
}

Ⅵ 其余路径,判断登录状态

a、已登录,则放行

BaseContext是自定义存储线程userId的类

// D. 判断登录状态,如果已登录,则直接放行
// 【EMPLOYEE】:用于员工登录判断
Long empId = (Long) request.getSession().getAttribute(CUR_EMPLOYEE);
if (empId != null){
    log.info("用户已登录,用户ID为:{}", empId);
    // 将 empId 存入 ThreadLocal
    BaseContext.setCurrentId(empId);

    filterChain.doFilter(request, response);
    return;
}
// 【USER】:用于用户登录判断
Long userId = (Long) request.getSession().getAttribute(CUR_USER);
if (userId != null){
    log.info("用户已登录,用户ID为:{}", userId);
    // 将 userId 存入 ThreadLocal
    BaseContext.setCurrentId(userId);

    filterChain.doFilter(request, response);
    return;
}

b、未登录,拦截

自定义常量

public static final String NOT_LOGIN = "NOTLOGIN"; // LoginCheckFilter 拦截器使用

拦截,此处使用response向前端返回响应数据R.error(NOT_LOGIN)

// E. 如果未登录, 则返回未登录结果
// 通过输出流方式,向客户端页面响应数据
log.info("用户未登录!");
response.getWriter().write(JSON.toJSONString(R.error(NOT_LOGIN)));

3、扫描Filter

在启动类上添加@ServletComponentScan注解,用于扫描 @WebFilter 注解,如下:

@Slf4j // lombok 提供的日志注解,方便直接使用 log 输出指定日志
@SpringBootApplication
@ServletComponentScan // 扫描 @WebFilter 注解
public class ReggieApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReggieApplication.class, args);
        log.info("项目启动成功!");
    }
}

4、测试

编写Controller类,启动测试。

三、使用总结

  • ① 拦截所有请求;
  • ② 自定义放行URI数组;
  • ③ 对比放行URI数组直接放行;
  • ④ 未直接放行部分判断条件,满足放行;
  • ⑤ 不满足,使用response对象返回结果响应。

补充:完整Filter实现类代码

/**
 * 检查用户是否已经登录的过滤器
 */
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {

    // Spring 框架提供的用于路径比较的类:路径匹配器,支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // A. 获取本次请求的URI
        String requestURI = request.getRequestURI();
        log.info("拦截到请求:{}", requestURI);
        // 定义不需要处理的请求路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**",
                "/user/sendMsg", // 移动端短信验证码
                "/user/login" // 移动端登录
        };

        // B. 判断本次请求, 是否需要登录, 才可以访问
        boolean check = checkURI(urls, requestURI);

        // C. 如果不需要拦截,则直接放行
        if (check){
            log.info("本次{}请求不需要处理!", requestURI);
            filterChain.doFilter(request, response);
            return;
        }

        // D. 判断登录状态,如果已登录,则直接放行
        // 【EMPLOYEE】:用于员工登录判断
        Long empId = (Long) request.getSession().getAttribute(CUR_EMPLOYEE);
        if (empId != null){
            log.info("用户已登录,用户ID为:{}", empId);
            // 将 empId 存入 ThreadLocal
            BaseContext.setCurrentId(empId);

            filterChain.doFilter(request, response);
            return;
        }
        // 【USER】:用于用户登录判断
        Long userId = (Long) request.getSession().getAttribute(CUR_USER);
        if (userId != null){
            log.info("用户已登录,用户ID为:{}", userId);
            // 将 empId 存入 ThreadLocal
            BaseContext.setCurrentId(userId);

            filterChain.doFilter(request, response);
            return;
        }

        // E. 如果未登录, 则返回未登录结果
        // 通过输出流方式,向客户端页面响应数据
        log.info("用户未登录!");
        response.getWriter().write(JSON.toJSONString(R.error(NOT_LOGIN)));
    }

    /**
     * 路径匹配,检查本次请求是否需要放行
     * @param urls 需放行的 urls
     * @param requestURI 请求进来的 URI
     * @return 放回结果
     */
    public boolean checkURI(String[] urls, String requestURI){
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if (match) return true;
        }
        return false;
    }
}

四、结尾

以上即为Filter基础使用的内容,感谢阅读。

你可能感兴趣的:(Spring Boot-Filter过滤器使用)