SpringMVC自定义消息转换器的使用其实很简单
作者:kusedexingfu
在我们的日常开发中,作为服务端,接收的数据是加密的字符串。我们可能会在Controller中获取到加密的字符串,然后手动解密,类似于如下做法(用base64做样例):
@PostMapping public void base64Post(String base64Param) throws UnsupportedEncodingException { String jsonStr = new String(Base64.getDecoder().decode(base64Param), "UTF-8"); }
其实通过SpringMVC的消息转换器HttpMessageConverter可以统一的处理这种问题。
下面就来介绍下实现方式吧。
什么是消息转换器
在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,这种灵活的消息转换机制就是利用HttpMessageConverter来实现的,Spring内置了很多HttpMessageConverter,比如MappingJackson2HttpMessageConverter,StringHttpMessageConverter等,下面我们来自定义自己的消息转换器来满足上面的需求
自定义消息转换器
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.util.StreamUtils; import java.io.IOException; import java.nio.charset.Charset; import java.util.Base64; /** * 针对Object的base64消息处理器 */ public class Base64ObjMessageConverter extends AbstractHttpMessageConverter<Object> { public Base64ObjMessageConverter() { // 新建一个我们自定义的媒体类型application/base64obj super(new MediaType("application", "base64obj", Charset.forName("UTF-8"))); } @Override protected boolean supports(Class<?> clazz) { return true; } @Override protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { String source = new String(Base64.getDecoder().decode(StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8"))), "UTF-8"); return new ObjectMapper().readValue(source, clazz); } @Override protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { byte[] encode = Base64.getEncoder().encode(new ObjectMapper().writeValueAsString(obj).getBytes()); outputMessage.getBody().write(encode); } }
如上,我们继承了泛型类AbstractHttpMessageConverter,并重写了它的几个方法。
supports
:设置处理哪些类。readInternal
:处理输入内容,即处理请求值。writeInternal
:处理输出内容,即处理返回值。
构造方法定义了要处理的MediaType,这里我定义的是application/base64obj;charset=utf-8,接下来在Controller中也要用到这个MediaType
上面我自定义的消息转换器处理的是Object类型,你也可以指定泛型为特定的类型,只处理该种类型的数据。
将自定义的消息转换器加入到springmvc容器中
这里采用配置类的形式
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration public class MessageConverterConfig implements WebMvcConfigurer { @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(base64ObjMessageConverter()); } @Bean public Base64ObjMessageConverter base64ObjMessageConverter() { return new Base64ObjMessageConverter(); } }
Controller代码
@PostMapping(value = "base64obj", consumes = "application/base64obj;charset=utf-8",produces = "application/base64obj;charset=utf-8") public User base64obj(@RequestBody User user) { System.out.println(user); return user; }
我们可以通过设置consumes和produces来让springmvc采用不同的消息转换器处理我们的请求。
我们的测试代码设置的@PostMapping的属性consumers和produces都为我们的自定义的消息处理器要处理的类型application/base64obj;charset=utf-8。
即请求和返回都需要经过自定义消息处理器Base64ObjMessageConverter的处理。
注意:
- 我们可以将consumers和produces设置为不同的MediaType来让不同的消息转换器来处理,但是开发中一般不会这么做。
- 比如输入的格式是XML,返回的格式确实JSON,这样做是很逆天的。
- consumers和produces一般都会采用相同的MediaType。
PostMan请求测试
我们将json字符串 {"id":1,"name":"name","sex":"男"} 转为base64字符串:eyJpZCI6MSwibmFtZSI6Im5hbWUiLCJzZXgiOiLnlLcifQ==
用postma请求,设置Content-Type为我们自定义的application/base64obj;charset=utf-8
设置请求体,发送请求,结果能响应
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。