@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);
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐