zoukankan      html  css  js  c++  java
  • 采用Filter的方法解决HttpServletRequest.getParameter乱码的问题

    其实就是利用这么一个原理:

    byte[] bytes = str.getBytes("iso-8859-1");
    String result = new String(bytes, charset); // 将str转化为你指定的charset encoding

    这个filter解决了什么问题呢?其实就是解决了使用request.getParameter时的乱码问题,比如说,你有一个a.html或者a.jsp发送request给servlet_b,servlet_b利用request.getParameter把参数提取出来,然后送到c.jsp去显示,如果你的a.html/jsp使用的编码是GB2312或者UTF-8之类的,那么在传输的过程中就可能出现乱码(具体我就不描述了,你拿这个代码去试试就知道乱码到底出现在哪里)

    在web.xml中关于这个filter的一个参数是enable,如果你想关闭这个filter,那么令enable为false即可

    完整的代码如下,先给出测试代码(见http://www.cnblogs.com/qrlozte/p/3515171.html):

    input_attribute.html

    AttributeSetterServlet.java

      req.getParameter读取attribute,然后req.setAttribute(attribute),接着跳转到display_attribute.jsp

    display_attribute.jsp

      request.getAttribute("attribute")提取attribute

    ------------------------------Filter代码-------------------------------

    I18nServletFilter:

      注意,由于编码的filter是属于最基本的的filter,所以在web.xml中一定要把编码的filter放在靠前的位置,至少是要放在encoding-sensitive的filter和servlet之前

      此filter从web.xml中读取参数charset,charset就是你希望使用的编码参数,比如说GBK、UTF-8之类的

      这个filter使用了一个自定义的类叫做I18nHttpServletRequestWrapper,继承自HttpServletRequestWrapperHttpServletRequestWrapper提供了实现HttpServletRequest的基本框架,client可以继续extends(参考design pattern:adapter),所以I18nHttpServletRequestWrapper重写了的getParameter()以及getParameterValues()方法,添加了encoding的代码,确保了getParameter()和getParameterValues()返回的内容都是由charset参数指定的编码。并且,这个filter一但被调用,那么chain.doFilter()就会把这里的wrapper给传递下去,从而确保在filter-chain后面的filter或者其他的servlet的编码问题都得到解决。

     1 /**
     2  * If this filter is enabled, it will wrap the default
     3  * HttpServletRequest with I18nHttpServletRequestWrapper and 
     4  * pass it to filters/servlets following this filter in the chain,
     5  * the purpose is to add charset-conversion functionality to the
     6  * HttpServletRequest, so that when you invoke getParameter()
     7  * or getParameterValues(), the returned string is encoded in the
     8  * specified charset. The charset name is specified by the init-param
     9  * of this filter. 
    10  * */
    11 public class I18nServletFilter implements Filter {
    12 
    13     private FilterConfig filterConfig;
    14 
    15     private String charsetName = "UTF-8";
    16     private boolean enable = false;
    17     //Handle the passed-in FilterConfig
    18     public void init(FilterConfig filterConfig) throws ServletException {
    19         this.filterConfig = filterConfig;
    20         String enableString = filterConfig.getInitParameter("enable");
    21         if (enableString != null && enableString.equalsIgnoreCase("true")) {
    22             this.enable = true;
    23         }
    24         String charset = filterConfig.getInitParameter("charset");
    25         if (charset != null && charset.trim().length() != 0) {
    26             this.charsetName = charset;
    27         }
    28     }
    29 
    30     //Process the request/response pair
    31     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    32         if (this.enable) {
    33             try {
    34                 if (this.charsetName != null) {
    35                     // System.out.println(this + ", " + this.charsetName); // @Debug
    36                     I18nHttpServletRequestWrapper requestWrapper = 
    37                         new I18nHttpServletRequestWrapper( (HttpServletRequest) request, this.charsetName);
    38                     // 注意:传递下去的是requestWrapper而不是request
    39                     filterChain.doFilter(requestWrapper, response);
    40                 } else {
    41                     filterChain.doFilter(request, response);
    42                 }
    43             } catch(ServletException sx) {
    44                 filterConfig.getServletContext().log(sx.getMessage());
    45             } catch(IOException iox) {
    46                 filterConfig.getServletContext().log(iox.getMessage());
    47             }
    48         } else {
    49             filterChain.doFilter(request, response);
    50         }
    51     }
    52 
    53     // Clean up resources
    54     public void destroy() {
    55         filterConfig = null;
    56         charsetName = null;
    57     }
    58     
    59 }

    HttpServletRequestWrapper

      上面已经解释过了,这个是利用decorator pattern对HttpServletRequest进行了一次封装,对getParameter()以及getParameterValues()方法增加编码转换的功能

     1 /**
     2  * This class wraps the default HttpServletRequest to provide
     3  * a charset-conversion functionality, so that getParameter()
     4  * and getParameterValues() can return parameter-strings encoded
     5  * in your specified charset. 
     6  * 
     7  * The charset is specified by the constructor
     8  * of this class.
     9  * */
    10 public class I18nHttpServletRequestWrapper extends HttpServletRequestWrapper {
    11     private Map<String, String[]> paramMap = new HashMap<String, String[]>();
    12     private String charsetName = "iso-8859-1";
    13     /**
    14      * 每次I18nServletFilter.doFilter()被调用,就会新建一个I18nHttpServletRequestWrapper.
    15      * 那么I18nHttpServletRequestWrapper就会提取出HttpServletRequest中的所有parameters并
    16      * 存放到paramMap中.
    17      * 
    18      * 由于服务器跳转是request范围的,所以服务器跳转始终是一个request,只会new一个I18nHttpServletRequestWrapper
    19      * */
    20     public I18nHttpServletRequestWrapper(HttpServletRequest request, String charsetName) {
    21         super(request);
    22         // System.out.println("constructing " + this); // @Debug
    23         this.charsetName = charsetName;
    24         initParameterMap(request);
    25     }
    26     private void initParameterMap(HttpServletRequest request) {
    27         if (request == null) {
    28             return;
    29         }
    30         Map<String,String[]> map = request.getParameterMap();
    31         Set<String> names = map.keySet();
    32         String[] values;
    33         for (Iterator<String> i = names.iterator(); i.hasNext(); ) {
    34             String name = i.next();
    35             values = map.get(name);
    36             for (int j = 0; j < values.length; j++) {
    37                 values[j] = convertCharset(values[j]);
    38             }
    39             this.paramMap.put(name, values);
    40         }
    41     }
    42     public String getParameter(String name) {
    43         String[] values = this.getParameterValues(name);
    44         if (values != null && values.length > 0) {
    45             return values[0];
    46         } else {
    47             return null;
    48         }
    49     }
    50     public String[] getParameterValues(String name) {
    51         return this.paramMap.get(name);
    52     }
    53     private boolean isInParamValues(String s) {
    54         for (String[] values : paramMap.values()) {
    55             for (String value : values) {
    56                 if (s.equals(value)) {
    57                     return true;
    58                 }
    59             }
    60         }
    61         return false;
    62     }
    63     @Override
    64     public void setAttribute(String name, Object o) {
    65         /*
    66          * 防止已经被编码过的String被重新编码、
    67          * 比如说,一个String x本来是iso-8859-1,通过convertCharset转码成为了utf-8
    68          * 然后,你又调用convertCharset(x),那么convertCharset就会首先把x解码成
    69          * iso-8859-1的byte(导致乱码,因为此时x已经是utf-8编码了),然后再用utf-8编码(还是乱码)
    70          * 
    71          * 那么已经被编码过的String来源有哪些?
    72          * 1、通过request.setAttribute已经添加的string attribute value
    73          * 2、已经在paramMap中的value
    74          * */
    75         if (o instanceof String && !isInParamValues((String)o) && !o.equals(getAttribute(name))) {
    76             // System.out.println("setAttr:check " + paramMap + "
    " + getAttribute(name)); // @Debug
    77             o = convertCharset((String)o);
    78         }
    79         super.setAttribute(name, o);
    80     }
    81     
    82     private String convertCharset(String str) {
    83         if (str == null) {
    84             return null;
    85         }
    86         try {
    87             // System.out.println("before convert: " + str); // @Debug
    88             str = new String(str.getBytes("iso-8859-1"), this.charsetName);
    89             // System.out.println("	after convert: " + str); // @Debug
    90             return str;
    91         } catch (UnsupportedEncodingException ex) {
    92             Logger.getLogger(this.getClass().toString()).log(Level.SEVERE, ex + ", charset = " + this.charsetName);
    93         }
    94         return null;
    95     }
    96 }

    web.xml

     1     <!-- i18nservletfilter -->
     2     <filter>
     3         <filter-name>i18nservletfilter</filter-name>
     4         <filter-class>org.foo.filterdemo.I18nServletFilter</filter-class>
     5         <init-param>
     6             <param-name>enable</param-name>
     7             <param-value>true</param-value>
     8         </init-param>
     9         <init-param>
    10             <param-name>charset</param-name>
    11             <param-value>UTF-8</param-value>
    12         </init-param>
    13     </filter>
    14     <filter-mapping>
    15         <filter-name>i18nservletfilter</filter-name>
    16         <url-pattern>/*</url-pattern>
    17     </filter-mapping>

    总结

      这个什么I18nServletFilter是我先前在翻阅资料的时候找到的,现搬过来吧,又解决不了编码的问题

      自己捣鼓了半天吧,好歹算是能用了,但是总的感觉就是:Verbose + Error-prone.

      推荐使用http://www.cnblogs.com/qrlozte/p/3515171.html给出的方法

  • 相关阅读:
    C# 管理IIS7(转)
    KeyDown,KeyPress和KeyUp详解(转)
    C#中事件的声明与使用
    在类中使用SERVER
    什么是强类型,强类型集合
    配置sql server 2000以允许远程访问
    如何使textbox只能输入数字和小数点
    在BUTTON中触发GRIDVIEW的方法
    多个GRIDVIEW同时导入到一个EXCEL文件中
    ajax3.5的BUG
  • 原文地址:https://www.cnblogs.com/qrlozte/p/3178370.html
Copyright © 2011-2022 走看看