解決Spring?MVC中文亂碼的編碼配置
SpringMVC配置編碼方式
SpringMVC的中文亂碼問題其實已經不是什么問題了,無非就是配置編碼方式->解決問題。
但是由于SpringMVC可以通過:xml方式配置、Servlet3.0方式配置,以及是否使用@EnableWebMvc等,不同配置方式下,解決中文亂碼問題的方案有所不同。
xml配置的方式
xml配置方式的解決方案最簡單:
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在web.xml文件中加編碼過濾器,并強制過濾器對Request和Response都生效,可以解決request請求、以及response返回參數(shù)中的中文亂碼問題。
但是返回體,也就是response body中的中文亂碼問題,以上過濾器方案無法解決。
Response body中的中文亂碼問題需要在spring MVC中增加以下配置:
<mvc:annotation-driven > <!--設置響應輸出字符集--> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=utf-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
前面一篇文章[Spring MVC 五:DispatcherServlet初始化之 mvc:annotation-driven] 分析過<mvc:annotation-driven />標簽的解析過程,該標簽在創(chuàng)建RequestMappingHandlerAdapter的過程中,會讀取到xml文件中messageConverters的定義并設置到RequestMappingHandlerAdapter對象的messageConverters屬性中并最終在DispatcherServlet處理請求的過程中生效。
Servlet3.0配置
Servlet3.0的配置方式,是指通過WebApplicationInitializer接口完成SpringMVC配置的方式。
可以通過接口方法getServletFilters增加編碼過濾器:
public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // return null; return new Class[] {RootConfiguration.class}; } @Override protected Class<?>[] getServletConfigClasses() { // return null; return new Class[] {MvcConfiguration.class,CommonConfiguration.class}; } @Override protected String[] getServletMappings() { return new String[] {"/"}; } @Override protected Filter[] getServletFilters() { // ShallowEtagHeaderFilter shallowEtagHeaderFilter = new ShallowEtagHeaderFilter(); // shallowEtagHeaderFilter.setWriteWeakETag(true); CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("utf-8"); characterEncodingFilter.setForceEncoding(true); return new Filter[]{characterEncodingFilter}; } }
以上方式增加過濾器后,可以解決request和response請求及返回參數(shù)中的中文編碼問題。
但是無法解決response body的中文亂碼問題。
由于WebApplicationInitializer接口并沒有提供任何關于messageConverters的接口,看了很多遍源碼也并沒有找到可以配置的地方,網上也沒有找到相關解決方案......所以解決這個問題還是費了很多周折。
由于我們已經知道,response body的中文亂碼問題最終是通過RequestMappingHandlerAdapter對象的messageConverters解決的,所以還是想通過定制化RequestMappingHandlerAdapter的初始化過程、設置其messageConverters的方式解決問題。
如果沒有定制化處理的話,DispatcherServlet在初始化的過程中是在initStrategies方法中創(chuàng)建DispatcherServlet.properties文件中默認的RequestMappingHandlerAdapter,是通過反射機制直接new出來的,最終會調用到RequestMappingHandlerAdapter的默認構造器:
public RequestMappingHandlerAdapter() { this.messageConverters = new ArrayList<>(4); this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); try { this.messageConverters.add(new SourceHttpMessageConverter<>()); } catch (Error err) { // Ignore when no TransformerFactory implementation is available } this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); }
默認構造器會直接new一個StringHttpMessageConverter()加進來,不修改的話StringHttpMessageConverter的默認字符集是ISO_8859_1,一定會出現(xiàn)中文亂碼問題:
public static final Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
所以我們必須找到某種方式可以定制化RequestMappingHandlerAdapter的初始化過程。
繼續(xù)分析源碼:
private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; if (this.detectAllHandlerAdapters) { // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts. Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList<>(matchingBeans.values()); // We keep HandlerAdapters in sorted order. AnnotationAwareOrderComparator.sort(this.handlerAdapters); } } else { try { HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerAdapter later. } } // Ensure we have at least some HandlerAdapters, by registering // default HandlerAdapters if no other adapters are found. if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerAdapters declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } } }
發(fā)現(xiàn)initHandlerAdapters方法首先會從Spring容器中獲取HandlerAdapter!
我們是否有辦法定制一個HandlerAdapter、加入到Spring容器中?Spring當然給我們提供了這種機會,回想一下@Configuration+@Bean注解,是否就可以解決?
在MvcConfig文件中增加如下代碼:
@Configuration @ComponentScan({"org.example.controller"}) public class MvcConfiguration { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } //定制RequestMappingHandlerAdapter @Bean public RequestMappingHandlerAdapter handlerAdapter(){ RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter(); List<HttpMessageConverter<?>> messageConverters; messageConverters = new ArrayList<>(4); messageConverters.add(new ByteArrayHttpMessageConverter()); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); messageConverters.add(stringHttpMessageConverter); try { messageConverters.add(new SourceHttpMessageConverter<>()); } catch (Error err) { // Ignore when no TransformerFactory implementation is available } messageConverters.add(new AllEncompassingFormHttpMessageConverter()); handlerAdapter.setMessageConverters(messageConverters); return handlerAdapter; }
參考RequestMappingHandlerAdapter默認構造器的代碼,修改其中StringHttpMessageConverter的創(chuàng)建過程、設置其默認字符集為UTF-8......驗證后發(fā)現(xiàn),問題已解決!
使用@EnableWebMvc
由于@EnableWebMvc是必須和@configuration配合使用的,所以,一定會存在配置類。這種情況下,配置類實現(xiàn)WebMvcConfigurer、通過擴展extendMessageConverters方法解決:
@Configuration @EnableWebMvc @ComponentScan({"org.example.controller"}) public class MvcConfiguration implements WebMvcConfigurer{ public MvcConfiguration(){ System.out.println("mvc configuration constructor..."); } // 通過@EnableWebMVC配置的時候起作用, @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for(HttpMessageConverter httpMessageConverter:converters){ if(StringHttpMessageConverter.class.isAssignableFrom(httpMessageConverter.getClass())){ ((StringHttpMessageConverter)httpMessageConverter).setDefaultCharset(Charset.forName("UTF-8")); } } } }
以上就是解決Spring MVC中文亂碼的編碼配置的詳細內容,更多關于Spring MVC中文亂碼解決的資料請關注腳本之家其它相關文章!
相關文章
Java之SpringBoot集成ActiveMQ消息中間件案例講解
這篇文章主要介紹了Java之SpringBoot集成ActiveMQ消息中間件案例講解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07Java用BigDecimal類解決Double類型精度丟失的問題
這篇文章主要介紹了Java用BigDecimal類解決Double類型精度丟失的問題,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12SpringBoot+Tess4j實現(xiàn)牛的OCR識別工具的示例代碼
這篇文章主要介紹了SpringBoot+Tess4j實現(xiàn)牛的OCR識別工具的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01java如何根據HttpServletRequest獲取IP地址
文章介紹了幾種代理服務器轉發(fā)服務請求頭的方法,這些請求頭可能包含真實IP地址,但并不是所有的代理都會包括這些請求頭,而且這些IP地址可能被偽造2025-03-03Mybatis代碼生成器Mybatis Generator(MBG)實戰(zhàn)詳解
本文我們主要實戰(zhàn)Mybatis官方的代碼生成器:Mybatis Generator(MBG),掌握它以后,可以簡化大部分手寫代碼,我們只需要寫復雜邏輯代碼,需要的朋友可以參考下2023-05-05