Spring boot + thimeleaf + tomcatでWEBアプリ開発を行っております。
<使用ミドルウェア>
spring boot:1.3.2
thimeleaf
<開発マシン>
jdk:1.8.0.74
マシン:Windows7
IDE:eclipse4.4
ビルドツール:Gradle
tomcat:8.0.32
上記開発マシンにおいて、gradleタスクでwarファイルを作成し、
開発マシン上のTomcatにデプロイして動作確認を行ったところ、
HTML画面からPOST送信された画面入力値が、メソッドにおいて文字化けしていました。
各部分の記述は以下の通りです。
・HTML
<meta charset="UTF-8">
・Spring
AbstractAnnotationConfigDispatcherServletInitializerを継承したクラスで、
下記のように記述。
@Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); characterEncodingFilter.setForceEncoding(true); return new Filter[] { characterEncodingFilter }; }
・Tomcxat
Server.xmlに下記のように記述
web.xmlにcharacterEncodingFilter を追加すれば治るよ、という情報があちこちにあったため、
追加してみたのですがそれでもだめでした……、
FindBugなどでPOSTの中身を見てみると、
/search?_csrf=d473774b-719c-4903-8f57-f4975138f755&baseCdC=&clntDnoC=&clntSeqC=&loginDateFrom=&loginDateTo=&nmKaV=%EF%BD%B1%EF%BD%B1%EF%BD%B1&nmKjV=%E3%81%82%E3%81%82%E3%81%82&ofcdC=&shcdC=&telNo=&zpcdC=
のようにUTF-8で送信されているように見えるので、
サーバー内部で文字コードが変換されているように思えます。
また、Javaで取得した文字コードをチェックしたところ、
ISO-8859_1になってしまっているようで、文字コード変換をかけてUTF8にすれば正しい値が取得できました。
とりとめもなく記載してしまいましたが、
上記のような現象に何か心当たりなどあるかたがおられましたら、
ご教授いただきたく思います。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
過去にSpringBootを利用したときに、同じように POST したデータが文字化けするという事象があり
もしかしたら同じ状況かもしれません
その際の状況で分かったのは、
SpringSecurityFilterChain の方が CharacterEncodingFilter より先に実行される場合があり、
CharacterEncodingFilter で指定した文字コードが有効にならないというのが原因でした
以下の WebSecurityConfig を追加して、強制的に SpringSecurityFilterChain より先に CharacterEncodingFilter を実行するように設定することで解決できましたよ
java
1@Configuration 2@EnableWebSecurity 3public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 4 @Override 5 protected void configure(HttpSecurity http) throws Exception { 6 CharacterEncodingFilter filter = new CharacterEncodingFilter(); 7 filter.setEncoding("UTF-8"); 8 filter.setForceEncoding(true); 9 http.addFilterBefore(filter, CsrfFilter.class); 10 } 11}
これは環境依存な問題のようで、
文字化けしない環境では CharacterEncodingFilter の方が先に実行されるんですが、
サーバーによって SpringSecurityFilterChain が先に実行される場合があり、その時に文字化けしているようでした
実行の順番はデバッグログに出てきます
その先は時間がなく調査はしてないので根本原因は分かっていませんが。。
投稿2016/03/16 01:38
編集2016/03/16 01:47総合スコア97
0
Local環境では問題なかったということでしょうか?
私は以下のような設定で問題なかったのですが…
参考になれたらいいなと思います。
すでに解決されたかもしれませんが…笑
java
1@Configuration 2public class ThymeleafConfig { 3 4 @Bean 5 public ServletContextTemplateResolver templateResolver() { 6 ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(); 7 resolver.setPrefix("/templates/"); 8 resolver.setSuffix(".html"); 9 resolver.setTemplateMode("HTML5"); 10 resolver.setOrder(1); 11 resolver.setCharacterEncoding("UTF-8"); 12 13 //Test 14 //resolver.setCacheable(false); 15 16 return resolver; 17 } 18 19 /** 20 * ThymeleafのDialect 21 * IEのHack対応、コメントの中にもThymeleaf使えるようにする。 22 * <!--[if IE]> 23 * <![endif]--> 24 * 25 * @return 26 */ 27 @Bean 28 public ConditionalCommentsDialect conditionalCommentDialect() { 29 return new ConditionalCommentsDialect(); 30 } 31 32}
java
1 2import java.io.File; 3import java.io.IOException; 4import java.nio.charset.Charset; 5import java.util.List; 6 7import javax.servlet.Filter; 8import javax.servlet.FilterChain; 9import javax.servlet.FilterConfig; 10import javax.servlet.MultipartConfigElement; 11import javax.servlet.ServletException; 12import javax.servlet.ServletRequest; 13import javax.servlet.ServletResponse; 14import javax.servlet.http.HttpServletRequest; 15 16import org.apache.catalina.Context; 17import org.apache.catalina.session.StandardManager; 18import org.apache.catalina.startup.Tomcat; 19import org.springframework.beans.factory.annotation.Autowired; 20import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; 21import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; 22import org.springframework.boot.context.embedded.FilterRegistrationBean; 23import org.springframework.boot.context.embedded.MultipartConfigFactory; 24import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; 25import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; 26import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; 27import org.springframework.context.annotation.Bean; 28import org.springframework.context.annotation.ComponentScan; 29import org.springframework.context.annotation.Configuration; 30import org.springframework.context.annotation.Import; 31import org.springframework.context.annotation.PropertySource; 32import org.springframework.context.support.ResourceBundleMessageSource; 33import org.springframework.core.env.Environment; 34import org.springframework.data.domain.PageRequest; 35import org.springframework.data.web.PageableHandlerMethodArgumentResolver; 36import org.springframework.http.converter.HttpMessageConverter; 37import org.springframework.http.converter.StringHttpMessageConverter; 38import org.springframework.remoting.rmi.RmiProxyFactoryBean; 39import org.springframework.validation.Validator; 40import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 41import org.springframework.web.method.support.HandlerMethodArgumentResolver; 42import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 43import org.springframework.web.servlet.config.annotation.EnableWebMvc; 44import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 45import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 46import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 47 48/** 49 * MVCの全体を設定する 50 * @author park 51 */ 52@EnableWebMvc 53@ComponentScan(basePackages = {"xxx"}) 54@Import({JpaConfiguration.class, JavaMailConfiguration.class}) 55@PropertySource({ "classpath:config.properties" }) 56@Configuration 57public class WebMvcConfig extends WebMvcConfigurerAdapter { 58 59 @Autowired 60 private Environment env; 61 62 // ********************************************************************** 63 // URLとVIEWページのマッピング設定 64 // ********************************************************************** 65 @Override 66 public void addViewControllers(ViewControllerRegistry registry) { 67 registry.addViewController("/common/category.html").setViewName("common/category"); 68 } 69 70 // ********************************************************************** 71 // ページング処理のDefault値設定 72 // ********************************************************************** 73 @Override 74 public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { 75 PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver(); 76 resolver.setFallbackPageable(new PageRequest(0, 20)); // Default page 77 // list 20 78 resolver.setPageParameterName("page.page"); 79 resolver.setSizeParameterName("page.size"); 80 argumentResolvers.add(resolver); 81 } 82 83 // ********************************************************************** 84 // リソースのURLと実際の経路のマッチングやキャッシュなどを指定 85 // APサーバの指定で実際はWEBサーバ側で処理を行うこと 86 // ********************************************************************** 87 @Override 88 public void addResourceHandlers(ResourceHandlerRegistry registry) { 89 90 registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/").setCachePeriod(31556926); 91 registry.addResourceHandler("/font-awesome/**").addResourceLocations("classpath:/static/font-awesome/").setCachePeriod(31556926); 92 registry.addResourceHandler("/fonts/**").addResourceLocations("classpath:/static/fonts/").setCachePeriod(31556926); 93 registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/").setCachePeriod(31556926); 94 registry.addResourceHandler("/img/**").addResourceLocations("classpath:/static/img/").setCachePeriod(31556926); 95 registry.addResourceHandler("/pdf/**").addResourceLocations("classpath:/static/pdf/").setCachePeriod(31556926); 96 97 //set Upload Path 98 registry.addResourceHandler("/uploads/**").addResourceLocations("file:" + env.getProperty("upload.path") + File.separatorChar); 99 100 } 101 102 @Override 103 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 104 configurer.enable(); 105 } 106 107 108 // ********************************************************************** 109 // 国際化関連設定 110 // ********************************************************************** 111 // Provides internationalization of messages 112 @Bean 113 public ResourceBundleMessageSource messageSource() { 114 ResourceBundleMessageSource source = new ResourceBundleMessageSource(); 115 source.setBasename("messages"); 116 return source; 117 } 118 119 //Validatorのメッセージ 120 @Override 121 public Validator getValidator() { 122 123 LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 124 validator.setValidationMessageSource(messageSource()); 125 return validator; 126 } 127 128 // ********************************************************************** 129 // Exception Handler追加 130 // 予期してないエラーが発生した場合 131 // ********************************************************************** 132 @Bean 133 public GlobalException handlerExceptionResolver() { 134 GlobalException handler = new GlobalException(); 135 return handler; 136 } 137 138 139 // ********************************************************************** 140 // エンコード設定 141 // ********************************************************************** 142 // JSON(@RestController、@ResponseBody)時の文字化け対応 143 @Override 144 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 145 converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); 146 } 147 148 // リクエストパラメタのエンコードを設定する 149 @Bean 150 public FilterRegistrationBean getFilterRegistrationBean() { 151 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); 152 filterRegistrationBean.setFilter(new CharacterEncodingFilter()); 153 return filterRegistrationBean; 154 } 155 156 private static class CharacterEncodingFilter implements Filter { 157 protected String encoding; 158 public void init(FilterConfig filterConfig) throws ServletException { 159 encoding = "UTF-8"; 160 } 161 public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 162 HttpServletRequest request = (HttpServletRequest) servletRequest; 163 request.setCharacterEncoding(encoding); 164 filterChain.doFilter(servletRequest, servletResponse); 165 } 166 public void destroy() { encoding = null; } 167 } 168 169 170 @Bean 171 public TomcatEmbeddedServletContainerFactory tomcatFactory() { 172 return new TomcatEmbeddedServletContainerFactory() { 173 @Override 174 protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer( 175 Tomcat tomcat) { 176 tomcat.enableNaming(); 177 return super.getTomcatEmbeddedServletContainer(tomcat); 178 } 179 }; 180 } 181 182 @Bean 183 public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() { 184 return new EmbeddedServletContainerCustomizer() { 185 @Override 186 public void customize(ConfigurableEmbeddedServletContainer container) { 187 if (container instanceof TomcatEmbeddedServletContainerFactory) { 188 TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory = (TomcatEmbeddedServletContainerFactory) container; 189 tomcatEmbeddedServletContainerFactory 190 .addContextCustomizers(new TomcatContextCustomizer() { 191 @Override 192 public void customize(Context context) { 193 194 /** 195 * 196 */ 197 198 StandardManager m = new StandardManager(); 199 m.setPathname(env.getProperty("session.persistence.path")); 200 context.setManager(m); 201 202 } 203 }); 204 } 205 } 206 }; 207 } 208 209 210 // ********************************************************************** 211 // ファイルアップロードダウンロード関連設定 212 // ********************************************************************** 213 @Bean 214 MultipartConfigElement multipartConfigElement() { 215 MultipartConfigFactory factory = new MultipartConfigFactory(); 216 factory.setMaxFileSize("5MB"); 217 factory.setMaxRequestSize("5MB"); 218 return factory.createMultipartConfig(); 219 } 220 221 222} 223
投稿2016/03/11 05:32
総合スコア53
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/03/15 02:12
2016/03/15 02:21
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/03/16 03:58 編集
2016/03/16 05:59
2016/03/16 06:07