[转]使用自定义HttpMessageConverter对返回内容进行加密
今天上午技术群里的一个人问” 如何在 Spring MVC 中统一对返回的 Json 进行加密?”。
大部分人的第一反应是通过 Spring 拦截器(Interceptor)中的postHandler方法处理。实际这是行不通的,因为当程序运行到该方法,是在返回数据之后,渲染页面之前,所以这时候 Response 中的输出流已经关闭了,自然无法在对返回数据进行处理。
其实这个问题用几行代码就可以搞定,因为 Spring 提供了非常丰富的扩展支持,无论是之前提到的Interceptor和MethodArgumentResolver,还是接下来要提到的HttpMessageConverter。
在 Spring MVC 的 Controller 层经常会用到@RequestBody和@ResponseBody,通过这两个注解,可以在 Controller 中直接使用 Java 对象作为请求参数和返回内容,而完成这之间转换作用的便是HttpMessageConverter。
HttpMessageConverter接口提供了 5 个方法:
canRead:判断该转换器是否能将请求内容转换成 Java 对象canWrite:判断该转换器是否可以将 Java 对象转换成返回内容getSupportedMediaTypes:获得该转换器支持的 MediaType 类型read:读取请求内容并转换成 Java 对象write:将 Java 对象转换后写入返回内容其中
read和write方法的参数分别有有HttpInputMessage和HttpOutputMessage对象,这两个对象分别代表着一次 Http 通讯中的请求和响应部分,可以通过getBody方法获得对应的输入流和输出流。这里通过实现该接口自定义一个 Json 转换器作为示例:
|
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
class CustomJsonHttpMessageConverter implements HttpMessageConverter {
//Jackson 的 Json 映射类
private ObjectMapper mapper = new ObjectMapper ();
// 该转换器的支持类型:application/json
private List supportedMediaTypes = Arrays.asList (MediaType.APPLICATION_JSON);
/**
* 判断转换器是否可以将输入内容转换成 Java 类型
* @param clazz 需要转换的 Java 类型
* @param mediaType 该请求的 MediaType
* @return
*/
@Override
public boolean canRead (Class clazz, MediaType mediaType) {
if (mediaType == null) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes ()) {
if (supportedMediaType.includes (mediaType)) {
return true;
}
}
return false;
}
/**
* 判断转换器是否可以将 Java 类型转换成指定输出内容
* @param clazz 需要转换的 Java 类型
* @param mediaType 该请求的 MediaType
* @return
*/
@Override
public boolean canWrite (Class clazz, MediaType mediaType) {
if (mediaType == null || MediaType.ALL.equals (mediaType)) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes ()) {
if (supportedMediaType.includes (mediaType)) {
return true;
}
}
return false;
}
/**
* 获得该转换器支持的 MediaType
* @return
*/
@Override
public List getSupportedMediaTypes () {
return supportedMediaTypes;
}
/**
* 读取请求内容,将其中的 Json 转换成 Java 对象
* @param clazz 需要转换的 Java 类型
* @param inputMessage 请求对象
* @return
* @throws IOException
* @throws HttpMessageNotReadableException
*/
@Override
public Object read (Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return mapper.readValue (inputMessage.getBody (), clazz);
}
/**
* 将 Java 对象转换成 Json 返回内容
* @param o 需要转换的对象
* @param contentType 返回类型
* @param outputMessage 回执对象
* @throws IOException
* @throws HttpMessageNotWritableException
*/
@Override
public void write (Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
mapper.writeValue (outputMessage.getBody (), o);
}
}
|
当前 Spring 中已经默认提供了相当多的转换器,分别有:
| 名称 | 作用 | 读支持 MediaType | 写支持 MediaType |
|---|---|---|---|
| ByteArrayHttpMessageConverter | 数据与字节数组的相互转换 | \/\ | application/octet-stream |
| StringHttpMessageConverter | 数据与 String 类型的相互转换 | text/\* | text/plain |
| FormHttpMessageConverter | 表单与 MultiValueMap的相互转换 | application/x-www-form-urlencoded | application/x-www-form-urlencoded |
| SourceHttpMessageConverter | 数据与 javax.xml.transform.Source 的相互转换 | text/xml 和 application/xml | text/xml 和 application/xml |
| MarshallingHttpMessageConverter | 使用 Spring 的 Marshaller/Unmarshaller 转换 XML 数据 | text/xml 和 application/xml | text/xml 和 application/xml |
| MappingJackson2HttpMessageConverter | 使用 Jackson 的 ObjectMapper 转换 Json 数据 | application/json | application/json |
| MappingJackson2XmlHttpMessageConverter | 使用 Jackson 的 XmlMapper 转换 XML 数据 | application/xml | application/xml |
| BufferedImageHttpMessageConverter | 数据与 java.awt.image.BufferedImage 的相互转换 | Java I/O API 支持的所有类型 | Java I/O API 支持的所有类型 |
回到最开始所提的需求,既然要对返回的 Json 内容进行加密,肯定是对MappingJackson2HttpMessageConverter进行改造,并且只需要重写write方法。
从MappingJackson2HttpMessageConverter的父类AbstractHttpMessageConverter中的write方法可以看出,该方法通过writeInternal方法向返回结果的输出流中写入数据,所以只需要重写该方法即可:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter () {
return new MappingJackson2HttpMessageConverter () {
// 重写 writeInternal 方法,在返回内容前首先进行加密
@Override
protected void writeInternal (Object object,
HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
// 使用 Jackson 的 ObjectMapper 将 Java 对象转换成 Json String
ObjectMapper mapper = new ObjectMapper ();
String json = mapper.writeValueAsString (object);
LOGGER.error (json);
// 加密
String result = json + "加密了!";
LOGGER.error (result);
// 输出
outputMessage.getBody ().write (result.getBytes ());
}
};
}
|
在这之后还需要将这个自定义的转换器配置到 Spring 中,这里通过重写WebMvcConfigurer中的configureMessageConverters方法添加自定义转换器:
|
1
2
3
4
5
6
|
// 添加自定义转换器
@Override
public void configureMessageConverters (List> converters) {
converters.add (mappingJackson2HttpMessageConverter ());
super.configureMessageConverters (converters);
}
|
测试一下:

如此便简单的完成了对返回内容进行加密的功能。
(原文地址:http://www.scienjus.com/custom-http-message-converter/)
[转]使用自定义HttpMessageConverter对返回内容进行加密的更多相关文章
- 自定义HttpMessageConverter实现RestTemplate的exchange方法返回自定义格式数据
一 概述 实现如下效果代码,且可正常获取到返回数据: ResponseEntity<JsonObject> resEntity = restTemplate .exchange(url, ...
- .net中自定义过滤器对Response内容进行处理
原文:http://www.cnblogs.com/zgqys1980/archive/2008/09/02/1281895.html 代码DEMO:http://files.cnblogs.com/ ...
- Fiddler 修改返回内容 OnBeforeResponse 无效 没用
Fiddler自定义脚本可以实现很强大的内容替换,包括很有意义的——修改返回内容. 具体的方法可以参考官网:http://docs.telerik.com/fiddler/KnowledgeBase/ ...
- SpringBoot自定义HttpMessageConverter
Spring就是一个大大的插线板,上面插着各种各样的Bean. SpringBoot大大简化了Spring的配置,将原来放在XML中的配置大量的在代码中使用注解实现.这么做有利有弊,总体上利大于弊. ...
- Django(四) 后台管理:创建管理员、注册模型类、自定义管理页面显示内容
后台管理 第1步.本地化:设置语言.时区 修改project1/settings.py #LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-hans' #设置语言 ...
- WPF界面设计技巧(5)—自定义列表项呈现内容
原文:WPF界面设计技巧(5)-自定义列表项呈现内容 接续上次的程序,稍微改动一下原有样式,并添加一个数据模板,我们就可以达成下面这样的显示功能: 鼠标悬停于文件列表项上,会在工具提示中显示图像缩略图 ...
- 自定义View 可清除内容、设置图标、下划线的输入框 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Spring mvc 注解@ResponseBody 返回内容编码问题
@ResponseBody 在@Controller 类方法中能够让字符串直接返回内容. 其返回处理的类是org.springframework.http.converter.StringHttpMe ...
- echarts自定义tooltip提示框内容
1.echarts自定义tooltip提示框内容 https://blog.csdn.net/dreamsup/article/details/56667330 2.关于Echarts的formatt ...
随机推荐
- 微信小程序 - 接口更新记录以及解决方案(2018/12/26)
2018/8/17 - 背景音频需要在app.json添加requireBackGroundModes 2018/9/12 - 微信更改获取用户信息接口/获取位置等接口 - button 2018/1 ...
- esxtop 指标%RDY,NUMA,Wide-VMs
参考文章:http://www.boche.net/blog/index.php/2010/10/21/cpu-ready-to-rdy-conversion/ http://kb.vmware.co ...
- JAVA 数据库连接池(伪代码,简单易读)
一.引言 近年来,随着 Internet/Intranet 建网技术的飞速发展和在世界范围内的迅速普及,电子商务的冲击波又一次在世界范围内掀起巨浪,各类商务网站吸引着大量用户的青睐,商务网站的访问量也 ...
- Python-统计svn代码总行数
1 #!/bin/bash/python 2 # -*-coding:utf-8-*- 3 #svn统计url代码行数脚本,过滤空行,不过滤注释. 4 5 import subprocess,os,s ...
- Jackson序列化日期类型的属性
@JsonProperty("BankSettlementDate") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = ...
- lvalue & rvalue
https://www.youtube.com/watch?v=UTUdhjzws5g 作者:知乎用户链接:https://www.zhihu.com/question/50652989/answer ...
- django之创建第4个项目编写第一个动态模板文件
修改的地方: 1.index.html <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- 最大整数(Noip1998连接多位数)
最大整数(Noip1998连接多位数)[问题描述] 设有n个正整数(n≤20),将它们联接成一排,组成一个最大的多位整数. 例如:n=3时,3个整数13,312,343联接成的最大整数为:343312 ...
- 拦截导弹问题(NOIP1999)
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统,但是这种拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度, 但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭,由于该 ...
- linux rpm 安装后 mysql 默认安装目录等信息
MySQL安装完成后不象SQL Server默认安装在一个目录,它的数据库文件.配置文件和命令文件分别在不同的目录,了解这些目录非常重要,尤其对于Linux的初学者,因为 Linux本身的目录结构就比 ...