最近作网页这块时碰到了正文字符乱码问题、别看这小小的一个问题,对我来讲却花费了好长一段时间。如今让我慢慢分析它吧(说实话、这些有部分是从网上找的,但都是本身亲自打出来的、这样对本身来讲不只理解了并且还加深了印象)。
在java内部运算中、涉及到全部字符串都会被转化UTF-8编码来运算,然而、在被java转化以前,字符串是怎么样的字符集呢?其实java老是根据操做系统的默认编码字符集来决定字符串的初始编码的;并且java系统的输入输出都是采起操做系统的默认编码。因此、咱们若是能统一java系统的输入输出以及操做系统三者的编码字符集合,那么就可以正确处理和显示汉字。这也是处理java系统汉字的一个原则。
然而在实际项目中、可以正确抓住和控制住java系统的输入输出部分是比较难的。在J2EE中、因为涉及到外部浏览器和数据库等,中文乱码问题很明显。J2EE应用程序是运行在J2EE容器中的、在这个系统中,输入途径有多种:一种是经过页面表单打包成请求(request)发往服务器的;第二种是经过数据库读入;而第三种输入比较复杂,jsp在第一次运行时老是被编译成Servlet,jsp中经常包含中文字符、那么编译使用javac时,java将根据默认的操做系统编码做为初始编码;除非本身特别指定了编码。
J2EE中的输出途径也有几种:第一种是jsp页面输出、因为jsp页面已经被编译成Servlet,那么在输出时、也将根据操做系统的默认编码来选择输出编码,除非指定输出编码方式;第二种输出途径即是将字符串输出到数据库。因此一个J2EE系统的输入输出是很是复杂、并且仍是动态变化的。而java是跨平台运行的、在实际编译和运行中,均可能涉及到不一样的操做系统;若是任由java自由地根据操做系统来决定输入输出的编码字符集、那将不可控制的出现乱码了。
要处理此种状况、根本办法就是明确指定整个应用系统的统一字符集,指定统一字符集究竟是ISO8859_一、GBK、仍是UTF—8呢?下面咱们来分析下:
一、若是统一指定为ISO8859_1,由于目前大多数软件都是西方人编制的、他们默认的字符集就是ISO8859_1,包括Linux和数据库MySQL等。因此咱们通常只须要注意在jsp头部声明、运行操做系统默认编码以及开发和编译代码时指定字符集是否为默认为ISO8859_1。
二、统一指定为GBK中文字符集、上面提到的三个地方须要一样作到,不一样的是只能运行在编码默认为GBK的操做系统上、好比Windows;统一编码为ISO8859_1和GBK虽然能带来编制代码的方便、可是各自只能在相应的操做系统上运行;因此破坏了java跨平台运行的优越性、在必定范围内行得通;好比:为了使得GBK编码在linux上运行,设置Linux编码为GBK。
三、将java/j2EE系统的统一 编码定义为UTF-8,那么除应用系统之外就不须要任何附加设置的中文编码了。UTF-8是一种兼容全部语言的编码方式,惟一比较麻烦的就是要找到应用系统的全部出入口;而后用UTF-8来更改它。
一个J2EE应用系统须要作下面几项工做:
一、开发和编译代码时指定字符集为UTF-8,JBuild(一种可视化java开发工具)和Ecplise均可以在项目属性中设置。
二、使用过滤器、若是全部请求都通过一个Servlet控制分配器,那么咱们使用Servlet时用filter执行语句,将全部来自浏览器的请求(request)转换为UTF-8;这是由于浏览器发过来的请求包括浏览器所在的操做系统编码多是各类形式的编码、咱们在他们数据流通的必经之地设置过滤:request.setCharacterEncoding(“UTF-8”);在使用filter时咱们须要配置web.xml里文件来激活Filter。同时在jsp代码中声明UTF-八、设定数据库链接方式也是UTF-8,好比链接mysql时的配置URL :jdbc:mysql://localhost:3306/test?useUnicode=true&charcaterEncoding=UTF-8;
下面看看java中文乱码问题的由来吧:
Java的内核和class文件是基于unicode的,这使得java程序具备很好的跨平台性;由此也带来了一些中文乱码问题。缘由主要有两方面:java和jsp文件自己编译时产生的乱码问题和java程序于其余媒介交互时产生的乱码问题。
首先java(包括jsp)源文件中极可能包含有中文,而java和jsp源文件的保存方式是基于字节流的;若是java和jsp编译成class文件过程当中、使用的编码方式与源文件的编码不一致,就会出现乱码。对于处理这种乱码、建议在java文件中尽可能不要写中文,若是必须写的话、尽可能手动带参数-ecoding GBK 或者-ecoding gb2312编译;对于jsp、在文件头加上<%@ page contentType =”text/html;charset=GBK”%>或者是<%@ page contentType="text/html;charset=gb2312"%> 就能基本解决这类乱码问题。
下面就来重点讨论第二类乱码问题吧、即java程序与其余存储媒介交互时产生的乱码;不少存储媒介如数据库、文件、流等等的存储方式都是基于字节流的;java程序与这类媒介交互时就会发生字符(char)与字节(byte)之间的转换;具体状况以下:
页面form提交数据---->java程序(byte-->char)
java程序---->页面数据显示(char--->byte)
数据库---->java程序(char----->byte)
Java程序---->数据库(byte--->char)
文件--->java程序(byte-->char)
Java程序---->文件(char---->byte)
流--->java程序(byte---->char)
Java程序--->流(char--->byte)
若是以上转换过程当中使用编码方式与字节原有编码不一致,极可能会出现乱码。
解决方法:关键在于确保转换时使用的编码方式与字节原有的编码方式保持一致。
一、jsp与页面参数之间的乱码
Jsp获取页面参数时通常采用系统默认的方式,若是页面参数的编码类型与系统默认的 编码类型不一致、极可能就会出现乱码。因此解决它的办法是在页面获取参数以前,强制指定request获取参数的编码方式:request.setCharacterEncoding(“GBK”);若是在jsp将变量输出到页面时出现了乱码、能够经过设置request.setContentType(“text/html;charset=GBK”).若是不想在每一个文件里都写这样两句话,更简洁的办法是使用Servlet规范中的过虑器指定编码,过滤器的在web.xml中的典型配置和主要代码以下:
- <filter>
- <filter-name>CharacterEncodingFilter</filter-name>
- <filter-class>travel.web.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>GBK</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- 过滤器中的代码:
- public class CharacterEncodingFilter implements Filter {
-
- protected String encoding = null;
-
- public void init(FilterConfig filterConfig) throws ServletException {
-
- this.encoding = filterConfig.getInitParameter("encoding");
- }
-
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-
- request.setCharacterEncoding(encoding);response.setContentType("text/html;charset="+encoding);chain.doFilter(request, response);
-
- }
- }
二、java与数据库之间的乱码 大部分数据库都支持以unicode编码方式,因此解决Java与数据库之间的乱码问题比较明智的方式是直接使用unicode编码与数据库交互。不少数据库驱动自动支持unicode,如Microsoft的SQLServer驱动。其余大部分数据库驱动,能够在驱动的url参数中指定,如mysql驱动:jdbc:mysql://localhost/WEBCLDB?useUnicode=true&characterEncoding=GBK。 三、java与文件/流之间的乱码 Java读写文件最经常使用的类是FileInputStream/FileOutputStream和FileReader/FileWriter。其中FileInputStream和FileOutputStream是基于字节流的,经常使用于读写二进制文件。读写字符文件建议使用基于字符的FileReader和FileWriter,省去了字节与字符之间的转换。但这两个类的构造函数默认使用系统的编码方式,若是文件内容与系统编码方式不一致,可能会出现乱码。 在这种状况下,建议使用FileReader和FileWriter的父类:InputStreamReader/OutputStreamWriter,它们也是基于字符的,但在构造函数中能够指定编码类型: InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。 四、其余 上面提到的方法应该能解决大部分乱码问题,若是在其余地方还出现乱码,可能须要手动修改代码。解决Java乱码问题的关键在于在字节与字符的转换过程当中,你必须知道原来字节或转换后的字节的编码方式,转换时采用的编码必须与这个编码方式保持一致。