奇思妙想---基于fastJson让Java像js(user.name,data[0].id)一样取json的值

背景

    在某些系统当中,我们经常在前端看到一些操作的滚动屏,例如:“谁谁谁登录了系统”,“谁谁谁提交了***号订单”,所以突发奇想,能否在部分接口上
通过自定义注解生成滚动内容,然后推送到前端或者保存至数据库呢?
例如:
	@RollRecord("${customParam.nickName}操作了客户${requestParam.customerName}的订单,并生成订单号${returnBody.orderNumber}")
	@RollRecord("${customParam.nickName}批量接取了${returnbody[*].orderNumber}")订单
这样能使得代码具有更少的侵入性。
	至于,注解里面的表达式的取值,我们可以提供一个ThreadLocal<String,Object> 类型变量 rollRecordContextParam来保存,一个默认把请求参数requestParam,以及返回参数returnBody放入,以及部分特殊需要扩展的需求可以通过customParam(Map<String,Object>)在业务中放入.
	由此可知rollRecordContextParam的基本结构应该是:{requestParam:{},returnBody:{},customParam:{}};
	那么问题来了,如何通过 “customParam.nickName”,“returnbody[*].orderNumber”这种表达式去取rollRecordContextParam当中的值呢?

问题

 在js当中,面对一个json对象,我们可以直接通过user.id,user[0].name来获取json对象的值。
 那么,我们能够通过Java来实现这种效果,或者扩展呢?

目标效果:

给定如下数据:
{ "code":200, "data":{ "current":1, "pages":1, "records":[ { "bindAccount":"A202203030000002", "bindCustomer":"C2022030300001", "bindStatus":true, "contactEmail":null, "contactMobile":"", "contactName":"", "ctdTime":"2022-03-03 10:17:39", "customerInfo":{ "cooperate":true, "ctdTime":"2022-03-03 10:14:53", "customerCode":"CSKHFJX", "customerName":"测试客户发件箱新增", "customerSimpleName":"测试客户发件箱新增", "customerUnId":"C2022030300001", "dealRemark":"", "delegate":0, "delegateUrl":null, "globalId":"C2021121700002", "id":32, "remark":"", "types":[ "BG" ], "updTime":"2022-03-03 10:14:53" }, "employeeInfo":{ "accountName":"CKF001", "accountUnId":"A202203030000002", "ctdTime":"2022-03-03 10:16:11", "departmentName":"", "email":null, "employeeNo":"", "globalId":"C2021121700002", "headUrl":null, "id":67, "idNumber":null, "lastLoginTime":"2022-03-04 10:36:02", "locked":false, "mobile":"14566666666", "password":"$2a$10$wVm3Uz4pe9WBvkZXzB8LjOyzBKXY92PKpS7vo0YNyv9j0Pa3ZBu86", "passwordExpireTime":"2022-06-01 10:16:10", "qq":null, "realName":"测客发001", "superAdmin":false, "updTime":"2022-03-03 10:16:11", "workStatus":0, "wx":null }, "globalId":"C2021121700002", "id":34, "remark":"ceshikehufajiangxiangxinzeng", "sendEmail":"68944442@qq.com", "updTime":"2022-03-03 10:17:39" }, { "bindAccount":"A202112250000001", "bindCustomer":"C2022030200001", "bindStatus":true, "contactEmail":null, "contactMobile":"", "contactName":"", "ctdTime":"2022-03-03 10:11:56", "customerInfo":{ "cooperate":true, "ctdTime":"2022-03-02 18:33:52", "customerCode":"HAIHAI", "customerName":"杭州嗨嗨厂", "customerSimpleName":"嗨嗨", "customerUnId":"C2022030200001", "dealRemark":"", "delegate":0, "delegateUrl":null, "globalId":"C2021121700002", "id":31, "remark":"", "types":[], "updTime":"2022-03-02 18:33:52" }, "employeeInfo":null, "globalId":"C2021121700002", "id":33, "remark":"", "sendEmail":"9999999999@qq.com", "updTime":"2022-03-03 10:11:56" }, { "bindAccount":"A202112250000001", "bindCustomer":"C2022030200001", "bindStatus":true, "contactEmail":null, "contactMobile":"", "contactName":"", "ctdTime":"2022-03-02 18:34:31", "customerInfo":{ "cooperate":true, "ctdTime":"2022-03-02 18:33:52", "customerCode":"HAIHAI", "customerName":"杭州嗨嗨厂", "customerSimpleName":"嗨嗨", "customerUnId":"C2022030200001", "dealRemark":"", "delegate":0, "delegateUrl":null, "globalId":"C2021121700002", "id":31, "remark":"", "types":[], "updTime":"2022-03-02 18:33:52" }, "employeeInfo":null, "globalId":"C2021121700002", "id":31, "remark":"", "sendEmail":"1019486403@qq.com", "updTime":"2022-03-02 18:34:31" } ], "size":10, "total":3 }, "developerMessage":null, "msg":"success" }

在这里插入图片描述

通过以下代码取下列表达式的值
	- "data.records[0].customerInfo.customerName"
	- "data.records[*].customerInfo.customerName"
	- "code"
  public static void main(String[] args) throws IOException {
    String express1 = "data.records[0].customerInfo.customerName";
    String express2 = "data.records[*].customerInfo.customerName";
    String express3 = "code";
    String jsonContent1 = "{ \"code\":200, \"data\":{ \"current\":1, \"pages\":1, \"records\":[ { \"bindAccount\":\"A202203030000002\", \"bindCustomer\":\"C2022030300001\", \"bindStatus\":true, \"contactEmail\":null, \"contactMobile\":\"\", \"contactName\":\"\", \"ctdTime\":\"2022-03-03 10:17:39\", \"customerInfo\":{ \"cooperate\":true, \"ctdTime\":\"2022-03-03 10:14:53\", \"customerCode\":\"CSKHFJX\", \"customerName\":\"测试客户发件箱新增\", \"customerSimpleName\":\"测试客户发件箱新增\", \"customerUnId\":\"C2022030300001\", \"dealRemark\":\"\", \"delegate\":0, \"delegateUrl\":null, \"globalId\":\"C2021121700002\", \"id\":32, \"remark\":\"\", \"types\":[ \"BG\" ], \"updTime\":\"2022-03-03 10:14:53\" }, \"employeeInfo\":{ \"accountName\":\"CKF001\", \"accountUnId\":\"A202203030000002\", \"ctdTime\":\"2022-03-03 10:16:11\", \"departmentName\":\"\", \"email\":null, \"employeeNo\":\"\", \"globalId\":\"C2021121700002\", \"headUrl\":null, \"id\":67, \"idNumber\":null, \"lastLoginTime\":\"2022-03-04 10:36:02\", \"locked\":false, \"mobile\":\"14566666666\", \"password\":\"$2a$10$wVm3Uz4pe9WBvkZXzB8LjOyzBKXY92PKpS7vo0YNyv9j0Pa3ZBu86\", \"passwordExpireTime\":\"2022-06-01 10:16:10\", \"qq\":null, \"realName\":\"测客发001\", \"superAdmin\":false, \"updTime\":\"2022-03-03 10:16:11\", \"workStatus\":0, \"wx\":null }, \"globalId\":\"C2021121700002\", \"id\":34, \"remark\":\"ceshikehufajiangxiangxinzeng\", \"sendEmail\":\"68944442@qq.com\", \"updTime\":\"2022-03-03 10:17:39\" }, { \"bindAccount\":\"A202112250000001\", \"bindCustomer\":\"C2022030200001\", \"bindStatus\":true, \"contactEmail\":null, \"contactMobile\":\"\", \"contactName\":\"\", \"ctdTime\":\"2022-03-03 10:11:56\", \"customerInfo\":{ \"cooperate\":true, \"ctdTime\":\"2022-03-02 18:33:52\", \"customerCode\":\"HAIHAI\", \"customerName\":\"杭州嗨嗨厂\", \"customerSimpleName\":\"嗨嗨\", \"customerUnId\":\"C2022030200001\", \"dealRemark\":\"\", \"delegate\":0, \"delegateUrl\":null, \"globalId\":\"C2021121700002\", \"id\":31, \"remark\":\"\", \"types\":[], \"updTime\":\"2022-03-02 18:33:52\" }, \"employeeInfo\":null, \"globalId\":\"C2021121700002\", \"id\":33, \"remark\":\"\", \"sendEmail\":\"9999999999@qq.com\", \"updTime\":\"2022-03-03 10:11:56\" }, { \"bindAccount\":\"A202112250000001\", \"bindCustomer\":\"C2022030200001\", \"bindStatus\":true, \"contactEmail\":null, \"contactMobile\":\"\", \"contactName\":\"\", \"ctdTime\":\"2022-03-02 18:34:31\", \"customerInfo\":{ \"cooperate\":true, \"ctdTime\":\"2022-03-02 18:33:52\", \"customerCode\":\"HAIHAI\", \"customerName\":\"杭州嗨嗨厂\", \"customerSimpleName\":\"嗨嗨\", \"customerUnId\":\"C2022030200001\", \"dealRemark\":\"\", \"delegate\":0, \"delegateUrl\":null, \"globalId\":\"C2021121700002\", \"id\":31, \"remark\":\"\", \"types\":[], \"updTime\":\"2022-03-02 18:33:52\" }, \"employeeInfo\":null, \"globalId\":\"C2021121700002\", \"id\":31, \"remark\":\"\", \"sendEmail\":\"1019486403@qq.com\", \"updTime\":\"2022-03-02 18:34:31\" } ], \"size\":10, \"total\":3 }, \"developerMessage\":null, \"msg\":\"success\" }";
    System.out.println(getJsonContentByExpress(express1,jsonContent1));
    System.out.println(getJsonContentByExpress(express2,jsonContent1));
    System.out.println(getJsonContentByExpress(express3,jsonContent1));
  }
输出下面的结果:

在这里插入图片描述

开始编码

依赖准备:
	fastjson
	google guva
	common-lang3

工具代码:
  /**
   *  根据表达式取json字符串当中的值
   * @exampleInput "user.name", "{\"user\":{\"name\":\"liming\",\"age\":18}}"
   * @exampleReturn liming
   * @param express 
   * @param jsonContent 
   * @return java.lang.String
   * @throws 
   * @version V1.0.0
   * @date  2022/3/4 12:53
   */
  public static String getJsonContentByExpress(String express,String jsonContent){
    List<JsonFiledInfo> jsonFiledInfos = analyseExpress(express);
    return getByJsonFieldInfos(jsonFiledInfos, jsonContent);
  }

   /**
  * 将表达式解析为所需要的JSON字段信息层级数组
  * @exampleInput result[1].id
  * @exampleReturn [{"field":"result","type":"object"},{"field":"1","type":"array"},{"field":"id","type":"object"}]
  * @param express
  * @return java.util.List<org.shining.base.common.entity.mo.JsonFiledInfo>
  * @throws
  * @version V1.0.0
  * @date  2022/3/4 9:48
  */
  public static List<JsonFiledInfo> analyseExpress(String express) {
    List<JsonFiledInfo> jsonFiledInfos = new ArrayList<>();
    List<String> params = string2List(express, ".");
    for (String param : params) {
      List<String> ps = string2List(param, "[");
      for (String p : ps) {
        JsonFiledInfo jsonFiledInfo = new JsonFiledInfo();
        if (p.contains("]")) {
          List<String> ss = string2List(p, "]");
          jsonFiledInfo.setField(ss.get(0));
          jsonFiledInfo.setType(JsonFiledInfo.ARRAY_TYPE);
          boolean f = ss.get(0).startsWith("'") && ss.get(0).endsWith("'");
          boolean ff = ss.get(0).startsWith("\"") && ss.get(0).endsWith("\"");
          if (f || ff) {
            String str = ss.get(0);
            jsonFiledInfo.setField(str.substring(1, str.length() - 1));
            jsonFiledInfo.setType(JsonFiledInfo.OBJECT_TYPE);
          }
          jsonFiledInfos.add(jsonFiledInfo);
          if (ss.size() > 1) {
            JsonFiledInfo jfi = new JsonFiledInfo();
            jfi.setField(ss.get(1));
            jfi.setType(JsonFiledInfo.OBJECT_TYPE);
            jsonFiledInfos.add(jfi);
          }
        } else {
          jsonFiledInfo.setField(p);
          jsonFiledInfo.setType(JsonFiledInfo.OBJECT_TYPE);
          jsonFiledInfos.add(jsonFiledInfo);
        }
      }
    }
    return jsonFiledInfos;
  }
  
 /**
   *  根据jsonFiledInfos(json层级数组提取json字符串当中的值)
   * @param jsonFiledInfos
   * @param jsonContent
   * @return java.lang.String
   * @throws
   * @version V1.0.0
   * @date  2022/3/4 9:55
   */
  private static String getByJsonFieldInfos(List<JsonFiledInfo> jsonFiledInfos, String jsonContent) {
    String all = "*";
    if (jsonFiledInfos == null || jsonFiledInfos.size() == 0||StringUtils.isEmpty(jsonContent)) {
      return EMPTY_STRING;
    }
    try {
      //如果只是取json第一层,那简单转数组或者对象直接getString就行
      if (jsonFiledInfos.size() == 1) {
        if (JsonFiledInfo.ARRAY_TYPE.equals(jsonFiledInfos.get(0).getType())) {
          JSONArray jsonArray = JSONArray.parseArray(jsonContent);
          if (all.equals(jsonFiledInfos.get(0).getField())) {
            List<String> ss = new ArrayList<>();
            for (int z = 0; z < jsonArray.size(); z++) {
              ss.add(jsonArray.getString(z));
            }
            return list2String(ss, ",");
          } else {
            return jsonArray.getString(Integer.parseInt(jsonFiledInfos.get(0).getField()));
          }
        } else {
          JSONObject jsonObject = JSONObject.parseObject(jsonContent);
          return jsonObject.getString(jsonFiledInfos.get(0).getField());
        }
      }
      //如果是多层
      if (jsonFiledInfos.size() > 1) {
        JSON json = new JSONObject();
        boolean curTypeObject;
        boolean nextTypeObject;
        for (int i = 0; i < jsonFiledInfos.size() - 1; i++) {
          JsonFiledInfo curJsonFieldInfo = jsonFiledInfos.get(i);
          JsonFiledInfo nextJsonFieldInfo = jsonFiledInfos.get(i + 1);
          curTypeObject = curJsonFieldInfo.getType().equals(JsonFiledInfo.OBJECT_TYPE);
          nextTypeObject = nextJsonFieldInfo.getType().equals(JsonFiledInfo.OBJECT_TYPE);
          if (all.equals(curJsonFieldInfo.getField())) {
            List<String> ss = new ArrayList<>();
            JSONArray ja;
            if (i == 0) {
              ja = JSONArray.parseArray(jsonContent);
            } else {
              ja = (JSONArray) json;
            }
            for (int o = 0; o < ja.size(); o++) {
              JsonFiledInfo jsonFiledInfo = new JsonFiledInfo();
              jsonFiledInfo.setType(JsonFiledInfo.ARRAY_TYPE);
              jsonFiledInfo.setField(String.valueOf(o));
              List<JsonFiledInfo> jfs = Lists.newArrayList(jsonFiledInfos);
              jfs.remove(i);
              jfs.add(i, jsonFiledInfo);
              ss.add(getByJsonFieldInfos(jfs, jsonContent));
            }
            return list2String(ss, ",");
          }
          if (i == 0) {
            json = getJsonIfExpressSingle(jsonContent, curTypeObject, curJsonFieldInfo);
          } else {
            json = getJsonIfExpressMultiple(json, curTypeObject, nextTypeObject, curJsonFieldInfo);
          }
        }
        try {
          return ((JSONObject) json)
              .getString(jsonFiledInfos.get(jsonFiledInfos.size() - 1).getField());
        } catch (ClassCastException e) {
          return ((JSONArray) json)
              .getString(Integer.parseInt(jsonFiledInfos.get(jsonFiledInfos.size() - 1).getField()));
        }
      }
    }catch (Exception e){
      e.printStackTrace();
      log.error("json取值异常:",e);
      return null;
    }
    return EMPTY_STRING;
  }

  public static JSON getJsonIfExpressSingle(
      String content, Boolean curTypeObject, JsonFiledInfo curJsonFiledInfo) {
    if (curTypeObject) {
      return JSONObject.parseObject(content).getJSONObject(curJsonFiledInfo.getField());
    } else {
      return JSONArray.parseArray(content)
          .getJSONArray(Integer.parseInt(curJsonFiledInfo.getField()));
    }
  }

  public static JSON getJsonIfExpressMultiple(
      JSON json, Boolean curTypeObject, Boolean nextTypeObject, JsonFiledInfo curJsonFiledInfo) {
    if (curTypeObject) {
      JSONObject jsonObject = (JSONObject) json;
      if (nextTypeObject) {
        return jsonObject.getJSONObject(curJsonFiledInfo.getField());
      } else {
        return jsonObject.getJSONArray(curJsonFiledInfo.getField());
      }

    } else {
      JSONArray jsonArray = (JSONArray) json;
      if (nextTypeObject) {
        return jsonArray.getJSONObject(Integer.valueOf(curJsonFiledInfo.getField()));
      } else {
        return jsonArray.getJSONArray(Integer.valueOf(curJsonFiledInfo.getField()));
      }
    }
  }

   /**
   * 字符串List转按分隔符拼接后字符串
   *
   * @param stringList List<String> 字符串List
   * @param delimiter String 分隔符
   * @return String 拼接后的字符串
   * @author liting
   * @date 2018/10/29-13:45
   */
  public static String list2String(List<String> stringList, String delimiter) {
    return Joiner.on(delimiter).skipNulls().join(stringList);
  }
补充代码:
import lombok.Data;

/**
 * json字段信息
 *
 * @author LiTing
 * @date 2021/2/26 11:08
 **/
@Data
public class JsonFiledInfo {
    public static final String OBJECT_TYPE = "object";
    public static final String ARRAY_TYPE = "array";
    private String type = OBJECT_TYPE;
    private String field;
}

完毕

OK,代码完毕,跑一下目标的案例就行了。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的孤独与美酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值