1. 程式人生 > 其它 >springboot專案與資料庫互動時中文編碼錯誤問題(非???亂碼)

springboot專案與資料庫互動時中文編碼錯誤問題(非???亂碼)

技術標籤:javamysqlspringlinux

  1. 背景
    先概述一下我的專案編碼,專案使用的rpc框架讓前後端分離,前端傳遞瀏覽器的請求然後通過socket傳遞資料,遠端呼叫後端的服務。前端設定了tomcat使用utf-8編碼,後端資料來源使用utf8;mysql的client、mysqld、mysql system、資料表都是使用utf8mb4(mysql中的utf8)。你可以先確定自己專案中以上方面是否都使用了正確的編碼,再往下繼續看。

  2. 問題
    當瀏覽器傳遞中文相關的查詢請求時,在windows執行的前端時顯示還是正常的(utf8形式輸出);前端通過socket傳遞給在windows執行的後端時顯示也是正常的(utf8輸出);但是當後端發查詢語句給在linux執行的mysql時,查閱日誌發現變成了生僻字,與原來不同(utf輸出,但還是中文),導致查詢沒有結果,如圖:

    (瀏覽器輸入的莎士比亞(utf8)在mysql日誌中顯示(utf8),圖中單引號中文字):
    mysql日誌
    更奇怪的是,如果後端程式通過gui下的idea執行的話,表現正常;但是如果在powershell下用
    mvn spring-boot:run
    或是
    java -jar xx.jar
    執行後端程式的話就會像上面說的那樣表現異常。

  3. 問題排查

我試著把後端放在linux上,然後通過bash執行,發現表現正常。
於是瀏覽器->前端是正常的;前端->後端通過列印到控制檯是正常的(如果列印到powershell,要記得powershell預設是gbk,需先改內碼表為65001);然後到了mysql就變怪了,所以問題出在後端->資料庫。事實證明後端移到linux上也解決了問題。

想起來java的預設編碼好像與平臺相關,於是試著在powershell用

System.out.println(Charset.defaultCharset());

列印預設編碼,果然是gbk!然而在idea控制檯列印是utf-8!是windows的鍋。

  1. 問題原因

(下面將圖中那串生僻字用生僻字代替)
所以錯碼原因就是,前端將字串“莎士比亞”的utf-8編碼(二進位制形式記為x)通過socket發給後端,後端以為這是gbk編碼,所以utf8的"莎士比亞"代表的二進位制串x被翻譯成了gbk的 生僻字(二進位制表示也是x); 因為約定了與資料來源mysql通訊使用utf8,所以後端將gbk的生僻字

(二進位制為x)翻譯成utf8的生僻字(二進位制為y,然而他們顯示出來都是生僻字)。

  1. 解決辦法

所以解決辦法就是去更改jvm執行時編碼。網上找了許多怎麼更改defaultCharset的方法,jvm啟動引數、環境變數什麼的方法,皆無效。遂在後端收取前端資料時的輸入輸出流指定編碼為utf8:

try (BufferedReader clientMessage = new BufferedReader(new InputStreamReader(
                    incomingSocket.getInputStream(), StandardCharsets.UTF_8)); PrintStream serverMessage = new PrintStream(
                    incomingSocket.getOutputStream(), true, StandardCharsets.UTF_8)) 

問題就得以解決了。