您看到的效果都可以通過假設數據以UTF-8字節寫入數據庫的假設來解釋,但數據庫認爲這些字節是其他字符集(ISO-LATIN-1或Windows-1252),然後在讀取數據時,返回的字符串是解釋爲ISO-LATIN-1或相關字符集的字節。
UTF-8中的字符ú
是兩個字節0xC3 0xBA。當這些字節被解釋爲ISO-LATIN-1或者win-1252時,你會得到兩個字符ú
。
用UTF-8編寫的兩個字符ú
是四個字節0xC3 0x83 0xC2 0xBA。當這四個字節被解釋爲ISO-LATIN-1(或win-1252)時,你會得到四個字符ú
。
(WINDOWS-1252和ISO-LATIN-1發生在對有問題的所有字節/字符的同意,因此,從證據看,我不能告訴他們之間的區別)
發生了什麼事給你,我相信是這樣的:
的JDBC客戶端查詢數據庫,並取回含有從數據庫中兩個字符ú
的字符串。
當JVM打印結果到Windows 7的儲物箱,如果不開始-Dfile.encoding=utf-8
,將其發送到扶手箱,以表示雙贏1252字符串所需的字節數。如果啓動該選項的JVM 爲,則它將以UTF-8格式表示字符串所需的字節數發送到控制檯框。
您的Windows 7控制檯框設置爲窗口1252,並顯示通過解釋字節的java什麼的Java打印出根據窗口1252
當你調用.getBytes()
不帶參數的,你把它使用JVM的默認編碼將字符串轉換爲字節。因此,如果默認JVM編碼爲UTF-8,則new String(str.getBytes(), "UTF-8")
將導致相同的字符串,並且如果默認編碼與UTF-8不同,則只能導致實際發生的情況。
這就解釋了所有你所提交的證據:通過JDBC檢索到的Java字符串包含字符ú
,然後當一個非UTF-8 JVM試圖打印此控制檯中,這是打印爲ú
。當utf-8 JVM嘗試將此字符串打印到控制檯盒時,它會打印四個字節0xC3 0x83 0xC2 0xBA,並且控制檯將其解釋爲四個字符ú
。當一個java web服務器試圖將這個字符串發送回瀏覽器時,它會這樣做 - 瀏覽器看到的是java應用程序從JDBC接收到的內容。
首先要檢查的是Spring JDBCTemplate正確接收數據並正確寫入數據庫。你可以讓Spring記錄它從瀏覽器接收到的內容,並確保瀏覽器發送UTF-8,並且Spring知道瀏覽器正在發送UTF-8? (你可能想要檢查的一件事是記錄接收到的字符串以及每個字段中字符串的長度,這可以讓你知道是否正確解釋爲UTF-8)
假設數據越來越到正確的數據庫,就像你說的,你不能讓在數據庫方面的變化,並希望從應用端純粹的變化,你可以做到這一點從JDBC收到的每個字符串:
new String(str.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
無論JVM的默認編碼是什麼,這應該會將您的字符串轉換回您想要的。
爲了將來的參考,從windows命令行運行一個帶有-Dfile.encoding=utf-8
的jvm通常需要先更改控制檯上的代碼頁,以便正確查看內容。 (這可以通過命令chcp 65001
來完成,只要記住在運行沒有設置該選項的JVM命令前使用chcp 1252
即可)
您使用的String的雙參數構造函數將字節數組作爲第一個參數。在調用新的String(str,「UTF-8」)之前,如何將字符串結果從數據庫轉換爲字節? –
@Daniel:我對從數據庫中獲得的字符串調用str.getBytes()。 – User2709
在JDBC中,你必須指定編碼你已經完成了嗎? –