概念
当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤
过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行过滤器放行代码下边的代码
注解配置
只要加上 @WebFilter
注解,并且访问 /*
的时候就会走这里,可以在打印的地方做一些拦截处理。
执行顺序:先拦截,如果通过的话就去请求资源,请求完资源再去执行放行后面的代码。也就是洋葱圈模型。
js
package cn.itcast.web.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* 过滤器快速入门程序
*/
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1、对request对象请求消息增强
System.out.println("filterDemo1被执行了....");
//2、放行
filterChain.doFilter(servletRequest,servletResponse);
// 3、获取资源(比如请求的一个servlet的jsp页面)
// 4、对response对象的响应消息增强
System.out.println("filterDemo1回来了...");
}
@Override
public void destroy() {
}
}
web.xml配置
web/WEB-INF/web.xml
xml
<filter>
<filter-name>demo1</filter-name>
<filter-class>cn.xxx.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器生命周期方法
- init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
- doFilter:每一次请求被拦截资源时,会执行。执行多次
- destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
过滤器配置详解
- 拦截路径配置:
- 具体资源路径:
/index.jsp
只有访问index.jsp资源时,过滤器才会被执行 - 拦截目录:
/user/*
访问/user下的所有资源时,过滤器都会被执行 - 后缀名拦截:
*.jsp
访问所有后缀名为jsp资源时,过滤器都会被执行 - 拦截所有资源:
/*
访问所有资源时,过滤器都会被执行
- 具体资源路径:
- 拦截方式配置:资源被访问的方式
- 注解配置:
- 设置dispatcherTypes属性
- REQUEST:默认值。浏览器直接请求资源
- FORWARD:转发访问资源
- INCLUDE:包含访问资源
- ERROR:错误跳转资源
- ASYNC:异步访问资源
- 设置dispatcherTypes属性
- web.xml配置
- 设置
<dispatcher></dispatcher>
标签即可
- 设置
- 注解配置:
java
package cn.itcast.web.filter;
import javax.servlet.*;
import java.io.IOException;
//@WebFilter("/index.jsp") //1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
//@WebFilter("/user/*") //2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
//@WebFilter("*.jsp") //3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
//浏览器直接请求index.jsp资源时,该过滤器会被执行
//@WebFilter(value="/index.jsp",dispatcherTypes = DispatcherType.REQUEST)
//只有转发访问index.jsp时,该过滤器才会被执行
//@WebFilter(value="/index.jsp",dispatcherTypes = DispatcherType.FORWARD)
//浏览器直接请求index.jsp或者转发访问index.jsp。该过滤器才会被执行
//@WebFilter(value="/*",dispatcherTypes ={ DispatcherType.FORWARD,DispatcherType.REQUEST})
public class FilterDemo5 implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("filterDemo5....");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
过滤器链(配置多个过滤器)
-
执行顺序:如果有两个过滤器:过滤器1和过滤器2。(洋葱圈模型)
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
-
过滤器先后顺序问题:
- 注解配置:按照类名的字符串比较规则比较,值小的先执行
- 如: AFilter 和 BFilter,AFilter就先执行了。
- web.xml配置:
<filter-mapping>
谁定义在上边,谁先执行
- 注解配置:按照类名的字符串比较规则比较,值小的先执行
综合例子
验证其是否登录,如果登录了,则直接放行。如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。
java
package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 登录验证的过滤器
*/
@WebFilter("/*")
public class LoginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println(req);
//0.强制转换
HttpServletRequest request = (HttpServletRequest) req;
//1.获取资源请求路径
String uri = request.getRequestURI();
//2.判断是否包含登录相关资源路径,要注意排除掉 css/js/图片/验证码等资源
if(uri.contains("/login.jsp") || uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/") || uri.contains("/checkCodeServlet") ){
//包含,用户就是想登录。放行
chain.doFilter(req, resp);
}else{
//不包含,需要验证用户是否登录
//3.从获取session中获取user
Object user = request.getSession().getAttribute("user");
if(user != null){
//登录了。放行
chain.doFilter(req, resp);
}else{
//没有登录。跳转登录页面
request.setAttribute("login_msg","您尚未登录,请登录");
request.getRequestDispatcher("/login.jsp").forward(request,resp);
}
}
// chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
综合例子2
对录入的数据进行敏感词汇过滤,敏感词汇参考《敏感词汇.txt》,如果是敏感词汇,替换为 *** 。
这里有个难点,我们通过过滤器拿到 req 对象的用户输入值,我们想把这个值替换后再赋值到 req 对象上然后交给 servlet,但是 req 对象没有赋值操作,那么就需要增强 req 对象的 getParameter 方法了,产生一个新的 req 对象。
java
package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* 敏感词汇过滤器
*/
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.创建代理对象,增强getParameter方法
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter方法
//判断是否是getParameter方法
if(method.getName().equals("getParameter")){
//增强返回值
//获取返回值
String value = (String) method.invoke(req,args);
if(value != null){
for (String str : list) {
if(value.contains(str)){
value = value.replaceAll(str,"***");
}
}
}
return value;
}
//判断方法名是否是 getParameterMap
//判断方法名是否是 getParameterValue
return method.invoke(req,args);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<String>();//敏感词汇集合
public void init(FilterConfig config) throws ServletException {
try{
//1.获取文件真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//2.读取文件
BufferedReader br = new BufferedReader(new FileReader(realPath));
//3.将文件的每一行数据添加到list中
String line = null;
while((line = br.readLine())!=null){
list.add(line);
}
br.close();
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}
}
public void destroy() {
}
}
代理 :https://blog.csdn.net/weixin_43972437/article/details/133687772