采用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 + "\n" + 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("\tafter 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给出的方法

你可能感兴趣的:(采用Filter的方法解决HttpServletRequest.getParameter乱码的问题)