Jersey MVC + Thymeleafしたら文字化けた時の対策
環境
- OS X 10.11.4
- Google Chrome
- Payara Web ML 4.1.1.161.1 (Jersey 2.22.1)
- Thymeleaf 2.1.4.RELEASE
プログラム概要
@bufferingさんの記事を参考に、Thymeleaf用のTemplateProcessorを作成。
@Provider public class ThymeleafTemplateProcessor extends AbstractTemplateProcessor<String> { @Inject private javax.inject.Provider<Ref<HttpServletRequest>> requestProviderRef; @Inject private javax.inject.Provider<Ref<HttpServletResponse>> responseProviderRef; private TemplateEngine templateEngine; @Inject public ThymeleafTemplateProcessor(Configuration config, ServletContext servletContext) { super(config, servletContext, "html", "html"); TemplateResolver templateResolver = new ServletContextTemplateResolver(); templateResolver.setPrefix((String)config.getProperty(MvcFeature.TEMPLATE_BASE_PATH)); templateResolver.setSuffix(".html"); templateEngine = new TemplateEngine(); templateEngine.setTemplateResolver(templateResolver); } @Override protected String resolve(String templatePath, Reader reader) throws Exception { return templatePath; } @Override public void writeTo(String templateReference, Viewable viewable, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream out) throws IOException { HttpServletRequest httpServletRequest = requestProviderRef.get().get(); HttpServletResponse httpServletResponse = responseProviderRef.get().get(); WebContext webContext = new WebContext( httpServletRequest, httpServletResponse, super.getServletContext(), httpServletRequest.getLocale()); Object model = viewable.getModel(); if (model instanceof Map) { Map<String, Object> map = (Map) model; webContext.setVariables(map); } else { Map<String, Object> variables = new HashMap<>(); variables.put("model", viewable.getModel()); webContext.setVariables(variables); } templateEngine.process(viewable.getTemplateName(), webContext, httpServletResponse.getWriter()); } }
リソースクラス。
@Path("employee") @RequestScoped @Produces(MediaType.TEXT_HTML) public class EmployeeResource { @GET @Path("index") public Viewable index() throws Exception { return new Viewable("/employee/index"); } }
Thymeleafのビュー。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>入力画面</title> <link rel="stylesheet" href="../../css/style.css"/> </head> <body> <p>社員IDを入力してください(77, 88, 99で例外発生)</p> <!-- 検証エラーメッセージの表示 --> <ul class="error" th:if="${violations != null}"> <li th:each="violation : ${violations}" th:text="${violation.message}">ダミーのメッセージ</li> </ul> <form action="./result" method="get"> 社員ID:<input type="text" name="id" value="" th:value="${param.id == null} ? '' : ${param.id[0]}"/> <input type="submit" value="検索"/> </form> </body> </html>
現象
画面の全日本語メッセージが文字化けている。
原因と対策
レスポンスヘッダーやブラウザが現在開いている文字コードを見ると、正しくUTF-8になっていた。
よって、そもそもレスポンスを書き込む際に文字コードが正しく設定されていないっぽい。
TemplateProcessorにhttpServletResponse.setCharacterEncoding("UTF-8");
を追加したら、正しく表示された。
@Provider public class ThymeleafTemplateProcessor extends AbstractTemplateProcessor<String> { // 中略 @Override public void writeTo(String templateReference, Viewable viewable, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream out) throws IOException { HttpServletRequest httpServletRequest = requestProviderRef.get().get(); HttpServletResponse httpServletResponse = responseProviderRef.get().get(); // これを追加 httpServletResponse.setCharacterEncoding("UTF-8"); WebContext webContext = new WebContext( httpServletRequest, httpServletResponse, super.getServletContext(), httpServletRequest.getLocale()); Object model = viewable.getModel(); if (model instanceof Map) { Map<String, Object> map = (Map) model; webContext.setVariables(map); } else { Map<String, Object> variables = new HashMap<>(); variables.put("model", viewable.getModel()); webContext.setVariables(variables); } templateEngine.process(viewable.getTemplateName(), webContext, httpServletResponse.getWriter()); } }
ちなみに
Ozark + Thymeleafだと、この記述が無くても正しく表示された。
(ViewEngineクラスにもそれらしい記述は無い)
理由は不明。。。