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;

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

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.io.Serializable;

@Data

@AllArgsConstructor

@NoArgsConstructor

public class UserBo implements Serializable {

@JsonProperty("姓名")

private String name;

@JsonProperty("电话")

private String phone;

@JsonProperty("城市")

private String city;

}

/**

* @Author ZhaoShuHao

* @Date 2023/11/11 15:09

*/

public class UserController {

public static void main(String[] args) throws IOException {

String user = "{\"姓名\":\"张三\",\"城市\":\"北京\",\"电话\":\"1212323\"}";

// UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);

ObjectMapper objectMapper = new ObjectMapper();

UserBo userBo1 = objectMapper.readValue(user, UserBo.class);

System.out.println(userBo1);

}

}

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也可以映射中英文,但我映射中文没有成功,暂时没有找到问题所在,这里就以映射英文举例了

import com.alibaba.fastjson.annotation.JSONField;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data

@AllArgsConstructor

@NoArgsConstructor

public class UserBo implements Serializable {

@JSONField(name = "names")

// @JsonProperty("姓名")

private String name;

@JSONField(name = "phones")

// @JsonProperty("电话")

private String phone;

@JSONField(name = "citys")

// @JsonProperty("城市")

private String city;

}

/**

* @Author ZhaoShuHao

* @Date 2023/11/11 15:09

*/

public class UserController {

public static void main(String[] args) throws IOException {

// String user = "{\"姓名\":\"张三\",\"城市\":\"北京\",\"电话\":\"1212323\"}";

String user = "{\"names\":\"张三\",\"citys\":\"北京\",\"phones\":\"1212323\"}";

UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);

/* ObjectMapper objectMapper = new ObjectMapper();

UserBo userBo1 = objectMapper.readValue(user, UserBo.class);*/

System.out.println(userBo1);

}

}

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

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

1.4.1 结构

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

(1)

    0             病例数: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     

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

    0             近一月:入径人数:37,         完成人数:37,         出径人数:0,         出院人数:47,         变异人数:0     

1.4.2 解决方案

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

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

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

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

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

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

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

大功告成,代码如下:

package com.lc.ibps.medical.utils;

import com.alibaba.fastjson.JSON;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.lc.ibps.medical.enums.BizDataMethodEnums;

import lombok.extern.slf4j.Slf4j;

import org.w3c.dom.Document;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import java.io.StringReader;

import java.util.HashMap;

import java.util.Map;

/**

* Xml的解析工具类,根据泛型,动态返回不同的对象

* @Author ZhaoShuHao

* @Date 2023/11/10 15:52

*/

@Slf4j

public class ParseXmlUtils {

/**

* 解析xml为对应的对象

* @param clazz 自定义对象的类

* @param xmlString 需要解析的xml对象

* @param code 接口标识(因为个别接口返回的结构不一样,所以这里对特别的结构进行处理)

* @param 自定义对象

* @return

* @throws Exception

*/

public static T getData(Class clazz ,String xmlString,String code) throws Exception {

//根据泛型,动态返回不同的对象

T obj = clazz.getDeclaredConstructor().newInstance();

// 创建一个 DocumentBuilderFactory 实例

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

// 创建 DocumentBuilder 实例

DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();

InputSource is = new InputSource(new StringReader(xmlString));

// 使用 parse 方法解析输入源

Document doc = dBuilder.parse(is);

// 检查解析是否成功

if (doc != null) {

log.info("解析输入源成功:"+doc);

// 获取所有 name 节点

NodeList nodes = doc.getElementsByTagName("resultMessage");

StringBuilder stringBuilder = new StringBuilder();

// 遍历所有的 name 节点

for (int i = 0; i < nodes.getLength(); i++) {

Node node = nodes.item(i);

// 获取每个节点的文本内容

stringBuilder.append(node.getTextContent());

}

//因为获取到的信息不符合Json格式,所以不能直接转化为Josn,或者通过JSON转其他格式,对字符串进行处理

// 解析字符串为 Map

String oldStr = String.valueOf(stringBuilder);

String str = oldStr.replaceAll("\\n", "");

//TODO (等接口调通还需确认)因为,个人临床路径数据和个人电子病历数据返回的结构有点变化,所以这里进行处理,去掉多余字符

if(BizDataMethodEnums.MES0735.getCode().equals(code)||BizDataMethodEnums.MES0736.getCode().equals(code)){

str = str.substring(4);

}

log.info("xml转字符串:"+str);

Map map = new HashMap<>();

String[] pairs = str.split(",");

for (String pair : pairs) {

String[] keyValue = pair.split(":");

//解决value不存在的情况,默认给他设置为null

if(keyValue.length==1){

map.put(keyValue[0], null);

}else {

map.put(keyValue[0], keyValue[1]);

}

}

log.info("字符串转map:"+map);

// 将 Map 转换为 JSON 字符串

String jsonString = JSON.toJSONString(map);

log.info("map转Json:"+jsonString);

ObjectMapper objectMapper = new ObjectMapper();

//根据不同的类型返回不同的对象

obj = (T) objectMapper.readValue(jsonString, obj.getClass());

log.info("Json映射对象:"+obj);

}

return obj;

}

}

@ApiModel(value = "DRG质量数据对象")

public class DrgYearTbl extends AbstractPo{

@ApiModelProperty(value = "主键")

@JsonProperty("主键")

protected String id; /*主键*/

@ApiModelProperty(value = "外键")

@JsonProperty("外键")

protected String parentId; /*外键*/

@ApiModelProperty(value = "租户ID")

@JsonProperty("租户ID")

protected String tenantId; /*租户ID*/

@ApiModelProperty(value = "IP地址")

@JsonProperty("IP地址")

protected String ip; /*IP地址*/

@ApiModelProperty(value = "数据删除状态")

@JsonProperty("数据删除状态")

protected String deleted; /*数据删除状态*/

@ApiModelProperty(value = "版本")

@JsonProperty("版本")

protected Long version; /*版本*/

@ApiModelProperty(value = "序号")

@JsonProperty("序号")

protected Long orderNo; /*序号*/

@ApiModelProperty(value = "流程状态")

@JsonProperty("流程状态")

protected String flowStatus; /*流程状态*/

@ApiModelProperty(value = "部门")

@JsonProperty("部门")

protected String sysDeptId; /*部门*/

@ApiModelProperty(value = "公司")

@JsonProperty("公司")

protected String sysOrgId; /*公司*/

@ApiModelProperty(value = "姓名")

@JsonProperty("姓名")

protected String name; /*姓名*/

@ApiModelProperty(value = "工号")

@JsonProperty("工号")

protected String number; /*工号*/

@ApiModelProperty(value = "年度")

@JsonProperty("年度")

protected String year; /*年度*/

@ApiModelProperty(value = "CMI")

@JsonProperty("CMI")

protected String cmi; /*CMI*/

@ApiModelProperty(value = "平均住院日")

@JsonProperty("平均住院日")

protected String pjzyr; /*平均住院日*/

@ApiModelProperty(value = "入组率")

@JsonProperty("入组率")

protected String rzl; /*入组率*/

@ApiModelProperty(value = "药占比")

@JsonProperty("药占比")

protected String yzb; /*药占比*/

@ApiModelProperty(value = "耗占比")

@JsonProperty("耗占比")

protected String hzb; /*耗占比*/

@ApiModelProperty(value = "次均费")

@JsonProperty("次均费")

protected String cjf; /*次均费*/

@ApiModelProperty(value = "检查占比")

@JsonProperty("检查占比")

protected String jczb; /*检查占比*/

@ApiModelProperty(value = "耗材费(元)")

@JsonProperty("耗材费(元)")

protected String hcf; /*耗材费(元)*/

@ApiModelProperty(value = "检查费(元)")

@JsonProperty("检查费(元)")

protected String jcf; /*检查费(元)*/

@ApiModelProperty(value = "检查费占比")

@JsonProperty("检查费占比")

protected String jcfzb; /*检查费占比*/

@ApiModelProperty(value = "检验费(元)")

@JsonProperty("检验费(元)")

protected String jyf; /*检验费(元)*/

@ApiModelProperty(value = "检验费占比")

@JsonProperty("检验费占比")

protected String jyfzb; /*检验费占比*/

@ApiModelProperty(value = "时间消耗指数")

@JsonProperty("时间消耗指数")

protected String sjxhzs; /*时间消耗指数*/

@ApiModelProperty(value = "费用消耗指数")

@JsonProperty("费用消耗指数")

protected String fyxhzs; /*费用消耗指数*/

@ApiModelProperty(value = "病例数")

@JsonProperty("病例数")

protected String bls; /*病例数*/

@ApiModelProperty(value = "费用极高病例")

@JsonProperty("费用极高病例")

protected String fyjgbls; /*费用极高病例*/

@ApiModelProperty(value = "费用极低病例")

@JsonProperty("费用极低病例")

protected String fyjdbls; /*费用极低病例*/

@ApiModelProperty(value = "医疗总费用(元)")

@JsonProperty("医疗总费用(元)")

protected String ylzfy; /*医疗总费用(元)*/

@ApiModelProperty(value = "DRG支付标准(元)")

@JsonProperty("DRG支付标准(元)")

protected String drgzfbz; /*DRG支付标准(元)*/

@ApiModelProperty(value = "盈亏额(元)")

@JsonProperty("盈亏额(元)")

protected String yke; /*盈亏额(元)*/

@ApiModelProperty(value = "次均盈亏额(元)")

@JsonProperty("次均盈亏额(元)")

protected String cjyke; /*次均盈亏额(元)*/

@ApiModelProperty(value = "DRG支付费用(元)")

@JsonProperty("DRG支付费用(元)")

protected String drgzffy; /*DRG支付费用(元)*/

@ApiModelProperty(value = "总权重")

@JsonProperty("总权重")

protected String zqz; /*总权重*/

@ApiModelProperty(value = "DRG组数")

@JsonProperty("DRG组数")

protected String drgzs; /*DRG组数*/

@ApiModelProperty(value = "盈余病组")

@JsonProperty("盈余病组")

protected String ykbz; /*盈余病组*/

@ApiModelProperty(value = "亏损病组")

@JsonProperty("亏损病组")

protected String ksbz; /*亏损病组*/

@ApiModelProperty(value = "药品费(元)")

@JsonProperty("药品费(元)")

protected String ypf; /*药品费(元)*/

@ApiModelProperty(value = "月度")

@JsonProperty("月度")

protected String month; /*月度*/

//省略get、set方法

}

/**调用该方法的代码,只粘贴有关的内容:**/

String result = "\n" +

" 0\n" +

" 病例数:10,\n" +

"费用极高病例:0,\n" +

"费用极低病例:0,\n" +

"医疗总费用(元):507753.35,\n" +

"DRG支付标准(元):457775.76,\n" +

"盈亏额(元):-15109.75,\n" +

"次均盈亏额(元):-1510.98,\n" +

"DRG支付费用(元):182516.69,\n" +

"CMI:,\n" +

"总权重:42.8062,\n" +

"入组率:80.00%,\n" +

"DRG组数:4,\n" +

"盈余病组:6,\n" +

"亏损病组:4,\n" +

"平均住院日:12.3,\n" +

"药品费(元):100457.29,\n" +

"药占比:19.66%,\n" +

"耗材费(元):164819.55,\n" +

"耗占比:32.46%,\n" +

"检查费(元):37136,\n" +

"检查费占比:7.31%,\n" +

"检验费(元):75670.5,\n" +

"检验费占比:14.90%,\n" +

"时间消耗指数:1.06,\n" +

"费用消耗指数:1.11\n" +

"";

DrgYearTbl drgYearTbl = new DrgYearTbl();

try {

drgYearTbl=ParseXmlUtils.getData(DrgYearTbl.class,result,BizDataMethodEnums.MES0734.getCode());

} catch (Exception e) {

log.error("xml转对象出现异常:"+e);

}

1.5 扩展(自定义工具类)

public class ObjectConvertUtil {

/**

* @param sourceClass 源对象

* @param targetClass 目的对象class

* */

public static U objectConvert(T sourceClass, Class targetClass){

String sourceStr= JSON.toJSONString(sourceClass);

return JSONObject.parseObject(sourceStr,targetClass);

}

}

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

UserPo userpo = new UserPo();

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

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

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: