XML序列化和反序列化的学习

news/2025/1/15 22:46:14 标签: xml, java, 开发语言

1、基本介绍

        在工作中,经常为了调通上游接口,从而对请求第三方的参数进行XML序列化,这里常使用的方式就是使用JAVA扩展包中的相关注解和类来实现xml的序列化和反序列化。

2、自定义工具类

java">
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 1、实现 对象 转 xml
 * 2、实现 xml 转对象
 */
public class XmlInterfaceUtils {
    private static final ConcurrentHashMap<Class<?>, JAXBContext> contextMap =
            new ConcurrentHashMap<>();


    private static JAXBContext context(Class<?> clazz) {
        // JAXBContext 是线程安全的,可以在多个线程中复用
        // computeIfAbsent 方法,如果map集合存在相同的key,则覆盖value值;不存在相同key,则添加到map集合中
        return contextMap.computeIfAbsent(clazz, cls -> {
            try {
                return JAXBContext.newInstance(cls);
            } catch (JAXBException e) {
                throw new IllegalStateException(e);
            }
        });
    }

    public static String convertToXml(Object obj) {
        StringWriter sw = new StringWriter();
        JAXBContext context = context(obj.getClass());
        Marshaller marshaller;
        try {
            marshaller = context.createMarshaller();

            //1.格式化输出,即按标签自动换行,否则就是一行输出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);

            //2.设置编码(默认编码就是utf-8)
//            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

            //3.是否省略xml头信息,默认不省略(false)
            //   <?xml version="1.0" encoding="UTF-8">  这一句就是"头信息"
//            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);

            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            throw new IllegalStateException(e);
        }
        return sw.toString();
    }



    /**
     * xml转object
     *
     * @param clazz 转换类
     * @param xml   XML 字符串
     * @param <T>   对象类型
     * @return 转换结果
     */
    public static <T> T xmlToObject(Class<T> clazz, String xml) {
        JAXBContext context = context(clazz);

        // 每次都创建 Unmarshaller
        Unmarshaller unmarshaller;
        try {
            unmarshaller = context.createUnmarshaller();
        } catch (JAXBException e) {
            throw new IllegalStateException(e);
        }

        StringReader reader = new StringReader(xml);
        T message;
        try {
            message = (T) unmarshaller.unmarshal(reader);
        } catch (JAXBException e) {
            throw new IllegalStateException(e);
        }
        return message;
    }
}

3、模拟请求第三方的请求参数-V1.0

3.1  定义业务实体

Provider类

java">import javax.xml.bind.annotation.*;


@XmlRootElement
public class Provider {
    
    private User user;

    private String id;

    private Integer providerTelephone;

    private String providerAddress;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getProviderTelephone() {
        return providerTelephone;
    }

    public void setProviderTelephone(Integer providerTelephone) {
        this.providerTelephone = providerTelephone;
    }

    public String getProviderAddress() {
        return providerAddress;
    }

    public void setProviderAddress(String providerAddress) {
        this.providerAddress = providerAddress;
    }
}

User类 

java">public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

3.2  运行代码

java">
public class Application {

    public static void main(String[] args) {
        Provider provider = new Provider();
        User user = new User();
        user.setUsername("hu");
        user.setPassword("123456");
        provider.setUser(user);
        provider.setProviderTelephone(4008123);
        provider.setProviderAddress("BeiJing");
        provider.setId("No.1");

        //序列化成xml格式的字符串
        String xml = XmlInterfaceUtils.convertToXml(provider);
        System.out.println(xml);

        //反序列化成对象
        Provider provider1 = XmlInterfaceUtils.xmlToObject(Provider.class, xml);

    }
}

控制台打印结果 

必须要有一个@XmlRootElement用来标记哪个类作为根节点。否则,反序列化会失败,提示缺少 @XmlRootElement注解。

4、模拟请求第三方的请求参数-V2.0

        假如第三方发生改变,要求我们进行适配。

        将Provider类原本的id标签设置为根节点的属性,其他标签全部首字母大写,且按照手机号码,地址,用户信息的顺序进行反序列化,而User类的标签仍然是小写开头。

java">mport javax.xml.bind.annotation.*;

@XmlType(
        //指定序列化的时候,生成每个标签的顺序,不指定的话,默认按照从上到下的顺序生成
        propOrder = {"providerTelephone", "providerAddress", "user","id"}
)
@XmlRootElement(name = "Provider")
@XmlAccessorType(XmlAccessType.FIELD)
public class Provider {
    
    @XmlElement(name = "User")
    private User user;

    //该字段映射为一个属性
    @XmlAttribute(name = "id")
    private String id;

    @XmlElement(name = "ProviderTelephone")
    private Integer providerTelephone;

    @XmlElement(name = "ProviderAddress")
    private String providerAddress;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getProviderTelephone() {
        return providerTelephone;
    }

    public void setProviderTelephone(Integer providerTelephone) {
        this.providerTelephone = providerTelephone;
    }

    public String getProviderAddress() {
        return providerAddress;
    }

    public void setProviderAddress(String providerAddress) {
        this.providerAddress = providerAddress;
    }
}

运行结果如下

5、@XmlAccessorType的作用

        通过上面的例子可以发现,@XmlElement注解用来是生成子节点,@XmlAttribute注解用来生成节点的属性。

        那@XmlAccessorType注解的作用呢?

        默认序列化的时候,会根据类的get()方法生成一个子节点或者是属性,但是,我在字段名上又用@XmlElement标记了,这也会生出一个子节点。两个相同的子节点名称,就会导致反序列化失败。

因此,就需要用【 @XmlAccessorType(XmlAccessType.FIELD) 】来直接对类的字段进行映射,不考虑get方法,这样就会正常序列化。


http://www.niftyadmin.cn/n/5824416.html

相关文章

Mongodb相关内容

Mongodb相关内容 1、Windows平台安装2、Linux平台安装3、基本常用命令文档更新删除文档分页查询索引 pymongo操作 客户端下载&#xff1a;https://download.csdn.net/download/guoqingru0311/90273435 1、Windows平台安装 方式一&#xff1a; 方式2&#xff1a; 方式3&#…

【计算机网络】lab7 TCP协议

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;计算机网络_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 实验目的…

当自动包布机遇上Profinet转ModbusTCP网关,“妙啊”,工业智能“前景无限

在自动化控制技术日新月异的当下&#xff0c;Profinet与ModbusTCP这两种协议在工业通信领域占据着举足轻重的地位。ModbusTCP是基于以太网的串行通信协议&#xff0c;而Profinet则是依托工业以太网的现场总线协议。它们在数据传输速度、实时性表现以及兼容性等方面各具特色。不…

OpenCV相机标定与3D重建(54)解决透视 n 点问题(Perspective-n-Point, PnP)函数solvePnP()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 根据3D-2D点对应关系找到物体的姿态。 cv::solvePnP 是 OpenCV 库中的一个函数&#xff0c;用于解决透视 n 点问题&#xff08;Perspective-n-Po…

HTML5 滚动动画详解

HTML5 滚动动画详解 滚动动画是一种在用户滚动网页时触发的动态效果&#xff0c;可以增强用户体验并吸引用户注意力。下面将介绍如何使用 HTML5 和 CSS 创建简单的滚动动画。 1. 基本概念 滚动动画通常涉及以下几个要素&#xff1a; 触发条件&#xff1a;用户滚动到特定位置…

AI电商展台咒语分享丨新年红色护肤品

工具&#xff1a;startai 功能&#xff1a;flux文生图 咒语&#xff1a;New Year skin care shooting scene,Centered Composition,A red circular booth on the beige table,Next to the red gift box,Window background,Outside the window is the city night scene and bl…

注册中心及技术选型对比分析

注册中心是微服务架构中的核心组件之一&#xff0c;主要用于服务的管理和发现。以下是对注册中心及其技术选型的详细对比分析&#xff1a; 文章目录 一、注册中心的基本概念二、注册中心的关键功能三、注册中心的技术选型对比分析四、技术选型建议 一、注册中心的基本概念 注册…

Frida调试il2cpp的程序打印原生c#对象为json

主要的思路是&#xff0c;输入一个对象&#xff0c;那么使用反射的GetType, 然后使用type的GetFields&#xff0c; 拿到Field的列表&#xff0c;然后遍历field列表。 需要配合il2cpp原来程序里的一些json序列化的工具来进行&#xff0c;一般都可以找到&#xff0c;如下面的。…