java乱码处理

乱码对于使用非英语文字程序员基本上是一直缠绕在身边的麻烦事,这个谁也避免不了。下面是我解决乱码时候的一点小经验。欢迎指正
 
一、避免乱码的一些注意点:
1.尽量使用统一的编码,如果你是重头开发一个系统,特别是Java开发的,推荐从页面到数据库再到配置文件都使用UTF-8进行编码,安全第一。
2.SetCharacterEncodingFilter的使用,这个东西不是万能的,但是没有它就会很麻烦,如果是基于Servlet开发的东西,能用的就给它用上,省心。不过有一个注意的地方,这个Filter只是对POST请求有效,GET一律忽略,不信你可以debug一下,看看它怎么做的,至于为什么不过滤get请求,好象是它对GET请求是无能为力的。
3.就如上面所说,GET请求有问题,尽量使用POST请求,这个也是Web开发的一个基本要领:
Web Health Warning:Put All Destructive Actions Behind a POST method(from Agile Web Development with Rails)
有点扯远了,不过少用GET,是会有回报滴。
4.JavaScript和Ajax乱码的避免,注意JavaScript默认是ISO8859的编码,避免JS/AJAX乱码和GET一样,不要在URL里面使用中文,实在避免不了,就只能在生成链接的时候转码,绝对不能想当然的认为SetCharacterEncodingFilter会帮你做什么事情。
5.尽早统一开发环境,早点模拟真实环境测试,这个好像也有跑题的嫌疑,但凡软件开发都是这么干的,但仍然值得注意。我这出现过一次状况,程序是在Win下编译的,拿去Linux上测试没问题,等实际部署的时候代码是在Linux下编译,结果乱码,秋后算帐总觉得有点晚。

二、乱码发生的情况和应对措施
1.开发环境乱码
      由于Java默认使用UTF-8编码,而且网上很多人都建议Struts开发的时候应尽量选用UTF-8做为默认编码,而非GBK。IDE使 用Eclipse,在第一次使用Eclipse的时候应将default text editor改为UTF-8编码,免得日后后悔再改就惨了,我本次开发的时候就忽视了这一点,刚开始没注意,结果到快交工时乱码问题无法解决,导致将所有 的文件全部修改一遍,呜……
      自打使用Ubuntu,我就开心的笑阿,再也不用为搞这些乱码问题而烦恼^^(Ubuntu公益广告)
2.POST请求的过滤
      这个是最基本的了,每个Servlet系统基本都会用到这个东西。不过只对POST请求有效,这个挺关键的。
      使用SetCharacterEncodingFilter,这个很基础的一套过滤器,将所有来自页面的POST请求全部过滤为UTF-8编码。
3. JSP ,HTML页面乱码
     将JSP页面全部改为charset=UTF-8,这样可以保证与后台交互的时候都是UTF-8编码,一般应用做了以上工作就基本可以应付了。
4.资源文件中汉字转化UTF-8字符问题
      国际化问题,在使用资源文件的时候,由于中文在properties文件中无法被程序所识别,需要将其进行转码,我在资源文件下面制作了一个很简单的 bat文件,每次修改资源文件的时候都是在一个临时文件中修改,然后执行这个bat文件,将其转化并保存为所需要的资源文件,这个动作挺烦的,也有项目组 成员使用一些插件,但是那些东西都是直接写UTF-8码的,有时候反倒不方便,不过以后任务量巨大的时候可能会考虑使用。Bat文件内容:   set path=%path%;%JAVA_HOME%/bin/,native2ascii -encoding UTF-8 ApplicationResources_bk.txt > ApplicationResources_zh.properties

     PS:上面的方法好老了,实际操作起来相当麻烦,现在基本都是使用Eclipse插件,Eclipse3.1时使用PropertyEditor,但是这 个项目看上去好像停摆了,到Eclipse3.2时改用了ResourseBundle,相当的强劲的一个插件,推荐使用。
5. GET请求乱码
      如果在本项目中采用了get方式提交请求并附加参数,结果导致编码乱码,原因是Tomcat默认请求编码是ISO8859,需要在Tomcat的配置文件 server.xml添加一个参数,URIEncoding=”UTF-8”,这样请求中附件的参数就会以UTF-8来进行编码。
6.Ajax请求乱码
    使用Ajax,JS也是默认使用ISO8859编码,所以在进行请求时遇到中文参数需要进行编码,如:var url = "GetSelectListAction.do?queryData=subTrade" + "&queryId=" + encodeURI(obj.value) + "&r=" + Math.random();   
    这里有两个地方需要注意:第一个地方是encodeURI(),方法,可以将参数进行转码,默认是转化为UTF-8,如果需要转为其他码制,需要在方法中添加第二个参数。
     第二个地方是Math.random(),由于Ajax有缓存机制,在接受请求的时候第一时间先判断该请求的地址是否被访问过,如果被访问过则 直接使用缓存中的内容返回,这个东西很讨厌,客户在访问过一次出错后以后每次出现的都是这个错误,所以在请求中给其增加一个时间戳,只要可以随机生成一个 不同的字串就可以,保证Ajax每次都去访问服务器。
7. GET方法的另一个乱码问题
      在项目即将交工的时候突然又出现乱码问题,发现对于超长的汉字做为参数传递仍然会出现乱码问题,解决方法是采用java.net.URLEncoder的 Encode方法强制转码,缺点是会使JSP页面代码相当的长,但是目前还没有其他好的解决办法,我想最好的办法就是不用中文做为参数传递 :P,写法如:

8.乱码仍然是偶们的心病,一直牵动着大家的心,最近一位朋友说连接MSSQL数据库有乱码,使用了很多办法,都没解决,后来重新下了个新的驱动搞定……
数据库乱码其实也很讨厌的,一般来说驱动问题比较常见,所以一旦碰到比较难缠的乱码可以先考虑下换换驱动。也有如MySQL这种,直接连接的时候就需要显示进行编码转化的,这个就要不同情况区别对待了。

//2007年11月30日添加
9.WebService乱码,由于对WebService不怎么熟悉,使用的是Weblogic提供的WebService支持,乱码再次出现搞得手忙脚乱,而且无从下手,在自己系统上跑都没有问题,结果跑到服务器上就全乱套,又无法调试,愁人。
    反复尝试的过程就不说了,绝对比普通的Web开发麻烦的多。最终解决方法:
    A.为WebService服务也加上一个filter,WebService也是走HTTP协议的,这个东西同样有用,先得加上。
    B.修改服务器上的环境变量,LANG=zh_CN.UTF-8,改成这个是为什么我仍然说的不是很清楚,不过当时开发人员就是在Win下开发的,我在自己的Ubuntu上测试没问题,拿到Redhat服务器上就不行,因为服务器上默认的是LANG=en_US.UTF-8,这个明显是不支持汉字的。
    经过这两个步骤WebService乱码总算得到抑制,它主要的麻烦在于所有与协议有关的东西都被Weblogic包办,里面做什么事情我们不好控制,所以只能采取这种比较笨的办法,虽然解燃煤之急但无法寻根溯源的搞定它,说不定哪天又会出来搞鬼。果然又一次出现乱码问题,经过比较环境变量发现服务器上的LC_CTYPE被修改了,所以强制改成LC_CTYPE=zh_CN。修改环境变量的方法不到万不得已不推荐使用。

Java乱码是因为Java和JSP源文件的保存方式是基于字节流的,如果Java和JSP编译成class文件过程中,使用的编码方式与源文件的编码不一致,就会出现乱码。在这里,总结一下java乱码的一些常见情况

 

1.Javascript传参乱码:

在浏览器端对要传递的中文参数进行编码处理.代码如下:
xmlhttp.open("POST",url,true); //请求参数初始化
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //因为请求方式为POST,所以这里要设置请求头.(如果请求方式为GET,此句代码可以省略)
xmlhttp.send("name="+encodeURI(encodeURI("星期日"))); //向服务器端发送参数
在服务器端代码:

页面jsp保证是utf-8编码

<%@ page contentType="text/html; charset=utf-8"%>

接受中文参数
PrintWriter out = response.getWriter(); //得到response的输出流对象
String name1 = request.getParameter("name"); //得到KEY为"name"的请求参数
String name = URLDecoder.decode(name1,"utf-8"); //对得到的参数进行解码
out.print(name); //向浏览器端发送数据

 

2.JSP与页面参数之间的乱码
       JSP获取页面参数时一般采用系统默认的编码方式,如果页面参数的编码类型和系统默认的编码类型不一致,很可能就会出现乱码。解决这类乱码问题的基本方法是在页面获取参数之前,强制指定request获取参数的编码方式:request.setCharacterEncoding("UTF-8") 。
    如果在JSP将变量输出到页面时出现了乱码,可以通过设置response.setContentType("text/html;charset=UTF-8")。

JSP页面乱码通常只要在页面开始地方用上面代码指定字符集编码即可。如果还不行,那么请用下面这句话来转换 str=new String(str.getBytes("ISO-8859-1"),"页面编码方式");

 

3.热链接传参乱码

在传参的jsp对中文进行编码:href="new.jsp?name=java.net.URLEncoder.encode("链接")";

在接受的jsp对中文进行转码:String str = URLDecoder.decode(request.getParameter("name "), "utf-8");

 

4.Java与数据库之间的乱码
  大部分数据库都支持以unicode编码方式,所以解决Java与数据库之间的乱码问题比较明智的方式是直接使用unicode编码与数据库交互。很多数据库驱动自动支持unicode,如Microsoft的SQLServer驱动。其他大部分数据库驱动,可以在驱动的url参数中指定,如mysql驱动:jdbc:mysql://localhost/MYAPPS?useUnicode=true&characterEncoding=GBK。

 

5.Java与文件/流之间的乱码
  Java读写文件最常用的类是FileInputStream/FileOutputStream和FileReader/FileWriter。其中FileInputStream和FileOutputStream是基于字节流的,常用于读写二进制文件。读写字符文件建议使用基于字符的FileReader和FileWriter,省去了字节与字符之间的转换。但这两个类的构造函数默认使用系统的编码方式,如果文件内容与系统编码方式不一致,可能会出现乱码。在这种情况下,建议使用FileReader和FileWriter的父类:InputStreamReader/OutputStreamWriter,它们也是基于字符的,但在构造函数中可以指定编码类型:InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。

关于三者之间的中文乱码问题,各大论坛都讨论过不少了,但是很多都是给矛了针对某种转换的解决办法,有的搞了几年开发,对这个问

题的原理,三者之间的转换关系,还是比较模糊的,包括我自己. 于是今天下决心砌底地把这个web应用中最常见的问题搞明白,请各位达人指点一下。

    根据以往的经验,这种中文乱码问题,都是由于jsp,java,数据库三者之前的编码不同造成的,jsp的编码是在
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*"%>
中设定的,java文件中的字符串编码,众所周知是unicode的,而数据表的字符编码,也是可以设定的。

好了,我先开了个头了,现在我想通过几个例子来让大家讨论有个焦点。

程序的流程是这样的,我们先从java文件中读到数据库中的中文字符,然后,在jsp页面上,用<jsp:useBean />标签来取出字符,并out.println()显示出来。


例1 如果jsp的CHARSET=utf8,数据库的字符编码也是GBK的,三者之间的编码转换的过程是怎样的?

例2 如果jsp的charset=UTF-8, 数据库的字符编码是GBK呢?

例3 如果jsp的charset=UTF-8,数据库中的字符编码也是UTF-8的呢?

其实,最重要的是原理跟过程,希望大家把自己知道的都说出来,能让别人或自己在此贴中学习到一些之前忽略了的东西就够了。
   

顺便提两个小问题:

1   jsp页头的,charset和pageEncoding这两者的作用分别是什么呢?

2  前后两个页面的charset的不同,对request对象的characterEncoding又有什么决定影响呢?因为常常见到request.setCharacterEncoding("GB2312");的。

你可能感兴趣的:(大杂烩,java,乱码,编码)