SpringBoot之jackson之复杂XML和Object互转、泛型、List、传参/接参、忽略未知变量
SpringBoot之jackson之复杂XML和Object互转、泛型、List、传参/接参、忽略未知变量
@JacksonXmlRootElement 注解用于对象,表示对象的名称节点
@JacksonXmlProperty注解用于变量,表示(反)序列化变量的名称
@JacksonXmlElementWrapper 注解用于集合变量,表示(反)序列化集合变量的名称。如:List<?>等
@JsonIgnoreProperties(ignoreUnknown = true) 注解表示忽略未知的反序列化的变量
引入依赖
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- jackson xml 转换工具 -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
创建第1层请求对象Bsxml
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.io.Serializable;
@Data
@JacksonXmlRootElement(localName = "Bsxml") //XML根节点名称
public class Bsxml<T> implements Serializable {
@JacksonXmlProperty(localName = "MsgHeader")
private MsgHeader msgHeader;//请求头对象
@JacksonXmlProperty(localName = "MsgBody")
private T msgBody;//泛型消息体,我这里的泛型是可以去掉的,直接用MsgBody对象,这里只是为了模拟复杂对象。
}
创建第2层请求头对象MsgHeader
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.io.Serializable;
@Data
@ToString
@JacksonXmlRootElement(localName = "MsgHeader")
public class MsgHeader implements Serializable {
@JacksonXmlProperty(localName = "Organization")
private String organization;
@JacksonXmlProperty(localName = "Sender")
private String sender;
@JacksonXmlProperty(localName = "ServiceType")
private String serviceType;
@JacksonXmlProperty(localName = "MsgType")
private String msgType;
@JacksonXmlProperty(localName = "MsgVersion")
private String msgVersion;
}
创建第2层请求头体MsgData
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
/**
* MsgBody对象就是Bsxml里面的泛型T
*/
@Data
@JacksonXmlRootElement(localName = "MsgBody")
public class MsgBody<D> {
@JacksonXmlProperty(localName = "Status")
private Boolean status;//状态
@JacksonXmlProperty(localName = "Code")
private Integer code;//成功状态码
@JacksonXmlProperty(localName = "ErrCode")
private Integer errCode;//错误状态码
@JacksonXmlProperty(localName = "Detail")
private String detail;//详细信息
@JacksonXmlProperty(localName = "Data")
private D data;//返回数据,泛型
}
创建第2层请求头体MsgData内层某个Data泛型对象
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
/**
* LabReportAudit对象就是MsgBody里面的泛型 D
*/
@Data
@JacksonXmlRootElement(localName = "Data")
public class LabReportAudit {
@JacksonXmlProperty(localName = "Name")
private String name;
}
模拟Controller接参传参
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("test")
public class TestController {
/**
* 传xml转json,json转对象
* @param bsxml Bsxml<T<D>>
*/
@PostMapping("xmlToObject")
public void xmlToObject(@RequestBody Bsxml<MsgBody<LabReportAudit>> bsxml) throws JsonProcessingException {
log.info("Bsxml转成实体后的信息:{}",bsxml);
ObjectMapper objectMapper = new ObjectMapper();
log.info("bsxml JSON:{}", objectMapper.writeValueAsString(bsxml));
}
/**
* 传json转成对象,对象转xml
* @param bsxml 实体类json
*/
@PostMapping("objectToXml")
public void objectToXml(@RequestBody Bsxml<MsgBody<LabReportAudit>> bsxml) throws JsonProcessingException {
ObjectMapper objectMapper = new XmlMapper();
String xmlString = objectMapper.writeValueAsString(bsxml);
log.info("对象转xml:{}", xmlString);
}
}
Postman传参
xmlToObject
传参
<Bsxml>
<MsgHeader>
<Organization>123456789</Organization>
<Sender>Meta39</Sender>
<ServiceType>service</ServiceType>
<MsgType>msgType</MsgType>
<MsgVersion>1.0</MsgVersion>
</MsgHeader>
<MsgBody>
<Code>1</Code>
<Status>true</Status>
<Detail>描述信息</Detail>
<Data>
<Name>名称</Name>
</Data>
</MsgBody>
</Bsxml>
转换
objectToXml
传参
{
"msgHeader": {
"organization": "123456789",
"sender": "Meta39",
"serviceType": "service",
"msgType": "msgType",
"msgVersion": "1.0"
},
"msgBody": {
"status": true,
"code": 1,
"errCode": null,
"detail": "描述信息",
"data": {
"name": "名称"
}
}
}
转换
List的转换
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
@JacksonXmlRootElement(localName = "Xml")//自定义根路径名称
public class XmlObeject implements Serializable {
@JacksonXmlProperty(localName = "Name")
private String name;
/**
* JacksonXmlElementWrapper注解用于指定列表或数组属性在XML中的包装元素,以提供更好的结构化层次和语义意义。
* 简单理解就是外层用@JacksonXmlElementWrapper,内层用@JacksonXmlProperty。
*/
@JacksonXmlElementWrapper(localName = "XmlObejectInfos")//JacksonXmlElementWrapper用于集合
private List<XmlObejectInfo> xmlObejectInfos;
}
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.io.Serializable;
@Data
@JacksonXmlRootElement(localName = "XmlInfo")
public class XmlObejectInfo implements Serializable {
@JacksonXmlProperty(localName = "Age")
private Integer age;
}
转换
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class JacksonXmlTests {
@Test
void test() throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
XmlObeject xmlObeject = new XmlObeject();
xmlObeject.setName("XML");
//集合
List<XmlObejectInfo> xmlObejectInfos = new ArrayList<>();
XmlObejectInfo xmlObejectInfo = new XmlObejectInfo();
xmlObejectInfo.setAge(25);
xmlObejectInfos.add(xmlObejectInfo);
xmlObeject.setXmlObejectInfos(xmlObejectInfos);
//序列化成XML字符串
String xmlString = xmlMapper.writeValueAsString(xmlObeject);
log.info("{}", xmlString);
//反序列化成Java对象
XmlObeject xmlObj = xmlMapper.readValue(xmlString, XmlObeject.class);
log.info("{}", xmlObj);
}
}
拓展
有时候我们序列化内容可能无法转换成我们想要的,因为内层的@JacksonXmlRootElement(localName = “XXX”),没有生效,我们可以用反射获取到传过来的类,然后获取JacksonXmlRootElement的注解,序列化成字符串后通过.replace(“”, “<”+otherHeader+“>”).replace(“”, “</”+otherHeader+“>”)的方式替换掉我们的请求头。
ObjectMapperUtils
工具类把泛型Data标签替换具体类的根别名
/**
* 替换Data的名称为实体类的@JacksonXmlRootElement注解localName的值
* @param object 实体类
*/
public static <T> String objectToXmlReplaceMsgBodyDataName(T object, Class<?> clazz){
try {
String JacksonXmlRootElementlocalNameValue = clazz.getAnnotation(JacksonXmlRootElement.class).localName();//获取类的@JacksonXmlRootElement注解localName的值
String xmlMetaString = xmlMapper.writeValueAsString(object);//原始xml数据,替换<Data></Data>为clazz的@JacksonXmlRootElement注解localName的值
return xmlMetaString
.replace("<Data>","<"+JacksonXmlRootElementlocalNameValue+">")
.replace("</Data>","</"+JacksonXmlRootElementlocalNameValue+">");
} catch (JsonProcessingException e) {
log.error("objectToXml error:", e);
throw Err.msg("objectToXml error:" + e.getMessage());
}
}
使用
@Data
@ToString
@JacksonXmlRootElement(localName = "LabBarcode")
public class LabBarcodeDTO {
}
上面这个@JacksonXmlRootElement(localName = “LabBarcode”)会不生效,因为会被上一层级的泛型Data所覆盖。所以要用通过传入具体的类,通过反射获取@JacksonXmlRootElement注解对应localName变量的值。
//泛型类里默认是<Data> 》》》<LabBarcode>
ObjectMapperUtils.objectToXmlReplaceMsgBodyDataName(bsxml, LabBarcodeDTO.class));
头部追加<?xml version='1.0' encoding='UTF-8'?>
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)