# Filter:过滤器
1. 概念:
* 生活中的过滤器:净水器,空气净化器,土匪、
* web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
* 过滤器的作用:拦截请求增强其功能
* 一般用于完成通用的 *** 作。如:登录验证(登陆过才能访问资源,直接访问list.jsp地址如果不登陆的话会拦下来不显示界面而会直接要求登录)、
统一编码处理(post很多地方需要设置编码 把设置编码的任务放在过滤器中来写简化代码)
敏感字符过滤(敏感字符用***表示)
过滤器形象举例:我去外婆家 有一条山路 山路上有好土匪 去的时候说前面要下雨给一把伞增强了功能 回来之后还拦我又增强了功能
注意来回都栏 而且增强功能的含义是什么
注意下面图片中的浏览器 服务器 请求 资源的标注
2. 快速入门:
1. 步骤:
1. 定义一个类,实现接口Filter(类似于实现servlet)
2. 复写方法
3. 配置拦截路径(与servlet不同 servlet配置的是访问路径 filter配置的是拦截路径)
1. web.xml
2. 注解
2. 代码:
package cn.itcat.web.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * 过滤器快速入门 */ @WebFilter("/*")//访问所有资源之前都会执行该过滤器 public class FilterDemo01 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() { } }
index.jsp
3. 过滤器细节:
1. web.xml配置 这里也可以直接注解配置
demo1
cn.itcast.web.filter.FilterDemo1
demo1
/*
demo01 cn.itcat.web.filter.FilterDemo01 demo01 /*
2. 过滤器执行流程
1. 执行过滤器
2. 执行放行后的资源
3. 回来执行过滤器放行代码下边的代码注意颜色对应
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//chain.doFilter();之前对request对象的请求消息进行增强
System.out.println("filterDemo02执行了....");
//放行
chain.doFilter(req, resp); 可以是index.jsp中的资源
//chain.doFilter();之后对response对象的响应消息进行增强
System.out.println("filterDemo02回来了....");};
@WebFilter("/*") public class FilterDemo02 implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { //chain.doFilter();之前对request对象的请求消息进行增强 System.out.println("filterDemo02执行了...."); //放行 chain.doFilter(req, resp); //chain.doFilter();之后对response对象的响应消息进行增强 System.out.println("filterDemo02回来了...."); } public void init(FilterConfig config) throws ServletException { } public void destroy() { } } ------------------------------------------------------------------- index.jsp: <%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$ index.jsp <% System.out.println("index.jsp...."); %>控制台输出:
先打印FilterDemo02中的放行前的filterDemo02执行了....
再放行
再请求资源打印index.jsp中的代码index.jsp...
再回来直接执行FilterDemo02中过滤器放行下面的代码 打印过滤器后面的filterDemo02....回来了
注意:
//chain.doFilter();之前对request对象的请求消息进行增强
//放行
chain.doFilter(req, resp);
//chain.doFilter();之后对response对象的响应消息进行增强
3. 过滤器生命周期方法
1. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源 注意是启动服务器就执行
2. doFilter:每一次请求被拦截资源时,会执行。执行多次注意这里可以理解为访问index.jsp就执行
3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源注意这里是停掉服务器执行
4. 过滤器配置详解
* 拦截路径配置:4种
1. 具体资源路径: /index.jsp /servletDemo01 只有访问index.jsp或者某个特定资源资源时,过滤器才会被执行
2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行@WebServlet("/user/servletDemo01") //加一个目录统一管理 访问时也要加整个目录才能找到
3. 后缀名拦截: *.jsp /*.do/*.action 访问所有后缀名为jsp资源时,过滤器都会被执行 注意后缀名拦截没有/
4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行
* 拦截方式配置:资源被访问的方式 2种
* 注解配置:(是在注解中写的)
* 设置dispatcherTypes属性 有五种取值可以设置
1. REQUEST:默认值。浏览器直接请求资源@WebFilter(value="/*",dispatcherTypes = DispatcherTypeREQUEST)//注意设置两个值就要加名字了 浏览器直接请求index.jsp资源时,过滤器才会被执行
2. FORWARD:转发访问资源@WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.FORWARD)
还可以同时request和forward 用大括号
@WebFilter(value = "/index.jsp",dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})
3. INCLUDE:包含访问资源---了解
4. ERROR:错误跳转资源---了解
5. ASYNC:异步访问资源---了解
* web.xml配置-----感觉用的不多
* 在下面直接设置 标签即可
5. 过滤器链(配置多个过滤器)
* 执行顺序:如果有两个过滤器:过滤器1和过滤器2比如一条路两个土匪你过去拿资源再回来 也是这么个顺序
1. 过滤器1
2. 过滤器2
3. 资源执行
4. 过滤器2
5. 过滤器1* 过滤器先后顺序问题:
1. 注解配置:按照类名的字符串比较规则比较,值小的先执行字符串的比较规则:每个字符逐字比较大小
* 如: AFilter 和 BFilter,AFilter就先执行了。
2. web.xml配置:谁定义在上边,谁先执行 浏览器访问index.jsp
控制台打印:
filterDemo06被执行
filterDemo17被执行
index.jsp....
filterDemo17回来了
filterDemo06回来了
4. 案例:
1. 案例1_登录验证
* 需求:
1. 访问day17_case案例的资源。验证其是否登录
2. 如果登录了,则直接放行。
3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。
注意:1.过滤器配置的拦截路径/*
2.哪些资源是登陆相关的:login.jsp 显示index.jsp里面的验证码 css js样式 点击登录按钮访问的loginservlet等
代码:
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 { //1.强转ServletRequest req为HttpServletRequest HttpServletRequest request= (HttpServletRequest) req; //2.获取资源的请求路径 String uri = request.getRequestURI(); //3.判断是否包含登录相关的资源路径 要注意排除css /js /图片 /验证码等资源 if (uri.contains("/login.jsp")||uri.contains("/loginServlet")||uri.contains("/checkCode")||uri.contains("/css/")||uri.contains("/js/")||uri.contains("/fonts/")){ //包含证明用户就是想登录直接放行 chain.doFilter(req, resp); }else{ //不包含的话需要验证用户是否登录 //从session里面获取user Object user = request.getSession().getAttribute("user"); if (user!=null){ //user不等于null说明登陆了可以放行 chain.doFilter(req, resp); }else{ //没有登陆跳转登录页面 跳转之前存点提示信息 request.setAttribute("login_msg","您尚未登录,请登录!"); request.getRequestDispatcher("/login.jsp").forward(request,resp); } } /*chain.doFilter(request, response);*/ } public void init(FilterConfig config) throws ServletException { } public void destroy() { } }
2. 案例2_敏感词汇过滤
* 需求:
1. 对day17_case案例录入的数据进行敏感词汇过滤
2. 敏感词汇参考《敏感词汇.txt》
3. 如果是敏感词汇,替换为 ***注意这里想一个问题 doFilter()的参数req和resp其实就是浏览器的请求 dofilter放行之后再传下去 到资源
* 分析:
1. 对request对象进行增强。产生一个新的reqquest对象 增强获取参数相关方法
2. 放行。传递新的request对象 传递代理对象代码:
* 增强对象的功能: 注意代理的是对象 增强的也是对象
* 设计模式:一些通用的解决固定问题的方式 --------用设计模式来实现增强对象的功能
1. 装饰模式
2. 代理模式
* 概念:概念举例:好比说我要去买联想电脑,联想的总部在北京厂在北京,联想公司的功能可以生产电脑卖电脑,我作为一个购买者,一种方式去北京买;现在代理商出现了,西安的联想代理商功能是卖电脑,我可以直接在西安的联想代理商用他的卖电脑的功能,但是西安代理是能卖电脑吗其实是北京联想的一个代理对象,我调用的是代理对象,代理对象要调用联想公司的卖电脑功能;我省了事省力
1. 真实对象:被代理的对象------------------------联想北京
2. 代理对象:--------------------------------- --------西安联想代理商
3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
* 实现方式:两种 静态和动态代理
1. 静态代理:有一个类文件描述代理模式
2. 动态代理:在内存中形成代理类
* 实现步骤:
1. 代理对象和真实对象实现相同的接口
2. 代理对象 = Proxy.newProxyInstance();
3. 使用代理对象调用方法。
4. 增强方法* 增强方式:
1. 增强参数列表
2. 增强返回值类型
3. 增强方法体执行逻辑
代码:
注意思考为什么直接代理的测试类 中就有 proxy_lenovo 而没有代理类
因为是在内存中形成代理类而不展示出来
接口:SellComputer package cn.itcat.proxy; public interface SellComputer { public String sell(double money); public void show(); } 真实类 package cn.itcat.proxy; /** * 真实类 对应一个真实对象 联想的两个功能 sell show */ public class Lenovo implements SellComputer { @Override public String sell(double money) { System.out.println("花"+money+"买了一台联想电脑"); return "联想电脑"; } @Override public void show() { System.out.println("展示电脑"); } } ---------------------------------------------------------------------------------- 代理测试类 package cn.itcat.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) { //创建真实对象 Lenovo lenovo = new Lenovo(); //2.动态代理来增强lenovo对象 /* 三个参数: 1.类加载器:真实对象.getClass().getClassLoader() 2.接口数组:真实对象.getClass().getInterfaces() 3.处理器 : new InvocationHandler() */ /* 强转*/ /* Objext-->sellcomputer 这样就可以使用sellcomputer的方法了*/ SellComputer proxy_lenovo = (SellComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() { //proxy_lenovo就是代理对象 注意但是没有代理类 代理类是直接生成在内存中 /*下面重写的是代理逻辑编写的方法 代理对象调用的所有方法都会触发该方法执行 invoke();方法的三个参数: 1.proxy 代理对象 2.method 代理对象调用的方法被封装为的对象 3.args: 参数列表:代理对象调用的方法时,传递的实际参数 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*System.out.println("该方法执行了...."); System.out.println(method.getName()); System.out.println(args[0]);*/ //增强参数: //判断是否是sell方法 if (method.getName().equals("sell")) { //1.增强参数 double money = (double) args[0]; money = money * 0.85; System.out.println("专车接你"); String obj = (String) method.invoke(lenovo, money); System.out.println("免费送货"); return obj+"送一个鼠标垫"; //这里返回的就是lenovo的代理对象proxy_lenovo中的sell();方法的输出 } else { //使用真实对象调用该方法 Object obj = method.invoke(lenovo, args); //这里的前一个参数是真实对象 后一个参数是参数 就是后面.sell中的8000 return obj; /* 返回下面调用 obj-->computer*/ } } }); //2.调用方法 /*上面的obj就是这里的computer*/ String computer = proxy_lenovo.sell(8000); // proxy_lenovo是代理对象代理了对象真实lenono 这里用代理对象调用的方法跟由Lenovo类创建的lenovo真实对象中有的方法一致 System.out.println(computer); proxy_lenovo.show(); //show就是原样调用 } }
控制台输出:
专车接你
花6800.0买了一台联想电脑
免费送货
联想电脑送一个鼠标垫
展示电脑
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)