Filter:过滤器
-
filter是web中的过滤器
-
功能:
用来拦截客户端和浏览器之间的请求,request请求和response请求都会拦截 -
作用:
一般用于完成通用的操作,如:登录验证,统一编码处理,敏感字符过滤等等 -
快速入门:
-
步骤
- 定义一个类,实现接口Filter(javax包下的Filter)
- 复写方法
- 配置拦截路径的方法有两个
- web.xml
- 注解:例:
- @WebFilter("/*") //访问所有资源之前都会执行该过滤器
- @WebFilter("/demo.jsp*") //只有访问demo.jsp时才会执行该过滤器
-
代码
package cn.itcast.web.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/*") //‘/*’是不管什么url,都拦截 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 { System.out.println("filter被执行了..."); //放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
-
过滤器细节
-
web.xml配置
<filter> <filter-name>demo1</filter-name> <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>demo1</filter-name> <url-pattern>/*</url-pattern> <!--拦截路径--> </filter-mapping>
-
过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行过滤器放行代码下面的代码
-
过滤器生命周期方法
- init: 在服务器启动后,会创建Filter对象,然后调用init方法。一般用于加载资源
- doFilter:每一次请求被拦截资源时,会执行
- destory:在服务器关闭后,Filter对象被销毁。如果服务器正常关闭,则会执行destory方法,用于释放资源
-
过滤器配置详解
- 拦截路径配置:
- 具体资源路径:/index.jsp 只有访问index.jsp资源时,过滤器才会执行
- 目录拦截:/user/* 访问/user下的所有资源时过滤器都会被执行
- 后缀名拦截:*.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
- 拦截所有资源:/* 访问所有资源时过滤器都会被执行
- 拦截方式配置
- 拦截路径配置:
-
过滤器链(配置多个过滤器)
- 执行顺序:如果有两个过滤器A和B,A放在B的前面
- 先执行过滤器A再执行B,之后是访问资源,然后再执行过滤器B,再是A。
- 先后顺序:
- 注解方式配置:按照类名的字符串比较规则,值小的先执行。如:AFilter和BFilter,比较出来的是AFilter先执行。
- web.xml方式配置,哪个过滤器配置放在前面哪个过滤器先执行。
- 执行顺序:如果有两个过滤器A和B,A放在B的前面
-
-
-
案例:
- 案例1,登录案例:
-
访问某个资源时需要验证其是否登录,如果登录了就放行,没有登录就跳转到登录页面,并提示用户登录。
@WebFilter("/*") public class FilterDemo4 implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { //想要获取用户当前访问的路径,就需要用到getRequestURI(),而这个方法在HttpServletRequest中,所以这儿需要强制转换。 HttpServletRequest request = (HttpServletRequest) resp; String uri = request.getRequestURI(); //如果包含登录页面就放行 //这儿也需要对一些css样式和js等其它的进行放行。 if (uri.contains("/login.jsp") || uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/")) { chain.doFilter(req, resp); } else { //不包含,需要验证用户是否登录。用户登录过后会有个session,根据这个来判断是否登录 //从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 { } }
-
- 案例2,敏感词汇过滤
- 需求:对录入的数据进行敏感词汇过滤,敏感词汇放在《敏感词汇.txt》,将敏感词汇替换为***。
- 分析:对request对象进行增强
- 为什么要增强?
当我们可以根据request获取parameter,那怎样修改这个参数呢?request对象中是否有setparameter呢,当然是没有的。因此在这里就需要增强request对象。 - 增强对象的功能:
设计模式:一些通用的解决问题的方式- 装饰模式:增强对象的功能
- 代理模式:增强对象的功能
- 概念:
- 真实对象:被代理的对象
- 代理对象:
- 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的。
- 实现方式:
- 静态代理:有一个类文件描述代理模式
- 动态代理:在内存中形成代理类
- 实现步骤:
- 代理对象和真实对象实现相同的接口
- 代理对象 = Proxy.newProxyInstance();
- 使用代理对象调用方法。
- 增强方法
- 增强方式:
- 增强参数列表
- 增强返回值类型
- 增强方法体执行逻辑
动态代理代码举例:
package Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { //1.创建真实对象 Lenovo lenovo = new Lenovo(); //2.动态代理增强Lenovo对象 /* 三个参数 1.类加载器:与真实对象相同的类加载器 2.接口数组:真实对象所实现的所有接口 3.处理器 */ SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() { /* 代理对象调用的所有方法都会触发这个方法执行 */ @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { //判断是否是sale方法 if(method.getName().equals("sale")) { //1.增强参数 double money = (double)objects[0] * 0.85; System.out.println("专车接"); String obj = (String)method.invoke(lenovo, money); System.out.println("免费送货"); //2.增强返回值 return obj+"_鼠标垫"; } else { Object obj = method.invoke(lenovo, objects); return obj; } } }); //2.调用方法 String sale = proxy_lenovo.sale(8000); System.out.println(sale); } }
- 实现步骤:
- 概念:
- 为什么要增强?
- 案例1,登录案例:
敏感词汇过滤:
package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
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(filterName = "MinGanCiHuiFilter")
public class MinGanCiHuiFilter implements Filter {
public void destroy() {
}
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 o, Method method, Object[] objects) throws Throwable {
//增强getParameter方法
//判断是否是这个方法
if(method.getName().equals("getParameter")) {
//增强返回值
//获取返回值
String value = (String)method.invoke(req, objects);
if(value != null) {
for (String str:list) {
if(value.contains(str)) {
value = value.replaceAll(str,"***");
}
}
}
return value;
}
return method.invoke(req,objects);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<>(); //敏感词汇集合
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 (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}