??大家好,我是 展菲,目前在上市企業從事人工智能項目研發管理工作,平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術,包括iOS、前端、Harmony OS、Java、Python等方向。在移動端開發、鴻蒙開發、物聯網、嵌入式、云原生、開源等領域有深厚造詣。
圖書作者:《ESP32-C3 物聯網工程開發實戰》
圖書作者:《SwiftUI 入門,進階與實戰》
超級個體:COC上海社區主理人
特約講師:大學講師,谷歌亞馬遜分享嘉賓
科技博主:華為HDE/HDG
我的博客內容涵蓋廣泛,主要分享技術教程、Bug解決方案、開發工具使用、前沿科技資訊、產品評測與使用體驗。我特別關注云服務產品評測、AI 產品對比、開發板性能測試以及技術報告,同時也會提供產品優缺點分析、橫向對比,并分享技術沙龍與行業大會的參會體驗。我的目標是為讀者提供有深度、有實用價值的技術洞察與分析。
展菲:您的前沿技術領航員
👋 大家好,我是展菲!
📱 全網搜索“展菲”,即可縱覽我在各大平臺的知識足跡。
📣 公眾號“Swift社區”,每周定時推送干貨滿滿的技術長文,從新興框架的剖析到運維實戰的復盤,助您技術進階之路暢通無阻。
💬 微信端添加好友“fzhanfei”,與我直接交流,不管是項目瓶頸的求助,還是行業趨勢的探討,隨時暢所欲言。
📅 最新動態:2025 年 3 月 17 日
快來加入技術社區,一起挖掘技術的無限潛能,攜手邁向數字化新征程!
文章目錄
- 前言
- 背景:為什么會出現編碼問題?
- 常見場景分析
- 控制臺輸出亂碼
- 文件讀寫亂碼
- 數據庫存取亂碼
- 解決方案
- 統一使用 UTF-8
- 設置 JVM 參數
- 數據庫設置字符集
- 實際案例:亂碼排查經驗
- 總結
前言
在日常 Java 開發中,字符編碼問題是一個非常常見卻又特別容易踩坑的地方。尤其是在不同操作系統之間切換,或者從前端傳到后端、再到數據庫,編碼沒統一好,中文就會出現“亂碼”。很多同學第一次遇到的時候,會被一大堆奇怪的方塊符號或者問號整崩潰。
這篇文章就帶你一步一步看清楚字符編碼的來龍去脈,并結合可運行的代碼,看看如何在 Java 項目里徹底解決編碼不一致的問題。
背景:為什么會出現編碼問題?
其實原因很簡單:不同系統、不同軟件的默認字符編碼不一樣。
- Windows 上默認編碼是 GBK 或 CP936。
- Linux、Mac 大部分是 UTF-8。
- 數據庫可能是 Latin1、GBK 或 UTF-8。
- Tomcat、IDEA 默認也可能不是 UTF-8。
舉個例子,如果你的 Java 程序里寫了一行中文字符串 "你好"
,在 UTF-8 下存儲沒問題,但如果有人用 GBK 來讀取,就會直接炸掉,變成“亂碼”。
常見場景分析
控制臺輸出亂碼
在 Windows 的 CMD 下運行 Java 程序時,經常會看到控制臺打印中文是亂碼。這是因為 Windows 控制臺默認用 GBK 編碼,但你的 Java 程序里可能用的是 UTF-8。
public class EncodingDemo {public static void main(String[] args) {String msg = "你好,世界";System.out.println(msg);}
}
在 Linux/Mac 控制臺上運行,大概率沒問題。但在 Windows CMD 里,就會看到一堆奇怪符號。
文件讀寫亂碼
當你從文件里讀中文內容時,如果讀的時候用的編碼和寫的時候不一樣,也會直接出錯。
import java.io.*;public class FileEncodingDemo {public static void main(String[] args) throws Exception {String text = "中文內容測試";// 寫入文件,強制使用 UTF-8try (Writer writer = new OutputStreamWriter(new FileOutputStream("test.txt"), "UTF-8")) {writer.write(text);}// 讀取文件(錯誤示范:不指定編碼)try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {System.out.println("讀到的內容:" + reader.readLine());}// 正確方式:指定 UTF-8try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt"), "UTF-8"))) {System.out.println("正確讀到的內容:" + reader.readLine());}}
}
運行后你會發現,沒指定編碼時中文是亂碼,指定了 UTF-8 之后就正常了。
數據庫存取亂碼
數據庫也是高頻出錯點,比如 MySQL 默認的 latin1
編碼就很坑。假設表結構是這樣的:
CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50)
) DEFAULT CHARSET=latin1;
如果你在 Java 里用 UTF-8 往里面寫入 "張三"
,再讀出來時就會發現已經是亂碼。
解決辦法是:
- 建庫建表時就指定
utf8mb4
:
CREATE DATABASE demo DEFAULT CHARSET=utf8mb4;
- JDBC 連接時也要加上編碼參數:
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
解決方案
那我們該怎么統一解決這個問題呢?其實有幾個常見思路:
統一使用 UTF-8
UTF-8 是現在最通用的編碼方式,跨系統兼容性最好。所以最穩妥的做法就是:整個鏈路都統一成 UTF-8。
包括:源代碼文件、編譯參數、運行參數、數據庫配置、Tomcat 配置。
比如在 Maven 項目里,你可以在 pom.xml
里強制指定源碼編碼:
<project><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
</project>
這樣即便在 Windows 上編譯,結果也不會變。
設置 JVM 參數
如果你發現運行環境默認編碼不是 UTF-8,可以在 JVM 啟動時加上參數:
java -Dfile.encoding=UTF-8 -jar app.jar
這會讓整個 Java 虛擬機的默認編碼改成 UTF-8,很多情況下能一勞永逸。
數據庫設置字符集
在 MySQL 里,推薦直接用 utf8mb4
,這樣連 emoji 表情都能存:
ALTER DATABASE demo CHARACTER SET utf8mb4;
ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;
同時,Java 里的 JDBC 連接也要顯式指定編碼,否則還是會出問題。
實際案例:亂碼排查經驗
我自己就踩過一個坑:在 Windows 下本地開發,數據庫是 utf8mb4,項目里也設了 -Dfile.encoding=UTF-8
,一切正常。但是代碼上線到 Linux 服務器后,日志里的中文全是亂碼。排查了半天,最后發現是 日志框架的配置文件沒聲明 UTF-8,導致寫日志文件時被當成系統默認編碼。
后來改了一行配置就好了:
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><charset>UTF-8</charset><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
所以要點就是:不要依賴默認值,凡是涉及到字符集的地方都要顯式聲明 UTF-8。
總結
Java 的字符編碼問題,說白了就是“讀和寫不一致”。解決它的核心就是統一,特別是統一用 UTF-8。
- 源代碼、編譯、運行 JVM 都統一 UTF-8。
- 文件讀寫時顯式指定編碼。
- 數據庫用
utf8mb4
并在 JDBC 連接里加上參數。
只要做到這幾點,基本就不會再遇到莫名其妙的亂碼問題。