本当に苦労したSpringでの文字化け問題

Spring MVC + Thymeleaf + HTML + JavaScripttwitterGoogle Mapに表示するアプリを作っていたが、tweetGoogle Mapのmarkerに表示したところmarkerに表示されるtweetの日本語が文字化けした。

以前、Thymeleafで文字化けした際は、servlet-context.xmlのorg.thymeleaf.templateresolver.ServletContextTemplateResolverとorg.thymeleaf.spring3.view.ThymeleafViewResolverの設定でcharacterEncodingを指定することで解消した。今回は既にその設定は済んでいる。

そこで一旦、(今回関係ない設定も含めて)文字化けに関係しそうな文字エンコーディング関連の箇所を整理してみた。

結論から述べると、SpringのControllerの@RequestMappingでproduces="text/plain;charset=UTF-8"の指定を行うことで文字化けは解消した。

ただ、このブログを見るまでは、この設定を知らずに相当試行錯誤して苦労した。

まず試したことは、ブラウザ側(クライアント側)の問題かもしれないと考えて、HTMLのcharsetを明示的に指定したこと。それでも変わらなかった。
次に、試したことは、GoogleMap、jQueryを使用していたので、それらのcharsetかと考え、JavaScriptを読み込む際のcharsetを明示的に指定したこと。それでも変わらなかった。
そうなるとサーバ側でのエンコーディングかと考え、Javaソース、APサーバの設定すべて、もう途中から疲れたので手当たり次第にw試していったが全然解決せず。

こうなってくると自分が知らない世界(自分の書いたJavaとクライアント側とのやりとりの間)で何かがcharsetを自動変換しているのではと疑いだして、「Spring MVCで直接文字列を返した際のレスポンスヘッダのContent-Typeを指定する」に辿り着いた。
ここでは下記のように書かれていた。

コントローラのメソッドに@ResponseBodyアノテーションを付けるとメソッドの返り値がそのままレスポンスボディになります。返り値がStringの場合StringHttpMessageConverterがMessageConverterとして使用されますが、デフォルトの設定ではレスポンスヘッダのContent-Typeの値が「text/plain;charset=ISO-8859-1」になってしまいます。
「text/plain;charset=UTF-8」にするための簡易な方法として、@RequestMappingのパラメータにproducesを設定することができます。

それでこの設定をしたところ、文字化けは解消された。

@RequestMapping(value = "/getJSON", method = RequestMethod.GET, produces="text/plain;charset=utf-8")
	@ResponseBody
	public String getJSON() throws TwitterException,UnsupportedEncodingException{
 ・・・・・ 中略 ・・・・・
 Gson gson = new Gson();
 return gson.toJson(hashMapList);
}


hashMapListをGSONでJSONに変換して文字列として返却している。
JSONなので"text/plain"ではなくて、"application/json"かとも思ったが単なる文字列だから、text/plainでも問題ないのか。

なお、servlet-context.xmlでの設定は下記のようにしてみたが、機能しなかった。Springのバージョンが変わったせいかもしれないので、Spring本家のページなどを利用して調べる必要がありそう。

<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven>
	<message-converters register-defaults="true">
			<beans:bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<beans:property name="supportedMediaTypes" value="application/json;charset=UTF-8" />
				<beans:property name="writeAcceptCharset" value="false" />
			</beans:bean>
		</message-converters>
	</annotation-driven>