在构建一个基于JSON的API的时候, 往往我们还会需要添加一些额外的字段, 形成类似于 数据主体/额外信息 结构的数据, 如:
{
"mainContent": { // 数据主体
"name": "小明",
"age": 11
},
"external": { // 额外信息
"errorMsg": "OK",
"errorCode": "0"
}
}
方法1 建一个带泛型的 pojo , 将数据塞进去, 然后JSON化输出
这样的类可以是:
public class BizDto {
public BizDto() {
// 为了方便, 设置默认值
External external = new External();
external.setErrorCode("0");
external.setErrorMsg("OK");
}
private T mainContent;
private External external;
public T getMainContent() {
return mainContent;
}
public void setMainContent(T mainContent) {
this.mainContent = mainContent;
}
public External getExternal() {
return external;
}
public void setExternal(External external) {
this.external = external;
}
public class External{
private String errorMsg;
private String errorCode;
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
}
}
然后所有的 restfull api 都用这个 pojo 封装一下再输出
方法2 干预 spring json 序列化的过程
使用这个办法的好处是 controller 方法的返回值不需要做任何改变, 可以直接输出数据主体
先自定义HttpMessageConverter
来实现自定义的 java转换过程 (from java/ to java)
然后呢 通过覆盖 spring 默认的 HttpMessageConverters, 或者将自己的 converter 加上去, 办法是声明一个 bean
@Bean
public HttpMessageConverters additionalConverters() {
return new HttpMessageConverters(new TheCustomConverter());
}
HttpMessageConverters 有3个构造方法
HttpMessageConverters(HttpMessageConverter>... additionalConverters)
HttpMessageConverters(Collection> additionalConverters)
HttpMessageConverters(boolean addDefaultConverters, Collection> converters)
前两个是给spring 默认处理列表中添加一个新的 converter, 第三个是覆盖掉默认的 converters, 只使用自己定义的
使用这个方法还需要考虑一种情况, 就是出错了, 要怎么输出错误信息到前端
思路是使用@ControllerAdvice
+ 自定义 runtime Exception
遇到错误, 直接 throw new CustomeRuntimeException("errorcode","errormsg", ex)
交给框架去处理
小尾巴:
既然 spring 默认带了 jackson 作为 json 的序列化工具, 有没有人想过直接使用这个工具来序列化java对象呢, 多数时候我们都是再用一个第三方jar包比如著名的 fastJSON. 但再添加一个第三方工具带来的麻烦是 json 序列化时配置的不统一了
比如说 jackson 默认会将 Date 对象格式化成 utc 格式, 而fastJson会将日期输出成 毫秒 时间戳
有一个全局统一的配置, 可以避免在输出时每次都控制一下格式化, 而且很容易遗漏
办法就是, 注入 jackson 的ObjectMapper
@Autowired
private ObjectMapper objectMapper; // 注入
// 输出JSON字符串
objectMapper.writer().writeValueAsString(javaObj));
// 将JSON字符串转成java bean;
objectMapper.readValue(jsonStr,javaObj.class);
Map map = new HashMap();
// JSON string to Map
map = objectMapper.readValue(json, new TypeReference