`
whistler
  • 浏览: 25176 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

通过HttpServletRequestWrapper(装饰模式的应用)增强HttpServletRequest的功能

    博客分类:
  • java
阅读更多

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

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

 

过滤器代码:

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中过滤器配置:

<!--将采用的字符编码配置成应用初始化参数而不是过滤器私有的初始化参数是因为在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字段中的参数不起作用,我们通常通过下面的代码来完成编码转换:

 

String paramValue = request.getParameter("paramName");
paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);

 

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

 

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

 

    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" 
               URIEncoding="UTF-8"
     />

 

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

 

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

 

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方法 代码如下:

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方法来获取参数,就已经完成了字符编码的转换过程,我们就不需要在每次获取参数时来进行字符编码转换了。

 

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

  • demo.rar (8.6 KB)
  • 描述: 附:源程序
  • 下载次数: 400
分享到:
评论
5 楼 prowl 2009-10-09  
whistler 写道
文章中已经说明了,原文如下:
原因是post请求和get请求存放参数位置是不同的:
post方式参数存放在请求数据包的消息体中。 get方式参数存放在请求数据包的请求行的URI字段中,以?开始以param=value&parame2=value2的形式附加在URI字段之后。而request.setCharacterEncoding(charset); 只对消息体中的数据起作用,对于URI字段中的参数不起作用。

你可以下载demo工程,运行下效果就可以看到了
1. 首先把ContentTypeFilter中的以下代码注释掉
if(req.getMethod().equalsIgnoreCase("get")) 

     req = new GetHttpServletRequestWrapper(req,charset); 


2. 然后把表单的method属性置为get提交表单,servlet会输出乱码

3. 把表单的method属性置为post提交表单,servlet不会输出乱码

这就印证了上面叙述的原因。

然后将注释的代码取消注释,把表单的method属性置为get提交表单,servlet就不会输出乱码了。


仔细看了下你的代码,确实是这样,多谢。
4 楼 whistler 2009-10-09  
文章中已经说明了,原文如下:
原因是post请求和get请求存放参数位置是不同的:
post方式参数存放在请求数据包的消息体中。 get方式参数存放在请求数据包的请求行的URI字段中,以?开始以param=value&parame2=value2的形式附加在URI字段之后。而request.setCharacterEncoding(charset); 只对消息体中的数据起作用,对于URI字段中的参数不起作用。

你可以下载demo工程,运行下效果就可以看到了
1. 首先把ContentTypeFilter中的以下代码注释掉
if(req.getMethod().equalsIgnoreCase("get")) 

     req = new GetHttpServletRequestWrapper(req,charset); 


2. 然后把表单的method属性置为get提交表单,servlet会输出乱码

3. 把表单的method属性置为post提交表单,servlet不会输出乱码

这就印证了上面叙述的原因。

然后将注释的代码取消注释,把表单的method属性置为get提交表单,servlet就不会输出乱码了。
3 楼 prowl 2009-10-09  
这个问题没遇到过,页面上设置charset=utf-8之后再经过filter过滤不会出现中文乱码的问题了吧

能否详细说下使用你自定义的ContentTypeFilter还会出现乱码的场景及原因。

另外,楼主是老师?
2 楼 hbcui1984 2009-10-09  
个人感觉还是直接修改tomcat配置文件方便,毕竟部署项目时,一般一个tomcat下只有一个应用
1 楼 freerambo 2009-10-08  
写的不错,很详细。编码问题在项目中经常会遇到,值得分享

相关推荐

    用装饰模式装饰HttpServletRequest对象

    这种模式在Swing开发中尤为常见,用于增强或改进现有对象的功能,尤其在Web应用程序中,如Java的J2EE环境,依然具有广泛的应用价值。在Servlet框架中,装饰模式能够解决特定问题,例如处理HttpServletRequest对象。 ...

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

    它的主要作用是为原始请求提供一种装饰模式,让我们可以在不修改原始请求的情况下添加额外的功能或改变其行为。在处理文件上传时,我们可能需要对请求的参数、头信息或者输入流进行特殊处理,这时`...

    JavaWeb之装饰 HttpServletRequest 对象

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

    HttpServletRequestWrapper 用法

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

    使用HttpServletRequestWrapper在filter修改request参数

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

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

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

    HttpServletRequestWrapper

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

    MyEclipse中文字过滤器

    class Request extends HttpServletRequestWrapper { public Request(HttpServletRequest request) { super(request); } public String toChi(String input) { try { byte[] bytes=...

    struts的request包装替换的思想

    然而,出于一些特定需求,例如日志记录、安全性增强或者性能优化,开发者可能希望对请求进行包装,即创建一个新的类来包裹原始的HttpServletRequest对象,以便在处理请求的过程中添加额外的功能。这种包装替换的思想...

    J2EE基础,设计模式

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

    java HttpServletRequest和HttpServletResponse详解

    HttpServletRequest和HttpServletResponse的包装类,如HttpServletRequestWrapper和HttpServletResponseWrapper,是为了提供额外的功能或者改变默认行为。它们实现了原接口,并允许你覆盖或添加方法,以适应特定的...

    J2EE设计模式与Structs详解

    5. **装饰者模式**:动态地给一个对象添加一些额外的职责,使得增加功能变得更加灵活,避免了子类的大量生成。在J2EE中,如HttpServletRequestWrapper和HttpServletResponseWrapper。 6. **适配器模式**:将一个类...

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

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

    ParameterRequestUtils.java

    实现自定义增加请求参数,通常是由于需要对参数进行特殊业务处理,然而HttpServletRequest的request.getPrameterMap是不允许修改的(被锁,可查看底层源码),该工具类通过继承HttpServletRequestWrapper可增加...

    Killtest 免费提供 310-084 最新资料下载

    `HttpServletRequestWrapper`类是Servlet API的一部分,它实现了`HttpServletRequest`接口,并作为装饰者模式的一个示例,提供了扩展和修改请求对象的能力。以下是对`HttpServletRequestWrapper`的一些关键理解: -...

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

    通过合理的配置和设计,开发者可以利用`Filter`来实现诸如统一字符编码设置、权限验证、日志记录等多种功能。 #### 二、统一全站字符编码 在实际项目开发过程中,统一处理字符编码是非常关键的一步,特别是当涉及...

    jsp中Filter类实现过滤器功能

    ### JSP中Filter类实现过滤器功能 #### 概述 ...它不仅能够确保数据的安全性,还能够在不影响应用性能的情况下增强用户体验。对于任何需要处理用户输入的Web应用程序来说,这种方法都是非常有价值的。

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

    HttpServletRequest httpreq = (HttpServletRequest) request; if (httpreq.getMethod().equals("POST")) { request.setCharacterEncoding("GBK"); } else { request = new Request(httpreq); } chain....

Global site tag (gtag.js) - Google Analytics