`
1enny
  • 浏览: 70227 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

 
阅读更多

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

(2012-11-16 21:03:03)
标签:

it

分类:spring

Ajax响应中文乱码 [SpringMVC使用@ResponseBody处理Ajax请求]

Spring3.0 MVC @ResponseBody 的作用是把返回值直接写到HTTP response body里。

Spring使用AnnotationMethodHandlerA<wbr>dapter的handleResponseBody方法, AnnotationMethodHandlerA<wbr>dapter使用request header中"Accept"的值和messageConverter支持的MediaType进行匹配,然后会用"Accept"的第一个值写入response的"Content-Type"。一般的请求都是通过浏览器进行的,request header中"Accept"的值由浏览器生成。 <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 有人跟踪<strong>@ResponseBody</strong>的实现类发现其默认的编码是<strong>iso-8859-1</strong>,</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> <strong>解决办法,在spring mvc的配置文件中手工配置bean:<br></strong>&lt;!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --&gt;<br> &lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerA<wbr>dapter" &gt;<br> &lt;property name="messageConverters"&gt;<br> &lt;list&gt;<br> &lt;bean class = "org.springframework.http.converter.StringHttpMessageConvert<wbr>er"&gt;<br> &lt;property name = "supportedMediaTypes"&gt;<br> &lt;list&gt;<br> &lt;value&gt;text/html;charset=UTF-8&lt;/value&gt;<br> &lt;/list&gt;<br> &lt;/property&gt;<br> &lt;/bean&gt;<br> &lt;/list&gt;<br> &lt;/property&gt;<br> &lt;/bean&gt;<br></wbr></wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 这样通过配置<strong>AnnotationMethodHandlerA<wbr>dapter</wbr></strong>类messageConverters属性来指定编码。<br> 记住,需要把bean部分加入到&lt;context:component-scan base-package="com.zlscw.mvc"/&gt;前面,</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 这样就可以在jquery中直接调用而不出现乱码了。</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> -------------------------------------------这篇文章说的很到位</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 近日用Spring3的MVC写东西,深感其之于Webwork/Struts2的便利,但是在通过@ResponseBody这个annotation输出一个json字符串的时候,发现页面上获得的json字符串中文字符出现了乱码的现象。通过firefox观察返回的字符串,中文部分全部变成了???????的形式,初步判定是返回时,spring处理@ResponseBody使用了错误的编码。</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 因为我在web.xml中已经配置了Spring的CharacterEncodingFilter,并且强制将request和response的编码都指定为utf-8,所以出现乱码的原因肯定是在Spring内部某处的逻辑了。</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 把log4j中关于spring的输出级别调为debug,通过访问出问题的地址,发现Spring在处理@ResponseBody这个annotation的时候,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerA<wbr>dapter使用了org.springframework.http.converter.StringHttpMessageConvert<wbr>er进行处理,于是打开了Spring的源码,看看这个类究竟做了哪些事情。</wbr></wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 不看不要紧,一看吓一跳,里面竟然是这样定义其默认编码的:</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 1<strong>publicstaticfinal</strong>Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 顿时心生N种不爽:堂堂Spring,竟然还在其中用西欧字符集作为其默认编码,坑爹啊!(很多spring的类中,涉及编码的已经都是utf-8了,比如负责JSON视图的MappingJacksonHttpMessag<wbr>eConverter,就是默认使用UTF-8)。本来想直接修改spring的源码重新打包一个jar出来,后来看spring的java doc发现,其父类org.springframework.http.converter.AbstractHttpMessageConve<wbr>rter中的getDefaultContentType方法是可以重写的:</wbr></wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> By default, this returns the first element of the supportedMediaTypes property, if any. Can be overridden in subclasses.</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 心想这下就简单了,你的DEFAULT_CHARSET不是final么?那我自己继承一个出来,按照我的需求定义为utf-8不就得了?代码如下:</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 01<strong>publicclass</strong>UTF8StringHttpMessageCon<wbr>verter<strong>extends</strong>StringHttpMessageConvert<wbr>er { 02 03<strong>privatestaticfinal</strong>MediaType utf8 =<strong>new</strong>MediaType("text", "plain", 04 Charset.forName("UTF-8")); 05<strong>privateboolean</strong>writeAcceptCharset =<strong>true</strong>; 06 07 @Override08<strong>protected</strong>MediaType getDefaultContentType(String dumy) { 09<strong>return</strong>utf8; 10 } 11 12<strong>protected</strong>List getAcceptedCharsets() { 13<strong>return</strong>Arrays.asList(utf8.getCharSet()); 14 } 15 16<strong>protectedvoid</strong>writeInternal(String s, HttpOutputMessage outputMessage) 17<strong>throws</strong>IOException { 18<strong>if</strong>(<strong>this</strong>.writeAcceptCharset) { 19 outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets()); 20 } 21 Charset charset = utf8.getCharSet(); 22 FileCopyUtils.copy(s,<strong>new</strong>OutputStreamWriter(outputMessage.getBody(), 23 charset)); 24 } 25 26<strong>publicboolean</strong>isWriteAcceptCharset() { 27<strong>return</strong>writeAcceptCharset; 28 } 29 30<strong>publicvoid</strong>setWriteAcceptCharset(<strong>boolean</strong>writeAcceptCharset) { 31<strong>this</strong>.writeAcceptCharset = writeAcceptCharset; 32 } 33 34}</wbr></wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 然后,在spring的配置文件中添加如下bean声明,用自己写的类替换掉原有的StringHttpMessageConvert<wbr>er:</wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 1<em>"org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerA<wbr>dapter"</wbr></em>&gt; 2<em>"messageConverters"</em>&gt; 3 4<em>"utf8StringHttpMessageCon<wbr>verter"</wbr></em>class=<em>"xxx.xxx.UTF8StringHttpMessageCon<wbr>verter"</wbr></em>/&gt; 5 6 7</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 再看通过@ResponseBody返回的json字符串,终于中文都可以正常显示了。</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> -------------------------------------------下面有一些解释</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 但我们一般会在标注@ResponseBody的方法上返回String或byte[]类型的结果,期望的"Content-Type"的值应为"text/plain"或"application/octet-stream"。<br> 这样导致了浏览器不能正确处理返回的内容。<br> 实际上Spring在用HttpMessageConverter处理的过程中首先会判断response header中有没有写入"Content-Type",如果没有写入的话才会使用request header中"Accept"的第一个值。<br> 但是由于Spring对HttpServletResponse进行了封装,实际上使用的是ServletServerHttpRespons<wbr>e,这个类有一个对真正的HttpServletResponse的引用。<br> 判断response header的过程中使用的是ServletServerHttpRespons<wbr>e的getHeaders()方法,但该方法并没有返回真正的HttpServletResponse中的header。(这应该有问题吧?)<br> 所以我们虽然可以在Controller的方法中加入对HttpServletResponse的引用,然后设置"Content-Type"的值,但是并不会起作用。<br> 来处理@ResponseBody,该类再使用一些HttpMessageConverter来具体处理信息。<br> Chrome生成的值为application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,**<br> 所以最后写入response中"Content-Type"的值为"application/xml"或"application/x-ms-application"。</wbr></wbr></p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> -------------------------------------------------其实这个注解完全可以不用,直接使用response往输出流里面写。</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> 使用jQuery ajax调用的返回json,中文乱码问题</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> Jquery :</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> $.ajax({<br> url: '/test/testAction.do?method=test',<br> type: 'POST',<br> dataType: 'json',<br> timeout: 5000,<br> async: false,<br> error: function(){<br> alert('获取数据失败!');<br> },<br> success: function(json){<br> jsObject = eval_r(json);<br> }<br> });<br> return jsObject;</p> <p style="margin-top:0px; margin-bottom:5px; padding-top:0px; padding-bottom:0px; border:0px; list-style:none; word-wrap:normal; word-break:normal"> JSONArray json = JSONArray.fromObject(SysList);//SysList是一个List<br> // 设置response的ContentType解决中文乱码<br> response.setContentType("text/html;charset=UTF-8");<br> response.getWriter().print(json.toString());<br> return null;</p> </wbr></wbr>
分享到:
评论

相关推荐

    org.springframework.web.servlet-3.0.5.RELEASE.jar

    spring mvc 开发的必须有的架包org.springframework.web.servlet-3.0.5.RELEASE.jar

    springweb3.0MVC注解(附实例)

    &lt;bean class="org.springframework.web.servlet.mvc.annotation. AnnotationMethodHandlerAdapter"/&gt; &lt;!-- ③:对模型视图名称的解析,即在模型视图名称添加前后缀 --&gt; class="org.springframework.web....

    springMVC3使用@ResponseBody向浏览器返回 json,注意区分jar包前缀

    &lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt; &lt;property name="messageConverters"&gt; &lt;list&gt; &lt;!-- Support JSON --&gt; &lt;bean class="org.spring...

    springweb-Jackson

    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt; class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /&gt; ...

    spring_MVC源码

    14. &lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /&gt; 15. 16. &lt;!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 --&gt; 17. &lt;bean class="org....

    springjdbc

    &lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /&gt; &lt;!-- apache.dbcp连接池的配置 --&gt; &lt;bean id="dataSource" class="org.apache.commons.dbcp....

    apache-tomcat-7.0.69.zip

    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689) at org.springframework.web.servlet.mvc.method....

    springmvc的一个简单实例

    import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class HelloController { @RequestMapping("/Login.jsp") public ...

    SpringMVC-SSH全注解

    import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.org.core.entity.User; import com.org.core.service.UserService; import ...

    SpringMVC+Hibernate全注解整合

    &lt;bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /&gt; ...

    Spring.MVC.A.Tutorial.2nd.Edition.1771970316

    This is a tutorial on Spring MVC, a module in the Spring Framework for rapidly developing web applications. The MVC in Spring MVC stands for Model-View-Controller, a design pattern widely used in ...

    SpringMVC+Hibernate实例

    &lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt; ...

    Spring3中配置DBCP,C3P0,Proxool,Bonecp数据源

    &lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; &lt;property name="prefix" value="/WEB-INF/views/"/&gt; &lt;property name="suffix" value=".jsp"/&gt; ...

    基于MyEclipse搭建maven+springmvc整合图文教程(含源码0

    import org.springframework.web.bind.annotation.RequestMapping; @Controller public class GeneralController { @RequestMapping(value="index.do") public void index_jsp(Model model){ model....

    spring-framework-reference-4.1.2

    3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................

    spring applicationContext 配置文件

    &lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:order="0"&gt; &lt;property name="interceptors"&gt; &lt;list&gt; &lt;ref bean="doubleSubmitInterceptor"/&gt; &lt;/list&gt; ...

    spring-framework-reference4.1.4

    3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................

    spring-boot-reference.pdf

    27.1. The “Spring Web MVC Framework” 27.1.1. Spring MVC Auto-configuration 27.1.2. HttpMessageConverters 27.1.3. Custom JSON Serializers and Deserializers 27.1.4. MessageCodesResolver 27.1.5. Static...

    iLink:拉丁云代码测试Spring MVC

    1.项目管理和综合工具:maven(1)Maven安装和配置:参考(2)Eclipse和IDEA配置Maven2.Spring版本:5.0.73.MVC:Spring MVC配置(1)jar包:spring-webmvc.jar(2)web.xml配置SpringMVC监听类:org.springframework.web....

Global site tag (gtag.js) - Google Analytics