SpringBoot(七)Filter的使用

    思考一个问题,服务端对于客户端的请求,真的应该照单全收吗?不是的。比如拿我们之前实现的用户注册功能来看,如果用户的昵称带了一些不友好的字母或汉字,你是给他过滤掉呢还是让他注册呢?毫无疑问,我们需要过滤掉一些不友好的请求。 

    如果你是新手,且没看过我之前的一系列SpringBoot文章,建议至少看一下这一篇:

SpringBoot(四)SpringBoot搭建简单服务端_springboot做成服务_heart荼毒的博客-CSDN博客​​​​​​​

    如果你想从头到尾系统地学习,欢迎关注我的专栏,持续更新:

https://blog.csdn.net/qq_21154101/category_12359403.html

目录

一、过滤器Filter

二、创建Filter

三、SpringBoot使用Filter

1、@WebFilter注解 + @ServletComponentScan注解

2、使用@Component注解

四、实践-敏感字过滤器


一、过滤器Filter

    Filter,过滤器,是在客户端和服务端之间用来过滤一些请求的中间件。它的作用通常包括以下几个方面:

1、Session校验

2、用户权限判断

3、敏感词过滤

4、设置编码等

    过滤器可以有0-多个,如下图所示:

二、创建Filter

    Filter是servlet下的一个接口。创建filter的方法比较简单,实现Filter接口就可以了。通常,我们不需要去修改init和destroy的实现,只需要去重写doFiler的方法就可以:

import javax.servlet.*;
import java.io.IOException;

public class TestFilter implements Filter {
    @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 {
        
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

三、SpringBoot使用Filter

    SpringBoot支持使用Filter,那么如何使用呢?有多种方式,除了狗都不用的配置方式外,在这里介绍两种方式。两种方式各有优缺点,可以根据自己的实际需要去使用。

1、@WebFilter注解 + @ServletComponentScan注解

    第一种方式,是分别在Filter的实现类使用@WebFilter注解(表明该类是一个Filter)并且在Application类添加ServletComponentScan注解(告诉Application去什么路径扫描Filter)。如下所示:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class TestFilter implements Filter {
    @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 {
        System.out.println("测试第一个过滤器");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan(basePackages = "com.zhaojun.server.filter")
public class AndroidServerApplication {

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

    运行一下项目,访问如下接口试试:

http://localhost:8080/register?name=hhh&phone=19999999999&password=123456

 可以看到,输出了如下日志,说明filter是生效的:

@WebFilter注解 + @ServletComponentScan注解的方式使用Filter,可以指定要拦截的url , 但是不能指定过滤器执行顺序。

2、使用@Component注解

    前面我们也说到了,filter可以有0-多个。在实际的项目中,我们可能有多个过滤器并且多个过滤器可能存在必要的先后顺序。那么,使用上面说到的第一种方式就无法满足我们的诉求。这种场景下,可以使用第二种方式@Component注解。如下:

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import java.io.IOException;

@Component
@Order(1)
public class Filter1 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("第1个过滤器");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import java.io.IOException;

@Component
@Order(2)
public class Filter2 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("第2个过滤器");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

    build一下,还是访问这个接口:

​​​​​​​http://localhost:8080/register?name=hhh&phone=19999999999&password=123456

    可以看到,Filter的执行顺序:

使用@Component注解的方式使用Filter,可以保证执行顺序, 但是过滤器不能指定拦截的url , 只能默认拦截全部。

四、实践-敏感字过滤器

    上面介绍了两种使用过滤器的方法,接下来,我们基于之前写的注册接口,去实现一个敏感字过滤器。当注册接口的请求含有敏感字时拦截该请求,不包含敏感字时放行。在这里,我使用的是第一种方式:

package com.zhaojun.server.filter;

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

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

    String[] sensitiveWords = {"sb", "2b", "cnm"};

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) servletResponse);
        String uri = request.getRequestURI();
        // 暂时只针对register接口过滤
        if (uri.contains("/register")) {
            String queryString = request.getQueryString();
            System.out.println(queryString);
            // 敏感字过滤校验通过,放行
            if (checkSensitiveWords(queryString)) {
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                // 校验不通过,重定向到fail接口
                wrapper.sendRedirect("/fail");
                System.out.println("敏感词过滤拦截");
            }
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    /**
     * 校验请求参数敏感字是否通过
     *
     * @param queryString 请求参数
     * @return true/false
     */
    private boolean checkSensitiveWords(String queryString) {
        for (int i = 0; i < sensitiveWords.length; i++) {
            if (queryString.contains(sensitiveWords[i])) {
                return false;
            }
        }
        return true;
    }
}

    如果敏感词校验没通过,重定向到的fail接口实现如下:

package com.zhaojun.server.controller;

import com.zhaojun.server.result.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterFailController {
    @RequestMapping("fail")
    public Result registerFail() {
        Result result = new Result();
        result.code = 0;
        result.status = "fail";
        result.msg = "昵称含有敏感字";
        return result;
    }
}

    请求接口试试,注意,这次使用一个包含敏感字的名字:​​​​​​​http://localhost:8080/register?name=2b&phone=19999999999&password=123456​​​​​​​

    可以看到,重定向到fail接口,并且输出了昵称含有敏感字:

    本篇介绍了Filter的作用,在SpringBoot中使用Filter的两种方式,并且介绍了两种方式的优缺点(顺序和指定url)。在最后,基于之前的注册接口,实现了一个简单的敏感字过滤器。如果你觉得这篇文章对你有帮助,欢迎留言或点赞。

猜你喜欢

转载自blog.csdn.net/qq_21154101/article/details/131717615
今日推荐