自学内容网 自学内容网

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方法,这样就会正常序列化。


原文地址:https://blog.csdn.net/qq_54655539/article/details/145137709

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!