黑马程序员技术交流社区

标题: Web核心-Filter&&Listener [打印本页]

作者: 森111    时间: 2019-1-4 10:18
标题: Web核心-Filter&&Listener
本帖最后由 森111 于 2019-1-4 10:21 编辑

Filter过滤器的概念一般用于完成通用的操作,如登陆验证,统一编码处理,敏感字符过滤快速入门1.WebFilter注解
  配置url-pattern(默认为value)为要拦截的路径
2.web.xml配置
  <filter>
    <fileter-name>demo1</filter-name>
    <filter-class>cn.itcast.web.filter.FliterDemo1</filter-class>
  </filter>
  <filter-mapping>
    <fileter-name>demo1</filter-name>
    <url-pattern>cn.itcast.web.filter.FliterDemo1</url-pattern>
  </filter-mapping>
!!!注意,这里url-pattern配置的是要拦截的路径
Filter细节浏览器--> servletChian.doFilter()-->Servlet
-->servletChian.doFilter之后的代码-->浏览器1.init():在服务器启动后会创建Filter对象,调用init()方法
2.doFilter():每一次请求拦截资源,执行一次
3.destory():服务器正常关闭,执行一次1./具体资源  (很少使用)
2./user/*    过滤user下的所有资源
3. *.jsp    过滤所有后缀名为jsp的资源
4./*        过滤所有资源1.注解配置
  设置dispatcherType属性
     - REQUEST:默认值.浏览器直接请求资源
     - FORWAR:转发访问资源
     - INCLUDE:包含访问资源 (了解)
     - ERRO:错误访问资源,Jsp中配置的erroPage (了解)
     - ASYNC:异步访问资源(了解)
2.web.xml配置
   <filter-mapping>中的<dispatcher></dispatcher>浏览器-->Filter1.filterChain.doFilter()
-->Fileter2.filterChian.doFilter()-->Servlet
-->Fileter2.filterChian.doFilter()之后的代码
-->Fileter1.filterChian.doFilter()之后的代码
-->浏览器1.WebFilter注解
  按照字母顺序排序
2.web.xml
  按照<filter-mapping>中的顺序
设计模式动态代理
概念
1.真实对象:被代理的对象
2.代理对象:代理真实对象的对象
3.代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
实现方式
1.静态代理:有一个类文件描述代理模式
2.动态代理:在内存中形成代理类1.代理对象和真实对象实现相同的接口
2.Proxy.newProxyInstance(ClassLoader,Class<?>[],InvocationHandler)来获取一个代理对象
3.使用代理对象来调用方法
4.增强方法1.参数
  - Classloader:真实对象.getClass().getClassLoader()
  - Class<?>[](接口数组):真实对象.getClass().getInterfaces()
  - InvocationHandler(处理器): new InvocationHandler()
  - 例:
     Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
2.invoke方法详解
1).参数
- proxy:代理对象  一般不用
- method:代理对象调用的方法,被封装为的对象
- args:代理对象调用方法时,传递的实际参数数组1.增强参数列表
2.增强返回值
3.增强方法体执行逻辑1.创建一个Lenovo类
public class Lenovo implements SaleComputer {
    @Override
    public String sale(double money) {
        System.out.println("客户花了"+money+"元买了一台联想电脑");
        return "联想电脑";
    }
    @Override
    public void show() {
        System.out.println("展示电脑");
    }
}
2.参数增强
    public static void main(String[] args) {
        //1.创建真实对象
        Lenovo lenovo = new Lenovo();
        //2.动态代理增强lenovo对象
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            //代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //1判断是否是sale方法
                if (method.getName().equals("sale")) {
                    //2.增强参数:(代理商要赚钱,将电脑加价)如果是sale方法,增加售价
                    double money = (double) args[0];
                    money = money * 1.25;
                    //3.增强方法体及返回值:(代理商为了欺骗客户,让客户不要产生心理落差)
                    System.out.println("专车接你....");
                    String obj = (String) method.invoke(lenovo, money);
                    System.out.println("免费送货....");
                    //4.使用真实对象调用该方法,并增强返回值
                    return obj + "_鼠标垫";
                } else {
                    //4.如果是show方法直接调用真实对象的show方法
                    Object obj = method.invoke(lenovo, args);
                    return obj;
                }
        });
        //4.调用方法
        String computer = proxy_lenovo.sale(8000);
        System.out.println(computer);

       //最后输出结果为:
       /*
       专车接你....
       客户花了10000.0元买了一台联想电脑
       免费送货....
       联想电脑_鼠标垫
       */
装饰模式
1.原始类
public class Man implements Person{

    @Override
    public void eat(){
        System.out.println("吃饭");
    }
   
}
2.装饰者模式增强
puliuc class ManWrapper implements Person{

    private Person man;
   
    public ManWrapper(Person p){
        man = p;
    }
   
    public void eat(){
        System.out.println("吃饭前喝点水");
        man.eat();
        System.out.println("吃饭后溜溜弯");
    }
}
3.使用装饰的类
public void test1(){
     Man man = new Man();
     ManWrapper man2 = new ManWrapper(man);
     man2.eat();
}
继承(不是设计模式)
典型案例
登陆校验
    1. 访问day17_case案例的资源。验证其是否登录
    2. 如果登录了,则直接放行。
    3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
    throws ServletException, IOException {
        //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{
            //不包含,需要验证用户是否登陆
            User user = (User)request.getSession().getAttribute("admin");
            //3.判断session中是否存在admin属性
            if (user != null) {
                //如果存在,则证明用户已经登陆.放行
                chain.doFilter(req,resp);
            }else{
                //如果不存在,则需要用户登陆,转发至login.jsp
                request.setAttribute("msg","您尚为登陆,请登陆");
                request.getRequestDispatcher("/login.jsp").forward(request,resp);
            }
        }
    }
敏感字过滤
    1. 对day17_case案例录入的数据进行敏感词汇过滤
    2. 敏感词汇参考《敏感词汇.txt》 笨蛋/坏蛋
    3. 如果是敏感词汇,替换为 ***@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
    private List<String> list = new ArrayList<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //1.获取文件的真实路径
        ServletContext context = filterConfig.getServletContext();
        String realPath = context.getRealPath("/WEB-INF/classes/敏感词汇.txt");
        //2.读取realPath中的敏感词汇
        try (FileInputStream fis = new FileInputStream(realPath);
             BufferedReader br = new BufferedReader(new InputStreamReader(fis, "utf-8"));) {
            //3.使用br读取敏感词汇
            String line;
            while ((line = br.readLine()) != null) {
                list.add(line);
            }
            System.out.println(list);
            //4.不用释放资源了,fis和br的作用域仅在这个try中
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        //0.强制转型
        HttpServletRequest request = (HttpServletRequest) req;
        //1.创建proxy_req对象
        HttpServletRequest proxy_req = (HttpServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                //2.1 判断方法是否为getParameter对象
                if (methodName.equals("getParameter")) {
                    String value = (String) method.invoke(request, args);
                    if (value != null) {
                        for (String str : list) {
                            value = value.replaceAll(str, "***");
                        }
                    }
                    return value;
                }
                //2.2判断方法是否为getParameterValues
                if (methodName.equals("getParameterValues")) {
                    String[] values = (String[]) method.invoke(request, args);
                    List<String> sb = new ArrayList<>();
                    if (values != null) {
                        for (String value : values) {
                            for (String str : list) {
                                value = value.replaceAll(str, "***");
                            }
                            sb.add(value);
                        }
                    }
                    String[] sBuffer = new String[values.length];
                    String[] sb_string = sb.toArray(sBuffer);
                    return sb_string;
                }
                //2.3判断方法是否为getParameterMap
                if (methodName.equals("getParameterMap")) {
                    Map<String, String[]> map = (Map<String, String[]>) method.invoke(request, args);
                    Set<String> keys = map.keySet();
                    Map<String, Object> newMap = new HashMap<>();
                    for (String key : keys) {
                        String[] values = map.get(key);
                        List<String> sb = new ArrayList<>();
                        for (String value : values) {
                            for (String str : list) {
                                value = value.replaceAll(str, "***");
                            }
                            sb.add(value);
                        }
                        String[] sBuffer = new String[values.length];
                        String[] sb_string = sb.toArray(sBuffer);
                        newMap.put(key, sb_string);
                    }
                    return newMap;
                }
                return method.invoke(request, args);
            }
        });
        //3.放行
        chain.doFilter(proxy_req, resp);
    }

    @Override
    public void destroy() {
    }
}

注:字符流转化
问在FileReader读取文件的过程中,FileReader继承了InputStreamReader,但并没有实现父类中带字符集参数的构造函数,所以FileReader只能按系统默认的字符集来解码,然后在UTF-8 -> GBK -> UTF-8的过程中编码出现损失,造成结果不能还原最初的字符。
用InputStreamReader代替FileReader,InputStreamReader isr=new InputStreamReader(new FileInputStream(fileName),"UTF-8");这样读取文件就会直接用UTF-8解码,不用再做编码转换。
Listener概念:web三大组件之一方法1:void contextDestroyed(ServletContextEvent sce) ServletContext对象销毁之前会调用该方法

方法2:void contextInitialized(ServletContextEvent sce) ServletContext对象创建之后会调用该方法1.注解配置
@WebListener
2.web.xml配置
<listener>
  <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class>
</listener>1.void contextInitialized(ServletContextEvent sce):一般用于加载配置文件
设置初始化文件[可以通过servletContext.getInitParameter("参数名")来获取参数值]
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/classes/applicationContext.xml</param-name>
</context-param>








欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2