編碼與解碼及亂碼解決方案
編碼與解碼及亂碼解決方案

編碼與解碼.png
碼錶:
碼錶 | 解釋 |
---|---|
ASCII | 美國標準資訊交換碼。用一個位元組的7位可以表示。 -128~127 256 |
ISO8859-1 | 拉丁碼錶。歐洲碼錶,用一個位元組的8位表示。又稱Latin-1(拉丁編碼)或“西歐語言”。ASCII碼是包含的僅僅是英文字母,並且沒有完全佔滿256個編碼位置,所以它以ASCII為基礎,在空置的0xA0-0xFF的範圍內,加入192個字母及符號,藉以供使用變音符號的拉丁字母語言使用。從而支援德文,法文等。因而它依然是一個單位元組編碼,只是比ASCII更全面。 |
GB2312 | 中國的中文編碼表。 英文佔一個位元組, 中文佔兩個位元組。 |
GBK | 中國的中文編碼表升級,融合了更多的中文文字元號。 |
Unicode | 國際標準碼,融合了多種文字。所有文字都用兩個位元組來表示,Java語言使用的就是unicode。 |
UTF-8 | 英文佔一個位元組,中文佔三個位元組。 最多用三個位元組來表示一個字元。 |
UTF-16 | 英文中文都是佔兩個位元組。 |
注意:Unicode不是一個碼錶,只是一個規範。
一、編碼
編碼: 把看得懂的字元變成看不懂碼值這個過程我們稱作為編碼。
字串--->位元組陣列
String類的getBytes() 方法進行編碼,將字串轉為對應的二進位制,並且這個方法可以指定編碼表。如果沒有指定碼錶,該方法會使用作業系統預設碼錶。
注意:中國大陸的Windows系統上預設的編碼一般為GBK。在Java程式中可以使用System.getProperty("file.encoding")方式得到當前的預設編碼。
二、解碼
解碼: 把碼值查詢對應的字元,我們把這個過程稱作為解碼。
位元組陣列--->字串
String類的建構函式完成。
String(byte[] bytes) 使用系統預設碼錶
String(byte[],charset)指定碼錶
注意:我們使用什麼字符集(碼錶)進行編碼,就應該使用什麼字符集進行解碼,否則很有可能出現亂碼(相容字符集不會)。
public class Demo7 { public static void main(String[] args) throws Exception { /* String str = "中國"; // getBytes() :使用的是平臺預設的編碼表---gbk編碼表。 一箇中文佔兩個位元組 byte[] buf = str.getBytes("utf-8"); //編碼過程 System.out.println("陣列的元素:"+Arrays.toString(buf)); str = new String(buf,"utf-8");//預設使用了gbk碼錶去解碼。 如果解碼過程與編碼是不一樣的碼錶,就會產生亂碼 System.out.println("解碼後的字串:"+ str); */ /*String str = "a中國"; //[-2,-1,0,97,78,45,86,-3] String str = "中國";//[-2,-1,78,45,86,-3] byte[] buf = str.getBytes("unicode");//編碼與解碼的時候指定的碼錶是unicode,實際上是用了utf-16. System.out.println("陣列的內容:"+ Arrays.toString(buf)); //[-2,-1,0,97,78,45,86,-3] */ //-2和-1是utf-16自己另外加的,作為UTF-16的標誌 String str = "大家好"; byte[] buf = str.getBytes(); //使用平臺預設的編碼gbk進行編碼,但是要以檔案本身的編碼為準 System.out.println("位元組陣列:"+ Arrays.toString(buf));// -76, -13, -68, -46, -70, -61 str = new String(buf,"iso8859-1"); //亂碼 大家好 //在iso8859-1碼錶中,每個數字都有對應不同的字元,是唯一一個填滿了的碼錶 // 還原:使用這一串特殊的字元找回之前的數字,再使用gbk進行編碼 byte[] buf2 = str.getBytes("iso8859-1"); str = new String(buf2,"gbk"); System.out.println(str); } }
注意: 編碼與解碼一般都使用統一的碼錶。否則非常容易出亂碼。
不是所有的亂碼都可以還原的:
以上情況拿著數字去iso8859-1去找,因為該碼錶每個數字都有對應的字元,但是如果對於一些其他碼錶,對應的數字沒有該字元,就會造成資料丟失。
三、亂碼解決方案
中文亂碼問題是編碼不一致導致的,只要保證了前端(頁面使用meta標記utf-8),後端(對引數的解析、與連線庫的連線),和資料庫(資料庫的編碼格式)都使用統一的編碼,一般不會出現亂碼問題。
1.檢視頁面是否使用utf-8編碼
①JSP頁面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
②HTML頁面
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2.在資料庫連線url後面加上unicode引數
①使用的是非properties檔案(如在hibernate.cfg.xml中配置):
<property name="hibernate.connection.url"> jdbc:mysql://localhost:3306/資料庫名?useUnicode=true&characterEncoding=UTF-8 </property>
②使用的是properties檔案
jdbcUrl=jdbc:mysql://localhost:3306/資料庫名?useUnicode=true&characterEncoding=UTF-8
注意:如果使用的是properties檔案配置資料庫的連線資訊,引數連線要用&,不要使用& amp;
3.在struts.xml中使用國際化
<constant name="struts.i18n.encoding" value="UTF-8" />
4.使用全域性中文亂碼過濾器
GlobalFilter類:
/** * 全域性中文過濾器 * 適用get和post請求引數的中文亂碼問題,從此不同在servlet中對引數做處理 */ public class GlobalFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; // 解決POST請求引數亂碼問題 // request.setCharacterEncoding("UTF-8"); req = new MyRequest(req); chain.doFilter(req, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } }
MyRequest:
/** * 使用裝飾模式包裝HttpServletRequest,解決getParamter中文亂碼問題 */ class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest req; private boolean flag = true;// 標記是否getParameterMap方法還未被呼叫過(如果在同個servlet中呼叫了2次getParameter等方法2次,沒有用flag做標記的話,會對引數進行2次編碼,結果第2次得到的引數會是亂碼) public MyRequest(HttpServletRequest request) { super(request); req = request; } @Override public String getParameter(String name) { return getParameterMap().get(name)[0]; } @Override public String[] getParameterValues(String name) { return getParameterMap().get(name); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> map = req.getParameterMap(); if (flag) { for (Map.Entry<String, String[]> entry : map.entrySet()) { String[] value = entry.getValue(); for (int i = 0; i < value.length; i++) { try { value[i] = new String(value[i].getBytes("iso-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } flag = false; } return map; } }
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <!-- filter要放在servlet之前 --> <filter> <filter-name>GlobalFilter</filter-name> <filter-class>com.java.filter.GlobalFilter</filter-class> </filter> <filter-mapping> <filter-name>GlobalFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> ... </servlet> <servlet-mapping> ... </servlet-mapping> </web-app>