最近在项目重构中,把原来项目中的Struts2换成了spring3.0的MVC,个人感觉Spring3 mvc比struts2开发方便多了。尤其它的RESTFUL URL。更多关于Spring3 mvc的资料网上也是一大堆,这里就不一一介绍了。
写此文的目的是记录一下自己解决Spring3.0 MVC @ResponseBody中文乱码问题。
Spring3.0 MVC @ResponseBody 的作用是把返回值直接写到HTTP response body里。具体实现AnnotationMethodHandlerAdapter类handleResponseBody方法,具体实现代码:
private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) throws ServletException, IOException { HttpInputMessage inputMessage = new ServletServerHttpRequest(webRequest.getRequest()); List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept(); if (acceptedMediaTypes.isEmpty()) { acceptedMediaTypes = Collections.singletonList(MediaType.ALL); } HttpOutputMessage outputMessage = new ServletServerHttpResponse(webRequest.getResponse()); Class<?> returnValueType = returnValue.getClass(); List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); if (messageConverters != null) { for (HttpMessageConverter messageConverter : messageConverters) { allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); for (MediaType acceptedMediaType : acceptedMediaTypes) { if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { messageConverter.write(returnValue, null, outputMessage); this.responseArgumentUsed = true; return; } } } } throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); } }
OK,了解了@ResponseBody 的实现,我们回到乱码问题上。
根据Spring3 MVC的最小配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 把标记了@Controller注解的类转换为bean --> <context:component-scan base-package="com.acity.**.web"/> <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" > </bean> <!--对模型视图名称的解析,即在模型视图名称添加前后缀 --> <bean id="defaultviewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/admin/" p:suffix=".jsp" /> </beans>
客户端使用JQuery AJAX方法发起请求:
$.ajax({ type:"POST", url:"/admin.jspx, dataType:String, data:new goodsparameter(), success:function(data){ $("#flitercontent").htm(data); } } });
结果输出乱码:???????
debug 跟踪@ResponseBody 的实现类发现其默认的编码是 iso-8859-1,见图片黄色部分
了解了其乱码原理我们来解决它。
springMVC 配置文件更改为:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 把标记了@Controller注解的类转换为bean --> <context:component-scan base-package="com.acity.**.web"/> <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" > <property name="messageConverters"> <list> <bean class = "org.springframework.http.converter.StringHttpMessageConverter"> <property name = "supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> </list> </property> </bean> <!--对模型视图名称的解析,即在模型视图名称添加前后缀 --> <bean id="defaultviewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/admin/" p:suffix=".jsp" /> </beans>
这样通过配置AnnotationMethodHandlerAdapter类messageConverters属性来指定编码。
貌似可以解决问题了,但其实不然。运行发现,AJAX都没有数据返回。拿谷歌浏览器调试发现:
Failed to load resource: the server responded with a status of 406 (Not Acceptable)
继续Debug发现handleResponseBody方法抛出的此异常。由于客户端请求的MediaType类型默认是:*/*
所以只要我们在客户端设置MIME类型,问题就可以解决。
解决方法利用JQuery AJAX提供的beforeSend方法,设置其请求接受的类型,如下:
beforeSend: function(XMLHttpRequest){ XMLHttpRequest.setRequestHeader("Accept", "text/plain"); }
这样问题就解决了。
这是小弟的解决方法,不知大侠们有没有好的解决方法,欢迎赐教。