思考一个问题,服务端对于客户端的请求,真的应该照单全收吗?不是的。比如拿我们之前实现的用户注册功能来看,如果用户的昵称带了一些不友好的字母或汉字,你是给他过滤掉呢还是让他注册呢?毫无疑问,我们需要过滤掉一些不友好的请求。
如果你是新手,且没看过我之前的一系列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)。在最后,基于之前的注册接口,实现了一个简单的敏感字过滤器。如果你觉得这篇文章对你有帮助,欢迎留言或点赞。