`

通过HttpServletRequestWrapper(装饰模式的应用)增强HttpServletRequest,实现解决get方式的中文乱码

    博客分类:
  • web
阅读更多

转自http://whistler.iteye.com/blog/483158

应用一:解决tomcat下中文乱码问题(先来个简单的) 

tomcat下,我们通常这样来解决中文乱码问题:

 

过滤器代码:

Java代码 复制代码
  1. package filter;   
  2.   
  3. import java.io.*;   
  4. import javax.servlet.*;   
  5. import javax.servlet.http.*;   
  6. import wrapper.GetHttpServletRequestWrapper;   
  7.   
  8. public class ContentTypeFilter implements Filter {   
  9.   
  10.     private String charset = "UTF-8";   
  11.     private FilterConfig config;   
  12.        
  13.     public void destroy() {   
  14.         System.out.println(config.getFilterName()+"被销毁");   
  15.         charset = null;   
  16.         config = null;   
  17.     }   
  18.   
  19.     public void doFilter(ServletRequest request, ServletResponse response,   
  20.             FilterChain chain) throws IOException, ServletException {   
  21.         //设置请求响应字符编码   
  22.         request.setCharacterEncoding(charset);   
  23.         response.setCharacterEncoding(charset);   
  24.            
  25.         HttpServletRequest req = (HttpServletRequest)request;   
  26.            
  27.            
  28.         System.out.println("----请求被"+config.getFilterName()+"过滤");   
  29.         //执行下一个过滤器(如果有的话,否则执行目标servlet)   
  30.         chain.doFilter(req, response);   
  31.            
  32.         System.out.println("----响应被"+config.getFilterName()+"过滤");   
  33.   
  34.     }   
  35.   
  36.     public void init(FilterConfig config) throws ServletException {   
  37.             this.config = config;   
  38.             String charset = config.getServletContext().getInitParameter("charset");     
  39.             if( charset != null && charset.trim().length() != 0)   
  40.             {   
  41.                 this.charset = charset;   
  42.             }   
  43.     }   
  44.   
  45. }  
package filter;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import wrapper.GetHttpServletRequestWrapper;

public class ContentTypeFilter implements Filter {

	private String charset = "UTF-8";
	private FilterConfig config;
	
	public void destroy() {
        System.out.println(config.getFilterName()+"被销毁");
		charset = null;
		config = null;
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
        //设置请求响应字符编码
		request.setCharacterEncoding(charset);
		response.setCharacterEncoding(charset);
		
        HttpServletRequest req = (HttpServletRequest)request;
		
		
		System.out.println("----请求被"+config.getFilterName()+"过滤");
		//执行下一个过滤器(如果有的话,否则执行目标servlet)
		chain.doFilter(req, response);
		
		System.out.println("----响应被"+config.getFilterName()+"过滤");

	}

	public void init(FilterConfig config) throws ServletException {
		    this.config = config;
            String charset = config.getServletContext().getInitParameter("charset");  
            if( charset != null && charset.trim().length() != 0)
            {
            	this.charset = charset;
            }
	}

}

 

 

web.xml中过滤器配置:

Xml代码 复制代码
  1. <!--将采用的字符编码配置成应用初始化参数而不是过滤器私有的初始化参数是因为在JSP和其他地方也可能需要使用-->  
  2.     <context-param>  
  3.             <param-name>charset</param-name>  
  4.             <param-value>UTF-8</param-value>  
  5.     </context-param>  
  6.   
  7.     <filter>  
  8.         <filter-name>ContentTypeFilter</filter-name>  
  9.         <filter-class>filter.ContentTypeFilter</filter-class>  
  10.     </filter>  
  11.   
  12.     <filter-mapping>  
  13.         <filter-name>ContentTypeFilter</filter-name>  
  14.         <url-pattern>/*</url-pattern>  
  15.     </filter-mapping>  
<!--将采用的字符编码配置成应用初始化参数而不是过滤器私有的初始化参数是因为在JSP和其他地方也可能需要使用-->
	<context-param>
			<param-name>charset</param-name>
			<param-value>UTF-8</param-value>
	</context-param>

	<filter>
		<filter-name>ContentTypeFilter</filter-name>
		<filter-class>filter.ContentTypeFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>ContentTypeFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

 

request.setCharacterEncoding(charset); 必须写在第一次使用request.getParameter()之前,这样才能保证参数是按照已经设置的字符编码来获取。
response.setCharacterEncoding(charset);必须写在PrintWriter out = request.getWriter()之前,这样才能保证out按照已经设置的字符编码来进行字符输出。

 

通过过滤器,我们可以保证在Servlet或JSP执行之前就设置好了请求和响应的字符编码。

 

但是这样并不能完全解决中文乱码问题:

对于post请求,无论是“获取参数环节”还是“输出环节"都是没问题的;

对于get请求,"输出环节"没有问题,但是"获取参数环节"依然出现中文乱码,所以在输出时直接将乱码输出了。

 

原因是post请求和get请求存放参数位置是不同的:

post方式参数存放在请求数据包的消息体中。get方式参数存放在请求数据包的请求行的URI字段中,以?开始以param=value&parame2=value2的形式附加在URI字段之后。而request.setCharacterEncoding(charset); 只对消息体中的数据起作用,对于URI字段中的参数不起作用,我们通常通过下面的代码来完成编码转换:

 

Java代码 复制代码
  1. String paramValue = request.getParameter("paramName");   
  2. paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);  
String paramValue = request.getParameter("paramName");
paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);

 

但是每次进行这样的转换实在是很麻烦,有没有统一的解决方案呢?

 

解决方案1: 在tomcat_home\conf\server.xml 中的Connector元素中设置URIEncoding属性为合适的字符编码

 

Java代码 复制代码
  1. <Connector port="8080" protocol="HTTP/1.1"    
  2.            connectionTimeout="20000"    
  3.            redirectPort="8443"    
  4.            URIEncoding="UTF-8"  
  5.  />  
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" 
               URIEncoding="UTF-8"
     />

 

这样做的缺点是,同一个tomcat下的其他应用也将受到影响。而其每次部署时都需要类修改配置也很麻烦。

 

解决方案2:自定义请求包装器包装请求,将字符编码转换的工作添加到getParameter()方法中

 

Java代码 复制代码
  1. package wrapper;   
  2.   
  3. import java.io.UnsupportedEncodingException;   
  4. import java.net.URLDecoder;   
  5.   
  6. import javax.servlet.http.HttpServletRequest;   
  7. import javax.servlet.http.HttpServletRequestWrapper;   
  8.   
  9. public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {   
  10.   
  11.     private String charset = "UTF-8";   
  12.   
  13.     public GetHttpServletRequestWrapper(HttpServletRequest request) {   
  14.         super(request);   
  15.     }   
  16.   
  17.     /**  
  18.      * 获得被装饰对象的引用和采用的字符编码  
  19.      * @param request  
  20.      * @param charset  
  21.      */  
  22.     public GetHttpServletRequestWrapper(HttpServletRequest request,   
  23.             String charset) {   
  24.         super(request);   
  25.         this.charset = charset;   
  26.     }   
  27.   
  28.     /**  
  29.      * 实际上就是调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换  
  30.      */  
  31.     public String getParameter(String name) {   
  32.         String value = super.getParameter(name);   
  33.         value = value == null ? null : convert(value);   
  34.         return value;   
  35.     }   
  36.   
  37.     public String convert(String target) {   
  38.         System.out.println("编码转换之前:" + target);   
  39.         try {   
  40.             return new String(target.trim().getBytes("ISO-8859-1"), charset);   
  41.         } catch (UnsupportedEncodingException e) {   
  42.             return target;   
  43.         }   
  44.     }   
  45.   
  46. }  
package wrapper;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {

	private String charset = "UTF-8";

	public GetHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	/**
	 * 获得被装饰对象的引用和采用的字符编码
	 * @param request
	 * @param charset
	 */
	public GetHttpServletRequestWrapper(HttpServletRequest request,
			String charset) {
		super(request);
		this.charset = charset;
	}

	/**
	 * 实际上就是调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换
	 */
	public String getParameter(String name) {
		String value = super.getParameter(name);
		value = value == null ? null : convert(value);
		return value;
	}

	public String convert(String target) {
		System.out.println("编码转换之前:" + target);
		try {
			return new String(target.trim().getBytes("ISO-8859-1"), charset);
		} catch (UnsupportedEncodingException e) {
			return target;
		}
	}

}

 

修改过滤器的doFilter方法 代码如下:

Java代码 复制代码
  1. public void doFilter(ServletRequest request, ServletResponse response,   
  2.             FilterChain chain) throws IOException, ServletException {   
  3.         //设置请求响应字符编码   
  4.         request.setCharacterEncoding(charset);   
  5.         response.setCharacterEncoding(charset);   
  6.         //新增加的代码           
  7.         HttpServletRequest req = (HttpServletRequest)request;   
  8.            
  9.         if(req.getMethod().equalsIgnoreCase("get"))   
  10.         {   
  11.             req = new GetHttpServletRequestWrapper(req,charset);   
  12.         }   
  13.            
  14.         System.out.println("----请求被"+config.getFilterName()+"过滤");   
  15.         //传递给目标servlet或jsp的实际上时包装器对象的引用,而不是原始的HttpServletRequest对象   
  16.         chain.doFilter(req, response);   
  17.            
  18.         System.out.println("----响应被"+config.getFilterName()+"过滤");   
  19.   
  20.     }  
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
        //设置请求响应字符编码
		request.setCharacterEncoding(charset);
		response.setCharacterEncoding(charset);
        //新增加的代码		
        HttpServletRequest req = (HttpServletRequest)request;
		
        if(req.getMethod().equalsIgnoreCase("get"))
        {
        	req = new GetHttpServletRequestWrapper(req,charset);
        }
		
		System.out.println("----请求被"+config.getFilterName()+"过滤");
		//传递给目标servlet或jsp的实际上时包装器对象的引用,而不是原始的HttpServletRequest对象
		chain.doFilter(req, response);
		
		System.out.println("----响应被"+config.getFilterName()+"过滤");

	}

 

这样一来,在servlet中调用包装器的getParameters方法来获取参数,就已经完成了字符编码的转换过程,我们就不需要在每次获取参数时来进行字符编码转换了。

 

这是我讲课时的一个例子,不对之处,敬请指教,以免误人子弟啊。

分享到:
评论

相关推荐

    用装饰模式装饰HttpServletRequest对象

    通过这种方式,装饰模式使得在不修改HttpServletRequest本身的情况下,我们可以扩展其功能,解决了在Servlet过滤器中无法直接修改请求参数的问题。 总之,装饰模式在Servlet编程中提供了一种灵活的、非侵入式的扩展...

    HttpServletRequestWrapper应用(二):包装文件上传请求

    在Java Web开发中,`HttpServletRequestWrapper`是一个非常重要的工具,它允许我们自定义或扩展标准的`HttpServletRequest`对象。在标题“HttpServletRequestWrapper应用(二):包装文件上传请求”中,我们将探讨...

    JavaWeb之装饰 HttpServletRequest 对象

    在实际开发中,我们经常需要对HttpServletRequest进行扩展或增强,以满足特定的业务需求,这时装饰模式就派上了用场。 装饰模式是一种设计模式,它允许我们向一个现有的对象添加新的行为或责任,而无需修改该对象的...

    Tomcat和weblogic中文乱码问题解决方案

    Tomcat和WebLogic中文乱码问题解决方案 在 Java Web 开发中,中文乱码问题一直是困扰开发者的主要问题之一。 Tomcat 和 WebLogic 是两个常用的 web 服务器,都是支持 Servlet 和 JSP 的。然而,在使用这些服务器时...

    HttpServletRequestWrapper 用法

    `HttpServletRequestWrapper`通过继承`HttpServletRequest`并重写其方法,为每个方法提供自定义的实现。当你调用这些方法时,实际上是在调用包装器中的方法。在这些方法中,你可以选择保留原始行为,或者添加自己的...

    Java关于中文乱码问题的多种解决方法

    通过实现`Filter`接口,重写`doFilter()`方法,设置请求和响应的编码,如`HttpServletRequestWrapper`和`HttpServletResponseWrapper`。 8. 字符集理解: 对于不同的字符集,如GBK、UTF-8、GB2312等,理解它们之间...

    使用HttpServletRequestWrapper在filter修改request参数

    `HttpServletRequestWrapper` 是Servlet API中的一个抽象类,它是`HttpServletRequest` 的包装类,可以用来扩展或修改原始请求对象的功能。 标题“使用HttpServletRequestWrapper在filter修改request参数”揭示了...

    HttpServletRequestWrapper

    这是一个关于HttpServletRequestWrapper使用的列子,工作需要,所以传上来的。

    9.设计模式-装饰器模式1

    `HttpServletRequestWrapper` 和 `HttpServletResponseWrapper` 就是典型的装饰器模式应用,它们允许开发者在原始请求和响应对象的基础上添加额外的功能,如日志记录、安全检查等,而无需修改原始的 `...

    Web开发 乱码过滤器.zip

    总结来说,这个压缩包提供了处理Web应用中乱码问题的解决方案,包括了自定义HttpServletRequestWrapper来正确解码GET参数,以及通过字符编码过滤器统一设置请求和响应的编码。这样的做法可以有效避免由于编码不一致...

    MyEclipse中文字过滤器

    String values[]=getHttpServletRequest().getParameterValues(name); if(values!=null) { for(int i=0;i;i++) { values[i]=toChi(values[i]); } } return values; } ...

    通过过滤器(Filter)解决JSP的Post和Request中文乱码问题

    通过指定filter-name和filter-class来配置过滤器类,然后通过filter-mapping标签来指定过滤器应用的URL模式和调度器类型。这里的URL模式为“/*”,表示过滤器会作用于所有的请求。调度器类型为REQUEST,表示过滤器仅...

    Android编程向服务器发送请求时出现中文乱码问题的解决方法

    通过这样的装饰模式设计,我们可以在不改变服务器或客户端代码结构的情况下,实现对所有请求的全局编码处理,确保中文参数的正确传递。 总结来说,解决Android向服务器发送请求时的中文乱码问题,关键在于对请求...

    用Filter来解决中文表单提交问题

    总的来说,`TomcatFormFilter`通过在请求到达目标资源之前设置合适的字符编码,有效地解决了中文表单提交时可能出现的乱码问题。此外,这种解决方案还具有一定的通用性,可以应用于其他类似的字符编码转换场景,增强...

    jsp中FilterDome(乱码过滤器源代码)

    通过理解`FilterDome`的工作原理和应用,我们可以有效地解决Java Web开发中的乱码问题,提升用户体验。在实际项目中,根据具体需求和环境,可能需要对`FilterDome`进行定制化调整,以满足特定场景下的编码需求。

    java,jsp,servlet 乱码

    以下是一些解决乱码问题的关键知识点: 1. **页面编码设置**: - 静态HTML页面可以通过`&lt;meta&gt;`标签设置编码,例如`; charset=utf-8"&gt;`。 - JSP页面通常在顶部使用`&lt;%@ page pageEncoding="utf-8"%&gt;`来指定页面...

    javaweb中Filter(过滤器)的常见应用.docx

    * @Description: 此过滤器用来解决全站中文乱码问题 */ public class CharacterEncodingFilter implements Filter { private FilterConfig filterConfig = null; // 设置默认的字符编码 private String default...

    java servlet 监听器

    return MyEncoding(getHttpServletRequest().getParameter(name)); } @Override public String[] getParameterValues(String name) { String[] values = getHttpServletRequest().getParameterValues...

    J2EE基础,设计模式

    5. 装饰器模式:在J2EE中,装饰器模式常用于动态地给对象添加新的行为或责任,例如HttpServletRequestWrapper和HttpServletResponseWrapper。 6. 适配器模式:在与不同标准或接口进行集成时,适配器模式可以帮助...

    java web 修改request携带的参数信息

    本程序就是针对这种情况设计的一个实用工具,它利用了Servlet Filter技术来实现这一功能。 **Filter技术详解** Filter是Java Servlet API的一部分,主要用于拦截和处理Servlet请求和响应。它们在请求到达目标...

Global site tag (gtag.js) - Google Analytics