组件必知必会|那些年我们使用过的轮子—Filter和Proxy

简介: 过滤器Filter是JavaWeb三大组件之一,它与Servlet很相似,过滤器是用来拦截请求的,而不是处理请求的。当用户请求某个Servlet时,会先执行部署在这个请求上的Filt...

 image.gif

image.gif

前言

过滤器Filter是JavaWeb三大组件之一,它与Servlet很相似,过滤器是用来拦截请求的,而不是处理请求的。当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter“不放行”,那么就不会执行用户请求的Servlet。可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码。

设计模式不是技术,也不是什么框架,只是前人的一个工作的总结,在实现某一个功能的时候,怎样来减少代码之间的耦合性,以及如何实现高内聚低耦合,设计模式说白了就是按照一定的步骤来完成相应的一个功能,这个就称为设计模式。代理Proxy是指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗来讲,代理设计模式就是我们生活中常见的中介。主要用来解决的问题第一个:监控目录一个类里面的方法的执行,第二个:在类里面某一个方法执行的前后动态的植入代码。

本文将带大家详细介绍Filter以及Proxy的具体原理以及使用。

公众号:「浅羽的IT小屋」

1、什么是过滤器

「定义:」

    • 过滤器按照我们的理解就是过滤东西的,那么到底这个过滤器能够来过滤啥呢?过滤的是请求
    • 请求:动态资源的请求(Servlet)就是程序在运行的过程中,代码会发生改变,那么这一类的资源请求,就称为动态的网络资源请求
    • 请求:静态资源的请求(css、html、js、img、png...)程序在运行的过程中,代码不会发生改变的那一类请求,就称为静态的网络资源请求
    • 总结:过滤器能够拦截所有的资源请求

    2、过滤器的作用

    「主要用途:」

      • 用户的身份认证
      • 字符串的和谐
      • 请求的Servlet的乱码问题处理

      3、过滤器的使用

      「使用案例:」

        • 编写一个类,这个类实现于Filter接口,并实现里面的方法
        public class HelloFilter implements Filter{
         /**
          * 在Filter实例被创建的时候 初始化方法的时候执行的 这个一般用于Filter的初始化
          * filterConfig:获取的是Filter的配置信息以及初始化信息的
          */
         @Override
         public void init(FilterConfig filterConfig) throws ServletException {
          System.out.println("init初始化执行了");
         }
            /**
             * 过滤器拦截的方法
             * request:当前的请求对象的封装
             * response:当前的响应的封装
             * chain:判断是否拦截的方法
             * 
             */
         @Override
         public void doFilter(ServletRequest request, ServletResponse response,
           FilterChain chain) throws IOException, ServletException {
          System.out.println("doFilter执行了....");
          //执行了这个方法那么就表示允许通过  没有执行那么就不允许通过
          chain.doFilter(request, response);
         }
            /**
             * 过滤器在死了之后 执行的这个方法
             */
         @Override
         public void destroy() {
          System.out.println("destory执行了....");
         }
        }

        image.gif

          • 在web.xml中配置Filter
          <filter>
               <filter-name>HelloFilter</filter-name>
               <filter-class>com.qy.filter.HelloFilter</filter-class>
            </filter> 
            <filter-mapping>
               <filter-name>HelloFilter</filter-name>
               <url-pattern>/*</url-pattern>
            </filter-mapping>

          image.gif

            • 测试
            • 总结:Filter的初始化方法是在程序启动的时候执行的

            4、过滤器的生命周期

            「生命周期:」

              • 首先在Web容器被使用的时候那么Filter对象被创建
              public HelloFilter() {
                System.out.println("类的对象被创建了....");
               }

              image.gif

                • 创建完成之后紧接着调用init方法进行Filter的初始化
                @Override
                 public void init(FilterConfig filterConfig) throws ServletException {
                  System.out.println("init初始化执行了");
                 }

                image.gif

                  • 当前端有请求到来的时候,那么这个时候doFilter方法被执行
                  @Override
                   public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
                    System.out.println("doFilter执行了....");
                    // 执行了这个方法那么就表示允许通过 没有执行那么就不允许通过
                    //放行
                    // chain.doFilter(request, response);
                   }

                  image.gif

                    • 当 Web容器死亡的时候,那么destory方法被执行
                    @Override
                     public void destroy() {
                      System.out.println("destory执行了....");
                     }

                    image.gif

                      • init中filterConfig如何使用
                      在web.xml中给filter添加初始数据 
                      <filter>
                           <filter-name>HelloFilter</filter-name>
                           <filter-class>com.qy.filter.HelloFilter</filter-class>
                           <init-param>
                              <param-name>userName</param-name>
                              <param-value>qianyu</param-value>
                           </init-param>
                           <init-param>
                              <param-name>password</param-name>
                              <param-value>123</param-value>
                           </init-param>
                        </filter>
                      使用filterConfig来获取这个数据 
                       public void init(FilterConfig filterConfig) throws ServletException {
                        System.out.println("init初始化执行了");
                        //获取fileter的初始化数据
                        String userName=filterConfig.getInitParameter("userName");
                        String password=filterConfig.getInitParameter("password");
                        //获取的所有参数的名字
                        filterConfig.getInitParameterNames();
                        //获取的是application
                        filterConfig.getServletContext();
                        //获取的是Filter的名字
                        filterConfig.getFilterName();
                        System.out.println("获取到的数据是:"+userName+"----"+password);
                       } 
                      过滤中器放行的方法是什么?
                                     chain.doFilter(request, response);

                      image.gif

                      5、代理设计模式

                      「解决的问题:」

                        • 问题:代理设计模式到底解决了一个什么问题?
                        什么是设计模式?  设计模式不是技术、也不是什么框架、设计模式只是前人的一个工作的总结、在实现某一个功能的时候 怎样来减少代码之间的耦合性、以及如何实现高内聚低耦合。设计模式说白了就是按照一定的步骤来完成相应的一个功能 这个就称为设计模式
                               代理的设计模式主要用来解决一个什么问题呢?  第一个:监控目录一个类里面方法的执行 第二个:在类里面某一个方法执行的前后 动态的植入代码

                        image.gif

                        「静态代理:」

                          • 静态代理的使用前提:被代理的这个类必须要实现接口
                          • 接口的玩法

                          image.gif

                            • 编写被代理类

                            image.gif

                              • 编写代理类

                              image.gif

                                • 测试

                                「动态代理(JDK代理):」

                                  • 使用前提:被代理的类也必须实现接口
                                  动态代理的实现原理:实际上也是生成了接口的实现类对象、然后在接口的实现类对象里面传入了 被代理的对象、在方法执行的时候使用了被代理类的方法去执行、实际上就跟静态代理差不多 区别是静态代理自己写的代 理类、动态代理是自动生成的这个代理类

                                  image.gif

                                    • 被代理的类以及接口的实现和上面类似
                                    • 代理类的生成和实现
                                    IUserDAO userDAO=(IUserDAO)Proxy.newProxyInstance(
                                    UserDAO.class.getClassLoader(),
                                                  UserDAO.class.getInterfaces(),
                                    new InvocationHandler() {
                                               /**
                                                * 第一个参数:代理对象
                                                * 第二个参数:当前要执行方法的一个封装
                                                * 第三个参数:执行方法要传递的这个参数
                                                */
                                               @Override
                                         public Object invoke(Object proxy, Method method, Object[] args)
                                           throws Throwable {
                                               System.out.println("执行前添加的功能....");
                                               Object result=method.invoke(new UserDAO(), args);
                                               System.out.println("执行后添加的功能....");
                                          return result;
                                         }
                                        });

                                    image.gif

                                      • 测试
                                      userDAO.save();

                                      image.gif

                                      「cglib代理:」

                                        • 需求:假设一个类没实现接口?假设我们也需要监听这个类里面的方法的执行呢?
                                        cglib的使用场景:就是一个类如果没有实现接口  而且我们想在这个类的方法里面动态植入代码 那么这种情况下就可以使用cglib代理

                                        image.gif

                                          • 首先导入cglib的包
                                          • 编写代理类
                                          public class UserDAOProxy {
                                           private UserDAO userDAO=null;
                                           public UserDAOProxy(UserDAO userDAO) {
                                            this.userDAO=userDAO;
                                           }
                                           /**
                                            * 编写一个方法 用来返回代理类的对象
                                            * @Title: getObjProxy   
                                            * @Description: TODO
                                            * @param: @return      
                                            * @return: Object      
                                            * @throws
                                            */
                                           public Object getObjProxy(){
                                            //这个对象就是用来返回代理类对象的方法
                                            Enhancer enhancer=new Enhancer();
                                            //给代理了设置父亲
                                           enhancer.setSuperclass(userDAO.getClass());
                                            //设置调用的回调
                                            enhancer.setCallback(new MethodInterceptor() {
                                             @Override
                                             public Object intercept(Object proxy, Method method, Object[] arg2,
                                               MethodProxy arg3) throws Throwable {
                                              System.out.println("植入了功能....");
                                              Object objResult=method.invoke(userDAO, arg2);
                                              System.out.println("植入了功能....1111");
                                              return objResult;
                                             }
                                            });
                                            //生成代理类
                                            return enhancer.create();
                                           }
                                          }

                                          image.gif

                                            • 编写测试类
                                            @Test
                                               public void testCglibProxy() throws Exception {
                                              //获取代理类的对象
                                              UserDAOProxy2 userDAOProxy=new UserDAOProxy2(new UserDAO());
                                              //第二步:调用
                                              UserDAO userDAO=(UserDAO) userDAOProxy.getObjProxy();
                                              //第三步
                                              userDAO.save();
                                               }

                                            image.gif

                                            6、基于代理和Filter的综合案例

                                            「编码处理的问题:」

                                              • 原理
                                              原理:过滤器技术拦截所有的controll的请求、在controll请求中使用了动态代理的设计模式监听了HttpServletRequest这个接口中getParameter方法的执行、在getParameter执行的时候、我们首先去获取这个数据、再通过判断当前的请求是GET还是POST、如果是GET那么先使用IOS-8859-1进行转码 然后使用UTF-8从新进行编码、如果是POST那么直接使用request.setCharacterEncoding(“UTF-8”)来进行处理

                                              image.gif

                                                • 字符编码处理的实现
                                                public class CharacterFilter implements Filter{
                                                 @Override
                                                 public void init(FilterConfig arg0) throws ServletException {
                                                 }  
                                                    /**
                                                     * 拦截的这个方法
                                                     */
                                                 @Override
                                                 public void doFilter(ServletRequest request, ServletResponse response,
                                                   final FilterChain chain) throws IOException, ServletException {
                                                      final HttpServletRequest req=(HttpServletRequest) request;
                                                      final HttpServletResponse resp=(HttpServletResponse) response;
                                                      //第一步:将返回数据的编码问题给处理了
                                                      resp.setContentType("text/html;charset=utf-8");
                                                      //POST的解决方案 
                                                      req.setCharacterEncoding("UTF-8");
                                                      //第二步:监听httpServletRequest中 getParameter方法的执行
                                                      HttpServletRequest req1= (HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(),
                                                        new Class[]{HttpServletRequest.class},
                                                        new InvocationHandler() {
                                                      @Override
                                                      public Object invoke(Object proxy, Method method, Object[] args)
                                                        throws Throwable {
                                                          //监听当前执行的方法是不是 getParameter
                                                          String methodName=method.getName();
                                                          if("getParameter".equals(methodName)){ //说明执行的是getParameter
                                                          //判断当前执行的是POST呢?还是GET呢?
                                                          String reqName=req.getMethod();
                                                          //通过key获取这个值
                                                          String val= (String) method.invoke(req, args);
                                                          if("GET".equalsIgnoreCase(reqName)){ //说明是GET方法
                                                           //执行这个方法获取这个值
                                                           val=new String(val.getBytes("ISO-8859-1"),"UTF-8");
                                                          }else if("POST".equalsIgnoreCase(reqName)){ //说明是POST方法
                                                          }
                                                          //返回这个方法执行的结果
                                                          return val; 
                                                          }else{
                                                          return  method.invoke(req, args);
                                                          }
                                                         }
                                                     });
                                                     //最终要进行放行
                                                     chain.doFilter(req1, resp);
                                                 }
                                                 @Override
                                                 public void destroy() { 
                                                 }
                                                }

                                                image.gif

                                                「字符和谐的问题:」

                                                  • 明白一个问题:什么是字符和谐:类似于博客网站上,比如你发表不文明语句不会直接显示出来,而是显示成***等这种现象就称为字符的和谐
                                                  • 要实现字符和谐首先要解决编码问题(上面已经解决了)
                                                  • 在过滤器中设置脏数据
                                                  //需要和谐的脏数据
                                                   private String[] dirtyData={"MMD","NND","GD","CTM"};

                                                  image.gif

                                                    • 在处理完字符编码问题的时候进行和谐(在处理完编码之后进行调用)
                                                    protected String handleDirtyData(String val) {
                                                      for (int i = 0; i < dirtyData.length; i++) {
                                                       if(val.contains(dirtyData[i])){
                                                        val=val.replaceAll(dirtyData[i],"***");
                                                       }
                                                      }
                                                      return val;
                                                     }

                                                    image.gif

                                                      • 测试

                                                      结语

                                                      本篇关于过滤器Filter及代理Proxy的介绍就先到这里结束了,后续会出更多关于Filter和代理Proxy系列更多文章,谢谢大家支持!

                                                      image.gif


                                                      image.gif

                                                      点点点,一键三连都在这儿!

                                                      相关文章
                                                      |
                                                      监控 安全 Java
                                                      【JavaWeb】 三大组件之过滤器 Filter
                                                      过滤器(Filter)是Java Web应用中的一种组件,它在请求到达Servlet或JSP之前或者响应送回客户端之前,对请求和响应进行预处理和后处理操作。通过使用过滤器,可以对请求进行过滤,拦截请求,修改请求参数,在请求被处理之前进行一些预处理操作;同时也可以对响应进行过滤,对响应内容进行修改,添加一些额外的处理。
                                                      |
                                                      2月前
                                                      |
                                                      前端开发
                                                      react配置proxy代理的两种方式
                                                      本文介绍了在React项目中配置代理的两种方式:通过在package.json中添加代理配置,以及通过创建setupProxy.js文件来实现更复杂的代理规则。
                                                      120 2
                                                      |
                                                      3月前
                                                      |
                                                      前端开发 JavaScript PHP
                                                      React Server Component 使用问题之路由的能力,如何实现
                                                      React Server Component 使用问题之路由的能力,如何实现
                                                      |
                                                      4月前
                                                      |
                                                      开发框架 前端开发 JavaScript
                                                      在ABP VNext框架中对HttpApi模块的控制器进行基类封装
                                                      在ABP VNext框架中对HttpApi模块的控制器进行基类封装
                                                      |
                                                      5月前
                                                      |
                                                      缓存 JavaScript 程序员
                                                      【奇葩问题】vue项目在谷歌浏览器开启开发者工具时部分接口报错500 Proxy error: Could not proxy request
                                                      【奇葩问题】vue项目在谷歌浏览器开启开发者工具时部分接口报错500 Proxy error: Could not proxy request
                                                      108 0
                                                      |
                                                      Java 应用服务中间件 数据安全/隐私保护
                                                      JavaWeb 三大组件之 过滤器 Filter
                                                      JavaWeb 三大组件之 过滤器 Filter
                                                      87 0
                                                      |
                                                      6月前
                                                      |
                                                      存储 应用服务中间件 nginx
                                                      Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现
                                                      Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现
                                                      195 0
                                                      |
                                                      监控 JavaScript 前端开发
                                                      webpack进阶篇(十九):使⽤ source map
                                                      webpack进阶篇(十九):使⽤ source map
                                                      138 0
                                                      webpack进阶篇(十九):使⽤ source map
                                                      |
                                                      存储 JSON 前端开发
                                                      🤓 Filter&Listener&Ajax(一)
                                                      🤓 Filter&Listener&Ajax
                                                      85 1
                                                      🤓 Filter&Listener&Ajax(一)
                                                      |
                                                      JSON 前端开发 JavaScript
                                                      🤓 Filter&Listener&Ajax(四)
                                                      🤓 Filter&Listener&Ajax
                                                      116 0
                                                      🤓 Filter&Listener&Ajax(四)