A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 森111 中级黑马   /  2019-1-4 10:18  /  678 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 森111 于 2019-1-4 10:21 编辑

Filter过滤器的概念
  • 当访问服务器资源时,过滤器可以将请求拦截下来,完成特殊功能
  • 过滤器的作用

一般用于完成通用的操作,如登陆验证,统一编码处理,敏感字符过滤快速入门
  • 1.创建一个类实现Filter接口(javax.servlet.Fileter)
  • 2.复写方法
  • 3.配置拦截路径

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>中的顺序
设计模式
  • 共有23种设计模式,其中用于对象增强的有两种

动态代理
概念
1.真实对象:被代理的对象
2.代理对象:代理真实对象的对象
3.代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
实现方式
1.静态代理:有一个类文件描述代理模式
2.动态代理:在内存中形成代理类
  • 动态代理的实现

1.代理对象和真实对象实现相同的接口
2.Proxy.newProxyInstance(ClassLoader,Class<?>[],InvocationHandler)来获取一个代理对象
3.使用代理对象来调用方法
4.增强方法
  • 增强方式
  • 1.==Proxy.newProxyInstance()方法详解==

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:代理对象调用方法时,传递的实际参数数组
  • 2.增强方式

1.增强参数列表
2.增强返回值
3.增强方法体执行逻辑
  • 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.看到Wrapper结尾的类而且该类构造需要传入对象
  • 2.原本类和增强类都要事先共同接口
  • 3.增强类需要持有原本类的对象

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三大组件之一
  • 事件监听机制
  • 事件:一件事情
  • 事件源:事件发生的地方
  • 监听器:一个对象
  • 注册监听:将事件、事件源、监听器绑定在一起,当事件源上发生某个事件后,执行监听代码
  • ServletContext监听器:
  • ServletContxtListener(现在只学习这一个):监听servletContext对象的创建和销毁

方法1:void contextDestroyed(ServletContextEvent sce) ServletContext对象销毁之前会调用该方法

方法2:void contextInitialized(ServletContextEvent sce) ServletContext对象创建之后会调用该方法
  • 步骤
  • 1.定义一个类实现ServletContextListener接口
  • 2.复写方法
  • 3.配置

1.注解配置
@WebListener
2.web.xml配置
<listener>
  <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class>
</listener>
  • 4.作用

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>



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马