网站字符编码

1、如何处理全站字符乱码?


  处理全站字符乱码,即POST和GET中文编码,一般处理如下:

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

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

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

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


2、分析


  全站乱码问题的难点就是处理GET请求参数的问题,因为普通处理get方法是提前知道get方法中的参数是什么,然后针对参数转码,但是如果参数不明确的话,就不能利用普通方法。

  处理POST请求的编码问题,以及响应编码问题:

public class EncodingFilter extends HttpFilter {
	public void doFilter(HttpServletRequest request,HttpServletResponse response, FilterChain chain)throws IOException, ServletException {
		String charset = this.getInitParameter("charset");
		if(charset == null || charset.isEmpty()) {
			charset = "UTF-8";
		}
		request.setCharacterEncoding(charset); //设置请求编码
		response.setContentType("text/html;charset=" + charset); //设置响应编码
		chain.doFilter(request, response);//放行
	}
}


  如果是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对象进行增强的手段:

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

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

     动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。

  对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 {
	private String charset;
	public EncodingRequest(HttpServletRequest request, String charset) {
		super(request);
		this.charset = charset;
	}

	public String getParameter(String name) {
		HttpServletRequest request = (HttpServletRequest) getRequest();
		
		String method = request.getMethod();
		if(method.equalsIgnoreCase("post")) {
			try {
				request.setCharacterEncoding(charset);
			} catch (UnsupportedEncodingException e) {}
		} else if(method.equalsIgnoreCase("get")) {
			String value = request.getParameter(name);
			try {
				value = new String(name.getBytes("ISO-8859-1"), charset);
			} catch (UnsupportedEncodingException e) {
			}
			return value;
		}
		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");
		if(charset == null || charset.isEmpty()) {
			charset = "UTF-8";
		}
		response.setCharacterEncoding(charset);
		response.setContentType("text/html;charset=" + charset);
		EncodingRequest res = new EncodingRequest(request, charset);
		chain.doFilter(res, response);
	}
}


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>


  小结:解决全站字符编码的关键就是运用装饰模式对getParameter进行增强,然后使用过滤器将request对象掉包。



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值