摘要:大部分人的第一反应是通过 Spring 拦截器(Interceptor)中的postHandler方法处理。实际这是行不通的,因为当程序运行到该方法,是在返回数据之后,渲染页面之前,所以这时候 Response 中的输出流已经关闭了,自然无法在对返回数据进行处理。

其实这个问题用几行代码就可以搞定,因为 Spring 提供了非常丰富的扩展支持,无论是之前提到的Interceptor和MethodArgumentResolver,还是接下来要提到的HttpMessageConverter。

这里你要明白一个原理:在 Spring MVC 的 Controller 层经常会用到@RequestBody和@ResponseBody,通过这两个注解,可以在 Controller 中直接使用 Java 对象作为请求参数和返回内容,而完成这之间转换作用的便是HttpMessageConverter。

HttpMessageConverter接口提供了 5 个方法:
1. canRead:判断该转换器是否能将请求内容转换成 Java 对象
2. canWrite:判断该转换器是否可以将 Java 对象转换成返回内容
3. getSupportedMediaTypes:获得该转换器支持的 MediaType 类型
4. read:读取请求内容并转换成 Java 对象
5. write:将 Java 对象转换后写入返回内容

其中read和write方法的参数分别有有HttpInputMessage和HttpOutputMessage对象,这两个对象分别代表着一次 Http 通讯中的请求和响应部分,可以通过getBody方法获得对应的输入流和输出流。

具体步骤:这里使用的springBoot的方法进行配置

首先继承 MappingJackson2HttpMessageConverter 并重写 writeInternal 和 read 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

/**
* @author lyc
* @Description: https://www.cnblogs.com/cnndevelop/p/7244686.html介绍
* @create 2019-01-02
*/
@Component
public class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {

Logger logger = LoggerFactory.getLogger(getClass());

/**
* 接受参数解密
* @param type
* @param contextClass
* @param inputMessage
* @return
* @throws IOException
* @throws HttpMessageNotReadableException
*/
@Override
public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
JavaType javaType = this.getJavaType(type, contextClass);

InputStream is = inputMessage.getBody();

ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[4096];
int n = 0;
while ((n = is.read(b)) > 0) {
out.write(b, 0, n);
}

//解密 解密 plainBody是未解密的参数串
String plainBody = out.toString();
logger.info("现在的参数是:"+plainBody);
String newParams = RSAUtils.decryptDataOnJava(plainBody, RsaConstant.privateKey);//私钥解密

try {
return this.objectMapper.readValue(new ByteArrayInputStream(newParams.getBytes()), javaType);
} catch (IOException ex) {
throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex);
}
}

/**
* 返回数据加密
* @param object
* @param type
* @param outputMessage
* @throws IOException
* @throws HttpMessageNotWritableException
*/
@Override
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
String json = objectMapper.writeValueAsString (object);
logger.info ("原来的json"+json);
// 加密
String result = json ;
logger.info ("加密后的json"+result);
// 输出
outputMessage.getBody().write(result.getBytes());
}

}

然后实现WebMvcConfigurer,需要将这个自定义的转换器配置到 Spring 中,这里通过重写WebMvcConfigurer中的configureMessageConverters方法添加自定义转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/**
* @author lyc
* @Description:
* @create 2018-12-28
*/

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

@Resource
private MyMappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;

Logger logger = LoggerFactory.getLogger(getClass());

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add (mappingJackson2HttpMessageConverter);
}

}

到这里大致的步骤已经做完,中间需要你加上你的加密解密的工具。其他的使用就和你平常还是一样。但是这里是全局加密也就是说所有的接口都被加密或者解密