著作權歸作者所有。
商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
連結:https://stazxr.cn/2024/12/05/JDK-18-以上使用標準輸出流中文輸出亂碼問題/
來源:終わり群星
問題描述
起因是 tomcat 呼叫servlet輸出的System.out.println
(也就是所說的控制檯輸出流)中文亂碼,但是其他輸出沒有受到影響。
問題分析
執行環境:JDK 21, Tomcat 10
我所有的程式碼都是UTF-8編碼的,而且在IDEA中設定了UTF-8編碼。
並且Tomcat也配置了-Dfile.encoding=UTF-8
選項
透過檢視System.out
的編碼方式,發現是GBK
,但是在控制檯的編碼方式是UTF-8
。
System.out.println(System.out.charset()); // System.out.charset()方法自jdk18起
// output: GBK
使用jdk17的時候沒有問題,但是使用jdk21就會出現亂碼問題。
解決方案
參考JEP 400: UTF-8 by Default (openjdk.org)透過呼叫getProperty方法獲取預設字符集
System.out.println("Java Runtime version " + System.getProperty("java.runtime.version"));
System.out.println("----------------------------------------------------------");
//全域性預設編碼 JDK21是UTF
System.out.println("Charset.defaultCharset() = " + Charset.defaultCharset());
//預設檔案的編碼,這個應該是位元組碼檔案
System.out.println("System.getProperty(\"file.encoding\") = " + Charset.defaultCharset().displayName());
//獲取的是本地的字符集編碼,中文windows系統應該是GBK
System.out.println("System.getProperty(\"native.encoding\") = " + System.getProperty("native.encoding"));
System.out.println("System.getProperty(\"sun.jnu.encoding\") = " + System.getProperty("sun.jnu.encoding"));
//這個是輸出流的預設字符集編碼
System.out.println("System.getProperty(\"sun.stdout.encoding\") = " + System.getProperty("sun.stdout.encoding"));
//這個是錯誤流的預設編碼
System.out.println("System.getProperty(\"sun.stderr.encoding\") = " + System.getProperty("sun.stderr.encoding"));
//console預設編碼
System.out.println("System.console().charset() = " + System.console().charset());
//當前輸出流的編碼
System.out.println("System.out.charset() = " + System.out.charset());
System.out.println("----------------------------------------------------------");
在一般的情況下System.getProperty("sun.stdout.encoding")
和System.getProperty("sun.stderr.encoding")
的值是UTF-8
,但是在Tomcat中是null
。
tomcat 10 不會指定輸出流的字元編碼
所以我們需要在啟動tomcat的時候指定輸出流的字元編碼
是在啟動配置中的 VM options 新增引數:
-Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8
這種方法只能解決所設定程式的編碼問題,若需解決 Javadoc 的亂碼,則需在-D前新增-J。
-J-Dstdout.encoding=UTF-8 -J-Dstderr.encoding=UTF-8
總結
亂碼問題只出現在jdk18及以上的版本,因為Java 18 中將預設編碼改為了 UTF-8,但沒有改動System.out和System.err的編碼。
所以使用jdk17沒有問題,但是在使用jdk21就會出現亂碼問題。
只要在 VM options 中新增 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8
即可設定輸出流的編碼。
參考
- JEP 400: UTF-8 by Default (openjdk.org)
- https://openjdk.java.net/jeps/400
- 解決 Java 18 以上 IDEA 中文輸出亂碼問題(知乎)
- 解決IDEA控制檯中輸出中文亂碼並探究原因(JDK18及以上)