当前位置:   article > 正文

关于JSON字符串中的字段名与Java类中的字段名不匹配的解决方法(@JsonProperty(““) 与@JSONField(name = ““)的使用 )

@jsonfield(name

1.1 背景

1.1.1 所谓的背景,也就是写这篇博客目的与原因是什么呢?

        最近在工作中遇到了一个非常奇葩的需求,通过WebService的方式去调第三方接口,但第三方接口的返回值是一个Xml结构,本来到这里并没什么奇怪。但接下来意外发生了,这个Xml结构的字段名是中文,而且我所需的节点中的数据还不是个JSON结构。所以我需要先将Xml节点中的数据解析出来,然后使用split进行分割,转化成JSON结构,最终对JSON做自定义对象的映射。但有个问题,我需要将该字段中文与Java实体字段相匹配,存到数据库中。但由于字段太多,如果用枚举或者if等方式一个一个匹配太麻烦了,还不够简洁,就想着有没有一个注解可以解决这个问题?

        首先我第一个想到的是MyBatis-Plus中,@TableField注解,但该注解主要用于实体类字段与数据库表字段的映射,与我的需求不符合(哈哈,因为毕业不久,我之前没遇到过这个问题,所以@JsonProperty("") 与@JSONField(name = "")这俩个注解我也是刚刚了解)。

        接着通过查阅了解到@JsonProperty("") 与@JSONField(name = "")的使用,经过测试我最终选用的是@JsonProperty("")。

1.2 关于@JsonProperty("")

1.2.1 简介

@JsonProperty 是 Jackson 库中的一个注解,用于在反序列化 JSON 数据时,将 JSON 对象中的某个属性映射到 Java 类中的某个字段上。

@JsonProperty 的语法格式为 @JsonProperty("propertyName"),其中 propertyName 是 JSON 对象中的属性名,也就是要映射到 Java 类中的字段名。

使用 @JsonProperty 注解可以确保 JSON 数据和 Java 类之间的字段名匹配,从而正确地进行反序列化。例如,如果 JSON 数据中有一个属性名为 "name",那么在 Java 类中应该有一个名为 "name" 的字段,并且使用 @JsonProperty("name") 注解进行标记,这样 Jackson 库就可以正确地将 JSON 数据中的 "name" 属性映射到 Java 类中的 "name" 字段上。

除了指定属性名之外,@JsonProperty 还支持一些其他的选项,例如可以设置字段的顺序、是否可序列化、是否可反序列化等。

总之,@JsonProperty 是 Jackson 库中用于反序列化 JSON 数据时进行字段映射的重要注解之一。

1.2.2 举个例子(@JsonProperty 不仅可以映射英文,还可以映射中文)

注:不要引错了依赖:import com.fasterxml.jackson.annotation.JsonProperty;

这里我就以映射中文举例了:

  1. import lombok.AllArgsConstructor;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. import com.fasterxml.jackson.annotation.JsonProperty;
  5. import java.io.Serializable;
  6. @Data
  7. @AllArgsConstructor
  8. @NoArgsConstructor
  9. public class UserBo implements Serializable {
  10. @JsonProperty("姓名")
  11. private String name;
  12. @JsonProperty("电话")
  13. private String phone;
  14. @JsonProperty("城市")
  15. private String city;
  16. }
  1. /**
  2. * @Author ZhaoShuHao
  3. * @Date 2023/11/11 15:09
  4. */
  5. public class UserController {
  6. public static void main(String[] args) throws IOException {
  7. String user = "{\"姓名\":\"张三\",\"城市\":\"北京\",\"电话\":\"1212323\"}";
  8. // UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);
  9. ObjectMapper objectMapper = new ObjectMapper();
  10. UserBo userBo1 = objectMapper.readValue(user, UserBo.class);
  11. System.out.println(userBo1);
  12. }
  13. }

1.3 关于@JSONField(name = "")

1.3.1 简介

@JSONField(name = "") 是 Jackson 库中的一个注解,用于在序列化或反序列化 JSON 数据时,将 Java 类中的某个字段映射到 JSON 对象中的某个属性上。

@JSONField 注解的语法格式为 @JSONField(name = "property_name"),其中 name 是 JSON 对象中的属性名,也就是要映射到 Java 类中的字段名。

使用 @JSONField 注解可以确保 Java 类和 JSON 数据之间的字段名匹配,从而正确地进行序列化或反序列化。例如,如果 Java 类中有一个名为 "name" 的字段,那么在 JSON 数据中应该有一个属性名为 "property_name",并且使用 @JSONField(name = "property_name") 注解进行标记,这样 Jackson 库就可以正确地将 Java 类中的 "name" 字段映射到 JSON 数据中的 "property_name" 属性上。

除了指定属性名之外,@JSONField 还支持一些其他的选项,例如可以设置字段的顺序、是否可序列化、是否可反序列化等。

总之,@JSONField 是 Jackson 库中用于序列化或反序列化 JSON 数据时进行字段映射的重要注解之一。

1.3.2 举个例子

注:查阅资料,@JSONField也可以映射中英文,但我映射中文没有成功,暂时没有找到问题所在,这里就以映射英文举例了

  1. import com.alibaba.fastjson.annotation.JSONField;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import java.io.Serializable;
  6. @Data
  7. @AllArgsConstructor
  8. @NoArgsConstructor
  9. public class UserBo implements Serializable {
  10. @JSONField(name = "names")
  11. // @JsonProperty("姓名")
  12. private String name;
  13. @JSONField(name = "phones")
  14. // @JsonProperty("电话")
  15. private String phone;
  16. @JSONField(name = "citys")
  17. // @JsonProperty("城市")
  18. private String city;
  19. }
  1. /**
  2. * @Author ZhaoShuHao
  3. * @Date 2023/11/11 15:09
  4. */
  5. public class UserController {
  6. public static void main(String[] args) throws IOException {
  7. // String user = "{\"姓名\":\"张三\",\"城市\":\"北京\",\"电话\":\"1212323\"}";
  8. String user = "{\"names\":\"张三\",\"citys\":\"北京\",\"phones\":\"1212323\"}";
  9. UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);
  10. /* ObjectMapper objectMapper = new ObjectMapper();
  11. UserBo userBo1 = objectMapper.readValue(user, UserBo.class);*/
  12. System.out.println(userBo1);
  13. }
  14. }

1.4 对于我所遇到的需求的解决方案

具体就不说了,直接步入正题。

1.4.1 结构

看看我的结构(不光是中文,结构还有些差异☺):

(1)

<Response>
    <resultCode>0</resultCode>
    <resultMessage>
        病例数:10,
        费用极高病例:0,
        费用极低病例:0,
        医疗总费用(元):507753.35,
        DRG支付标准(元):457775.76,
        盈亏额(元):-15109.75,
        次均盈亏额(元):-1510.98,
        DRG支付费用(元):182516.69,
        CMI:1,
        总权重:42.8062,
        入组率:80.00%,
        DRG组数:4,
        盈余病组:6,
        亏损病组:4,
        平均住院日:12.3,
        药品费(元):100457.29,
        药占比:19.66%,
        耗材费(元):164819.55,
        耗占比:32.46%,
        检查费(元):37136,
        检查费占比:7.31%,
        检验费(元):75670.5,
        检验费占比:14.90%,
        时间消耗指数:1.06,
        费用消耗指数:1.11
    </resultMessage>
</Response>

(2)这个更坑,key不仅是中文,还多了几个字,转化完Json,还要截取(刚开始没发现)

<Response>
    <resultCode>0</resultCode>
    <resultMessage>
        近一月:入径人数:37,
        完成人数:37,
        出径人数:0,
        出院人数:47,
        变异人数:0
    </resultMessage>
</Response>

1.4.2 解决方案

(1)先对xml进行解析,获取到resultMessage节点中的数据

(2)将节点中的数据拼接成一个字符串,去掉换行符

(3)因为解析出的数据不符合JSON格式,所以我们先用split进行分割,重新组装成Map结构

(4)将Map结构转化为Json字符串

(5)将Json字符串与自定义对象做映射

(6)因为好几个接口都需要解析xml,但映射的对象不同,返回类型不同,所以我这里用了泛型和反射

(7)又因为接口返回的xml中,数据的结构还有差异,所以我们还需一个类型,来判断是否需要做特殊处理

大功告成,代码如下:

  1. package com.lc.ibps.medical.utils;
  2. import com.alibaba.fastjson.JSON;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import com.lc.ibps.medical.enums.BizDataMethodEnums;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.w3c.dom.Document;
  7. import org.w3c.dom.Node;
  8. import org.w3c.dom.NodeList;
  9. import org.xml.sax.InputSource;
  10. import javax.xml.parsers.DocumentBuilder;
  11. import javax.xml.parsers.DocumentBuilderFactory;
  12. import java.io.StringReader;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. /**
  16. * Xml的解析工具类,根据泛型,动态返回不同的对象
  17. * @Author ZhaoShuHao
  18. * @Date 2023/11/10 15:52
  19. */
  20. @Slf4j
  21. public class ParseXmlUtils {
  22. /**
  23. * 解析xml为对应的对象
  24. * @param clazz 自定义对象的类
  25. * @param xmlString 需要解析的xml对象
  26. * @param code 接口标识(因为个别接口返回的结构不一样,所以这里对特别的结构进行处理)
  27. * @param <T> 自定义对象
  28. * @return
  29. * @throws Exception
  30. */
  31. public static <T> T getData(Class<T> clazz ,String xmlString,String code) throws Exception {
  32. //根据泛型,动态返回不同的对象
  33. T obj = clazz.getDeclaredConstructor().newInstance();
  34. // 创建一个 DocumentBuilderFactory 实例
  35. DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  36. // 创建 DocumentBuilder 实例
  37. DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
  38. InputSource is = new InputSource(new StringReader(xmlString));
  39. // 使用 parse 方法解析输入源
  40. Document doc = dBuilder.parse(is);
  41. // 检查解析是否成功
  42. if (doc != null) {
  43. log.info("解析输入源成功:"+doc);
  44. // 获取所有 name 节点
  45. NodeList nodes = doc.getElementsByTagName("resultMessage");
  46. StringBuilder stringBuilder = new StringBuilder();
  47. // 遍历所有的 name 节点
  48. for (int i = 0; i < nodes.getLength(); i++) {
  49. Node node = nodes.item(i);
  50. // 获取每个节点的文本内容
  51. stringBuilder.append(node.getTextContent());
  52. }
  53. //因为获取到的信息不符合Json格式,所以不能直接转化为Josn,或者通过JSON转其他格式,对字符串进行处理
  54. // 解析字符串为 Map
  55. String oldStr = String.valueOf(stringBuilder);
  56. String str = oldStr.replaceAll("\\n", "");
  57. //TODO (等接口调通还需确认)因为,个人临床路径数据和个人电子病历数据返回的结构有点变化,所以这里进行处理,去掉多余字符
  58. if(BizDataMethodEnums.MES0735.getCode().equals(code)||BizDataMethodEnums.MES0736.getCode().equals(code)){
  59. str = str.substring(4);
  60. }
  61. log.info("xml转字符串:"+str);
  62. Map<String, Object> map = new HashMap<>();
  63. String[] pairs = str.split(",");
  64. for (String pair : pairs) {
  65. String[] keyValue = pair.split(":");
  66. //解决value不存在的情况,默认给他设置为null
  67. if(keyValue.length==1){
  68. map.put(keyValue[0], null);
  69. }else {
  70. map.put(keyValue[0], keyValue[1]);
  71. }
  72. }
  73. log.info("字符串转map:"+map);
  74. // 将 Map 转换为 JSON 字符串
  75. String jsonString = JSON.toJSONString(map);
  76. log.info("map转Json:"+jsonString);
  77. ObjectMapper objectMapper = new ObjectMapper();
  78. //根据不同的类型返回不同的对象
  79. obj = (T) objectMapper.readValue(jsonString, obj.getClass());
  80. log.info("Json映射对象:"+obj);
  81. }
  82. return obj;
  83. }
  84. }
  1. @ApiModel(value = "DRG质量数据对象")
  2. public class DrgYearTbl extends AbstractPo<String>{
  3. @ApiModelProperty(value = "主键")
  4. @JsonProperty("主键")
  5. protected String id; /*主键*/
  6. @ApiModelProperty(value = "外键")
  7. @JsonProperty("外键")
  8. protected String parentId; /*外键*/
  9. @ApiModelProperty(value = "租户ID")
  10. @JsonProperty("租户ID")
  11. protected String tenantId; /*租户ID*/
  12. @ApiModelProperty(value = "IP地址")
  13. @JsonProperty("IP地址")
  14. protected String ip; /*IP地址*/
  15. @ApiModelProperty(value = "数据删除状态")
  16. @JsonProperty("数据删除状态")
  17. protected String deleted; /*数据删除状态*/
  18. @ApiModelProperty(value = "版本")
  19. @JsonProperty("版本")
  20. protected Long version; /*版本*/
  21. @ApiModelProperty(value = "序号")
  22. @JsonProperty("序号")
  23. protected Long orderNo; /*序号*/
  24. @ApiModelProperty(value = "流程状态")
  25. @JsonProperty("流程状态")
  26. protected String flowStatus; /*流程状态*/
  27. @ApiModelProperty(value = "部门")
  28. @JsonProperty("部门")
  29. protected String sysDeptId; /*部门*/
  30. @ApiModelProperty(value = "公司")
  31. @JsonProperty("公司")
  32. protected String sysOrgId; /*公司*/
  33. @ApiModelProperty(value = "姓名")
  34. @JsonProperty("姓名")
  35. protected String name; /*姓名*/
  36. @ApiModelProperty(value = "工号")
  37. @JsonProperty("工号")
  38. protected String number; /*工号*/
  39. @ApiModelProperty(value = "年度")
  40. @JsonProperty("年度")
  41. protected String year; /*年度*/
  42. @ApiModelProperty(value = "CMI")
  43. @JsonProperty("CMI")
  44. protected String cmi; /*CMI*/
  45. @ApiModelProperty(value = "平均住院日")
  46. @JsonProperty("平均住院日")
  47. protected String pjzyr; /*平均住院日*/
  48. @ApiModelProperty(value = "入组率")
  49. @JsonProperty("入组率")
  50. protected String rzl; /*入组率*/
  51. @ApiModelProperty(value = "药占比")
  52. @JsonProperty("药占比")
  53. protected String yzb; /*药占比*/
  54. @ApiModelProperty(value = "耗占比")
  55. @JsonProperty("耗占比")
  56. protected String hzb; /*耗占比*/
  57. @ApiModelProperty(value = "次均费")
  58. @JsonProperty("次均费")
  59. protected String cjf; /*次均费*/
  60. @ApiModelProperty(value = "检查占比")
  61. @JsonProperty("检查占比")
  62. protected String jczb; /*检查占比*/
  63. @ApiModelProperty(value = "耗材费(元)")
  64. @JsonProperty("耗材费(元)")
  65. protected String hcf; /*耗材费(元)*/
  66. @ApiModelProperty(value = "检查费(元)")
  67. @JsonProperty("检查费(元)")
  68. protected String jcf; /*检查费(元)*/
  69. @ApiModelProperty(value = "检查费占比")
  70. @JsonProperty("检查费占比")
  71. protected String jcfzb; /*检查费占比*/
  72. @ApiModelProperty(value = "检验费(元)")
  73. @JsonProperty("检验费(元)")
  74. protected String jyf; /*检验费(元)*/
  75. @ApiModelProperty(value = "检验费占比")
  76. @JsonProperty("检验费占比")
  77. protected String jyfzb; /*检验费占比*/
  78. @ApiModelProperty(value = "时间消耗指数")
  79. @JsonProperty("时间消耗指数")
  80. protected String sjxhzs; /*时间消耗指数*/
  81. @ApiModelProperty(value = "费用消耗指数")
  82. @JsonProperty("费用消耗指数")
  83. protected String fyxhzs; /*费用消耗指数*/
  84. @ApiModelProperty(value = "病例数")
  85. @JsonProperty("病例数")
  86. protected String bls; /*病例数*/
  87. @ApiModelProperty(value = "费用极高病例")
  88. @JsonProperty("费用极高病例")
  89. protected String fyjgbls; /*费用极高病例*/
  90. @ApiModelProperty(value = "费用极低病例")
  91. @JsonProperty("费用极低病例")
  92. protected String fyjdbls; /*费用极低病例*/
  93. @ApiModelProperty(value = "医疗总费用(元)")
  94. @JsonProperty("医疗总费用(元)")
  95. protected String ylzfy; /*医疗总费用(元)*/
  96. @ApiModelProperty(value = "DRG支付标准(元)")
  97. @JsonProperty("DRG支付标准(元)")
  98. protected String drgzfbz; /*DRG支付标准(元)*/
  99. @ApiModelProperty(value = "盈亏额(元)")
  100. @JsonProperty("盈亏额(元)")
  101. protected String yke; /*盈亏额(元)*/
  102. @ApiModelProperty(value = "次均盈亏额(元)")
  103. @JsonProperty("次均盈亏额(元)")
  104. protected String cjyke; /*次均盈亏额(元)*/
  105. @ApiModelProperty(value = "DRG支付费用(元)")
  106. @JsonProperty("DRG支付费用(元)")
  107. protected String drgzffy; /*DRG支付费用(元)*/
  108. @ApiModelProperty(value = "总权重")
  109. @JsonProperty("总权重")
  110. protected String zqz; /*总权重*/
  111. @ApiModelProperty(value = "DRG组数")
  112. @JsonProperty("DRG组数")
  113. protected String drgzs; /*DRG组数*/
  114. @ApiModelProperty(value = "盈余病组")
  115. @JsonProperty("盈余病组")
  116. protected String ykbz; /*盈余病组*/
  117. @ApiModelProperty(value = "亏损病组")
  118. @JsonProperty("亏损病组")
  119. protected String ksbz; /*亏损病组*/
  120. @ApiModelProperty(value = "药品费(元)")
  121. @JsonProperty("药品费(元)")
  122. protected String ypf; /*药品费(元)*/
  123. @ApiModelProperty(value = "月度")
  124. @JsonProperty("月度")
  125. protected String month; /*月度*/
  126. //省略get、set方法
  127. }
  1. /**调用该方法的代码,只粘贴有关的内容:**/
  2. String result = "<Response>\n" +
  3. " <resultCode>0</resultCode>\n" +
  4. " <resultMessage>病例数:10,\n" +
  5. "费用极高病例:0,\n" +
  6. "费用极低病例:0,\n" +
  7. "医疗总费用(元):507753.35,\n" +
  8. "DRG支付标准(元):457775.76,\n" +
  9. "盈亏额(元):-15109.75,\n" +
  10. "次均盈亏额(元):-1510.98,\n" +
  11. "DRG支付费用(元):182516.69,\n" +
  12. "CMI:,\n" +
  13. "总权重:42.8062,\n" +
  14. "入组率:80.00%,\n" +
  15. "DRG组数:4,\n" +
  16. "盈余病组:6,\n" +
  17. "亏损病组:4,\n" +
  18. "平均住院日:12.3,\n" +
  19. "药品费(元):100457.29,\n" +
  20. "药占比:19.66%,\n" +
  21. "耗材费(元):164819.55,\n" +
  22. "耗占比:32.46%,\n" +
  23. "检查费(元):37136,\n" +
  24. "检查费占比:7.31%,\n" +
  25. "检验费(元):75670.5,\n" +
  26. "检验费占比:14.90%,\n" +
  27. "时间消耗指数:1.06,\n" +
  28. "费用消耗指数:1.11</resultMessage>\n" +
  29. "</Response>";
  30. DrgYearTbl drgYearTbl = new DrgYearTbl();
  31. try {
  32. drgYearTbl=ParseXmlUtils.getData(DrgYearTbl.class,result,BizDataMethodEnums.MES0734.getCode());
  33. } catch (Exception e) {
  34. log.error("xml转对象出现异常:"+e);
  35. }

1.5 扩展(自定义工具类)

  1. public class ObjectConvertUtil {
  2. /**
  3. * @param sourceClass 源对象
  4. * @param targetClass 目的对象class
  5. * */
  6. public static <T,U> U objectConvert(T sourceClass, Class<U> targetClass){
  7. String sourceStr= JSON.toJSONString(sourceClass);
  8. return JSONObject.parseObject(sourceStr,targetClass);
  9. }
  10. }

想转什么对象,直接使用工具类去转就好了,省去很多麻烦,举个例子:

UserPo userpo = new UserPo();
User user = ObjectConvertUtil.objectConvert(userpo, User.class);

DogVo dogvo= new DogVo();
Dog dog= ObjectConvertUtil.objectConvert(dogvo, Dog.class);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/639769
推荐阅读
相关标签
  

闽ICP备14008679号