Servlet--j2e中文乱码解决

我们在写项目的时候常常会传递一些中文參数,可是j2e默认使用ISO-8859-1来编码和解码,所以非常easy出现中文乱码问题。

这里我做一个统一的整理,事实上这里的中文乱码问题和上一篇的路径问题都是j2e常常遇见的非常普遍的问题。无论你使用不使用框架都是非常easy发生的。所以好好的整理一下还是非常有必要的。

  • 详细有可能发生乱码的地方有:

1. 从数据库到Java程序 byte——〉char

2. 从Java程序到数据库 char——〉byte

3. 从文件到Java程序 byte——〉char

4. 从Java程序到文件 char——〉byte

5. 从流到Java程序byte——〉char

6. 从Java程序到流char——〉byte

7. 从Java程序到页面显示 char——〉byte

8. 从页面form提交数据到Java程序byte——〉char

其它的临时先无论,如今我们先来处理Servlet中的中文乱码,也就是上面最后2点。

  • 首先必需要明确的,Tomcat的參数问题不管是GET或是POST方式都是用8859_1编码的。

1,GET方式要看tomcat下源代码。

protected static Locale defaultLocale = Locale.getDefault();貌似这里的编码使用的本地的编码,可是我们细致看下

org.apache.tomcat.service.http. HttpRequestAdapter类

---- line=new String(buf, 0, count, Constants.CharacterEncoding.Default);

----  Constants.CharacterEncoding.Default=8859_1  

这段代码不好跟踪。千万不要被一些假象迷惑住,HttpRequestAdapter是从RequestImpl中派生的。

可是。实际上用8080port的Server并没有直接用到RequestImpl。而是用了HttpRequestAdapter来获得queryString。

2,POST方式我们看下javax.servlet.http.HttpUtils的parsePostData方法。以下贴出源代码。

public static Hashtable parsePostData(int len, ServletInputStream in)
	{
		if (len <= 0)
		{
			return new Hashtable();
		}
		if (in == null)
		{
			throw new IllegalArgumentException();
		}

		byte[] postedBytes = new byte[len];
		try
		{
			int offset = 0;
			do
			{
				int inputLen = in.read(postedBytes, offset, len - offset);
				if (inputLen <= 0)
				{
					String msg = lStrings.getString("err.io.short_read");
					throw new IllegalArgumentException(msg);
				}
				offset += inputLen;
			}
			while (len - offset > 0);
		}
		catch (IOException e)
		{
			throw new IllegalArgumentException(e.getMessage());
		}

		try
		{
			String postedBody = new String(postedBytes, 0, len, "8859_1");
			return parseQueryString(postedBody);
		}
		catch (UnsupportedEncodingException e)
		{
		}
		throw new IllegalArgumentException(e.getMessage());
	}

事实上研究这个tomcat的编码源代码没啥意义,也就不用管了,记住就好,无论是GET还是POST,tomcat都是用8859_1来编码的。

  • OK,如今開始整理中文乱码的处理,解决Servlet中的乱码问题。

1。表单提交

POST方式。在代码第一行设置request的编码格式就OK。

jsp页面中一般都是设置过编码格式的,一般都是UTF-8。所以我们在这里request也设置用UTF-8解码就OK。

req.setCharacterEncoding("UTF-8");

GET方式,上面的操作不生效,由于get方式提交參数丫的不是在header里面是在url后面跟着的,仅仅能自己用String来转换了。

String userName = new String(req.getParameter("userName").getBytes("ISO-8859-1"),"UTF-8");

2,超链接和重定向

比方:

<a href="/linkin/LinkinServlet?userName=林肯公园">GET方式传參</a>

这2种情况和上面的用GET方式提交表单一样,处理方式也一样,这里不做赘述了。

3,上面的情况都是属于编码级别的,一般的我们的项目上了生产上无论是GET方式还是POST方式,编码格式这些都设置好了。最多是ajxa异步请求的时候添加过滤器编码设置。

这里针对tomcat本地开发说下:

假设是GET方式。在改动tomcat配置的地方加入一个属性:URIEncoding,将该属性值设置为UTF-8,就可以让Tomcat(默认ISO-8859-1编码)以UTF-8的编码处理get请求。

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

假设是POST方式,就仅仅能添加编码过滤器。没使用框架的话用自己写一个过滤器,建议将过滤的编码写成配置的,比方写在<init-param>标签中。假设使用了spring,则直接配置就OK。

<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<!-- 编码格式 -->
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<!-- 控制是否强制设置编码,假设是true,无论request中有没有指定编码,这个过滤器设置编码都会被触发,假设是false,仅仅是在request中没有设置编码的时候被触发设置上这里的编码 -->
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<!-- 这里是jsp中的编码格式 都被设置为统一的了 -->
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping> 

以下贴出这个类的源代码:核心就是doFilterInternal()方法。

package org.springframework.web.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CharacterEncodingFilter extends OncePerRequestFilter
{

	/**
	 * @param request
	 * @param response
	 * @param filterChain
	 * @throws ServletException
	 * @throws IOException
	 * 个人不喜欢forceEncoding这样的控制和别的控制一起写的写法,单独拎出来写成旗标多好
	 * 普通情况下。为了不冲掉自己的request中原有的编码。建议forceEncoding配置成false
	 */
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
	{
		//1,假设配置的encoding为空。不设置编码
		//2,假设配置的encoding不为空,forceEncoding为true,无论request中有没有自己的编码都会设置编码
		//3,假设配置的encoding不为空,forceEncoding为false,仅仅有在request没有自己的编码的时候才会设置编码
		if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null))
		{
			request.setCharacterEncoding(this.encoding);
			if (this.forceEncoding)
			{
				response.setCharacterEncoding(this.encoding);
			}
		}
		filterChain.doFilter(request, response);
	}

}

另外这里也略微花点时间来说明一下,OncePerRequestFilter这个抽象过滤器非常好的实现了对每一个request仅仅运行一次过滤操作。假设有类似的需求能够继承该类并实现doFilterInternal方法来完毕。上面的CharacterEncodingFilter就是继承这个抽象类的,以下贴出这个抽象类的源代码,后面整理框架的时候我会做具体的整理的。

package org.springframework.web.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class OncePerRequestFilter extends GenericFilterBean {

	public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";

	//開始过滤,有点小技巧。实现了仅仅过滤一次的功能
	public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
			throw new ServletException("OncePerRequestFilter just supports HTTP requests");
		}
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
		if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {//第2次进来
			// Proceed without invoking this filter...
			filterChain.doFilter(request, response);
		}
		else {//第一次进来
			// Do invoke this filter...
			request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
			try {
				doFilterInternal(httpRequest, httpResponse, filterChain);
			}
			finally {//最后清空alreadyFilteredAttributeName属性
				// Remove the "already filtered" request attribute for this request.
				request.removeAttribute(alreadyFilteredAttributeName);
			}
		}
	}

	protected String getAlreadyFilteredAttributeName() {
		String name = getFilterName();
		if (name == null) {
			name = getClass().getName();
		}
		return name + ALREADY_FILTERED_SUFFIX;
	}

	protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
		return false;
	}

	//推迟到子类实现,真正的过滤的方法
	protected abstract void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException;

}

4,向页面传參

后台处理完逻辑后,跳转到页面上,假设页面上中文出现乱码,比方

resp.getWriter().write(req.getParameter("userName"));

在返回响应之前加入

response.setCharacterEncoding("UTF-8");

其有用上面那个设置编码格式的方式不怎么好,最好用以下这样的的。

response.setContentType("text/html;charset=UTF-8");
response.setContentType("application/json;charset=gbk");

5,最后2点补充。

第一点,经常使用中文字符用utf-8编码占用3个字节。用GBK、GB2312编码的汉字占2个字节,严格地用iso8859-1无法表示汉字,仅仅能转为问号。所以当我们传递的中文假设是基数的时候。即使我们正常编码和转码了也会出现乱码。在IE6版本号一下就会出现这样的情况。解决的办法就是在前台页面就编码下中文。

java.net.URLEncoder.encode("林肯公园","UTF-8");

在后台不须要转码,Servlet引擎已经帮我做好了。

某些情况下比方搜索引擎的搜索时。假设发送请求的是GET方式。浏览器上面的中文就会变成application/x-www-form-urlencoded MIME字符串。比方“%E6%E6”这样的。Servlet引擎来解析这段字符串的时候自己主动会给我们转会成汉字的。

转码的代码例如以下:

URLDecoder.decode(req.getParameter("userName"), "UTF-8");

第二点。BASE64Encoder,BASE64Decoder编码和解码,这样的编码和解码还会涉及算法的。了解下好了。

这2个类在API中查不到,由于JDK已经不推荐使用了。只是我个人认为还是挺好使的。

String name = new sun.misc.BASE64Encoder().encode("林肯公园".getBytes());// name:wda/z7mr1LA=
		System.out.println(new String((new sun.misc.BASE64Decoder()).decodeBuffer(name)));//林肯公园

OK。最后贴出自己写的Servlet和jsp:

package linkin;

import java.io.IOException;
import java.net.URLDecoder;

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

/**
 * @author LinkinPark
 * @author 2015-7-10
 * @Descri 解决j2e中文乱码问题
 */
public class LinkinServlet extends HttpServlet
{
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		//req.setCharacterEncoding("UTF-8");//解决POST方式
		//String userName = new String(req.getParameter("userName").getBytes("ISO-8859-1"),"UTF-8");//解决GET方式
		System.out.println(req.getParameter("userName"));
		System.out.println(URLDecoder.decode(req.getParameter("userName"), "UTF-8"));
		req.setAttribute("userName", "林肯公园");
		//resp.setCharacterEncoding("UTF-8");//解决向页面传參乱码问题。建议使用以下这样的
		resp.setContentType("text/html;charset=UTF-8");//解决向页面传參乱码问题。建议使用这样的
		resp.getWriter().write(req.getParameter("userName"));
		//req.getRequestDispatcher("/jsp/Linkin1.jsp").forward(req, resp);
		//resp.sendRedirect("/linkin/jsp/Linkin1.jsp");

		//以下使用base64来编码和解码
		String name = new sun.misc.BASE64Encoder().encode("林肯公园".getBytes());// name:wda/z7mr1LA=
		System.out.println(new String((new sun.misc.BASE64Decoder()).decodeBuffer(name)));//林肯公园

	}

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

	public static void main(String[] args) throws Exception
	{

	}

}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>Servlet中文乱码</title>
<script type="text/javascript" src="/linkin/jsp/jquery-1.8.0.js"></script>
<script type="text/javascript">
var huhu = function(){
	var userName = $("#userName").val();
	$.ajax({
        url : "/linkin/LinkinServlet",
        type : "GET",
        async : true,
        data:{userName:userName},
        dataType : "json",
        success : function(a) {
        }
    });
}

</script>

</head>

<body>
	<form action="/linkin/LinkinServlet" method="GET">
		姓名:<input type="text" name="userName" id="userName" />
		<input type="button" value="提交" name="tijiao" onclick="huhu();"/>
		<a href="/linkin/LinkinServlet?userName=<%=java.net.URLEncoder.encode("林肯公园","UTF-8") %>林肯公园">GET方式传參</a>
	</form>
</body>
</html>
时间: 2024-08-26 10:15:21

Servlet--j2e中文乱码解决的相关文章

JSP和Servlet的中文乱码处理

JSP和Servlet的中文乱码处理 前几天学习了JSP和Servlet中有关中文乱码的一些问题,写成了博客,今天进行更新一下.应该是可以解决日常的乱码问题了.现在作以下总结希望对需要的人有所帮助.我也是刚学,所以有不足之处希望谅解. 一.表单提交时出现乱码: 在进行表单提交的时候,经常提交一些中文,自然就避免不了出现中文乱码的情况,对于表单来说有两种提交方式:get和post提交方式.所以请求的时候便有get请求和post请求.以前我一直以为get请求和post请求方式出现的乱码的解决方式是一

java中文乱码解决之道(七)-----JSP页面编码过程

我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="GBK" %> 在上面代码中有两个地方存在编码:pageEncoding.contentType的charset.其中pageEnco

Javaee中文乱码解决方法

分类: javaee2015-07-09 16:35 29人阅读 评论(0) 收藏 编辑 删除 post 中文乱码解决方式 接受数据的时候设置 request.setCharacterEncoding("utf-8");//编码必须和页面编码一致 页面设置 <%@page import="java.net.URLDecoder"%> <%@page import="org.apache.naming.java.javaURLContext

cocos2d-x 3.4 中文乱码解决之道

cocos2dx 中文乱码解决之道 需要引入五个文件 1.iconv.h 2.iconvString.cpp 3.iconvString.h 4.iconv.dll 5.libiconv.lib 完整下载地址http://download.csdn.net/detail/dao_1990/8935089 iconv.h /* Copyright (C) 1999-2003 Free Software Foundation, Inc. This file is part of the GNU LI

Jsp---cookie中文乱码解决方法

//写cookie <form method="Get"> 姓名: <input type="text" name="name" /> <br /> <input type="submit" value="确定" /> </form> <!-- 写入cookie到客户端 --> <% if (request.getParamete

win7下zend studio5.5中文乱码解决方法

win7下zend studio5.5中文乱码解决方法 1.打开 C:Documents and SettingsAdministratorZDEconfig_5.5desktop_options.xml(这个地址要根据自己的电脑而定.) 2.查找 editing.encoding 3.修改里面为 <encoding name=”UTF-8″/> 4.保存,并将该文件属性设置为只读,否则zend每次启动都会将 desktop_options.xml 初始化 5.重启 zend 注意,你现在打开

SpringMVC中使用@ResponseBody注解返回值,Ajax取得中文乱码解决方法

Spring使用AnnotationMethodHandlerAdapter的handleResponseBody方法, AnnotationMethodHandlerAdapter使用request header中"Accept"的值和messageConverter支持的MediaType进行匹配,然后会用"Accept"的第一个值写入 response的"Content-Type".一般的请求都是通过浏览器进行的,request heade

PHP中文乱码解决办法

一.         首先是PHP网页的编码 1.     php文件本身的编码与网页的编码应匹配 a.     如果欲使用gb2312编码,那么php要输出头:header("Content-Type: text/html; charset=gb2312"),静态页面添加<meta http-equiv="Content-Type" content="text/html; charset=gb2312">,所有文件的编码格式为ANS

玩转web之ajax(一)---使用表单的serialize()方法中文乱码解决

有时候我们需要使用ajax提交去提交form的值,这样就需要使用serialize()去获取form的值,但这样获取的值如果有中文,会乱码,原因和解决方法如下: 原因:.serialize()自动调用了encodeURIComponent方法将数据编码了 解决方法:调用decodeURIComponent(XXX,true);将数据解码 如: var data=$('#addf').serialize(); data= decodeURIComponent(data,true); 玩转web之a