• Java_Web学习笔记_过滤器应用案例(解决全站字符乱码)


    解决全站字符乱码(POST和GET中文编码问题) 

    servlet:

    l  POST:request.setCharacterEncoding(“utf-8”);

    l  GET:

    • String username = request.getParameter(“username”);
    • username = new String(username.getBytes(“ISO-8859-1”), “utf-8”);
    1 说明
    乱码问题:

    l  获取请求参数中的乱码问题;

    • POST请求:request.setCharacterEncoding(“utf-8”);
    • GET请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);

    l  响应的乱码问题:response.setContextType(“text/html;charset=utf-8”)。 

      基本上在每个Servlet中都要处理乱码问题,所以应该把这个工作放到过滤器中来完成。 

    2 分析
      其实全站乱码问题的难点就是处理GET请求参数的问题。

         如果只是处理POST请求的编码问题,以及响应编码问题,那么这个过滤器就太!太!太简单的。

    public class EncodingFilter extends HttpFilter {

        public void doFilter(HttpServletRequest request,

               HttpServletResponse response, FilterChain chain)

               throws IOException, ServletException {

           String charset = this.getInitParameter("charset");[崔1] 

           if(charset == null || charset.isEmpty()) {

               charset = "UTF-8";

           }[崔2]    

           request.setCharacterEncoding(charset);[崔3]  //调用request的函数

           response.setContentType("text/html;charset=" + charset);[崔4] 

           chain.doFilter(request, response);

        }

    }

     [崔1]获取配置文件中的初始化参数:charset

     [崔2]如果没有给Filter配置charset参数,那么设置编码为UTF-8

     [崔3]处理POST请求编码

     [崔4]处理响应编码

          如果是POST请求,当执行目标Servlet时,Servlet中调用request.getParameter()方法时,就会根据request.setCharacterEncoding()设置的编码来转码!这说明在过滤器中调用request.setCharacterEncoding()方法会影响在目标Servlet中的request.getParameter()方法的行为!

          但是如果是GET请求,我们又如何能影响request.getParameter()方法的行为呢?这是不好做到的!我们不可能先调用request.getParameter()方法获取参数,然后手动转码后,再施加在到request中!因为request只有getParameter(),而没有setParameter()方法。 

         处理GET请求参数编码问题,需要在Filter中放行时,把request对象给“调包”了,也就是让目标Servlet使用我们“调包”之后的request对象。这说明我们需要保证“调包”之后的request对象中所有方法都要与“调包”之前一样可以使用,并且getParameter()方法还要有能力返回转码之后的参数。

    这可能让你想起了“继承”,但是这里不能用继承,而是“装饰者模式(Decorator Pattern)”!

    下面是三种对a对象进行增强的手段:

    l  继承:AA类继承a对象的类型:A类,然后重写fun1()方法,其中重写的fun1()方法就是被增强的方法。但是,继承必须要知道a对象的真实类型,然后才能去继承。如果我们不知道a对象的确切类型,而只知道a对象是IA接口的实现类对象,那么就无法使用继承来增强a对象了;

    l  装饰者模式:AA类去实现a对象相同的接口:IA接口,还需要给AA类传递a对象,然后在AA类中所有的方法实现都是通过代理a对象的相同方法完成的,只有fun1()方法在代理a对象相同方法的前后添加了一些内容,这就是对fun1()方法进行了增强;

    l  动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。动态代理会在最后一天的基础加强中讲解,这里就不再废话了。

    对request对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道request对象的具体类型,但我们知道request是HttpServletRequest接口的实现类。这说明我们写一个类EncodingRequest,去实现HttpServletRequest接口,然后再把原来的request传递给EncodingRequest类!在EncodingRequest中对HttpServletRequest接口中的所有方法的实现都是通过代理原来的request对象来完成的,只有对getParameter()方法添加了增强代码!

    JavaEE已经给我们提供了一个HttpServletRequestWrapper类,它就是HttpServletRequest的包装类,但它做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的request有什么分别呢?

    HttpServletRequestWrapper类虽然是HttpServletRequest的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承HttpServletRequestWrapper类,那么就只需要重写需要增强的方法即可了。

    3 代码

    EncodingRequest

    public class EncodingRequest extends HttpServletRequestWrapper [崔5] {

        private String charset;

        public EncodingRequest[崔6] (HttpServletRequest request, String charset) {

           super(request);

           this.charset = charset;

        }

     

        public String getParameter[崔7] (String name) {

           HttpServletRequest request [崔8] = (HttpServletRequest) getRequest();

          

           String method = request.getMethod()[崔9] ;

           if(method.equalsIgnoreCase("post[崔10] ")) {

               try {

                  request.setCharacterEncoding(charset);[崔11] 

               } catch (UnsupportedEncodingException e) {}

           } else if(method.equalsIgnoreCase("get[崔12] ")) {

               String value = request.getParameter(name);[崔13] 

               try {

                  value = new String(name.getBytes("ISO-8859-1"), charset);[崔14] 

               } catch (UnsupportedEncodingException e) {

               }

               return value[崔15] ;

           }

           return request.getParameter(name);

        }

    }

    EncodingFilter

    public class EncodingFilter extends HttpFilter {

        public void doFilter(HttpServletRequest request,

               HttpServletResponse response, FilterChain chain)

               throws IOException, ServletException {

           String charset = this.getInitParameter("charset");[崔16] 

           if(charset == null || charset.isEmpty()) {

               charset = "UTF-8";

           }[崔17] 

           response.setCharacterEncoding(charset);

           response.setContentType("text/html;charset=" + charset);

           EncodingRequest res = new EncodingRequest(request, charset);[崔18] 

           chain.doFilter(res, response);[崔19] 

        }

    }

    web.xml

      <filter>

        <filter-name>EncodingFilter</filter-name>

        <filter-class>cn.itcast.filter.EncodingFilter</filter-class>

        <init-param>

            <param-name>charset</param-name>

            <param-value>UTF-8</param-value>

        </init-param>

      </filter>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>/*</url-pattern>

      </filter-mapping>


     [崔5]包含HttpServletRequst

     [崔6]创建本类对象时,需要提供底层request,以及字符集

     [崔7]重写getParameter()方法

     [崔8]把底层对象转换成HttpServletRequest

     [崔9]获取请求方法

     [崔10]如果是post请求

     [崔11]设置编码,OK!

     [崔12]如果是GET请求

     [崔13]通过底层对象获取参数

     [崔14]把参数转码

     [崔15]返回转码后的参数值

     [崔16]获取初始化参数

     [崔17]如果没有配置初始化参数,那么把字符集设置为utf-8

     [崔18]创建EncodingRequest对象,使用request为底层对象

     [崔19]放行!这时用户获取到的request就是EncodingRequest对象了!

  • 相关阅读:
    (译)linux系统关于命令echo的15个例子
    linux之grep实例讲解
    linux grep练习
    (译)"usermod"命令使用完全指导---15个练习例程截图
    linux分区,文件系统,目录结构概述
    Linux 配置YUM
    Linux 强制安装rpm 包
    $LANG、$NLS_LANG 记录一下
    Oracle性能诊断艺术-相关脚本说明
    datafile相关(add、rename、drop)
  • 原文地址:https://www.cnblogs.com/snowwhite/p/4639531.html
Copyright © 2020-2023  润新知