JavaWeb笔记(13)-Filter

  1. Servlet,Filter,Listener称为JavaWeb的三大组件
  2. Filter:过滤器
1. web过滤器:
    -- 当浏览器访问服务器资源时,过滤器可以将请求拦截下来,并可以增加其一些特殊功能
2. 过滤器作用:完成一些访问资源的通用操作
    * 一般用于完成登陆校验功能,只有登陆过后才能看到其他资源
    * 可以用于设置编码功能
    * 敏感字符过滤
3. 实现过滤器步骤:
    a. 自定义一个类,实现接口Filter 
        -- 组件servlet实现接口Servlet
        -- 选择javax.servlet.*包下的Filter
    b. 实现接口中的抽象方法
        -- init:服务器启动时执行唯一一次 -- 一般用于申请加载资源
        -- doFilter:实现过滤器的特殊功能,每有一次请求被拦截时,调用一次该方法
        -- destroy:服务器正常关闭时,调用该方法 -- 一般用于释放资源
    c. 配置过滤拦截路径
        * 使用注解配置@WebFilter("servlet的urlPattern")
            -- 在注解中添加urlPattern后,表示当访问该资源时,过滤器将起作用
                例如:"/index.jsp" "/demoServlet"
            -- "/*"表示拦截所有的资源请求
        * web.xml中配置
            1. 先声明filter
                <filter>
                    <filter-name>demo1_filterName</filter-name>
                    <filter-class>过滤器类名的全路径</filter-class>
                </filter>
            2. 映射拦截路径
                <filter-mapping>
                    <filter-name>demo1_filterName</filter-name>
                    <url-pattern>/*</url-pattern>
                </filter-mapping>
                -- url-pattern表示拦截的路径
    d. 拦截与放行请求:
        -- 如果没有执行放行语句,则默认就是拦截下来
        -- 在实现抽象方法doFilter中进行放行操作:
            filterChain.doFilter(servletRequest, servletResponse);
4. 过滤器执行流程
    a. 在doFilter成员方法中执行放行前操作:
        * 一般对到来的request中存储的数据进行判定
        * 因此,放行前操作一般是对请求进行增强操作
            sout("放行前,被拦截了的操作!");
    b. 在doFilter成员方法合适位置进行放行操作:
        filterChain.doFilter(servletRequest, servletResponse);
        -- 此时,请求到达资源,如果资源文件中有jsp脚本,则执行其中代码
    c. 在doFilter成员方法中执行放行后操作:
        * 放行后操作:指请求到达服务器后,服务器做出响应,此时响应再次经过Filter
        * 此时,响应不再执行放行前操作,而是执行放行后操作
        * 因此,放行后操作一般是对响应进行增强操作
5. Filter的拦截路径和拦截方式:
    a. 拦截路径:
        1. 具体路径:"/index.jsp"
            只有访问该路径的具体资源时,过滤器才起作用
        2. 目录拦截:"/user/*"
            访问该目录下的所有资源时,过滤器被执行
            -- 给不同的servlet(可以在不同的目录下)加上相同的urlPattern父目录,则表示这些servlet在同一目录下
            -- 此时,访问该servlet资源时,同样需要加上该虚拟父目录
                例如:
                    @WebServlet("/user/testServlet")
                    public class TestServet extends HttpServlet{}
                    
                    @WebServlet("/user/demoServlet")
                    public class DemoServet extends HttpServlet{}
        3. 后缀名拦截:"*.jsp"
            访问所有jsp后缀资源时,过滤器被执行
        4. 拦截所有:"/*"
            访问所哟资源时,过滤器被执行
    b. 拦截方式:
        拦截方式配置:指对资源被访问的方式进行过滤拦截
            -- 例如:浏览器直接请求访问,服务器内部转发
            -- 配置拦截方式后,仅拦截通过该方式的资源访问
        1. 拦截方式的属性:
            * 注解配置:
                a. 设置dispatcherTypes属性值:
                    1. REQUEST:默认值。浏览器直接访问资源
                    2. FORWARD:转发访问资源
                    3. INCLUDE:包含访问资源
                    4. ERROR:错误跳转资源 -- 即如果在jsp页面中设置了isErrorPage会发生错误跳转时过滤器生效
                    5. ASYNC:异步访问资源
                b. dispatcherTypes属性值是一个数组,可以同时设置多个拦截方式{REQUEST,FORWARD}
            * web.xml配置:
                a. 配置<filter></filter>标签
                b. 配置<filter-mapping></filter-mapping>标签
                c. 在filter-mapping标签内添加<dispatcher></dispatcher>标签并设置拦截方式
6. 过滤器链(多个过滤器叠加)
    a. 执行顺序:
        1. 如果有多个过滤器Filter_1, Filter_2, ... Filter_n
        2. 过滤器拦截时,依次执行Filter_1, Filter_2, ... Filter_n的放行前操作
        3. 所有过滤器Filter_1, Filter_2, ... Filter_n都放行后,访问到资源
        4. 请求返回时,依次执行Filter_n, ... Filter_2, Filter_1的放行后操作
    b. 过滤器优先级
        1. 注解配置:
            * 按照类名的字符串比较规则比较,较小者优先执行
            例如:AFilter先于BFilter先执行
        2. web.xml配置:
            * 哪个过滤器的filter-mapping定义在上面哪个先执行
  1. 增强对象功能:
1. 装饰者模式:
2. 代理模式:
    a. 静态代理:
        有明确的代理类文件定义
    b. 动态代理:
        代理类仅存在于内存中
        1. 创建代理对象与真实对象需要实现的共同接口
        2. 创建真实对象,实现该接口
        3. 创建代理对象:
            * 调用内置Proxy.newProxyInstance()成员方法创建一个代理对象
            * 成员方法需要传入三个参数:
                1. 真实对象的类构造器:真实对象.getClass().getClassLoader()
                2. 真实对象实现的抽象接口:真实对象.getClass().getInterfaces()
                3. 处理器:new InvocationHandler() {}
        4. 实现匿名内部类(处理器)的成员方法,用于增强真实对象
            * public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //增强的内容
            }
            * 处理器的成员方法三个参数:
                1. 代理对象自身:proxy
                2. 代理对象调用的成员方法:method -- 利用反射实现,将成员方法封装为一个Method对象
                3. 代理对象调用成员方法的参数:args
        5. 使用Proxy创建的代理对象调用接口中定义的方法
            * 每次调用成员方法都会执行依次处理器中的invoke成员方法
            * 增强逻辑都将写在invoke成员方法中
                Object obj = method.invoke(真实对象, args);
                代理对象调用哪个成员方法,在处理器的invoke成员方法中,就会利用反射实现真实对象使用args参数执行相同的method成员方法
                obj为真实对象执行完成员方法的返回值
                处理器中invoke成员方法的返回值,应该返回真实对象成员方法的返回值obj
3. 增强方式:
    a. 增强参数列表
        1. 在invoke方法中对args参数进行修改
        2. 对明确的参数对象修改时进行强转修改
    b. 增强返回值
        1. 在invoke方法在,对method.invoke(真实对象, args)的返回值进行修改
        2. 对明确的返回值对象进行修改时进行强转修改
    c. 增强方法体
        1. 在invoke方法中,在method.invoke()调用前后进行增强逻辑的书写
    d. 增强方法名
        由于每一次调用成员方法都会调用一次invoke方法
        对于不同的成员方法不需要不同的增强时,需要在invoke中对method.getName()进行判定,再区分增强
4. 例如:增强过滤器中的getParameter方法,用于敏感词过滤
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1. 创建代理对象
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), (proxy, method, args) -> {
            //2. 增强getParameter方法
            if (method.getName().equals("getParameter")) {
                //3. 增强返回值,进行敏感词替换
                String words = (String) method.invoke(req, args);
                for (String s : list) {
                    if (words.contains(s)) {
                        words.replaceAll(s, "***");
                    }
                }
                return words;
            }
            //3. 增强getParameterMap方法,过滤从map中获取的值
                ...
            //4. 增强getParamterValue方法,过滤从数组中获取的值
                ...
            //调用其他成员方法时,原封返回
            return method.invoke(req, args);
        });
        chain.doFilter(proxy_req, resp);
    }
上一篇:java – 使用子类作为方法参数调用getMethod


下一篇:c# invoke和begininvoke方法