消息转化器的作用:
在springmvc中客户端提交数据到服务器,根据提供的数据和消息转化器可以将数据转换成对象。当服务器向客户端响应数据时也可根据消息转换器将数据转换成定义的格式发送给客户端
首先需要知道
requestHeaders中的Accept是指告诉服务器客户端能够接受的数据类型有哪些,越靠左优先级越高
在springboot的springmvc中已经默认配置了很多消息转换器,包括json数据转换,但默认并没有处理xml的消息转换器。
定义一个接口
@Controller
@RequestMapping("my")
public class Mycontroller {
@ResponseBody
@GetMapping("test")
public User test(){
User user = new User();
user.setId(1);
user.setUsername("张三");
user.setPassword("123");
return user;
}
}
用浏览器测试接口
content-Type就是服务器发送给客户端的数据格式,chrome浏览器支持所有格式的数据。
接下来自定义一种格式,application/my,因为浏览器能接受所有格式数据,并且有优先级显示,所以这里不用浏览器测试,使用测试工具postMan
指定能接收的数据格式只有application/my,由于springmvc中默认的消息转换器无法处理自定义的数据格式application/my。需要我们自定义一个消息转换器并放入spring容器中
扩展springmvc配置,并重写其中的方法。注意重写configureMessageConverters方法会覆盖默认的消息转换器
这里我只是进行扩展,重写extendMessageConverters方法
@Configuration
public class MyMvcConfig implements WebMvcConfigurer
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new myMessageConverter());
}
add方法参数是HttpMessageConverter接口,所以自定义一个实现HttpMessageConverter接口的消息转换器
class myMessageConverter implements HttpMessageConverter<User>{
@Override
public boolean canRead(Class<?> aClass, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class<?> aClass, MediaType mediaType) {
return aClass.isAssignableFrom(User.class);
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/my");
}
@Override
public void write(User user, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
String data=user.getId()+"、"+user.getUsername()+"、"+user.getPassword();
httpOutputMessage.getBody().write(data.getBytes());
}
@Override
public User read(Class<? extends User> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
}
实现其中的五个方法
public boolean canRead(Class<?> aClass, MediaType mediaType)
是否能从客户端接收
public boolean canWrite(Class<?> aClass, MediaType mediaType)
是否能向客户端发送
public List getSupportedMediaTypes()
支持的数据格式
public void write(User user, MediaType mediaType, HttpOutputMessage httpOutputMessage)
向客户端输出数据的格式
public User read(Class<? extends User> aClass, HttpInputMessage httpInputMessage)
从客户端读取数据的格式
在getSupportedMediaTypes中添加了
return MediaType.parseMediaTypes("application/my");
自定义了一种数据格式
并在write方法中自定义了输出数据的形式
String data=user.getId()+"、"+user.getUsername()+"、"+user.getPassword();
httpOutputMessage.getBody().write(data.getBytes());
在postMan中指定Accept为application/my
查看结果
确实是我们自定义的数据形式,以上就是将数据根据自定的消息转换器将消息发送到客户端
从客户端获取并封装信息
同样使用postMan工具
因为要使用消息转换器是从请求体当中获取数据,所以不能使用Get方式提交
按自定义的形式填入数据,并设置请求头Accept为自定义格式application/my告诉服务器我接收的数据格式为application/my,设置Content-Type也为application/my,告诉服务器我发送的数据格式是application/my,服务器就会用我们自定义的消息转换器进行数据转换
当然这里就需要实现消息转换器中的几个相关方法
//能不能将客户端的数据进行转换
public boolean canRead(Class<?> aClass, MediaType mediaType) {
return aClass.isAssignableFrom(User.class);
}
以什么格式进行转换
public User read(Class<? extends User> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
InputStream body = httpInputMessage.getBody();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(body));
StringBuffer data=new StringBuffer();
while((line=reader.readLine())!=null){
data.append(line);
}
log.info("MyMvcConfig--->{}",data);
String[] split = data.toString().split("、");
User user = new User();
user.setId(Integer.valueOf(split[0]));
user.setUsername(split[1]);
user.setPassword(split[2]);
return user;
}
在实现httpMessageConverter接口时需要添加泛型类
泛型为User,当发送的数据格式为自定义的application/my时、服务器向客户端发送的数据为User类型或者服务器将客户端的数据进行封装成User类型就会使用我们自定义的消息转换器进行处理
再定义一个接口
@PostMapping("test2")
@ResponseBody
public User test2(@RequestBody User user){
System.out.println(user);
return user;
}
注意:参数User需要加上@requestBody注解,因为不加此注解的话只能处理默认的Content-Type: application/x-www-form-urlencoded就不能根据其他Content-Type类型进行数据封装,因为在自定义消息转换器时的泛型是User,自定义了一种ContentType,所以一定要加上@RequestBody注解才能正确使用我们自定义的消息转换器进行数据封装
postMan
控制台打印
返回结果
总结
消息转换器的作用有两个
1、将数据指定的contentType发送给客户端
2、服务器接收数据按指定的contentTpe进行封装
在进行数据封装如果不是默认的contentType一定要加上 @requestBody注解
自定义消息转换器需要实现httmessageConverter或者继承自其子类, 并指定泛型,重写其中的几个方法来自定义contentType和数据发送和封装的格式