在开发过程遇到xml与java对象相互转化的问题(调用三方webService接口)----JAXB

一、关于JAXB

JAXB是干什么的?

JAXB可以实现xml格式与对象之间的相互转换

JAXB相关知识点

1、JABX相关的类

  • XmlType类:用于绑定java实体与XML之间的信息
  • Marshaller接口:将Java实体序列化为XML数据
  • Unmarshaller接口:将XML数据反序列化为Java对象
    java实体与XML之间的相互转换最重要的就是后面两个接口。

2、JAXB相关注解

  • @XmlType
  • @XmlAccessorType
  • @XmlAccessOrder
  • @XmlJavaTypeAdapter
  • @XmlElementWrapper
  • @XmlRootElement
  • @XmlElement
  • @XmlAttribute
    具体的用法可以借鉴一下【1】【2】

比较常用的是
@XmlRootElement
@XmlElement
@XmlAccessType(XmlAccessType.FIELD)/(XmlAccessType.NONE)
@XmlElementWrapper

二、通过JAXB将java对象转化为xml格式(字符串)

util类(通用)

/**
	 * 将对象直接转换成String类型的 XML输出
	 *
	 * @param obj
	 * @return
	 */
	public static String convertToXml(Object obj, boolean formatted) {
		// 创建输出流
		StringWriter sw = new StringWriter();
		try {
			// 利用jdk中自带的转换类实现
			JAXBContext context = JAXBContext.newInstance(obj.getClass());

			Marshaller marshaller = context.createMarshaller();
			// 格式化xml输出的格式
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatted);
			//设置encoding为utf-16(默认utf-8)
//			marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-16");

			//修改xml报文头
			//隐去报文头的生成
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
			//自定义生成报文头
			sw.write("<?xml version=\"1.0\" encoding=\"utf-16\"?>\n");

			// 将对象转换成输出流形式的xml
			marshaller.marshal(obj, sw);
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		return sw.toString();
	}

java对象

@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "info")
public class OrderListDataDTO implements Serializable {
	private static final long serialVersionUID = -6669401393597013310L;

	@XmlElement(name = "number")
	private Integer number;

	@XmlElement(name = "message")
	private List<OrderListMessageDataDTO> messages;

}

要转化成下面xml格式

<soap:Envelope xmlns:soap=\"http://****/\" xmlns:xsd=\"http://****\" xmlns:xsi=\"http://****\"><soap:Body><ns1:findDealOrderInfoByUserIdResponse xmlns:ns1=\"http://****\"><ns1:out>&lt;?xml version='1.0' encoding='UTF-8'?>&lt;info>&lt;number>1&lt;/number>&lt;message orderId =\"01\" distId=\"05\" >&lt;/message>&lt;/info></ns1:out></ns1:findDealOrderInfoByUserIdResponse></soap:Body></soap:Envelope>

转化代码

		CreateDTO createDTO = new CreateDTO();
		createDTO.setOrderInfoXml(XmlAndObjectUtils.convertToXml(orderListDataDTO , false));
		XmlSoapEnvelopBodyDTO<CreateDTO> soapBody = XmlSoapEnvelopBodyDTO.build(createDTO);

		String requestDataXml = XmlAndObjectUtils.convertToXml(soapBody, true);

createDTO.java

@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "createOrder")
public class CreateDTO {
	@XmlAttribute
	private String xmlns = "http://***.com";

	private String orderInfoXml;

}
@Data
@XmlRootElement(name = "soap:Envelope")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({CreateDTO.class})
public class XmlSoapEnvelopBodyDTO<T> {

	@XmlAttribute(name = "xmlns:soap")
	private String soap = "http://****/";

	@XmlAttribute(name = "xmlns:xsi")
	private String xsi = "http://****";

	@XmlAttribute(name = "xmlns:xsd")
	private String xsd = "http://****";

	@XmlElement(name = "soap:Body")
	private SoapBody<T> body;

	public T getData() {
		return body.getData();
	}

	public static <T> XmlSoapEnvelopBodyDTO<T> build(T data) {
		XmlSoapEnvelopBodyDTO<T> b = new XmlSoapEnvelopBodyDTO<>();
		b.setBody(new SoapBody<>());
		b.body.setData(data);
		return b;
	}

	@Data
	@XmlAccessorType(XmlAccessType.FIELD)
	private static class SoapBody<T> {
		@XmlAnyElement(lax = true)
		private T data;
	}

}

三、通过JAXB将xml字符串转化为java对象

要转化的xml,可以复制去网上的xml格式化工具格式化一下

<soap:Envelope xmlns:soap=\"http://****" xmlns:xsd=\"http://****" xmlns:xsi=\"http://****"><soap:Body><ns1:create xmlns:ns1=\"http://****"><ns1:out>&lt;?xml version='1.0' encoding='UTF-8'?>&lt;info>&lt;flag>0&lt;/flag>&lt;message>成功&lt;/message>&lt;/info></ns1:out></ns1:createOrderResponse></soap:Body></soap:Envelope>";

转化后的java对象如下:

public class result{
	private Integer flag;
	private String message;
}

开始整起

介绍一下util类(通用),可以直接拿去使用

/**
	 * 将XML转换为java对象
	 * @param xml
	 * @return
	 */
	public static DealOrderXmlDTO xmlToObject(String xml){
		if (xml.equals("")){
			return null;
		}
		DealOrderXmlDTO dto = null;
		JAXBContext context = null;
		try {
			context = JAXBContext.newInstance(DealOrderXmlDTO.class);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			dto = (DealOrderXmlDTO)unmarshaller.unmarshal(new StringReader(xml));
		} catch (JAXBException e) {
			e.printStackTrace();
		}

		return dto;
	}

xml最外层包装类

@Data
@XmlRootElement(name = "soap:Envelope")
@XmlAccessorType(XmlAccessType.FIELD)
//xml转对象:CreateResponseBodyDTO.class
@XmlSeeAlso({CreateResponseBodyDTO.class})
public class XmlSoapEnvelopBodyDTO<T> {

	@XmlAttribute(name = "xmlns:soap")
	private String soap = "http://****";

	@XmlAttribute(name = "xmlns:xsi")
	private String xsi = "http://****";

	@XmlAttribute(name = "xmlns:xsd")
	private String xsd = "http://****";

	@XmlElement(name = "soap:Body")
	private SoapBody<T> body;

	public T getData() {
		return body.getData();
	}

	public static <T> XmlSoapEnvelopBodyDTO<T> build(T data) {
		XmlSoapEnvelopBodyDTO<T> b = new XmlSoapEnvelopBodyDTO<>();
		b.setBody(new SoapBody<>());
		b.body.setData(data);
		return b;
	}

	@Data
	@XmlAccessorType(XmlAccessType.FIELD)
	private static class SoapBody<T> {
		@XmlAnyElement(lax = true)
		private T data;
	}

}

xml次层包装类-body

@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ns1:create")
public class CreateResponseBodyDTO {

	@XmlAttribute(name = "xmlns:ns1")
	private String ns1;

	@XmlElement(name = "ns1:out")
	private String out;

}

真正的实体类

@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "info")
public class Result {
	private Integer flag;
	private String message;
}

转化的代码

//通过两次转化
XmlSoapEnvelopBodyDTO<CreateResponseBodyDTO> b = XmlAndObjectUtils.xmlToObject(resultXml, XmlSoapEnvelopBodyDTO.class);
XmlAndObjectUtils.xmlToObject(b.getData().getOut(), CreateResultDataDTO.class);

四、补充

当java对象转化为xml时,若对象的某个字段值为null,则会导致生成的xml不会出现对象的标签,目前为止,还没有找到比较好的解决办法,网上也只是说在定义该字段时,给一个默认值(如:“”)。若还有更好的解决办法,欢迎在评论区解答。

参考:https://www.jianshu.com/p/795ccdc0caf0?from=groupmessage

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值