Filter:过滤器
1、概念:过滤器的作用:般用于完成通用的操作,如:登入验证,统一编码处理、敏感字符过滤…
快速入门:
- 创建一个web项目
- 定义一个类实现filter过滤器接口、从写方法。
- 将过滤器配置到web.xml中、
1、创建web的结构
2、filter类
/*
创建一个类实现javax.servlet.Filter接口、从写它里面的方法
init() --- 在你的服务启动时、会做数据的初始化、
doFilter() --- 过滤器的主要方法、对request、response做一些处理。
destroy() --- 在服务器关闭时销毁数据。
* */
public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filterConfig配置"+filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("进入过滤");
/*
这个调用chain.doFilter(request,response);//方法就是将执行下一个过滤器、或xxxServlet
如果没有下一个过滤就执行xxxServlet然后就会根据你的请求执行对应的get/post方法
* */
chain.doFilter(request,response);//简单来说这个就好比如过滤完成放行的意思
}
@Override
public void destroy() {
System.out.println("销毁过滤");
}
}
3、web.xml
<!-- 过滤器 -->
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>com.wei.config.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/a</url-pattern> <!-- 拦截路径-->
</filter-mapping>
<!--
<url-pattern>/a</url-pattern> 拦截路径
这里设置要过滤什么请求
-->
4、运行结果
把服务器关了后会执行销毁的方法。
5、案例小结
注意点
chain.doFilter(request,response);//简单来说这个就好比如过滤完成放行的意思
这个一定要放行
web.xml
<!-- 过滤器 -->
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>com.wei.config.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/a</url-pattern> <!-- 拦截路径-->
</filter-mapping>
<!--
<url-pattern>/a</url-pattern> 拦截路径
这里设置要过滤什么请求
配置要拦截的资源
以指定资源匹配。例如"/index.jsp"
以目录匹配。例如"/servlet/*"
以后缀名匹配,例如"*.jsp"
通配符,拦截所有web资源。"/*"
-->
多个过滤器执行的先后:
在web.xml中定义多个过滤、并指定你过滤同一个请求、最后他的执行先后是什么。
代码测试
1、创建多个xxxFilter类
public class AFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("A过滤");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
public class BFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("B过滤");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
2、配置webxml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- B过滤器 -->
<filter>
<filter-name>bFilter</filter-name>
<filter-class>com.wei.config.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>bFilter</filter-name>
<url-pattern>/abc</url-pattern> <!-- 拦截路径-->
</filter-mapping>
<!-- A过滤器 -->
<filter>
<filter-name>aFilter</filter-name>
<filter-class>com.wei.config.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>aFilter</filter-name>
<url-pattern>/abc</url-pattern> <!-- 拦截路径-->
</filter-mapping>
</web-app>
3、测试效果
B过滤
A过滤
进入UserServlet
4、小结
注意
在web.xml中定义多个过滤的执行效果可以看出来、<filter-mapping>
前面的过滤器会被先执行、后面的会接着执行
建议每个Filter做自己的逻辑判断、不要相互关联着。
注解版过滤器
使用注解开发、会减少大量代码、
代码测试
1、创建类实现Filter接口
@WebFilter(filterName = "AnnotationFilter",urlPatterns = {"/abc","/acd"})
public class AnnotationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("注解版过滤器");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
之前做过滤器都是创建好类之后、将过滤添加配置到web.xml中、配置过滤、使用注解后不用在web.xml中配置、简单来说就是使用注解来实现过滤器不用在web.xml中配置
2、测试结果
注解版过滤器
进入UserServlet
3、详解
@WebFilter() 注解
public @interface WebFilter {
String description() default "";
String displayName() default "";
WebInitParam[] initParams() default {}; //配置初始化参数,跟Servlet配置一样
String filterName() default ""; //设置过滤的名称、可以不写
String smallIcon() default "";
String largeIcon() default "";
String[] servletNames() default {};
String[] value() default {}; // 要过滤的资源路径或请求
String[] urlPatterns() default {}; // 要过滤的资源路径或请求
DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST}; //拦截方式配置:资源被访问的方式
boolean asyncSupported() default false;
}
没写注释的我就不知道什么意思了、自行百度。
注解属性使用
@WebFilter(filterName = "AnnotationFilter",
urlPatterns = {"/abc","/acd"},
dispatcherTypes = {DispatcherType.FORWARD},
initParams = {@WebInitParam(name = "a",value = "b")})
public class AnnotationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取注解的初始化的值
System.out.println(filterConfig.getInitParameter("a"));
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("注解版过滤器");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
要注意的就是这个属性
dispatcherTypes = {DispatcherType.FORWARD}
DispatcherType.XXXXX ---- 这个是设置拦截的类型
可以设置的值为:
1. REQUEST:默认值。浏览器直接请求资源
2. FORWARD:转发访问资源
3. INCLUDE:包含访问资源
4. ERROR:错误跳转资源
5. ASYNC:异步访问资源
设置了这个值、对资源的过滤就有一个过滤的条件、比如设置转发类型、在转发的地址、在@WebFilter
注解中设置了则此过滤器的被执行的路径、如果转发的地址不和注解中设置的过滤路径一样、则这个不执行该注解
如果有多个过滤器、一些过滤器是在web.xml中设置的一些是使用注解设置的过滤器该怎么办?会先运行谁?
- 注解配置:按照类名和字符串比较规则值小的先执行
- 如 AFilter 和 BFilter,AFilter就先执行
- web.xml配置
<filter-mapping>
谁定义在上边,谁先执行 - 优先执行web.xml中的过滤。
过滤器总结
- 过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行下一个过滤器或者servlet
- 过滤器生命周期方法
- init:在服务器启动后,会创建FIlter对象然后调用init方法。只执行一次。用于加载资源
- doFilter:每一次请求被拦截资源是会被创建。执行多次。
- destroy:在服务器正常关闭后,Filter对象被销毁、只执行一次。用于释放资源
- 多过滤器的执行顺序
- 注解配置:按照类名和字符串比较规则值小的先执行
- 如 AFilter 和 BFilter,AFilter就先执行
- web.xml配置
<filter-mapping>
谁定义在上边,谁先执行
敏感字过滤
敏感字过滤、常见于留言评论是出现辱骂、广告的一些词
技术所需
- servlet
- maven
前期准备
- 创建一个web项目
- 导入所需要的pom坐标
- 创建xxx.filter类、创建servlet
- 敏感字xx.txt文件
- 编写前端页面
最后实现的效果
- 将敏感字过滤掉、过滤后的敏感字设置为**
1、项目结构图
2、导入的pom依赖
<dependencies>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
3、xxx.servlet
@WebServlet("/a")
public class CharacterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
System.out.println("进入CharacterServlet");
String name = req.getParameter("name");
System.out.println("CharacterServlet的获取的>>>"+name);
req.setAttribute("flag",name);
req.getRequestDispatcher("index.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4、编写过滤器
/*
创建一个类实现javax.servlet.Filter接口、从写它里面的方法
init() --- 在你的服务启动时、会做数据的初始化、
doFilter() --- 过滤器的主要方法、对request、response做一些处理。
destroy() --- 在服务器关闭时销毁数据。
* */
@WebFilter(filterName = "CharacterFilter",urlPatterns = {"/a"})
public class CharacterFilter implements Filter {
private static List<String> list = null; // 敏感字集合
static {
BufferedReader br = null; // 字符缓存流
list = new ArrayList<String>();
try {
// 获取resources下指定文件路径
String fileName = CharacterFilter.class.getClassLoader().getResource("name.txt").getPath();//获取文件路径
// System.out.println(fileName);
br = new BufferedReader(new FileReader(fileName));
String str = null;
while ((str = br.readLine()) != null){ //读取数据
list.add(str); //添加到集合
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if (br != null) {
try {
br.close();//释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filterConfig配置"+filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("进入文字过滤");
//创建动态代理对象
ServletRequest Proxy_Request = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getParameter")) { // 判断是否是getParameter()、增强getParameter()方法
String value = (String) method.invoke(request, args); //增强返回值
if (value != null) {
for (String str : list) { //遍历敏感字
if (value.contains(str)) { // 验证是否包含
StringBuilder sb = new StringBuilder();
int length = str.length();
for (int i = 0; i < length; i++) {
sb.append("*"); // 添加星号
}
value = value.replace(str,sb.toString()); // 将敏感字替换为*、然后将值重新复制给value变量
}
}
}
return value; // 将新的值返回出去
}
return method.invoke(request,args); //执行方法
}
});
/*
这个调用chain.doFilter(request,response);//方法就是将执行下一个过滤器、或xxxServlet
如果没有下一个过滤就执行xxxServlet然后就会根据你的请求执行对应的get/post方法
* */
// 这里要注意这里传递过去的是增强后的代理对象
chain.doFilter(Proxy_Request,response);//简单来说这个就好比如过滤完成放行的意思/
}
@Override
public void destroy() {
System.out.println("销毁过滤");
}
}
5、敏感字xx.txt
xx
xxx
傻
//自行该敏感字
6、前端页面
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/a" method="post">
<input type="name" name="name">
<input type="submit" value="确定">
</form>
<h1>敏感词过滤结果>>>${flag != null ? flag : "无"}</h1>
</body>
</html>
7、测试结果
注意:
在实现filter类的doFilter()
方法中最为重要、当中使用了动态代理、对request中的getParameter()
进行了增强、将检查到的敏感字替换成***、将其后的结果做为最新的返回值返回。