1、介绍
HttpMessageConver 是SpringBoot中对Http请求数据与返回数据的转换接口,当我们需要定制化数据的转化时,就可以通过实现此接口来达成。
2、使用场景介绍
我们可以举一个例子,如下图:
当我们后台做好统一的API,当面对不同的客户端需要返回不同的格式的数据是,就可以很好的利用此功能定制 HttpMessageConver,从而在改动代码最小的情况下来完成需求。如:
当需要AES加密时,我们可以定制 AesHttpMessageConver,并设置支持的 MediaType为 json/aes,则:
-
当客户端设置的请求头为
Content-type:json/aes时,将会匹配到AesHttpMessageConver,并使用其readInternal方法来处理客户端发送来的数据。 -
当客户端设置的请求头为
Accept:json/aes时,也会匹配到AesHttpMessageConver,并使用其writeInternal来对数据进行处理后返回给客户端。
3、HttpMessageConver使用介绍
在实现的时候,我们主要是继承 AbstractHttpMessageConverter抽象类,其对 HttpMessageConverter接口进行了部分的实现, AbstractHttpMessageConverter抽象类如下所示:
-
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T>{}
当我们继承时,需要指定 T的类型,表明此 MessageConver是对什么类型起效。
在实现类中,也需要调用父类的构造函数,说明此 MessageConverter支持的 MediaType类型,简单实现如下:
-
public JsonMessageConver() {
-
super(MediaType.valueOf("json/aes;charset=UTF-8"));
-
setDefaultCharset(Charset.forName("UTF-8"));
-
}
上述代码主要做了两个动作:
-
设置此
MessageConverter支持的类型为json /aes ;charset =UTF -8 -
设置默认的编码为
UTF-8
还需要实现下面3个抽象方法,如下:
protected abstract boolean supports(Class<?> clazz);
protected abstract T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
protected abstract void writeInternal(T t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
-
protectedabstractbooleansupports(Class<?>clazz);方法主要是进行类型支持的判断,判断类型是否适合此converter处理,支持则返回true,不支持返回false, -
protectedabstractT readInternal(Class<?extendsT>clazz,HttpInputMessageinputMessage)方法是对用户请求的数据请求处理与转换,然后再返回到Controller层。如:
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
String read = IoUtil.read(inputMessage.getBody(), getDefaultCharset());
JSONObject personJson = JSONUtil.parseObj(AESUtils.decryptData(read));
return JSONUtil.toBean(personJson,clazz);
}
方法说明:
-
Class<?extendsObject>clazz:具体应该为Class <? extendsT >clazz,这个与我们实现类设置的类型有关。 -
HttpInputMessageinputMessage: 这个input为用户的请求的信息流,我们可以通过inputMessage.getBody()获取输入流,来获取用户的输入。 -
返回值具体也是为
T,这个也与我们实现类设置的类型有关。
返回值需要一定为
T类型,或者是其子类。
-
protectedabstractvoidwriteInternal(T t,HttpOutputMessageoutputMessage):此方法是对后台返回给客户的数据进行处理,消息是通过输出流的方式返回给客户,实现例子如下:
protected void writeInternal(Object person, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
OutputStreamWriter writer = IoUtil.getWriter(outputMessage.getBody(), getDefaultCharset());
JSONObject jsonObject = JSONUtil.parseObj(person);
writer.write(AESUtils.encryptData(JSONUtil.toJsonStr(jsonObject)));
writer.flush();
writer.close();
}
方法说明:
-
Objectperson:这个参数为后台返回给客户的数据。 -
HttpOutputMessageoutputMessage:这个参数为数据返回的输出流。
因此,我们可以对返回的数据 person进行处理后,通过获取输出流,然后写入,来进行数据的返回。
3、实现AesHttpMessageConver
首先,下面代码展示在没用使用AesHttpMessageConver时,正常的SpringBoot接收与处理代码逻辑。
-
定义一个Person类负责接收Json数据
public class Person {
private String id;
private Integer name;
}
-
定义Controller层,实现数据的接收与返回
@PostMapping(value = "/test")
@ResponseBody
public Person testPerson(@RequestBody Person person) {
return person;
}
上面是一个正常的逻辑,下面,我们需要对接收和返回的数据都进行加密,在很多人一般的做法如下图代码所示:
@PostMapping(value = "/test")
public String testPerson(@RequestParam String key) {
String decryptData = AESUtils.decryptData(key);
Person person = JSONUtil.toBean(decryptData, Person.class);
//person业务处理
return AESUtils.encryptData(JSONUtil.toJsonStr(person));
}
可以看到,上述代码将会比较冗余,我们可以在SpringBoot中使用更优雅的方式来进行处理,即自定义 HttpMessageConver,具体实现如下。
-
第一步,定制实现
AesMessageConver
public class AesMessageConver extends AbstractHttpMessageConverter<Object> {
public AesMessageConver() {
super(MediaType.valueOf("json/aes;charset=UTF-8"));
setDefaultCharset(Charset.forName("UTF-8"));
}
@Override
protected boolean supports(Class<?> aClass) {
return true;
}
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
String read = IoUtil.read(inputMessage.getBody(), getDefaultCharset());
JSONObject personJson = JSONUtil.parseObj(AESUtils.decryptData(read));
return JSONUtil.toBean(personJson,clazz);
}
@Override
protected void writeInternal(Object person, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
OutputStreamWriter writer = IoUtil.getWriter(outputMessage.getBody(), getDefaultCharset());
JSONObject jsonObject = JSONUtil.parseObj(person);
writer.write(AESUtils.encryptData(JSONUtil.toJsonStr(jsonObject)));
writer.flush();
writer.close();
}
}
-
第二步,注册
MessageConver到SpringBoot中
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new AesMessageConver());
}
}
只要通过上述的两个步骤,我们就可以在不改动原有 Controller层的代码情况下,来满足AES加密的需求。