spring 使用jsontemplate 处理rest 响应内容格式
实际上jsontemplate只是提供了一种简化json 格式的方法,实际上我们也是可以直接基于模版引擎的
只是jsontemplate 对于json 处理相对简单,同时提供了不少方便的功能
参考图
简单的集成图,只是对于处理我们基于了jsontemplate
代码集成
很简单,核心就是利用jsontemplate 函数,然后传入数据,返回数据就可以了
- maven 依赖
主要此版本是我自定义开发的,因为默认的对于处理不存在的变量是有问题的,具体代码参考github
<dependency>
<groupId>com.github.json-template</groupId>
<artifactId>jsontemplate</artifactId>
<version>0.2.2</version>
</dependency>
- 简单模版存储包装
实际使用可以基于配置中心,基于本地的推荐基于cache 管理 - 模版存储接口
public interface TemplateStorage {
String getTemplateContent(String bizID);
Boolean putTemplate(String bizID,String templateContent) throws Exception;
List<String> allTemplates();
List<String> allBizIDs();
}
默认实现
@Component
public class BasicTemplateStorage implements TemplateStorage {
private ConcurrentHashMap<String, String> basicStorage = new ConcurrentHashMap<>();
@Override
public String getTemplateContent(String bizID) {
String content = basicStorage.get(bizID);
return content;
}
@Override
public Boolean putTemplate(String bizID, String templateContent) throws Exception {
if (Strings.isNullOrEmpty(bizID)) {
throw new Exception("bizid can't be null");
}
if (Strings.isNullOrEmpty(templateContent)) {
throw new Exception("templateContent can't be null");
}
basicStorage.put(bizID,templateContent);
return true;
}
@Override
public List<String> allTemplates() {
return basicStorage.values().stream().collect(Collectors.toList());
}
@Override
public List<String> allBizIDs() {
return basicStorage.keySet().stream().collect(Collectors.toList());
}
}
- 模版初始化
@Bean
public CommandLineRunner commandLineRunner(TemplateStorage templateStorage){
return new CommandLineRunner() {
@Override
public void run(String
templateStorage.putTemplate("alert","{\n" +
" name:$name,\n" +
" age:$age,\n" +
" version:$name1,\n" +
" appdemo:$demoapp,\n" +
" rong:@s($demoapp),\n" +
" userinfo:$appconfs\n" +
"}");
templateStorage.putTemplate("warning","{\n" +
" name:$name,\n" +
" age:$age,\n" +
" userinfo:$appconfs\n" +
"}");
}
};
}
- 接口集成
@GetMapping(value = {"/t/{type}"},produces = {"application/json"})
public Object jsonTemplate(@PathVariable(value = "type") String type){
List<AppConf> appConfs = new ArrayList<>();
AppConf appConf = new AppConf();
appConf.setAge(33222);
appConf.setName("appconf");
appConfs.add(appConf);
AppConf appConfv2 = new AppConf();
appConfv2.setAge(33222);
appConfv2.setName("appconf");
appConfs.add(appConfv2);
MyUser myUser = new MyUser();
myUser.setAge(333);
myUser.setAppconfs(appConfs);
myUser.setName("demoapp");
JsonTemplate jsonTemplate = new JsonTemplate(templateStorage.getTemplateContent(type),new DefaultNullBuildHandler());
Map context = objectMapper.convertValue(myUser,Map.class);
System.out.println(context.toString());
return jsonTemplate.withVars(context).prettyString();
}
- 效果
jsontemplate一些问题
- 空值处理
默认对于空值的处理是有bug的,会造成异常,我基于官方代码调整了,同时添加了一个重载函数,可以自定义处理 - 默认null 处理
public class DefaultNullBuildHandler implements DefaultBuildHandler{
@Override
public JsonNode handle(String valueTypeName) {
return JsonStringNode.of(null);
}
}
src/main/java/com/github/jsontemplate/modelbuild/BasePropertyDeclaration.java
public void buildJsonTemplate(JsonBuilder builder,
Map<String, IValueProducer> producerMap,
Map<String, JsonNode> typeMap,
Map<String, JsonNode> variableMap,
String defaultTypeName,
DefaultBuildHandler defaultHandler) {
JsonNode jsonNode = null;
if (isNullValue()) {
jsonNode = new JsonNullNode();
} else {
jsonNode = findJsonNodeFromVariable(variableMap, typeSpec.getTypeName());
if (jsonNode == null) {
// it is not a variable, search type map
if (typeSpec.getTypeName() == null) {
TypeSpec ancestorTypeSpec = findAncestorTypeSpec(defaultTypeName);
this.typeSpec.setTypeName(ancestorTypeSpec.getTypeName());
if (typeSpec.getSingleParam() == null) {
this.typeSpec = ancestorTypeSpec;
}
}
jsonNode = buildNodeFromProducer(producerMap);
}
if (jsonNode == null) {
// this type is declared inside template
jsonNode = typeMap.get(this.typeSpec.getTypeName());
}
if (jsonNode == null) {
// cannot find any matched type
// 处理空值
jsonNode = new JsonNullNode();
defaultHandler.handle(this.typeSpec.getTypeName());
}
}
joinNode(builder, jsonNode);
}
说明
基于jsontemplate 的好处是我们可以基于配置就可以处理接口生成了,简单而且修改灵活,而且jsontemplate提供的能力还是很强大的,我们可以灵活的扩展
实现一个比较方便的接口响应处理,比如apigateway 中,模版引擎也是不错的选择,而且集成好了理论上会更好的,比如aws 的网关就有用到模版引擎技术
目前不太好的地方是尽管jsontemplate 是支持基于map以及变量应用获取数据的,实际上方法很多,一种就是我们直接将pojo 扁平化,就可以转换为一个可以
直接嵌套的变量了
参考资料
https://github.com/json-template/JsonTemplate
https://github.com/rongfengliang/JsonTemplate
https://github.com/wnameless/json-flattener
https://www.cnblogs.com/rongfengliang/p/13892745.html