MySQL中文乱码问题的完整解决方法

转载于https://www.cnblogs.com/nista/archive/2013/04/16/3023279.html


本文描述了在基于JSP +MySQL构建网站时,发生网页中文显示为乱码情况的解决办法。最终希望使用的编码是:统一的UTF-8编码。


试验网站的开发运行环境:

OS: Ubuntu 12.04 及 Windows 7

IDE: eclipse, Juno Service Release 2

Web Server: Tomcat 7.0.27

DataBase: MySQL 5.5.29


本文的一些观点应该也能推广到其他编码、平台或数据库。

网站的中文输入输出产生或接收到乱码的原因,可能发生在数据流动的任意节点处。但是,如果保证所有的位置都使用了统一的编码,则可以消除中文乱码的情况。这些可能发生转码的地方包括网页的编码定义,JSP页面的编码,Java代码文件的编码,Tomcat读取的web.xml中的定义,MySQL的client、server、connection以及每个数据库、每个表、甚至每个字段的编码设定。根据之前查找的一些资料,和刚刚做完的实验,将相关的设定总结如下:

在这个过程中,首先应保证数据库在存储数据、存入数据以及数据时应一致。其次,在进行网页服务器后台处理和传递的过程中应保证编码的一致。最后应保证,数据在进行浏览器前台显示和数据传递的过程中编码的一致。只要保证这一切都采用统一的编码格式,就不会产生中文乱码的问题。

(1) MySQL 数据库的相关定义和配置方法。

MySQL中有关于字符集的概念主要有两个,一个是字符集(Character Set),一个是字符序(collation)。MySQL内部会采用如下的变量进行字符集的设定:

– character_set_server:默认的内部操作字符集

– character_set_client:客户端来源数据使用的字符集

– character_set_connection:连接层字符集

– character_set_results:查询结果字符集

– character_set_database:当前选中数据库的默认字符集

– character_set_system:系统元数据(字段名等)字符集

– 还有以collation_开头的同上面对应的变量,用来描述字符序。

MySQL中的字符集转换过程如下:

① MySQL 客户端库收到请求时将请求数据从character_set_client转换为character_set_connection;

② MySQL服务器受到请求进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:

• 使用每个数据字段的CHARACTER SET设定值;

• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);

• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

• 若上述值不存在,则使用character_set_server设定值。

③ 将操作结果从内部操作字符集转换为character_set_results。

MySQL中文乱码问题的完整解决方法

(以上内容引用自Shunnar Meng

http://hi.baidu.com/shunnarmeng/item/97108dafb4b93638030a4dee

每个字符集都有一个或多个与之对应的字符序,MySQL中的字符序末尾ci表示大小写不敏感,si表示大小写敏感。一般情况下,可以不用设定字符序,因为系统会自动设定所选字符集的首选字符序,如选定字符集utf-8,则会自动选择默认字符序utf8_general_ci。

更多基本定义,可以参阅MySQL参考手册:

http://dev.mysql.com/doc/refman/5.1/zh/charset.html


因此,只要在MySQL的配置文件中进行如下的修改:

(Ubuntu下,一般位于/etc/mysql/my.cnf)

[client] 中,添加 default-character-set = utf8

[mysqld]中,添加

character-set-server = utf8

character-set-client = utf8

collation = utf8_general_ci

[mysql]中,添加 default-character-set = utf8

随后重启MySQL服务,$ sudo service mysql restart

之后进入MySQL,输入 mysql> show VARIABLES like ‘char%’;

+--------------------------+----------------------------+ 
| Variable_name | Value | 
+--------------------------+----------------------------+ 
| character_set_client | utf8 | 
| character_set_connection | utf8 | 
| character_set_database | utf8 | 
| character_set_filesystem | binary | 
| character_set_results | utf8 | 
| character_set_server | utf8 | 
| character_set_system | utf8 | 
| character_sets_dir | /usr/share/mysql/charsets/ | 
+--------------------------+----------------------------+ 
8 rows in set (0.00 sec)

这可以检查MySQL在各个处理层次所采用的编码

(2) eclipse开发环境编码的设定。

在eclipse的Window菜单中选择 Preferences → General → Workspace,在右侧的Text file encoding栏中,将Default(GBK) 改选为Other,并选择 UTF-8 项。

在Preferences → Web 中,可以将CSS、HTML等文件的默认编码形式进行更改。

随后可以在 Preferences → General → Content Types 中,找到右边的Text,选择JSP,在下方的Default encoding中输入UTF-8,这将会设定代码文件本身的编码存储格式。

但是,如果以前有大量源代码文件不是UTF-8编码格式的,可以使用Linux下的iconv或其他工具进行转码。

(如果使用NetBeans,也基本按照这个思路,在配置中找)

(3) 在编写JSP页面时,应该注意的相关代码。

① HTML代码部分,应在<head></head>中添加:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

从而保证浏览器在解析网页进行显示的过程中能够选择正确的编码方式。其他网页所引用的相关文件中也应添加字符集标识。

如,CSS头部添加:

@charset "utf-8";


② JSP代码页头部添加:

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

③ 如果在Windows环境下,编写代码,注意代码文件本身的编码也很重要,应保证以UTF-8格式进行保存(如,在记事本中保存时更改编码方式,在eclipse进行上文中的开发环境编码设定)

(4) 保证Tomcat在运行时进行正常的转码行为。

① 编写过滤器,并设定当前网站项目的配置文件web.xml,本质是设定页面和JSP后台程序之间专递过程的转码,具体的过程如下:

在工程中添加一个新的类,并编写如下代码。

MySQL中文乱码问题的完整解决方法
package com.nista.common.filter;

import java.io.IOException;

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

public class SetCharacterEncodingFilter implements Filter {
    // 相关的参数配置,请在本项目的Server.xml中设置
    // 如果未设定是否应用本Filter,则默认开启转码
    // 如果未设定使用编码,则默认采用UTF-8
    
    protected FilterConfig filterConfig = null; 
    protected String strEncodingSet = null; 
    protected boolean enableEncoding = true; 
    
    @Override
    public void destroy() {
        this.strEncodingSet = null;
        this.filterConfig = null;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig; 
        this.strEncodingSet = filterConfig.getInitParameter("EncodingSet");
        String strEnableEncoding = filterConfig.getInitParameter("EnableEncoding");
        
        if (null == strEnableEncoding || strEnableEncoding.equalsIgnoreCase("true")) {
            this.enableEncoding = true;
        } 
        else {
            this.enableEncoding = false;
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        if (this.enableEncoding) {
            if (null == this.strEncodingSet) {
                this.strEncodingSet = "UTF-8";
            }
            
            request.setCharacterEncoding(strEncodingSet);
        }
        
        chain.doFilter(request, response); 
    }
    
}
MySQL中文乱码问题的完整解决方法

在本工程的web.xml中,<welcome-file-list />标签之后添加如下代码,以调用上述的字符集编码过滤器。注意包名和类名需要与上方代码一致。

MySQL中文乱码问题的完整解决方法
<!-- request/response自定义的字符集编码过滤器  -->
  <filter> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <filter-class>com.nista.common.filter.SetCharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>EncodingSet</param-name>
        <param-value>UTF-8</param-value>    
    </init-param>
    <init-param>
        <param-name>EnableEncoding</param-name>
        <param-value>true</param-value>
    </init-param>    
  </filter> 
  <filter-mapping> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
  </filter-mapping>
MySQL中文乱码问题的完整解决方法

* 如果希望了解web.xml配置的更多说明,可以浏览 http://blog.sina.com.cn/s/blog_620782850100gam8.html

http://www.cnblogs.com/chinafine/archive/2010/09/02/1815980.html

② 如果需要利用get方式传递UTF-8编码的数据

将Tomcat配置文件中,所有的<Connector />标签的URIEncoding属性进行设置,例如:<Connector ……URIEncoding="UTF-8" />

这种方法实际上是将URI地址在传递过程中进行了转码,但是这可能会导致其他的一些问题,例如有时服务器端发生会发生编码问题(接受URI中中文数据时会出现问题),这时可以采用如下解决方法(不建议在URI中传中文):


在tomcat 的server.xml里设置如下:

<Connector port="8081" protocol="HTTP/1.1" 
    connectionTimeout="20000" 
    URIEncoding=”utf-8”
    useBodyEncodingForURI=”true”
    redirectPort="8443" />

然后在服务端解码:

new String (request.getParameter("id").getByte("ISO-8859-1"),"gbk");

通过这些设置以后,就可以基本保证可能发生转码的节点采用统一的UTF-8编码,防止中文乱码的产生。