赞
踩
最近在工作中遇到了一个非常奇葩的需求,通过WebService的方式去调第三方接口,但第三方接口的返回值是一个Xml结构,本来到这里并没什么奇怪。但接下来意外发生了,这个Xml结构的字段名是中文,而且我所需的节点中的数据还不是个JSON结构。所以我需要先将Xml节点中的数据解析出来,然后使用split进行分割,转化成JSON结构,最终对JSON做自定义对象的映射。但有个问题,我需要将该字段中文与Java实体字段相匹配,存到数据库中。但由于字段太多,如果用枚举或者if等方式一个一个匹配太麻烦了,还不够简洁,就想着有没有一个注解可以解决这个问题?
首先我第一个想到的是MyBatis-Plus中,@TableField注解,但该注解主要用于实体类字段与数据库表字段的映射,与我的需求不符合(哈哈,因为毕业不久,我之前没遇到过这个问题,所以@JsonProperty("") 与@JSONField(name = "")这俩个注解我也是刚刚了解)。
接着通过查阅了解到@JsonProperty("") 与@JSONField(name = "")的使用,经过测试我最终选用的是@JsonProperty("")。
@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 数据时进行字段映射的重要注解之一。
@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);
- }
- }
@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 数据时进行字段映射的重要注解之一。
注:查阅资料,@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)
<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)先对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 <T> 自定义对象
- * @return
- * @throws Exception
- */
- public static <T> T getData(Class<T> 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<String, Object> 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<String>{
- @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 = "<Response>\n" +
- " <resultCode>0</resultCode>\n" +
- " <resultMessage>病例数: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</resultMessage>\n" +
- "</Response>";
- DrgYearTbl drgYearTbl = new DrgYearTbl();
- try {
- drgYearTbl=ParseXmlUtils.getData(DrgYearTbl.class,result,BizDataMethodEnums.MES0734.getCode());
- } catch (Exception e) {
- log.error("xml转对象出现异常:"+e);
- }
- public class ObjectConvertUtil {
-
- /**
- * @param sourceClass 源对象
- * @param targetClass 目的对象class
- * */
- public static <T,U> U objectConvert(T sourceClass, Class<U> 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);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。