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

本文介绍了解决Spring MVC中@ResponseBody注解导致的中文乱码问题的方法。通过自定义UTF8StringHttpMessageConverter类并配置到Spring中,可以确保通过@ResponseBody返回的数据采用UTF-8编码。

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

 

Spring使用AnnotationMethodHandlerAdapter的handleResponseBody方 法, AnnotationMethodHandlerAdapter使用request header中"Accept"的值和messageConverter支持的MediaType进行匹配,然后会用"Accept"的第一个值写入 response的"Content-Type"。
一般的请求都是通过浏览器进行的,request header中"Accept"的值由浏览器生成。
  

有人跟踪@ResponseBody 的实现类发现其默认的编码是 iso-8859-1,

解决办法,在spring mvc的配置文件中手工配置bean:
<!-- 启动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/html;charset=UTF-8</value>   
                     </list>   
                </property>   
             </bean>   
         </list>   
   </property>  
</bean>  

 

这样通过配置AnnotationMethodHandlerAdaptermessageConverters属性来指定编码。
记住,需要把bean部分加入到<context:component-scan base-package="com.zlscw.mvc" />前面,

这样就可以在jquery中直接调用而不出现乱码了。

 

-------------------------------------------这篇文章说的很到位

近日用Spring3的MVC写东西,深感其之于Webwork/Struts2的便利,但是在通过@ResponseBody这个 annotation输出一个json字符串的时候,发现页面上获得的json字符串中文字符出现了乱码的现象。通过firefox观察返回的字符串,中 文部分全部变成了???????的形式,初步判定是返回时,spring处理@ResponseBody使用了错误的编码。

因为我在web.xml中已经配置了Spring的CharacterEncodingFilter,并且强制将request和response的编码都指定为utf-8,所以出现乱码的原因肯定是在Spring内部某处的逻辑了。

把log4j中关于spring的输出级别调为debug,通过访问出问题的地址,发现Spring在处理@ResponseBody这个 annotation的时 候,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 使用了org.springframework.http.converter.StringHttpMessageConverter进行处理,于是打 开了Spring的源码,看看这个类究竟做了哪些事情。

不看不要紧,一看吓一跳,里面竟然是这样定义其默认编码的: 

1 publicstaticfinalCharset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");

顿时心生N种不爽:堂堂Spring,竟然还在其中用西欧字符集作为其默认编码,坑爹啊!(很多spring的类中,涉及编码的已经都是utf-8 了,比如负责JSON视图的MappingJacksonHttpMessageConverter,就是默认使用UTF-8)。本来想直接修改 spring的源码重新打包一个jar出来,后来看spring的java doc发现,其父类org.springframework.http.converter.AbstractHttpMessageConverter 中的getDefaultContentType方法是可以重写的:

By default, this returns the first element of the supportedMediaTypes property, if any. Can be overridden in subclasses.

心想这下就简单了,你的DEFAULT_CHARSET不是final么?那我自己继承一个出来,按照我的需求定义为utf-8不就得了?代码如下:

01 publicclassUTF8StringHttpMessageConverter extendsStringHttpMessageConverter {
02   
03  privatestaticfinalMediaType utf8 = newMediaType("text""plain",
04  Charset.forName("UTF-8"));
05  privatebooleanwriteAcceptCharset = true;
06   
07  @Override
08  protectedMediaType getDefaultContentType(String dumy) {
09  returnutf8;
10  }
11   
12  protectedList<Charset> getAcceptedCharsets() {
13  returnArrays.asList(utf8.getCharSet());
14  }
15   
16  protectedvoidwriteInternal(String s, HttpOutputMessage outputMessage)
17  throwsIOException {
18  if(this.writeAcceptCharset) {
19  outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
20  }
21  Charset charset = utf8.getCharSet();
22  FileCopyUtils.copy(s, newOutputStreamWriter(outputMessage.getBody(),
23  charset));
24  }
25   
26  publicbooleanisWriteAcceptCharset() {
27  returnwriteAcceptCharset;
28  }
29   
30  publicvoidsetWriteAcceptCharset(booleanwriteAcceptCharset) {
31  this.writeAcceptCharset = writeAcceptCharset;
32  }
33   
34 }

然后,在spring的配置文件中添加如下bean声明,用自己写的类替换掉原有的StringHttpMessageConverter:

1 <beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
2     <propertyname="messageConverters">
3         <list>
4             <beanid="utf8StringHttpMessageConverter"class="xxx.xxx.UTF8StringHttpMessageConverter"/>
5         </list>
6     </property>
7 </bean>

再看通过@ResponseBody返回的json字符串,终于中文都可以正常显示了。

 

-------------------------------------------下面有一些解释

但我们一般会在标注@ResponseBody的方法上返回String或byte[]类型的结果,期望的"Content-Type"的值应为"text/plain"或"application/octet-stream"。
这样导致了浏览器不能正确处理返回的内容。
实际上Spring在用HttpMessageConverter处理的过程中首先会判断response header中有没有写入"Content-Type",如果没有写入的话才会使用request header中"Accept"的第一个值。
但是由于Spring对HttpServletResponse进行了封装,实际上使用的是ServletServerHttpResponse,这个类有一个对真正的HttpServletResponse的引用。
判断response header的过程中使用的是ServletServerHttpResponse的getHeaders()方法,但该方法并没有返回真正的HttpServletResponse中的header。(这应该有问题吧?)
所以我们虽然可以在Controller的方法中加入对HttpServletResponse的引用,然后设置"Content-Type"的值,但是并不会起作用。
来处理@ResponseBody,该类再使用一些HttpMessageConverter来具体处理信息。
Chrome生成的值为application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,**
所以最后写入response中"Content-Type"的值为"application/xml"或"application/x-ms-application"。

 

 -------------------------------------------------其实这个注解完全可以不用, 直接使用response往输出流里面写。

 使用jQuery ajax调用的返回json,中文乱码问题

Jquery :

$.ajax({
    url: '/test/testAction.do?method=test',
    type: 'POST',
    dataType: 'json',
    timeout: 5000,
    async: false,
    error: function(){
     alert('获取数据失败!');
    },
    success: function(json){
     jsObject  = eval_r(json);
    }
  });
  return jsObject;

 

JSONArray json = JSONArray.fromObject(SysList);//SysList是一个List
//  设置response的ContentType解决中文乱码
  response.setContentType("text/html;charset=UTF-8");
  response.getWriter().print(json.toString());
  return null;

### Spring MVC 使用指南与常见问题解决方案 #### 一、Spring MVC 框架简介 Spring MVC 是一种基于 Java 的轻量级 Web 开发框架,它遵循 Model-View-Controller (MVC) 设计模式。其核心组件是一个名为 `DispatcherServlet` 的前端控制器[^2]。 #### 二、Spring MVC 核心概念 1. **DispatcherServlet**: 这是 Spring MVC 中的核心组件,作为前端控制器接收所有的 HTTP 请求并将其分派给合适的处理器[^2]。 2. **HandlerMapping**: 它负责将请求映射到具体的处理器(Controller),通常通过 URL 路径匹配实现[^1]。 3. **Controller**: 控制器负责处理用户的请求逻辑,并返回模型和视图信息[^1]。 4. **ModelAndView**: 封装了模型数据和视图名称的信息,供 DispatcherServlet 渲染最终的页面。 5. **ViewResolver**: 解析视图名称,找到实际的视图资源(如 JSP 页面)[^1]。 --- #### 三、工作流程解析 当客户端发起请求时,Spring MVC 的执行过程如下: 1. 用户发送请求至服务器端; 2. `DispatcherServlet` 接收请求并将请求交给 HandlerMapping 处理; 3. HandlerMapping 查找适合的 Controller 并通知 DispatcherServlet; 4. Controller 执行业务逻辑后返回 ModelAndView 对象; 5. ViewResolver 解析视图名称,定位具体视图文件; 6. 最终由视图渲染结果响应给用户。 --- #### 四、常见注解及其作用 以下是 Spring MVC 中常见的注解及其用途: 1. **@Controller**: - 标记一个类为 Spring MVC 的控制器,使其被 Spring 容器管理。 2. **@RequestMapping**: - 映射特定的 HTTP 请求路径到对应的方法或类上。 3. **@ResponseBody**: - 表明方法返回的内容应直接写入 HTTP 响应体而非跳转到其他视图[^1]。 4. **@RequestParam** 和 **@PathVariable**: - `@RequestParam`: 绑定查询字符串参数或表单字段值到方法参数中。 - `@PathVariable`: 提取 URI 模板变量并注入到方法参数中[^1]。 --- #### 五、解决 POST/GET 请求中文乱码问题 1. **POST 请求**: - 在 web.xml 文件中配置过滤器 `CharacterEncodingFilter` 来设置编码格式为 UTF-8: ```xml <filter> <filter-name>encodingFilter</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> </filter> ``` 2. **GET 请求**: - GET 请求的编码问题可以通过 Tomcat 配置解决,在 server.xml 中修改 Connector 属性添加 `URIEncoding="UTF-8"`[^1]: ```xml <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/> ``` --- #### 六、异常处理机制 Spring MVC 支持全局异常捕获,可通过以下两种方式实现: 1. **@ExceptionHandler 注解**: - 在 Controller 类内部定义带此注解的方法来处理指定类型的异常。 2. **@ControllerAdvice 结合 @ExceptionHandler**: - 创建独立的全局异常处理器类,统一管理不同 Controller 抛出的异常[^1]。 --- #### 七、前后端交互(AJAX) 为了支持 AJAX 请求,可以在 Controller 方法上加上 `@ResponseBody` 或者使用 RESTful API 形式设计接口。例如: ```java @RestController public class AjaxController { @PostMapping("/ajaxExample") public String handleAjax(@RequestBody Map<String, Object> data) { return "Received: " + data; } } ``` --- #### 八、拦截器配置 如果希望拦截某些请求类型(比如仅拦截 GET 请求),可在自定义拦截器中判断当前请求的方式是否满足条件[^1]。示例代码如下: ```java @Component public class CustomInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if ("GET".equalsIgnoreCase(request.getMethod())) { System.out.println("Intercepted a GET request!"); } return true; } // Other methods... } ``` 接着注册该拦截器到配置类中: ```java @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Autowired private CustomInterceptor customInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(customInterceptor).addPathPatterns("/**"); } } ``` --- #### 九、获取 Request 和 Session 数据 在 Controller 方法签名中可以直接声明 HttpServletRequest 或 HttpSession 参数即可获得它们的对象实例。例如: ```java @Controller public class ExampleController { @GetMapping("/example") public String exampleMethod(HttpSession session, HttpServletRequest request) { session.setAttribute("key", "value"); String param = request.getParameter("name"); return "viewName"; } } ``` --- #### 十、批量接收对象属性 对于多个同属某一实体类的参数,推荐采用绑定整个对象的形式简化操作。假设有一个 User 实体类,则可以这样书写: ```java @PostMapping("/saveUser") public String saveUser(User user) { // 自动填充 user 对象中的各个字段 return "redirect:/success"; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值