一、HttpMessageConverter<T>
作用:
它负责将请求信息转换为一个对象(类型为T),将该对象输出为响应信息。
其实:DispatcherServlet默认已经安装了AnnotationMethodHandlerAdapter作为HandlerAdapter组件的实现类,HttpMessageConverter即由AnnotationMethodHandlerAdapter使用,将请求信息转换为对象,或将对象转换为响应信息。
那么问题来了?
问题1:如何使用HttpMessageConverter<T> 将请求信息转化并绑定到处理方法的入参当中呢?
解答:
1.使用@RequestBody/@ResponseBody对处理方法进行标注
2.使用HttpEntity<T>/ResponseEntity<T>作为处理方法的入参或者返回值
问题2:处理方法如何知道请求消息的格式?在处理完成后又是根据什么确定响应消息的格式嗯?
解答:根据请求消息头的”Content-Type“及Accept属性确定。
1.只有当处理器方法使用到 @RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T> 时,SpringMVC才使用注册的HttpMessageConverter 对请求响应消息进行处理。
2.当控制器处理方法使用到 @RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T> 时,Spring 首先根据请求头或响应头的 Accept 属性选择匹配的 HttpMessageConverter, 进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter,
若找不到可用的 HttpMessageConverter 将报错
3.@RequestBody 和 @ResponseBody 不需要成对出现。如果方法入参使用到了@RequestBody,SpringMVC将会选择匹配的HttpMessageConverter 将请求信息转换并绑定到该入参中。如果处理方法标注了@ResponseBody,SpringMVC选择匹配的HttpMessageConverter 将方法返回值转换并输出响应消息。
ResponseEntity< byte[]> re = new ResponseEntity<byte []>(bytes, headers, statusCode);
https://blog.csdn.net/u010834071/article/details/41773371
HttpMessageConverter主要针对那些不会返回view视图的response。其中StringHttpMessageConverter有两个构造函数。当你没有给它指定字符集时,使用默认的ISO-8859-1,这便是造成乱码的一个原因,由于我们经常使用utf-8,所以可以在构造它时指定一下字符集。
引言:如何在SpringMVC中统一对返回的Json进行加密?”。
大部分人的第一反应是通过SpringMVC拦截器(Interceptor
)中的postHandler
方法处理。实际这是行不通的,因为当程序运行到该方法,是在返回数据之后,渲染页面之前,所以这时候HttpServletResponse
中的输出流已经关闭了,自然无法在对返回数据进行处理。
其实这个问题用几行代码就可以搞定,因为SpringMVC提供了非常丰富的扩展支持,无论是之前提到的MethodArgumentResolver
和HandlerMethodReturnValueHandler
,还是接下来要提到的HttpMessageConverter
。
在SpringMVC的 Controller
层经常会用到@RequestBody
和@ResponseBody
,通过这两个注解,可以在Controller
中直接使用Java对象作为请求参数和返回内容,而完成这之间转换作用的便是HttpMessageConverter
。
--------------------- 本文来自 若水三千-LOVE 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/lovesomnus/article/details/73918025?utm_source=copy
@RequestBody作用:
- 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
- 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
- GET、POST方式提时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据 @RequestParam, @ModelAttribute也可以处理,当然 @RequestBody也能处理);
multipart/form-data, 不能处理(即使用 @RequestBody不能处理这种格式的数据);
其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用 @RequestBody来处理); - PUT方式提交时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 必须;
multipart/form-data, 不能处理;
其他格式, 必须;
说明:request的body部分的数据编码格式由header部分的Content-Type指定;
@ResponseBody作用:
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
https://www.cnblogs.com/cuiyf/p/6247862.html
json数据交互
☛ @RequestBody
@RequestBody
注解用于读取 http 请求的内容(字符串),通过 SpringMVC 提供的 HttpMessageConverter 接口将读到的内容转换为 json、xml 等格式的数据并绑定到 controller 方法的参数上。本例子的应用:@RequestBody 注解实现接收 http 请求的 json 数据,将 json 数据转换为 java 对象
List.action?id=1&name=zhangsan&age=12 复制代码
☛ @ResponseBody
作用:该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如:json,xml 等,通过 response 响应给客户端。
本例子的应用:@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端
作者:Jaybo
链接:https://juejin.im/post/5b83c4a151882542f105470e
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
REST支持
除了典型的MVC场景之外,我们还可以使用框架来创建REST Web服务。
简而言之,我们可以接受Resource作为输入,指定POJO作为方法参数,并使用@RequestBody对其进行注释。也可以使用@ResponseBody注释方法本身,以指定其结果必须直接转换为HTTP响应:
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; @ResponseBody @PostMapping("/message") public MyOutputResource sendMessage( @RequestBody MyInputResource inputResource) { return new MyOutputResource("Received: " + inputResource.getRequestMessage()); }
归功于Spring MVC的可扩展性,这也是可行的。
为了将内部DTO编组为REST表示,框架使用HttpMessageConverter基础结构。例如,其中一个实现是MappingJackson2HttpMessageConverter,它可以使用Jackson库将模型对象转换为JSON或从JSON转换。
https://www.zhihu.com/question/38696452
SpringMVC返回JSON
参考:http://blog.icoolxue.com/springmvc-3%E4%BD%BF%E7%94%A8fastjson%E4%BB%A3%E6%9B%BFjackson/
http://my.oschina.net/haopeng/blog/324934
由于SpringMVC默认采用Jackson解析Json,所以首先添加Jackson相关依赖。
<jackson.version>1.8.9</jackson.version>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-lgpl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-lgpl</artifactId>
<version>${jackson.version}</version>
</dependency>
然后进行如下步骤:
1、配置<mvc:annotation-driven/>
启用
2、controller 配置@ResponseBody
. @RequestBody注解的命令对象的转换,Spring会根据相应的HttpMessageConverter进行模型数据(处理方法的返回值)到JSON响应内容的转换。跳过View解析直接输出到客户端。
注意:使用@ResponseBody时不要忘记在@ReuqestMapping的属性中添加headers = "Accept=application/json"
注意:使用@RequestBody不要忘记在@ReuqestMapping的属性中添加headers = "Content-Type=application/json"
原因:当使用@RequestBody和@ResponseBody注解时,RequestMappingHandlerAdapter就使用HttpMessageConverter来进行读取或者写入相应格式的数据。
HttpMessageConverter匹配过程:@RequestBody注解时
: 根据Request对象header部分的Content-Type
类型,逐一匹配合适的HttpMessageConverter来读取数据;@ResponseBody注解时
: 根据Request对象header部分的Accept属性
(逗号分隔),逐一按accept中的类型,去遍历找到能处理的@Controller public class LoginController { @RequestMapping(value="/validataUser.json" headers = "Accept=application/json") @ResponseBody public Map<String,Object> validataUser(@RequestParam String userName){ logger.info(" validata user : {}",userName); Map<String,Object> map = new HashMap<String,Object>(); map.put("code", true); return map; } }
## 使用FastJson替换Jackson
首先别忘了添加Fastjson的包,如果使用Maven,可使用如下设置<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency>
<!-- 启用默认配置 --> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!-- 配置Fastjson支持 --> <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> <!-- 避免IE执行AJAX时,返回JSON出现下载文件 --> <property name="supportedMediaTypes"> <list> <!-- 这里顺序不能反,一定先写text/html,不然ie下出现下载提示 --> <value>text/html;charset=UTF-8</value> <value>application/json</value> </list> </property> <!-- <property name="features"> <list> <value>WriteMapNullValue</value> <value>QuoteFieldNames</value> </list> </property> --> </bean> </mvc:message-converters> </mvc:annotation-driven>
## @RequestBody, @ResponseBody详解
详细介绍下@RequestBody、@ResponseBody的具体用法和使用时机;
@RequestBody
作用:
i) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
ii) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
注意:使用@RequestBody不要忘记在@ReuqestMapping的属性中添加headers = "Content-Type=application/json"
@RequestMapping(value = "/{username}", method = RequestMethod.PUT,
headers = "Content-Type=application/json") // headers = "Content-Type=application/json"
@ResponseStatus(HttpStatus.NO_CONTENT)
public void updateSpitter(@PathVariable String username,
@RequestBody Spitter spitter) { // @RequestBody
spitterService.saveSpitter(spitter);
}
- application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据
@RequestParam, @ModelAttribute
也可以处理,当然@RequestBody也能处理); - multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
- 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
B) PUT方式提交时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 必须;
multipart/form-data, 不能处理;
其他格式, 必须;
说明:request的body部分的数据编码格式由header部分的Content-Type指定;
@ResponseBody
作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机: 返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
注意:使用@ResponseBody时不要忘记在@ReuqestMapping的属性中添加headers = "Accept=application/json"
@RequestMapping(value = "/{username}/spittles",
method = RequestMethod.GET,
headers = "Accept=application/json")//headers = "Accept=application/json"
public @ResponseBody List<Spittle> getSpittlesForSpitter(@PathVariable String username) { //@ResponseBody List<Spittle>
return spitterService.getSpittlesForSpitter(username);
}
HttpMessageConverter
该接口定义了四个方法,分别是读取数据时的 canRead(), read() 和 写入数据时的canWrite(), write()方法。
在使用<mvc:annotation-driven />
标签配置时:
- 1、默认配置了
RequestMappingHandlerAdapter
(注意SpringMVC3.1之后是RequestMappingHandlerAdapter不是AnnotationMethodHandlerAdapter,详情查看Spring 3.1 document “16.14 Configuring Spring MVC”章节), - 2、并为他配置了一下默认的
HttpMessageConverter
:
ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;StringHttpMessageConverter
: 负责读取字符串格式的数据和写出二进制格式的数据;
ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;FormHttpMessageConverter
: 负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
MappingJacksonHttpMessageConverter
: 负责读取和写入json格式的数据;
SouceHttpMessageConverter: 负责读取和写入 xml 中javax.xml.transform.Source定义的数据;
Jaxb2RootElementHttpMessageConverter: 负责读取和写入xml 标签格式的数据;
AtomFeedHttpMessageConverter: 负责读取和写入Atom格式的数据;
RssChannelHttpMessageConverter: 负责读取和写入RSS格式的数据;
当使用@RequestBody和@ResponseBody注解时,RequestMappingHandlerAdapter就使用它们来进行读取或者写入相应格式的数据。
HttpMessageConverter匹配过程:@RequestBody注解时
: 根据Request对象header部分的Content-Type
类型,逐一匹配合适的HttpMessageConverter来读取数据;@ResponseBody注解时
: 根据Request对象header部分的Accept属性
(逗号分隔),逐一按accept中的类型,去遍历找到能处理的
关于直接返回json格式字符串的注意:
MappingJacksonHttpMessageConverter 调用了 objectMapper.writeValue(OutputStream stream, Object)方法,使用@ResponseBody注解返回的对象就传入Object参数内。
方式一、若返回的对象为已经格式化好的json串时,不使用@ResponseBody注解,而应该这样处理:
''1、response.setContentType("application/json; charset=UTF-8");
2、response.getWriter().print(jsonStr);''
直接输出到body区,然后的视图为void。
方式二、不过也可以使用@ResponseBody,不过需要进行乱码配置:
直接返回字符串,使用@ResponseBody注解时,后台会调用StringHttpMessageConverter
,它默认的字符集为ISO-8859-1,这会导致中文乱码。可以参考[[spring:springmvc_json乱码]]进行配置即可。
参考:
http://blog.csdn.net/kobejayandy/article/details/12690555
http://www.xby1993.net/pages/dokuwiki/spring/springmvc%E8%BF%94%E5%9B%9Ejson.html