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... args) throws Exception {
        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

posted on 2022-05-21 10:29  荣锋亮  阅读(219)  评论(0编辑  收藏  举报

导航