Java的中文乱码处理
Java的中文乱码处理
Java的编码转换过程
我们总是用一个Java的类文件和用户进行最直接的交互(输入,输出),这些交互内容包含的文字可能会包含中文。无论这些的java类是与数据库交互,还是与前端页面交互,他们的生命周期总是这样的:
如图1所示,程序员在操作系统上通过编辑器编写程序代码并且以的.java的格式保存操作系统中,这些文件我们称之为源文件。
2,通过JDK中的的javac.exe编译这些源文件形成的.class类。
3,直接运行这些类或者部署在WEB容器中运行,得到输出结果。
这些过程是从宏观上面来观察的,了解这个肯定是不行的,我们需要真正来了解Java的是如何来编码和被解码的:
第一步:当我们用编辑器编写的Java源文件,程序文件在保存时会采用操作系统默认的编码格式(一般我们中文的操作系统采用的是GBK编码格式)形成一个的.java文件的.java源文件是采用操作系统默认支持的file.encoding的编码格式保存的。下面代码可以查看系统的file.encoding的参数值。
第二步:当我们使用的javac.exe编译我们的java的文件时,JDK首先会确认它的编译参数编码来确定源代码字符集,如果我们不指定该编译参数,JDK首先会获取操作系统默认的文件.encoding参数,然后JDK就会把我们编写的Java的源程序从file.encoding的编码格式转化为JAVA内部默认的UNICODE格式放入内存中。
第三步: JDK将上面编译好的且保存在内存中信息写入类文件中,形成.class文件。此时.class文件是Unicode编码的,也就是说我们常见的.class文件中的内容无论是中文字符还是英文字符,他们都已经转换为Unicode的编码格式了。
在这一步中对对JSP源文件的处理方式有点儿不同:WEB容器调用JSP编译器,JSP编译器首先会查看JSP文件是否设置了文件编码格式,如果没有设置则JSP编译器会调用调用JDK采用默认的编码方式将JSP文件转化为临时的servlet的类,然后再编译为的.class文件并保持到临时文件夹中。
第四步:运行编译的类:在这里会存在一下几种情况
如图1所示,直接在控制台上运行。
2,JSP / Servlet的类。
3,JAVA类与数据库之间。
这三种情况每种情况的方式都会不同,
1.Console上运行的类
这种情况下,JVM首先会把保存在操作系统中的类文件读入到内存中,这个时候内存中类文件编码格式为Unicode的,然后JVM运行它。如果需要用户输入信息,则会采用文件。编码编码格式对用户输入的信息进行编码同时转换为Unicode的编码格式保存到内存中程序运行后,将产生的结果再转化为file.encoding的格式返回给操作系统并输出到界面去整个流程如下。:
在上面整个流程中,凡是涉及的编码转换都不能出现错误,否则将会产生乱码。
2.Servlet类
由于JSP文件最终也会转换为servlet的文件(只不过存储的位置不同而已),所以这里我们也将JSP文件纳入其中。
当用户请求的Servlet时,WEB容器会调用它的JVM来运行Servlet的。首先JVM会把小服务程序的类加载到内存中去,内存中的servlet的代码是的Unicode编码格式的。然后JVM在内存中运行该Servlet中,在运行过程中如果需要接受从客户端传递过来的数据(如表单和URL传递的数据),则WEB容器会接受传入的数据,在接收过程中如果程序设定了传入参数的的编码则采用设定的编码格式,如果没有设置则采用默认的ISO-8859-1编码格式,接收的数据后JVM会将这些数据进行编码格式转换为Unicode的并且存入到内存中。运行的Servlet后产生输出结果,同时这些输出结果的编码格式仍然为Unicode的。紧接着WEB容器会将产生的Unicode的编码格式的字符串直接发送置客户端,如果程序指定了输出时的编码格式,则按照指定的编码格式输出到浏览器,否则采用默认的ISO-8859-1编码格式整个过程流程图如下:
3.数据库部分
我们知道的java程序与数据库的连接都是通过JDBC驱动程序来连接的,而JDBC驱动程序默认的是ISO-8859-1编码格式的,也就是说我们通过的java程序向数据库传递数据时,JDBC首先会将统一编码格式的数据转换为ISO-8859-1的编码格式,然后在存储在数据库中,即在数据库保存数据时,默认格式为ISO-8859-1。
编码和解码
在上篇博客中LZ阐述了三个渠道的编码转换过程,下面LZ将结束的java在那些场合需要进行编码和解码操作,并详序中间的过程,进一步掌握Java的的编码和解码过程。在Java的中主要有四个场景需要进行编码解码操作:
1:I / O操作
2:内存
4:的JavaWeb
下面主要介绍前面两种场景,数据库部分只要设置正确编码格式就不会有什么问题,的JavaWeb场景过多需要了解URL,GET,POST的编码,servlet的的解码,所以的JavaWeb场景下节LZ介绍。
I / O操作
在前面LZ就提过乱码问题无非就是转码过程中编码格式的不统一产生的,比如编码时采用UTF-8,解码采用GBK,但最根本的原因是字符到字节或者字节到字符的转换出问题了,而这中情况的转换最主要的场景就是I / O操作的时候。当然I / O操作主要包括网络I / O(也就是的JavaWeb)和磁盘I / O。网络I / O下节介绍。
首先我们先看I / O的编码操作。
的InputStream为字节输入流的所有类的超类,阅读器为读取字符流的抽象类的.java读取文件的方式分为按字节流读取和按字符流读取,其中的InputStream,读者是这两种读取方式的超类。
按字节
我们一般都是使用InputStream.read()方法在数据流中读取字节(读()每次都只读取一个字节,效率非常慢,我们一般都是使用读取(字节[])),然后保存在一个字节[]数组中,最后转换为字符串。在我们读取文件时,读取字节的编码取决于文件所使用的编码格式,而在转换为字符串过程中也会涉及到编码的问题,如果两者之间的编码格式不同可能会出现问题。例如存在一个问题的test.txt编码格式为UTF-8,那么通过字节流读取文件时所获得的数据流编码格式就是UTF-8 ,而我们在转化成字符串过程中如果不指定编码格式,则默认使用系统编码格式(GBK)来解码操作,由于两者编码格式不一致,那么在构造字符串过程肯定会产生乱码,如下:
文件文件= 新文件(“C:\\ test.txt” ); InputStream input = new FileInputStream(file); StringBuffer buffer = new StringBuffer(); byte [] bytes = new byte [1024 ]; for(int n;(n = input.read(bytes))!= - 1 ;){ buffer.append(new String(bytes,0 ,n)); } 的System.out.println(缓冲液);
输出结果:锘挎垜鏄厘米
test.txt中的内容为:我是cm。
要想不出现乱码,在构造字符串过程中指定编码格式,使得编码解码时两者编码格式保持一致即可:
buffer.append(new String(bytes,0,n,“UTF-8”));
按字符
其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在Java的中阅读器是读取字符流的超类。所以从底层上来看按字节读取文件和按字符读取没什么区别。在读取的时候字符读取每次是读取留个字节,字节流每次读取一个字节。
字节和字符转换
字节转换为字符一定少不了InputStreamReader.API解释如下:InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset
读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。每次调用InputStreamReader中的一个read()方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节.API解释非常清楚,InputStreamReader的在底层读取文件时仍然采用字节读取,读取字节后它需要根据一个指定的编码格式来解析为字符,如果没有指定编码格式则采用系统默认编码格式。
String file =“C:\\ test.txt” ; String charset =“UTF-8” ; // 写字符换转成字节流 FileOutputStream outputStream = new FileOutputStream(file); OutputStreamWriter writer = new OutputStreamWriter(outputStream,charset); 尝试{ writer.write( “我是cm” ); } finally { writer.close(); } // 读取字节转换成字符 FileInputStream inputStream = new FileInputStream(file); InputStreamReader reader = new InputStreamReader( inputStream,charset); StringBuffer buffer = new StringBuffer(); char [] buf = new char [64 ]; int count = 0 ; try { while((count = reader.read(buf))!= -1 ){ buffer.append(buf, 0 ,count); } } finally { reader.close(); } 的System.out.println(缓冲液);
内存
首先我们看下面这段简单的代码
String s =“我是cm” ; byte [] bytes = s.getBytes(); String s1 = new String(bytes,“GBK” ); String s2 = new String(bytes);
在这段代码中我们看到了三处编码转换过程(一次编码,两次解码)先看String.getTytes():
public byte [] getBytes(){ return StringCoding.encode(value,0 ,value.length); }
内部调用StringCoding.encode()方法操作:
static byte [] encode(char [] ca,int off,int len){ String csn = Charset.defaultCharset()。name(); try { // 使用提供缓存的charset name encode()变体。 return encode(csn,ca,off,len); } catch (UnsupportedEncodingException x){ warnUnsupportedCharset(CSN); } try { return encode(“ISO-8859-1” ,ca,off,len); } catch (UnsupportedEncodingException x){ // 如果在VM初始化期间遇到此代码,则MessageUtils是 // 我们能够获取任何类型的错误消息的唯一方法。 MessageUtils.err(“ISO-8859-1 charset not available:” + x.toString()); // 如果我们找不到ISO-8859-1(一个必需的编码)那么 // 安装严重错误。 System.exit(1 ); return null ; } }
encode(char [] paramArrayOfChar,int paramInt1,int paramInt2)方法首先调用系统的默认编码格式,如果没有指定编码格式则默认使用ISO-8859-1编码格式进行编码操作,进一步深入如下:
字符串csn =(charsetName == null)?“ISO-8859-1”:charsetName;
同样的方法可以看到new String的构造函数内部是调用StringCoding.decode()方法:
public String(byte bytes [],int offset,int length,Charset charset){ if(charset == null ) throw new NullPointerException(“charset” ); checkBounds(字节,偏移量,长度); 这个 .value = StringCoding.decode(字符集,字节,偏移量,长度); }
解码方法和编码对编码格式的处理是一样的。
对于以上两种情况我们只需要设置统一的编码格式一般都不会产生乱码问题。
编码和编码格式
首先先看看java的编码类图[1]
首先根据指定的图表设置ChartSet类,然后根据ChartSet创建ChartSetEncoder对象,最后再调用CharsetEncoder.encode对字符串进行编码,不同的编码类型都会对应到一个类中,实际的编码过程是在这些类中完成的。下面时序图展示详细的编码过程:
通过这编码的类图和时序图可以了解编码的详细过程。下面将通过一段简单的代码对ISO-8859-1,GBK,UTF-8编码
public class Test02 { public static void main(String [] args)throws UnsupportedEncodingException { String string =“我是cm” ; Test02.printChart(string.toCharArray()); Test02.printChart(string.getBytes( “ISO-8859-1” )); Test02.printChart(string.getBytes( “GBK” )); Test02.printChart(string.getBytes( “UTF-8” )); } / ** * char转换为16进制 * / public static void printChart(char [] chars){ for(int i = 0; i <chars.length; i ++ ){ System.out.print(Integer.toHexString(chars [i]) +“” ); } System.out.println( “” ); } / ** * byte转换为16进制 * / public static void printChart(byte [] bytes){ for(int i = 0; i <bytes.length; i ++ ){ String hex = Integer.toHexString(bytes [i]&0xFF ); if(hex.length()== 1 ){ hex ='0'+ hex; } System.out.print(hex.toUpperCase() +“” ); } System.out.println( “” ); } }
------------------------- outPut : 6211 662f 20 63 6d 3F 3F 20 63 6D CE D2 CA C7 20 63 6D E6 88 91 E6 98 AF 20 63 6D
通过程序我们可以看到“我是cm”的结果为:
char []:6211 662f 20 63 6d ISO- 8859-1:3F 3F 20 63 6D GBK:CE D2 CA C7 20 63 6D UTF -8:E6 88 91 E6 98 AF 20 63 6D
图如下:
编码和解码
通过下图我们可以了解在的JavaWeb中有哪些地方有转码:
用户想服务器发送一个HTTP请求,需要编码的地方有网址,饼干,参数,经过编码后服务器接受HTTP请求,解析HTTP请求,然后对网址,饼干,参数进行解码。在服务器进行业务逻辑处理过程中可能需要读取数据库,本地文件或者网络中的其他文件等等,这些过程都需要进行编码解码。当处理完成后,服务器将数据进行编码后发送给客户端,浏览器经过解码后显示给用户。在这个整个过程中涉及的编码解码的地方较多,其中最容易出现乱码的位置就在于服务器与客户端进行交互的过程。
上面整个过程可以概括成这样,页面编码数据传递给服务器,服务器对获得的数据进行解码操作,经过一番业务逻辑处理后将最终结果编码处理后传递给客户端,客户端解码展示给用户。所以下面我就请求对的JavaWeb的编码和解码进行阐述。
请求
客户端想服务器发送请求无非就通过四中情况:
1,URL方式直接访问。
2,页面链接。
3,表单得到提交
4,表单后提交
URL方式
对于URL,如果该URL中全部都是英文的那倒是没有什么问题,如果有中文就要涉及到编码了。如何编码?根据什么规则来编码?又如何来解码呢?下面LZ将一一解答!首先看URL的组成部分:
在这URL中浏览器将会对路径和参数进行编码操作。为了更好地解释编码过程,使用如下网址
http://127.0.0.1:8080/perbank/我是厘米?名称=我是厘米
将以上地址输入到浏览器URL输入框中,通过查看http报文头信息我们可以看到浏览器是如何进行编码的。下面是IE,Firefox,Chrome三个浏览器的编码情况:
可以看到各大浏览器对“我是”的编码情况如下:
路径部分 |
请求参数 |
|
火狐 |
E6 88 91 E6 98 AF |
E6 88 91 E6 98 AF |
铬 |
E6 88 91 E6 98 AF |
E6 88 91 E6 98 AF |
IE |
E6 88 91 E6 98 AF |
CE D2 CA C7 |
查看上篇博客的编码可知对于路径部分Firefox,chrome,IE都是采用UTF-8编码格式,对于查询字符串部分Firefox,chrome采用UTF-8,IE采用GBK。至于为什么会加上%,这是因为URL的编码规范规定浏览器将ASCII字符非ASCII字符按照某种编码格式编码成16进制数字然后将每个16进制表示的字节前加上“%”。
当然对于不同的浏览器,相同浏览器不同版本,不同的操作系统等环境都会导致编码结果不同,上表某一种情况,对于URL编码规则下任何结论都是过早的。由于各大浏览器,各个操作系统对URL的URI,查询字符串编码都可能存在不同,这样对服务器的解码势必会造成很大的困扰,下面我们将已tomcat的,看的tomcat是如何对URL进行解码操作的。
解析请求的URL是在org.apache.coyote.HTTP11.InternalInputBuffer的parseRequestLine方法中,这个方法把传过来的URL的byte []设置到org.apache.coyote.Request的相应的属性中。这里的URL仍然是字节格式,转成char是在org.apache.catalina.connector.CoyoteAdapter的convertURI方法中完成的:
protected void convertURI(MessageBytes uri,Request request) throws Exception { ByteChunk bc = uri.getByteChunk(); int length = bc.getLength(); CharChunk cc = uri.getCharChunk(); cc.allocate(length, -1 ); String enc = connector.getURIEncoding(); // 获取URI解码集 if(enc!= null ){ B2CConverter conv = request.getURIConverter(); try { if(conv == null ){ conv = new B2CConverter(enc); request.setURIConverter(CONV); } } catch (IOException e){...} if(conv!= null ){ try { conv.convert(bc,cc,cc.getBuffer()。length - cc.getEnd()); uri.setChars(cc.getBuffer(),cc.getStart(),cc.getLength()); 回归; } catch (IOException e){...} } } // 默认编码:快速转换 字节 [] bbuf = bc.getBuffer(); char [] cbuf = cc.getBuffer(); int start = bc.getStart(); for(int i = 0; i <length; i ++ ){ cbuf [i] =(char)(bbuf [i + start]&0xff ); } uri.setChars(cbuf, 0 ,length); }
从上面的代码可知,对URI的解码操作是首先获取连接器的解码集,该配置在server.xml中中
< 连接器URIEncoding =“utf-8” />
如果没有定义则会采用默认编码ISO-8859-1来解析。
对于查询字符串部分,我们知道无论我们是通过获取方式还是POST方式提交,所有的参数都是保存在参数,然后我们通过request.getParameter,解码工作就是在第一次调用getParameter方法时进行的。在getParameter方法内部它调用org.apache.catalina.connector.Request的parseParameters方法,这个方法将会对传递的参数进行解码。下面代码只是parseParameters方法的一部分:
// 获取编码 String enc = getCharacterEncoding(); // 获取ContentType中定义的Charset boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); if(enc!= null){ // 如果设置编码不为空,则设置编码为enc parameters.setEncoding(enc); if(useBodyEncodingForURI){ // 如果设置了Chartset,则设置queryString的解码为ChartSet parameters.setQueryStringEncoding(enc); } } else { // 设置默认解码方式 parameters.setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); if (useBodyEncodingForURI){ parameters.setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); } }
从上面代码可以看出对查询字符串的解码格式要么采用设置的ChartSet要么采用默认的解码格式ISO-8859-1。注意这个设置的ChartSet是在http Header中定义的ContentType,同时如果我们需要改指定属性生效,还需要进行如下配置:
< Connector URIEncoding =“UTF-8” useBodyEncodingForURI =“true” />
上面部分详细介绍了URL方式请求的编码解码过程。其实对于我们而言,我们更多的方式是通过表单的形式来提交。
表单GET
我们知道通过URL方式提交数据是很容易产生乱码问题的,所以我们更加倾向于通过表单形式。当用户点击提交提交表单时,浏览器会更加设定的编码来编码数据传递给服务器。通过GET方式提交的数据都是拼接在URL后面(可以当做查询字符串??)来提交的,所以tomcat服务器在进行解码过程中URIEncoding就起到作用了.tomcat服务器会根据设置的URIEncoding来进行解码,如果没有设置则会使用默认的ISO-8859-1来解码。假如我们在页面将编码设置为UTF-8,而的URIEncoding设置的不是或者没有设置,那么服务器进行解码时就会产生乱码。这个时候我们一般可以通过new String(request.getParameter(“name”)。getBytes(“iso-8859-1”),“utf-8”)的形式来获取正确数据。
表单POST
对于POST方式,它采用的编码也是由页面来决定的即的contentType。当我通过点击页面的提交按钮来提交表单时,浏览器首先会根据ontentType的字符集编码格式来对POST表单的参数进行编码然后提交给服务器,在服务器端同样也是用的contentType中设置的字符集来进行解码(这里与GET方式就不同了),这就是通过POST表单提交的参数一般而言都不会出现乱码问题。当然这个字符集编码我们是可以自己设定的:request.setCharacterEncoding(charset)。
我们知道JSP页面是需要转换为的servlet的,在转换过程中肯定是要进行编码的。在JSP转换为servlet的过程中下面一段代码起到至关重要的作用。
JSP在转换为的Servlet的过程中是需要经过主要的三次编码转换过程(除去数据库编码转换,页面参数输入编码转换):
第一次:转换为的.java文件;
第二次:转换为的.class文件;
第三次:业务逻辑处理后输出。
第一阶段
JVM将JSP编译为的.jsp文件。在这个过程中的pageEncoding就起到作用了,JVM首先会获取的pageEncoding的值,如果该值存在则采用它设定的编码来编译,否则则采用的file.encoding编码来编译。
第二阶段
JVM将的.java文件转换为的.class文件。在这个过程就与任何编码的设置都没有关系了,不管JSP采用了什么样的编码格式都将无效。经过这个阶段后的.jsp文件就转换成了统一的统一格式的的.class文件了。
第三阶段
后台经过业务逻辑处理后将产生的结果输出到客户端。在这个过程中的contentType的字符集就发挥了功效。如果设置了字符集则浏览器就会使用指定的编码格式进行解码,否则采用默认的ISO- 8859-1编码格式进行解码处理。
流程如如下:
我们主要通过两种形式提交向服务器发送请求:。URL,表单而表单形式一般都不会出现乱码问题,乱码问题主要是在URL上面通过前面几篇博客的介绍我们知道URL向服务器发送请求编码过程实在是实在太混乱了。不同的操作系统,不同的浏览器,不同的网页字符集,将导致完全不同的编码结果。如果程序员要把每一种结果都考虑进去,是不是太恐怖了?有没有办法,能够保证客户端只用一种编码方法向服务器发出请求?
有!这里我主要提供以下几种方法
一,javascript中
使用javascript编码不给浏览器插手的机会,然后在服务器中解码。在掌握该方法的时候,我们需要料及j avascript编码的三个方法,encodeURIComponent方法()。
逃逸
采用SIO Latin字符集对指定的字符串进行编码。所有非ASCII字符都会被编码为%xx格式的字符串,其中xx表示该字符在字符集中所对应的16进制数字。例如,格式对应的编码为%20。它对应的解码方法为UNESCAPE()。
事实上逸出()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode的编码值。比如上面“我是厘米”的结果为%u6211%u662Fcm,其中“我”对应的编码为6211, “是”的编码为662F,“CM”编码为厘米。
注意,逸出()不对 “+” 编码。但是我们知道,网页在提交表单的时候,如果有空格,则会被转化为+字符。服务器处理数据的时候,会把+号处理成空格。所以,使用的时候要小心。
是encodeURI
对整个URL进行编码,它采用的是UTF-8格式输出编码后的字符串不过是encodeURI除了ASCII编码外对于一些特殊的字符也不会进行编码如:!@#$&*()=:/; ?+'。
encodeURIComponent方法
把URI字符串采用UTF-8编码格式转化成逸出格式的字符串相对于是encodeURI,encodeURIComponent方法会更加强大,它会对那些在是encodeURI()中不被编码的符号(。/?:@&= + $,#)统统会被编码。但是encodeURIComponent只会对URL的组成部分进行个别编码,而不用于对整个URL进行编码。对应解码函数方法decodeURIComponent。
当然我们一般都是使用是encodeURI方来进行编码操作。所谓的JavaScript的两次编码后台两次解码就是使用该方法.javascript解决该问题有一次转码,两次转码两种解决方法。
一次转码
JavaScript的转码:
var url ='<s:property value =“webPath”/>/ShowMoblieQRCode.servlet?name=我是cm' ; window.location.href = encodeURI(url);
转码后的网址:http://127.0.0.1:8080 / perbank / ShowMoblieQRCode.servlet?name =%E6%88%91%E6%98%AFcm
后台处理:
String name = request.getParameter(“name” ); System.out.println( “前台传入参数:”+ 名称); name = new String(name.getBytes(“ISO-8859-1”),“UTF-8” ); System.out.println( “经过解码后参数:”+名称);
输出结果:
前台传入参数:??????厘米
经过解码后参数:我是厘米
二次转码
var url ='<s:property value =“webPath”/>/ShowMoblieQRCode.servlet?name=我是cm' ; window.location.href = encodeURI(encodeURI(url));
转码后的网址:http://127.0.0.1:8080 / perbank / ShowMoblieQRCode.servlet?name =%25E6%2588%2591%25E6%2598%25AFcm
后台处理:
String name = request.getParameter(“name” ); System.out.println( “前台传入参数:”+ 名称); name = URLDecoder.decode(name,“UTF-8” ); System.out.println( “经过解码后参数:”+名称);
输出结果:
前台传入参数:E68891E698AFcm
经过解码后参数:我是厘米
过滤
使用过滤器,过滤器LZ提供两种,第一种设置编码,第二种直接在过滤器中进行解码操作。
过滤器1
该过滤器是直接设置请求的编码格式的。
公共 类 CharacterEncoding 实现Filter { private FilterConfig config; String encoding = null ; public void destroy(){ config = null ; } public void doFilter(ServletRequest请求,ServletResponse响应, FilterChain chain)抛出IOException,ServletException { request.setCharacterEncoding(编码); chain.doFilter(request,response); } public void init(FilterConfig config)抛出ServletException { this .config = config; // 获取配置参数 String str = config.getInitParameter(“encoding” ); if(str!= null ){ encoding = str; } } }
配置:
<! - 中文过滤器的配置- > < filter > < filter-name > chineseEncoding </ filter-name > < filter-class > com.test.filter.CharacterEncoding </ filter-class > < init-param > < param-name > encoding </ param-name > < param-value > utf-8 </ param-value > </ init-param > </ filter > < filter-mapping > < filter-name > chineseEncoding </ filter-name > < url-pattern > / * </ url-pattern > </ filter-mapping >
过滤器2
该过滤器在处理方法中将参数直接进行解码操作,然后将解码后的参数重新设置到请求的属性中。
公共 类 CharacterEncoding 实现Filter { protected FilterConfig filterConfig; String encoding = null ; public void destroy(){ this .filterConfig = null ; } / ** *初始化 * / public void init(FilterConfig filterConfig){ this .filterConfig = filterConfig; } / ** *将inStr转为UTF-8的编码形式 * * @param inStr输入字符串 * @return UTF - 8的编码形式的字符串 * @throws UnsupportedEncodingException * / private String toUTF(String inStr)throws UnsupportedEncodingException { String outStr =“” ; if(inStr!= null ){ outStr = new String(inStr.getBytes(“iso-8859-1”),“UTF-8” ); } return outStr; } / ** *中文乱码过滤处理 * / public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain chain)抛出IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; // 获得请求的方式(1.post或2.get),根据不同请求方式进行不同处理 String method = request.getMethod(); // 1.以post方式提交的请求,直接设置编码为UTF-8 if(method.equalsIgnoreCase(“post” )){ try { request.setCharacterEncoding( “UTF-8” ); } catch (UnsupportedEncodingException e){ e.printStackTrace(); } } // 2.以获得方式提交的请求 else { // 取出客户提交的参数集 Enumeration <String> paramNames = request.getParameterNames(); // 遍历参数集取出每个参数的名称及值 while (paramNames.hasMoreElements()){ String name = paramNames.nextElement(); // 取出参数名称 String values [] = request.getParameterValues(name); // 根据参数名称取出其值 // 如果参数值集不为空 if(values!= null ){ // 遍历参数值集 for(int i = 0; i <values.length; i ++ ){ try { / / 回圈依次将每个值调用toUTF(values [i])方法转换参数值的字元编码 String vlustr = toUTF(values [i]); values [i] = vlustr; } catch (UnsupportedEncodingException e){ e.printStackTrace(); } } // 将该值以属性的形式藏在请求 request.setAttribute(name,values); } } } // 设置响应方式和支持中文的字元集 response.setContentType(“text / html; charset = UTF-8” ); // 继续执行下一个过滤器,无一下个过滤器则执行请求 chain.doFilter(request,response); } }
配置:
<! - 中文过滤器的配置- > < filter > < filter-name > chineseEncoding </ filter-name > < filter-class > com.test.filter.CharacterEncoding </ filter-class > </ filter > < filter-mapping > < filter-name > chineseEncoding </ filter-name > < url-pattern > / * </ url-pattern > </ filter-mapping >
其他
1,设置的pageEncoding,则contentType
<%@ page language =“java”contentType =“text / html; charset = UTF-8”pageEncoding =“UTF-8”%>
2,设置的Tomcat的的URIEncoding
在默认情况下,Tomcat的服务器使用的是ISO-8859-1编码格式来编码的,的URIEncoding参数对GET请求的URL进行编码,所以我们只需要在tomcat的server.xml中的文件的<连接>标签中加上的URIEncoding = “UTF-8” 即可。