一、前言:
在使用SSM框架搭建後臺時,有時經常會出現亂碼現象,網上針對亂碼大多隻是提供相應的思路,但在我看來,我們在解決錯誤的時候應該多深究背後錯誤的原因並做總結,以便日後面對類似問題可以得心應手。以下便是個人針對亂碼做的一個編碼設置總結。
二、編碼與解碼:
概念: 衆所周知,計算機的存儲和處理都是使用01二進制串(字節),而我們在頁面所編寫的和存儲在數據庫的數據是字符的形式。所以通俗來講,編碼即使將數據轉化爲字節形式,解碼即是恢復數據,將數據從字節形式轉化爲字符形式。
常見的字符集: ASCII、GB2312、GBK、GB18030、UTF-8、 ISO8859-1、BIG5;
詳細瞭解可參考:https://www.cnblogs.com/DannyShi/p/4616771.html
常見字符集兼容性如圖:(下圖字符集向下擴展,向上兼容,不同線不兼容)
中文亂碼產生原因:
第一種情況:使用不能識別中文的字符集來編碼(較少見)。
第二種情況:編碼和解碼時用了不同或者不兼容的字符集(較常見)。
三、編碼設置彙總(javaweb 、SSM、數據庫)
1、jsp頁面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- pageEncoding的作用是設置頁面編碼,也是設置服務器響應編碼。
- contentType的作用是指定對服務器響應進行重新編碼的編碼。
- 若響應編碼(上面的charset)未進行設置,將取pageEncoding值;
若同時設置ContentType 和 pageEncoding,取ContentType值;
若都未設置,就取默認的字符集ISO-8859-1編碼。
2、SSM
web.xml配置編碼過濾器(針對post請求)
<!-- 編碼過濾器 -->
<filter>
<filter-name>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
tomcat的配置文件server.xml設置對應端口編碼(針對get請求)
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
useBodyEncodingForURI="true"
disableUploadTimeout="true"
URIEncoding="UTF-8" />
(注:使用eclipse的,應該在eclipse中修改tomcat配置文件。)
- useBodyEncodingForURI是根據響應該請求的頁面的request.setCharacterEncoding參數對數據進行的重新編碼(解碼);
- URIEncoding是對所有GET方式的請求的數據進行統一的重新編碼(解碼);
- 不同的頁面可以有不同的重新編碼(解碼)的編碼。
controller控制請求和響應的編碼
- request.setCharacterEncoding(“UTF-8”)
作用是設置對客戶端請求進行重新編碼。僅適用於設置post提交的request body的編碼。 - response.setCharacterEncoding(“UTF-8”)
作用是指定對服務器響應進行重新編碼。瀏覽器會根據這個參數來對其接收到的數據進行解碼。 - response.setContentType(“text/html;charset=UTF-8”)
作用是瀏覽器對隨響應到來的數據的處理編碼方式。其優先級大於“Content-Type : text/html ;”
mybatis配置數據庫編碼
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
3、數據庫
對於數據庫的編碼,包含了系統字符集編碼、指定數據庫的字符集編碼、數據庫表字符集編碼、表字段字符集編碼。
- 查看mysql的系統字符集:
SHOW VARIABLES LIKE '%char%';
- 查看某數據庫字符集:
SHOW CREATE DATABASE db_name;
- 查看某數據表字符集:
SHOW CREATE TABLE tbl_name;
- 查看某表字段字符集:
SHOW FULL COLUMNS FROM tbl_name;
- 修改mysql的系統字符集:
SET character_set_connection=utf8;(例)
- 修改數據庫enterprises的字符集:
- ALTER DATABASE db_name CHARACTER SET utf8;
- 修改數據表employees的字符集:
ALTER TABLE tbl_name CHARACTER SET utf8;
- 修改字段的字符集:
ALTER TABLE tbl_name CHANGE name name VARCHAR(12) CHARACTER SET utf-8;
character_set_client:客戶端請求數據的字符集
character_set_connection:客戶機/服務器連接的字符集
character_set_database:默認數據庫的字符集,這個變量建議由系統自己管理,不要人爲定義。
character_set_filesystem:把os上文件名轉化成此字符集, 默認binary是不做任何轉換的。
character_set_results:結果集,返回給客戶端的字符集
character_set_server:數據庫服務器的默認字符集
character_set_system:系統字符集,這個值總是utf8,不需要設置。
詳細瞭解可參考:https://www.cnblogs.com/skying555/p/10512329.html
四、解惑
客戶端、服務器和數據庫的編碼一定要一致嗎?
可以不一致。第一字符集編碼可以兼容;第二,可以進行轉碼處理;但是建議配置編碼一致,以免出現不必要的bug,容易掉頭髮。
出現亂碼怎麼辦?
首先應該判斷錯誤的類型,判斷錯誤的產生是在客戶端與服務器之間的編解碼還是服務器與數據庫的編解碼。然後進行字符集比對,看是否一致或兼容。從數據的接收和發送兩方面去校對字符集。如果無法判斷在哪出現問題,那麼就按照上面取一一排除,相信大多數問題會逐漸浮出水面。