简介
我们使用**@RequestBody可以将请求体中的JSON字符串绑定到相应的bean,使用@ResponseBody**可以使返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中,而整个数据绑定的过程其实是HttpMessageConverter在起作用。
MediaType
MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。
@RequestBody的简单实用
@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。
1、解析json
1
|
Content-Type: application/json |
请求数据格式
1
2
3
4
|
{ "question" : "aaa" , "fromUser" : "bbb" } |
2、解析xml
1
|
Content-Type: application/xml |
请求数据格式
1
2
3
4
5
|
<? xml version = '1.0' encoding = "utf-8" ?> < Request > < question >aaa</ question > < fromUser >bbb</ fromUser > </ Request > |
上面两种方式都是可以把数据映射到Bean中的。
3、原理
Spring会根据MediaType查找合适的HttpMessageConverter的实现类进行序列化的操作
1
2
3
4
5
6
7
8
9
|
public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, MediaType mediaType); boolean canWrite(Class<?> clazz, MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; } |
方法 | 作用 |
---|---|
getSupportedMediaTypes | 获取支持的MediaType |
read | 读取request的body |
write | 把数据写到response的body中 |
@ResponseBody
ResponseBody中的使用和RequestBody类似
自定义HttpMessageConverter
1、目的
SpringBoot提供一系列的HttpMessageConverter,满足了我们的绝大部分需求,如果有特性需求,我们可以编写自定义的转换器
2、步骤
编写Converter类,需要实现HttpMessageConverter,或者继承已经存在的实现类,并重写上文中的关键方法
编写WebConfig(extends WebMvcConfigurerAdapter)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { /** * 自定义message_convert */ @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // 把converter添加到converters的最后(SpringBoot会使用第一个匹配到的Converter) converters.add( new XxxConverter()); // 把converter添加到converters的最前面 // converters.add(0, new XxxConverter()); } } |
到此为止,我们自定义的Converter已经生效了
3、自定义MediaType
虽然我们已经编写Converter,但是我们一般会为自定义的Converter指定可以处理的媒体类型,可以指定自定义的媒体类型
在自定义的Converter中新增自定义的MediaType,并且根据需要修改canRead,canWrite;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class XxxConverter implements HttpMessageConverter<Serializable> { public static final String CUSTOM_MEDIA = "application/custom-media" ; @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { return true ; } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return true ; } @Override public List<MediaType> getSupportedMediaTypes() { return Lists.newArrayList(MediaType.parseMediaType(CUSTOM_MEDIA)); } @Override public Serializable read(Class<? extends Serializable> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return null ; } @Override public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { } } |
这里一定要修改getSupportedMediaTypes方法,SpringBoot是根据这个方法的返回,以及Controller—@RequestMapping中指定的MediaType,判断是否可用于当前请求/返回。
在Controller的@RequestMapping中指定consumes或者produces
1
2
3
4
5
6
7
8
9
|
@RestController @RequestMapping (produces = CUSTOM_MEDIA, consumes = CUSTOM_MEDIA) @Validated public class HomeController { @GetMapping (HOME) JsonResult info( @RequestHeader ( "userId" ) Long userId) { return JsonResult.ok(); } } |
consumes是指定请求的MediaType,需要调用方设置成我们提供的application/custom-media
produces是指定返回的MediaType,如果我们设置成application/custom-media,那么方法返回的数据就会通过自定义的XxxConverter进行转换。
问题
注意:如果我们修改了produces的MediaType,那么HTTP返回中的MediaType也会是我们自定义的类型,除非和调用方约定好,否则调用方是没有办法解析的。
解决办法:
1
2
3
4
5
6
7
8
9
|
public class XxxConverter implements HttpMessageConverter<Serializable> { ...... @Override public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // 最后把Content-Type改成APPLICATION_JSON_UTF8_VALUE,要不然请求方会无法解析 ((ServletServerHttpResponse) outputMessage) .getServletResponse().setHeader( "Content-Type" ,APPLICATION_JSON_UTF8_VALUE); } } |
总结
一般情况下,SpringBoot提供的默认转换器已经足够我们使用,但是在一些接口的参数需要加解密,调整返回体的结构等情况下会用到。以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/weixin_29491885/article/details/100576881