当前位置: 首页 > article >正文

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

1、基本介绍

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

2、自定义工具类


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类

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类 

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  运行代码


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类的标签仍然是小写开头。

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.kler.cn/a/507375.html

相关文章:

  • 使用 Docker 部署 Java 项目(通俗易懂)
  • c++ 中的容器 vector、deque 和 list 的区别
  • redis(2:数据结构)
  • Java中的依赖注入是什么?它如何工作?
  • OpenGL中Shader LOD失效
  • 深入理解计算机系统阅读笔记-第十二章
  • 50.AppendAllText C#例子
  • 成功案例分享 — 芯科科技助力涂鸦智能打造Matter over Thread模块,简化Matter设备开发
  • C#数据库操作系列---SqlSugar完结篇
  • 摄像头模块在狩猎相机中的应用
  • 【Unity-Animator】通过 StateMachineBehaviour 实现回调
  • 华为HCIE-Security考试心得
  • SpringMVC复习笔记
  • Oracle系列---【Smallfile模式的表空间如何确定单个数据文件的最大大小?】
  • 踏上 C++ 编程之旅:开篇之作
  • Observability:组装 OpenTelemetry NGINX Ingress Controller 集成
  • yt-dlp脚本下载音频可选设置代理
  • 探索 Linux:(一)介绍Linux历史与Linux环境配置
  • 鸿蒙UI开发——文本级联选择器
  • 基于Python招聘职位数据采集与数据可视化分析
  • 用 HTML5 Canvas 和 JavaScript 实现雪花飘落特效
  • 基于Matlab实现微带贴片天线仿真程序
  • 深入探索Vue.js 3中基于Composition API的动态组件开发
  • 源码编译http
  • 让iPhone自带浏览器Safari能自动播放Video视频的办法
  • Python----Python高级(面向对象:封装、继承、多态,方法,属性,拷贝,组合,单例)