Servlet中通过过滤器实现统一的手动编码(解决中文乱码)

首先, 这里尝试解决的问题是针对GET方式的请求的.

 

因为GET方式的参数是追加在请求URL之后的, 会进行url转码, 这样, 往往会导致乱码问题.

 

首先, 提出几种可能的解决方式:

1. 在tomcat等容器中, 配置URI的编码.

2. 设置request的characterEncoding

3. 手动转码

4. 手动的二次转码, 完全避免乱码问题的发生.

如有其他方式, 请共享学习, 谢谢.

 

第一种不做介绍, 网上有相关资料查查配置即可解决.

第二种, 在GET参数处理时并不管用, 设置方法比较简单: request.setCharacterEncoding

 

那第三种, 手动转码:

request.getParameter("name");

这是我们从request中获取一个参数的方式, 得到的是一个字符串的值, 暂时没有相关的源码资料, 但是根据经验推断, 这里至少对GET传递的参数取值的时候采用了ISO8859-1编码.

因此, 我们需要手动的将这个编码修正成为我们需要的编码. 也就是自己将这个字符串进行转码, 如下:

 

//注意, 这里并不会在后台处理中出现, 但是, 对于理解这个编码问题非常重要

//浏览器首先将一个包含中文的参数做一次处理的, 或者UTF-8, 或者GBK, 我这边两种情况都碰到了

//那我们假设发送的参数最初是UTF-8的.

 

String value = request.getParameter("name");     //servlet内部会将参数转码成ISO8859-1编码

byte[] valueBytes = value.getBytes("ISO8859-1"); //根据他自身的编码获取到这个字符串原生(也就是原来的UTF-8)的字节数组.

value = new String(valueBytes, "UTF-8");    //此时的valueBytes字节数组中存放的字节序列已经是UTF-8的编码方式了, 那么我们使用UTF-8将其构建成为一个String对象即可完成手动编码的过程.

 

第四种:

第四种则是为了防止上面情况的发生, 提前做一次转码.

比如, 要传递一个中文参数"张三", 那么,

1, 在客户端, 先使用客户端语言(比如javascript)将"张三"进行一次编码(任何编码都可以),

    由于经过一次编码之后, 得到的肯定是一个只包含英文或数字这些ASCII字符的字符串了,

2. 那么, 在服务端接受的过程中是不会有任何问题的, 因为无论哪种编码, 对ASCII码的支持都是一致的.

3. 使用客户端使用的编码方式将接受到的参数的值进行解码, 这样就能够得到原来的那个字符串.

假设, 使用某种编码, "张三"会被编码成为"ZHANGSAN", 那么, 实际传输中, 传输的就是ZHANGSAN, 这是不会存在问题的, 那么在服务端, 将"ZHANGSAN"再转码回到"张三"就行了.

 

无论是哪一种, 都可以在filter中进行过滤实现的, 最近在看struts2, 借鉴struts的一点点小概念, 做了一个第三种方法的过滤器来使用.

请各位大侠指正:

 

配置: 测试的时候, 可以更换newEncoding来测试自己的浏览器对get参数的编码, 暂时对浏览器对get参数编码的规律没有掌握.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<servlet>
		<servlet-name>test</servlet-name>
		<servlet-class>selfimpr.web.encoding.test.TestServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>test</servlet-name>
		<url-pattern>/servlet/test</url-pattern>
	</servlet-mapping>
	<filter>
		<filter-name>parameterEncoding</filter-name>
		<filter-class>selfimpr.web.encoding.test.ParameterEncodingFilter</filter-class>
		<init-param>
			<param-name>oldEncoding</param-name>
			<param-value>ISO8859-1</param-value>
		</init-param>
		<init-param>
			<param-name>newEncoding</param-name>
			<param-value>GBK</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>parameterEncoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>
过滤器:

package selfimpr.web.encoding.test;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 参数编码过滤
 * 借鉴struts的方式, 将处理之后的值单独的存放到了request中.
 * @author selfimpr
 * @blog http://blog.csdn.net/lgg201
 * @email lgg860911@yahoo.com.cn
 *
 */
public class ParameterEncodingFilter implements Filter {
    private String oldEncoding;
    private String newEncoding;
    public static String key = "selfimpr.web.encoding.test.parameters";

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        Map<String, String> parameters = new HashMap<String, String>();
        Enumeration<String> names = request.getParameterNames();
        for(; names.hasMoreElements(); ) {
            String name = names.nextElement();
            parameters.put(name, new String(request.getParameter(name).getBytes(oldEncoding), newEncoding));
        }
        request.setAttribute(ParameterEncodingFilter.key, parameters);
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.oldEncoding = config.getInitParameter("oldEncoding");
        this.newEncoding = config.getInitParameter("newEncoding");
    }

}

测试的servlet:

package selfimpr.web.encoding.test;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 测试用servlet, 测试的时候, 访问这个servlet, 并追加名字为user的中文参数就可以了.
 * @author selfimpr
 * @blog http://blog.csdn.net/lgg201
 * @email lgg860911@yahoo.com.cn
 *
 */
public class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        Map<String, String> parameters = (Map<String, String>) req.getAttribute(ParameterEncodingFilter.key);
        String user = parameters.get("user");
        System.out.println(user);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        this.doGet(req, resp);
    }

    /**
     *
     */
    private static final long serialVersionUID = -1878035790525968488L;

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值