[转]使用自定义HttpMessageConverter对返回内容进行加密

今天上午技术群里的一个人问” 如何在 Spring MVC 中统一对返回的 Json 进行加密?”。

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

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

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

HttpMessageConverter接口提供了 5 个方法:

  • canRead:判断该转换器是否能将请求内容转换成 Java 对象
  • canWrite:判断该转换器是否可以将 Java 对象转换成返回内容
  • getSupportedMediaTypes:获得该转换器支持的 MediaType 类型
  • read:读取请求内容并转换成 Java 对象
  • write:将 Java 对象转换后写入返回内容

    其中readwrite方法的参数分别有有HttpInputMessageHttpOutputMessage对象,这两个对象分别代表着一次 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/)

时间: 2024-11-04 02:47:00

[转]使用自定义HttpMessageConverter对返回内容进行加密的相关文章

Spring mvc 注解@ResponseBody 返回内容编码问题

@ResponseBody 在@Controller 类方法中可以让字符串直接返回内容. 其返回处理的类是org.springframework.http.converter.StringHttpMessageConverter,此类默认编码 <span style="font-size:18px;">public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");&

Android 自定义TextView实现文本内容自动调整字体大小以适应TextView的大小

最近做通讯录小屏机 联系人姓名显示--长度超过边界字体变小 /**   * 自定义TextView,文本内容自动调整字体大小以适应TextView的大小   * @author yzp   */   public class AutoFitTextView extends TextView {       private Paint mTextPaint;       private float mTextSize;          public AutoFitTextView(Context

MVC3/4 自定义HtmlHelper截断文本内容(截取)

在MVC目录下新建一个名为 Extersions  的文件夹,在该文件夹中新建一个截断文本类,取名为:CutOfTextExtersions 该类代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace System.Web.Mvc //修改为所属System.Web.Mvc命名空间 方便直接使用 { ///

ASP函数:根据表和ID和字段名,返回内容

'//根据表和ID和字段名,返回内容Function dsf_fieldValueFromTable(fTable,id,fieldName) dim rs,sql set rs=server.createobject("adodb.recordset") sql="select * from " & fTable & " where id=" & id rs.open sql,conn,1,1 if not rs.eof

自定义导航栏返回按钮文字

自定义导航栏返回按钮文字 by 伍雪颖 navigationItem.backBarButtonItem = UIBarButtonItem(title: "返回", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)

anyproxy-修改返回内容(beforeSendResponse)

前言 fiddler可以抓包打断点后,修改返回的内容,便于模拟各种返回结果.anyproxy也可以通过写rule模块规则,模拟返回状态码.头部.body beforeSendResponse beforeSendResponse(requestDetail, responseDetail) AnyProxy向客户端发送请求前,会调用beforeSendResponse,并带上参数requestDetail responseDetail requestDetail 同beforeSendReque

关于Swagger @ApiModel 返回内容注释不显示问题

@ApiModel希望Swagger生成的文档出现返回的内容注释,发现需要用到@ApiModel注解到你需要返回的类上 @ApiModelProperty作为字段的描述例如 之后文档还是不显示返回内容的注释, 原来是因为封装的返回类没做泛型 需要加入泛型 封装的返回类加入泛型之后,还需要在你Controller返回的数据也加上泛型,不然还是展示不出来的 这样,返回的数据就带上注释了 完美解决了返回内容不带注释的问题 原文地址:https://www.cnblogs.com/airen123/p/

Java小知识--把服务器返回内容写成.jsp返回给客户端

从服务器直接返回  内容  给客户端的话 要写很多程序,很麻烦.服务器把客户端的请求  托管给jsp,再又jsp返回给客户端就比较容易. .jsp file  要建在Web Content目录下!!! 写法: req.getRequestDispatcher(path); dispatcher  调度程序 , 请求转发器,将请求由服务器转发给jsp (path)中要填接收请求的 jsp的路径 用forward(arg0,arg1)    进行转发 原文地址:https://www.cnblogs

Java使用RSA加密算法对内容进行加密

什么是RSA加密算法 RSA是一种典型的非对称性加密算法,具体介绍可参考阮一峰的日志 RSA算法原理 下面是使用RSA算法对传输内容进行加密的一个简要Java案例,主要用到了三个类,大体实现如下: 对内容进行RSA加密和解密校验的类 import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8Enco