JavaWeb第十八天

Filter

Java web 三大组件
  Filter过滤器 Listener监听器 Servlet

概念

Filter 过滤器
    概念
        web中的过滤器
        浏览器发送请求给服务器获取资源,过滤器拦截请求,增强请求的功能,请求资源,返回时再次拦截,再次增强请求的功能之后再响应
        请求资源的通用操作可以放在过滤器中,如登录验证、统一编码处理、敏感字符过滤
    快速入门
        1、定义一个类,实现接口Filter
        2、重写方法
            doFilter
                放行
                    filterChain.doFilter(servletRequest, servletResponse);
        3、配置拦截路径
            web.xml配置方式
            注解配置方式
                @WebFilter("/*") 访问所有资源之前都会执行该过滤器
                @WebFilter("/index.jsp") 访问index.jsp之前会执行该过滤器
    细节
        web.xml配置
            <filter>
                <filter-name>demo01</filter-name>
                <filter-class>filter.Demo01Filter</filter-class>
            </filter>
            <filter-mapping>
                <filter-name>demo01</filter-name>
                <url-pattern>/*</url-pattern> 拦截路径
            </filter-mapping>
        执行流程
            拦截请求,对request对象的请求消息做增强
            放行,执行被访问的资源
            拦截响应,对response对象的响应消息做增强 放行代码下的代码
        生命周期方法
            init 服务器启动后,创建Filter对象,调用init方法,只执行一次 用于加载资源
            doFilter 每一次请求被拦截资源时执行一次,会执行多次 拦截的逻辑操作
            destroy 服务器关闭时,销毁Filter对象,正常关闭会执行destroy方法,只执行一次 用于释放资源
        配置
            拦截路径
                /* 拦截所有资源
                /index.jsp 具体路径
                /user/* 目录拦截 拦截user目录下的所有资源
                *.jsp 后缀名拦截 拦截所有后缀名为jsp的资源
            拦截方式 资源被访问的方式
                web.xml
                    <filter>
                        <filter-name>demo01</filter-name>
                        <filter-class>filter.Demo01Filter</filter-class>
                    </filter>
                    <filter-mapping>
                        <filter-name>demo01</filter-name>
                        <url-pattern>/*</url-pattern> 拦截路径
                        <dispatcher>FORWARD</dispatcher>
                    </filter-mapping>
                注解 @WebFilter(value = "/*", dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
                    设置dispatcherTypes属性
                        REQUEST 默认值 浏览器直接请求资源
                        FORWARD 转发访问资源
                        INCLUDE 包含访问资源
                        ERROR 错误跳转资源
                        ASYNC 异步访问资源
        过滤器链(配置多个过滤器)
            执行顺序
                过滤器1 过滤器2 资源 过滤器2回 过滤器1回 这里过滤器1先于过滤器2
            先后顺序怎么确定
                web.xml 按配置文件中过滤器对应的filter-mapping定义的先后 先定义的先执行
                注解 按类名的字符串比较规则进行比较,值小的先执行 字符串比较规则是每个字符分别进行比较
package filter;


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

//Filter快速入门
@WebFilter("/*")
public class Demo01Filter 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("Demo01Filter被执行了");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

Filter案例

登录验证
    需求
        访问day17-case的资源,验证是否登录
        登录则直接放行
        未登录则跳转到登录页面,提示:您尚未登录,请先登录
    分析
        浏览器访问服务器中的day17-case项目中的资源,都需要进行登录验证,所以放在过滤器LoginFilter中比较合适
        LoginFilter
            排除不需要登录验证的资源
                不需要登录验证
                    直接放行
                需要登录验证
                    判断用户是否登录
                        用户登录完后会将当前用户存入session域中
                        只需要判断session域中是否有loginAdmin这个参数对应的值
    注意
        有些资源不需要登录验证
            登录相关资源路径 css/js/图片/验证码
            login.jsp LoginServlet css和js样式 CheckCodeServlet
        登录后浏览器未关闭情况下,再次访问,可以直接访问
             浏览器关闭后再次访问,需要再次登录
package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/*")//访问day17中资源时进行拦截
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        //HttpServletResponse response = (HttpServletResponse) resp;
        //判断是否是需要登录验证的资源
        //获取资源的请求路径
        String uri = request.getRequestURI();
        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 {
            HttpSession session = request.getSession();
            Object loginAdmin = session.getAttribute("loginAdmin");
            if (loginAdmin != null) {
                chain.doFilter(req, resp);
            } else {
                request.setAttribute("login_err", "您尚未登录,请先登录!");
                request.getRequestDispatcher("/login.jsp").forward(request, resp);
            }
        }

    }

    public void init(FilterConfig config) throws ServletException {

    }

}

过滤敏感词汇
    需求
        对day17-case中录入的数据进行敏感词汇过滤
        敏感词汇参考敏感词汇.txt
        敏感词汇替换为***
    分析
        项目中多个地方都需要录入数据,都需要敏感词汇过滤,所以放在过滤器SensitiveWordFilter中比较合适
        SensitiveWordFilter
            过滤request中的敏感词汇
                对request对象的获取参数的相关方法进行增强,产生一个新的request对象,新的request对象调用getParameter方法获取的参数是过滤后的
                    获取参数的相关方法:getParameter getParameterMap getParameterValues
                    步骤
                        创建代理对象 使用Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
                                          @Override
                                          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                            //代理逻辑
                                            //判断是否为getParameter方法
                                            if (method.getName().equals("getParameter")) {
                                                //增强返回值
                                                //获取返回值
                                                String value = (String) method.invoke(req, args);
                                                if (value != null) {
                                                    for (String s : list) {
                                                        if (value.contains(s)) {
                                                            value = value.replaceAll(s, "***");
                                                        }
                                                    }
                                                }
                                            }
                                            //判断是否为getParameterMap方法
                                            //判断是否为getParameterValues方法
                                            return method.invoke(req, args);
                                          }
                                      });
                    将敏感词汇替换为***
                放行,将新的request对象,即代理对象传入doFilter方法

敏感词汇.txt

笨蛋
傻逼
package 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 SensitiveWordFilter implements Filter {
    private List<String> list = new ArrayList<String>();//敏感词汇集合

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //创建代理对象,增强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方法
                if (method.getName().equals("getParameter")) {
                    //增强返回值
                    //获取返回值
                    String value = (String) method.invoke(req, args);
                    if (value != null) {
                        //对返回值,即要获取的参数进行敏感词汇过滤
                        for (String s : list) {
                            if (value.contains(s)) {
                                //如果要获取的参数包含敏感词汇
                                value = value.replaceAll(s, "***");
                            }
                        }
                    }
                    return value;
                }
                //判断是否为getParameterMap方法
//                if (method.getName().equals("getParameterMap")) {
//                    String value = method.invoke(re)
//                }
                //判断是否为getParameterValues方法
                return method.invoke(req, args);
            }
        });
        //放行
        chain.doFilter(proxy_req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        try {
            //加载配置文件 先获取文件的真实路径
            ServletContext servletContext = config.getServletContext();
            String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");//src下的资源
            //读取文件
            //本地创建的字符流是GBK,配置文件的编码需要改为GBK,否则会乱码
            BufferedReader br = new BufferedReader(new FileReader(realPath));
            //读取文件
            String line = null;
            while ((line = br.readLine()) != null) {
                //将文件中的每一行数据加到list中
                list.add(line);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

代理

概念

Filter和Servlet中获取的request对象都是同一个
增强对象的功能
    使用设计模式(一些通用的解决固定问题的方式)
        装饰模式
        代理模式
            概念
                例子:北京的联想公司具有生产电脑和卖电脑的功能,我直接去北京买电脑比较麻烦
                     本地的代理商具有卖电脑的功能,我可以跟代理商买,代理商需要跟联想进货
                     我调用的是联想公司的代理对象--代理商,代理商调用的是真是对象--联想公司
                真实对象 被代理的对象
                代理对象
                代理模式
                    代理对象代理真实对象,达到增强真实对象功能的目的
            实现方式
                静态代理 有一个类文件描述代理模式
                动态代理 在内存中生成代理类
            动态代理
                实现步骤
                    代理对象和真实对象实现相同接口
                    使用Proxy.newProxyInstance()获取代理对象
                        三个参数
                            类加载器 用于执行代理对象中的方法 真实类Lenovo.class.getClassLoader()
                            真实对象实现的接口数组,保证了代理对象和真实对象实现相同的接口 真实类Lenovo.class.getInterfaces()
                            处理器 使用匿名内部类new InvocationHandler() invoke方法实现代理逻辑,代理对象调用所有方法都会触发该方法执行
                                invoke方法
                                    参数
                                        proxy 代理对象
                                        method 代理对象调用的方法被封装为的Method对象
                                        args 代理对象调用方法时传递的实际参数封装为的数组
                                    如何增强
                                        调用真实对象的方法 method.invoke(lenovo, args); 方法对象.invoke(真实对象, 参数);
                                    增强方式
                                        增强参数列表
                                        增强方法体执行逻辑
                                        增强返回值
                    使用代理对象调用方法
                    增强方法

接口

package proxy;

public interface SaleComputer {
    public String sale(double money);
    public void show();
}

真实类

package proxy;

//真实类
public class Lenovo implements SaleComputer {
    @Override
    public String sale(double money) {
        System.out.println("花了" + money + "元买了一台联想电脑");
        return "联想电脑";
    }

    @Override
    public void show() {
        System.out.println("展示电脑");
    }
}

测试类

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) {
        //创建真实对象
        Lenovo lenovo = new Lenovo();
        //动态代理增强Lenovo真实对象
        //获取代理对象,执行其中的方法需要使用类加载器 真实对象实现的接口 以及
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(Lenovo.class.getClassLoader(), Lenovo.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //判断是否为sale方法
                if (method.getName().equals("sale")) {
                    //增强参数列表
                    double money = (double) args[0];
                    //代理商给联想的钱是消费者给的钱的0.85
                    money = money * 0.85;
                    //增强方法体执行逻辑
                    System.out.println("专车接");
                    String obj = (String) method.invoke(lenovo, money);
                    System.out.println("免费送货");
                    //增强返回值
                    return obj + "鼠标垫";
                } else {
                    Object obj = method.invoke(lenovo, args);
                    return obj;
                }
            }
        });
        //调用代理对象的方法
        String computer = proxy_lenovo.sale(8000);
    }
}

Listener 监听器

web的三大组件之一
事件监听机制
    事件 如点击按钮
    事件源 事件发生的地方 如按钮
    监听器 一个对象或一段代码
    注册监听 将事件 事件源 监听器绑定在一起,当事件源上发生某事件,执行监听代码
ServletContextListener 监听ServletContext对象的创建和销毁
    void contextInitialized(ServletContextEvent sce);
        ServletContext对象被创建后会调用,服务器启动后自动创建ServletContext对象
        一般用于加载资源文件
            获取servletContext对象
                ServletContext servletContext = sce.getServletContext();
            在web.xml中指定初始化参数
                <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>/WEB-INF/classes/applicationContext.xml<param-value> 文件路径
                </context-param>
            获取资源文件路径
                String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
            获取真实路径
                String realPath = servletContext.getRealPath(contextConfigLocation);
            使用流将文件加载进内存
                FileInputStream fis = new FileInputStream(realPath);
    void contextDestroyed(ServletContextEvent sce);ServletContext对象被销毁前会调用
        ServletContext对象被销毁前会调用,服务器正常关闭后自动销毁ServletContext对象
步骤
    定义一个类ContextLoaderListener实现接口ServletContextListener
        事件 ServletContext对象被创建/销毁
        事件源 tomcat
        监听器 ContextLoaderListener
        注册监听 在web.xml中配置监听器/在ContextLoaderListener类上使用注解配置监听器
    重写方法
    配置
        web.xml
            注册监听
            <listener>
                <listener-class>listener.ContextLoaderListener</listener-class>
            </listener>
            指定初始化参数
            <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/classes/applicationContext.xml<param-value> 文件路径
            </context-param>
        注解
            @WebListener()
package listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

@WebListener()
public class ContextLoaderListener implements ServletContextListener {
    //监听ServletContext对象的创建
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //加载资源文件
        ServletContext servletContext = sce.getServletContext();
        //获取资源文件路径
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
        //获取真实路径
        String realPath = servletContext.getRealPath(contextConfigLocation);
        //使用流将文件加载进内存
        try {
            FileInputStream fis = new FileInputStream(realPath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    //监听ServletContext对象的销毁
    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值