解決Spring?MVC中文亂碼的編碼配置
SpringMVC配置編碼方式
SpringMVC的中文亂碼問題其實(shí)已經(jīng)不是什么問題了,無非就是配置編碼方式->解決問題。
但是由于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文件中加編碼過濾器,并強(qiáng)制過濾器對(duì)Request和Response都生效,可以解決request請(qǐng)求、以及response返回參數(shù)中的中文亂碼問題。
但是返回體,也就是response body中的中文亂碼問題,以上過濾器方案無法解決。
Response body中的中文亂碼問題需要在spring MVC中增加以下配置:
<mvc:annotation-driven >
<!--設(shè)置響應(yīng)輸出字符集-->
<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 />標(biāo)簽的解析過程,該標(biāo)簽在創(chuàng)建RequestMappingHandlerAdapter的過程中,會(huì)讀取到xml文件中messageConverters的定義并設(shè)置到RequestMappingHandlerAdapter對(duì)象的messageConverters屬性中并最終在DispatcherServlet處理請(qǐng)求的過程中生效。
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請(qǐng)求及返回參數(shù)中的中文編碼問題。
但是無法解決response body的中文亂碼問題。
由于WebApplicationInitializer接口并沒有提供任何關(guān)于messageConverters的接口,看了很多遍源碼也并沒有找到可以配置的地方,網(wǎng)上也沒有找到相關(guān)解決方案......所以解決這個(gè)問題還是費(fèi)了很多周折。
由于我們已經(jīng)知道,response body的中文亂碼問題最終是通過RequestMappingHandlerAdapter對(duì)象的messageConverters解決的,所以還是想通過定制化RequestMappingHandlerAdapter的初始化過程、設(shè)置其messageConverters的方式解決問題。
如果沒有定制化處理的話,DispatcherServlet在初始化的過程中是在initStrategies方法中創(chuàng)建DispatcherServlet.properties文件中默認(rèn)的RequestMappingHandlerAdapter,是通過反射機(jī)制直接new出來的,最終會(huì)調(diào)用到RequestMappingHandlerAdapter的默認(rèn)構(gòu)造器:
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());
}默認(rèn)構(gòu)造器會(huì)直接new一個(gè)StringHttpMessageConverter()加進(jìn)來,不修改的話StringHttpMessageConverter的默認(rèn)字符集是ISO_8859_1,一定會(huì)出現(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方法首先會(huì)從Spring容器中獲取HandlerAdapter!
我們是否有辦法定制一個(gè)HandlerAdapter、加入到Spring容器中?Spring當(dāng)然給我們提供了這種機(jī)會(huì),回想一下@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默認(rèn)構(gòu)造器的代碼,修改其中StringHttpMessageConverter的創(chuàng)建過程、設(shè)置其默認(rèn)字符集為UTF-8......驗(yàn)證后發(fā)現(xiàn),問題已解決!
使用@EnableWebMvc
由于@EnableWebMvc是必須和@configuration配合使用的,所以,一定會(huì)存在配置類。這種情況下,配置類實(shí)現(xiàn)WebMvcConfigurer、通過擴(kuò)展extendMessageConverters方法解決:
@Configuration
@EnableWebMvc
@ComponentScan({"org.example.controller"})
public class MvcConfiguration implements WebMvcConfigurer{
public MvcConfiguration(){
System.out.println("mvc configuration constructor...");
}
// 通過@EnableWebMVC配置的時(shí)候起作用,
@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中文亂碼的編碼配置的詳細(xì)內(nèi)容,更多關(guān)于Spring MVC中文亂碼解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java使用正則表達(dá)式截取重復(fù)出現(xiàn)的XML字符串功能示例
這篇文章主要介紹了Java使用正則表達(dá)式截取重復(fù)出現(xiàn)的XML字符串功能,涉及java針對(duì)xml字符串及指定格式字符串的正則匹配相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
解決Eclipse發(fā)布到Tomcat丟失依賴jar包的問題
這篇文章介紹了如何在Eclipse中配置部署裝配功能,以確保在將Web項(xiàng)目發(fā)布到Tomcat服務(wù)器時(shí)不會(huì)丟失任何依賴jar包,通過手動(dòng)配置或使用構(gòu)建工具腳本,可以自動(dòng)化這個(gè)過程,提高開發(fā)效率和應(yīng)用程序的穩(wěn)定性,感興趣的朋友跟隨小編一起看看吧2025-01-01
java實(shí)現(xiàn)稀疏矩陣的壓縮與解壓的方法
這篇文章主要介紹了java實(shí)現(xiàn)稀疏矩陣的壓縮與解壓 ,把該稀疏矩陣壓縮以三元組形式表示并以文件形式保存,再寫另一個(gè)程序讀取文件中的信息把壓縮后的三元組還原成原來的稀疏矩陣,需要的朋友可以參考下2022-03-03
Guava是Google發(fā)布的一個(gè)開源庫,主要提供了一些在Java開發(fā)中非常有用的工具類和API,不管是工作還是學(xué)習(xí)都是非常值得我們?nèi)ナ煜さ?,一起來看看?/div> 2023-03-03
Spring Boot Jar 包部署腳本的實(shí)例講解
在本篇文章里小編給大家整理的是一篇關(guān)于Spring Boot Jar 包部署腳本的實(shí)例講解內(nèi)容,對(duì)此有興趣的朋友們可以跟著學(xué)習(xí)下。2021-12-12
spring?boot集成jasypt?并實(shí)現(xiàn)自定義加解密的詳細(xì)步驟
由于項(xiàng)目中的配置文件?配置的地方過多,現(xiàn)將配置文件統(tǒng)一放到nacos上集中管理?且密碼使用加密的方式放在配置文件中,配置文件的加密使用加密庫jasypt,本文給大家介紹spring boot集成jasypt并實(shí)現(xiàn)自定義加解密,感興趣的朋友一起看看吧2023-08-08
Java實(shí)現(xiàn)PDF轉(zhuǎn)為Word文檔的示例代碼
眾所周知,PDF文檔除了具有較強(qiáng)穩(wěn)定性和兼容性外,?還具有較強(qiáng)的安全性,在工作中可以有效避免別人無意中對(duì)文檔內(nèi)容進(jìn)行修改。本文將分為以下兩部分介紹如何在保持布局的情況下將PDF轉(zhuǎn)為Word文檔,希望對(duì)大家有所幫助2023-01-01最新評(píng)論

