[转]使用自定义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 ...
随机推荐
- ZH奶酪:LAMP环境中如何重新部署一个Yii2.0 web项目
使用Yii2.0 framework开发的项目,使用Github进行版本控制,现在要把这个项目部署到一个新的电脑/系统中: (1)安装LAMP (2)在/var/www/html目录下执行 git c ...
- HDS Truecopy实现原理及项目的选择-诸多案例
copy from:http://www.eygle.com/archives/2009/05/hds_truecopy_dataguard.html 诸多案例:http://wenku.baidu. ...
- 实验室报告:VMware vSphere Data Protection
dd Lab Reports VMware vSphere Data Protection Fast, Simple, and Agentless Deduplicated Virtual Machi ...
- linux高精度struct timespec 和 struct timeval
一.struct timespec 定义: typedef long time_t;#ifndef _TIMESPEC#define _TIMESPECstruct timespec {time_t ...
- android 安装调试第三方应用失败
Android Studio 3.0会在debug apk的manifest文件application标签里自动添加 android:testOnly="true"属性,导致IDE ...
- .NET/C#中对自定义对象集合进行自定义排序的方法
一个集合可否排序,要看系统知不知道排序的规则,像内建的系统类型,int ,string,short,decimal这些,系统知道怎么排序,而如果一个集合里面放置的是自定义类型,比如自己定义了一个Car ...
- java while循环语句
//循环语句 //符合条件,循环继续执行,否则循环退出. //特点: //先判断,后执行 public class Test16{ public static void main(String arg ...
- jQuery live事件说明及移除live事件方法
1.live事件说明 jQuery1.3增加了一个live()方法,下面是手册上的说明: jQuery 1.3中新增的方法.给所有当前以及将来会匹配的元素绑定一个事件处理函数(比如click事件).也 ...
- Serv-U精简版FTP服务端
Window搭建自己的FTP,Serv-U是很不错的选择... 00.运行视图 注意: 此版本是绿色破解版,个人使用很便捷的.不建议商业使用... download: https://pan.baid ...
- Libevent官方代码样例学习(二)
连接监听器: 接收TCP连接请求 evconnlistener机制用于监听并接受TCP连接请求. 这些方法在event2/listener.h中声明, 在Libevent 2.0.2-alpha之后的 ...