15课:关于自定义生成xml和解析xml的代码内容;
简介
现在的项目中请求和响应大多数使用的都是json个数的;但是有些需要调用三方的接口依然使用的是通过xml来接受参数以及响应结果的;就需要我们根据三方的要求生成指定格式的xml字符串,以及根据返回的xml格式字符串解析成map格式(或者对应的实体类)
项目demo下载
项目结构
生成的xml格式的样例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RootElement xmlns="https://www.baidu.com/">
<version>1.0</version>
<User>
<userName>小康康</userName>
<mobile>13051999560</mobile>
<age>10</age>
<money>200.22</money>
<birthday>2020-08-28T09:57:51.329+08:00</birthday>
<addressModel>
<address>北京市通州区</address>
<postCode>100010</postCode>
</addressModel>
</User>
<Order>
<orderId>20200811</orderId>
<orderName>淘宝商品</orderName>
</Order>
<Order>
<orderId>20200812</orderId>
<orderName>京东商品</orderName>
</Order>
<Msg>
<retCode>10000</retCode>
<retInfo>执行成功</retInfo>
</Msg>
</RootElement>
代码实现内容;
1.pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.khy.boot</groupId>
<artifactId>boot-xml</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- xml解析和设置的内容; -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--含有多个main 需要指定某一个启动class类 -->
<start-class>com.khy.SpringBootMainApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
主要需要引入的是
2.package-info.java
生成的xml根节点里面的xmlns 地址里面的链接内容;来自对于entity 包下面的package-info.java里面设置的;
@XmlSchema(namespace="https://www.baidu.com/", elementFormDefault= XmlNsForm.QUALIFIED)
package com.khy.entity;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
3.根节点里面的属性配置
package com.khy.entity;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* xml格式最外层的结构内容
* @author khy
* @createTime 2020年8月27日下午3:36:38
*/
@XmlRootElement(name = "RootElement")//指定xml最外层 root节点的名称
@XmlAccessorType(XmlAccessType.FIELD)
public class RootElement {
private String version;//root节点的version字段;
@XmlElement(name = "User")//标识root节点的子节点名称;
private UserModel userModel;
@XmlElement(name = "Order")//标识root节点的子节点名称;
private List<OrderModel> orders;
@XmlElement(name = "Msg")//标识root节点的子节点名称;
private MsgModel msgModel;
get/set省略/
}
@XmlRootElement 注解标识根节点的名称是;
@XmlElement标识根节点下面的属性名称是
当前案例中,我们的根节点下面有一个User节点以及一个List<Order>节点和一个Msg节点;
对应的User节点下面还有addressModel(属性如果不通过@XmlElement指定节点名称默认去字段属性)
其中对于的子节点中的属性配置
3.main入口方法
public static void main(String[] args) {
RootElement root = new RootElement();
root.setVersion("1.0");
UserModel user = new UserModel();
root.setUserModel(user);
user.setUserName("小康康");
user.setMobile("13051999560");
user.setMoney(new BigDecimal("200.22"));
user.setAge(10);
user.setBirthday(new Date());
user.setAddressModel(new AddressModel("北京市通州区", "100010"));
List<OrderModel>orders = new ArrayList<OrderModel>(){{
add(new OrderModel("20200811", "淘宝商品"));
add(new OrderModel("20200812", "京东商品"));
}};
root.setOrders(orders);
root.setMsgModel(new MsgModel("10000","执行成功"));
System.out.println(JSON.toJSONString(root));
String convertToXml = XMLUtil.convertToXml(root);
//这里打印的就是我们组装的xml格式的报文内容
System.out.println(convertToXml);
//解析对于的xml内容;
Element element = ParseXMLUtil.parseXML(convertToXml);
HashMap<String, Object> toMap = ParseXMLUtil.xmlToMap(element, "User", "Order");//设置我们需要解析的节点;
System.out.println(JSON.toJSONString(toMap));
HashMap<String, Object> xmlToMap = ParseXMLUtil.xmlToMap(element);
System.out.println(JSON.toJSONString(xmlToMap));
}
然后看一下代码中的打印的结果RootElement 转成json格式的数据的样式
然后看一下生成的xml 的样式内容
节点的名称不一样是因为model属性和@XmlElement 注解里面的设置的name不一样导致的;我们可以在RootElement 中将子节点属性名称@XmlElement注解给去掉这样的话就是一致的信息
然后看一下我们转成和实体类转成json相同目录结构的 map打印的结果
转成对应的map结构的数据内容;由于我们的key选择的是节点的名称所以导致的map打印成json格式和原来的RootElement对于转成json属性值不一样;
所以如果属性值是一样的可以转成map结构之后然后转成json字符串,在解析成我们指定的目标的对象内容;
4. XMLUtil.java
将目标对象转成xml格式的字符串输出
public static String convertToXml(Object obj) {
// 创建输出流
StringWriter sw = new StringWriter();
try {
// 利用jdk中自带的转换类实现
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
// 格式化xml输出的格式
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
// 将对象转换成输出流形式的xml
marshaller.marshal(obj, sw);
} catch (JAXBException e) {
e.printStackTrace();
}
return sw.toString();
}
5.ParseXMLUtil.java 解析xml转成map
/**
* 解析条件设置(如果root节点下的的子节点还有)
* @author khy
* @createTime 2020年8月27日下午5:20:37
* @param root
* @return
*/
public static HashMap<String,Object> xmlToMap(Element root){
if(null == root){
return null;
}
Element child=null; //定义一个Element元素对象
HashMap<String,Object> rootMap=new HashMap<String,Object>(); //初始化HashMap,用来保存得到的数据
//下面开始迭代循环
for (Iterator childs1= root.getChildren().iterator();childs1.hasNext();) {
child=(Element)childs1.next(); //获取每一个子元素
parseXml(child,rootMap);
}
//循环结束
return rootMap;
}
/**
* 通过递归解析对于的xml节点内容
* @author khy
* @createTime 2020年8月28日上午10:00:43
* @param child
* @param map
*/
private static void parseXml(Element child, Map<String, Object> map) {
String childName = child.getName(); //得到该节点的名称
boolean hasChild = hasChild(child);
if(hasChild){//说明下面没有子节点内容;
map.put(childName, child.getValue()); //将子元素保存到HashMap中
}else{
Object object = map.get(childName);
if(null == object){//标识没有设置过(则是map格式的)
Map<String,Object>childMap = new HashMap<String, Object>();
List children = child.getChildren();
for (Object obj : children) {
Element element = (Element) obj;
parseXml(element, childMap);
}
map.put(childName, childMap);
}else{//标识不等于空
if(object instanceof Map){
//标识第一次进来的设置的是map 然后需要将map转成List<Map>格式的;
List<Map<String,Object>>childList = new ArrayList<Map<String,Object>>();
childList.add((Map<String, Object>) object);
Map<String,Object>childMap = new HashMap<String, Object>();
List children = child.getChildren();
for (Object obj : children) {
Element element = (Element) obj;
parseXml(element, childMap);
}
childList.add(childMap);
map.put(childName, childList);
}else if(object instanceof List){
Map<String,Object>childMap = new HashMap<String, Object>();
List children = child.getChildren();
for (Object obj : children) {
Element element = (Element) obj;
parseXml(element, childMap);
}
List<Map<String,Object>>childList = (List<Map<String, Object>>) object;
childList.add(childMap);
map.put(childName, childList);
}
}
}
}
/**
* 是否有子节点
* @author khy
* @createTime 2020年8月27日下午5:31:00
* @param child
* @return
*/
private static boolean hasChild(Element child) {
List children = child.getChildren();
if(CollectionUtils.isEmpty(children)){
return true;
}
return false;
}
代码重要通过 jdk中自带的@Xml XXX注解来实现的功能内容;