前言
调用一些soap协议的项目你或许使用的到,也许我是在造轮子,但是我没在网上找到合适的轮子,就根据现有的项目自己造了一个,废话不说,说思路
使用反射获取对象的属性,根据属性的类型做出相应的处理,如果为基本类型直接使用dom4j创建节点赋值,如果遇到的集合递归处理集合中的对象,并生成相应的节点
自定义了几个注解处理相应的 标签别名、根对象别名、属性为集合类型的别名
先引入依赖
<dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.1</version></dependency>
项目背景,调用soap协议的项目,但是xml参数有点和想想中的不一样,下面看一下
属性大部分都是下划线命名;
如果你直接创建的java对象也使用这样的命名,然后使用 dom4j的Document也能生成,但是以前学习的时候 命名规范是不是驼峰命名法
代码
自定义注解
package com.zxw.xml.annotation;import java.lang.annotation.*;/*** @author zhangxuewei* @description 标签内的属性注解* @date 2023/7/6 17:08*/
@Target({ElementType.TYPE,ElementType.FIELD})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlAttributeName {String tagName() default "";// 标签名称
}
package com.zxw.xml.annotation;import java.lang.annotation.*;/*** @author zhangxuewei* @description 标签根对象的 标签别名 注解* @date 2023/7/6 17:07*/
@Target({ElementType.TYPE})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlRootElementName {String tagName() default "";// 标签名称}
package com.zxw.xml.annotation;import java.lang.annotation.*;/*** @author zhangxuewei* @description 对象属性的标签别名注解* @date 2023/7/6 17:09*/
@Target({ElementType.TYPE,ElementType.FIELD})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlTagName {String tagName() default "";// 标签名称/*** 如果属性为List,需要在集合对象追加标签名称,使用这个属性** 使用样例* public class SyncNcRecSettleBIillVO {* @XmlTagName(tagName = "items", arrayObjTagName = "item")* private List<RecSettleBIillDetail> items;* ....* }** <items>* <item>* <billdetail_no></billdetail_no>* <memo></memo>* <pk_account></pk_account>* </item>* <item>* <billdetail_no></billdetail_no>* <memo></memo>* <pk_account></pk_account>* </item>* </items>* @return*/String arrayObjTagName() default "";
}
需要生成xml的java对象
package com.zxw.xml.domain.vo;import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;/*** @projectName: ruoyi* @package: com.ruoyi.bmp.fi.domain.vo* @className: SyncNcUfinterface* @author: zhangxuewei* @description: TODO* @date: 2023/7/6 13:57* @version: 1.0*/
@XmlRootElementName(tagName = "ufinterface")
public class SyncNcUfinterface {@XmlAttributeName(tagName = "account")private String account = "develop";@XmlAttributeName(tagName = "billtype")private String billtype;@XmlAttributeName(tagName = "filename")private String filename;@XmlAttributeName(tagName = "groupcode")private String groupcode;@XmlAttributeName(tagName = "isexchange")private String isexchange = "Y";@XmlAttributeName(tagName = "replace")private String replace = "Y";@XmlAttributeName(tagName = "roottag")private String roottag;@XmlAttributeName(tagName = "sender")private String sender;@XmlTagName(tagName = "bill")private Bill bill;public String getAccount() {return account;}public SyncNcUfinterface setAccount(String account) {this.account = account;return this;}public String getBilltype() {return billtype;}public SyncNcUfinterface setBilltype(String billtype) {this.billtype = billtype;return this;}public String getFilename() {return filename;}public SyncNcUfinterface setFilename(String filename) {this.filename = filename;return this;}public String getGroupcode() {return groupcode;}public SyncNcUfinterface setGroupcode(String groupcode) {this.groupcode = groupcode;return this;}public String getIsexchange() {return isexchange;}public SyncNcUfinterface setIsexchange(String isexchange) {this.isexchange = isexchange;return this;}public String getReplace() {return replace;}public SyncNcUfinterface setReplace(String replace) {this.replace = replace;return this;}public String getRoottag() {return roottag;}public SyncNcUfinterface setRoottag(String roottag) {this.roottag = roottag;return this;}public String getSender() {return sender;}public SyncNcUfinterface setSender(String sender) {this.sender = sender;return this;}public Bill getBill() {return bill;}public Bill setBill(Object ob) {this.bill = new Bill();this.bill.setObject(ob);return this.bill;}class Bill {@XmlTagName(tagName = "billhead")private Object object;@XmlAttributeName(tagName = "id")private String id;public Object getObject() {return object;}public void setObject(Object object) {this.object = object;}public String getId() {return id;}public void setId(String id) {this.id = id;}}
}
package com.zxw.xml.domain.vo;import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;import java.math.BigDecimal;
import java.util.Date;
import java.util.List;/*** @projectName: ruoyi* @package: com.ruoyi.bmp.fi.domain.vo* @className: SyncncRecSettleBIillVO* @author: zhangxuewei* @description: 同步nc首款结算单VO* @date: 2023/7/6 10:06* @version: 1.0*/
public class SyncNcRecSettleBIillVO {// 单据日期@XmlTagName(tagName = "bill_date")private Date billDate;// 制单人private String billmaker;// 制单日期@XmlTagName(tagName = "billmaker_date")private Date billmakerDate;// 创建人private String creator;// 币种@XmlTagName(tagName = "pk_currtype")private String pkCurrtype;// 所属集团@XmlTagName(tagName = "pk_group")private String pkGroup;// 结算财务组织@XmlTagName(tagName = "pk_org")private String pkOrg;@XmlTagName(tagName = "items", arrayObjTagName = "item")private List<RecSettleBIillDetail> items;public static class RecSettleBIillDetail {// 单据分录编号@XmlTagName(tagName = "billdetail_no")private String billdetailNo;// 摘要private String memo;// 收款银行账户@XmlTagName(tagName = "pk_account")private String pkAccount;// 所属集团@XmlTagName(tagName = "pk_group")private String pkGroup;// 结算财务组织@XmlTagName(tagName = "pk_org")private String pkOrg;// 收支项目@XmlTagName(tagName = "pk_recproject")private String pkRecproject;// 收款原币金额@XmlTagName(tagName = "rec_primal")private BigDecimal recPrimal;public String getBilldetailNo() {return billdetailNo;}public void setBilldetailNo(String billdetailNo) {this.billdetailNo = billdetailNo;}public String getMemo() {return memo;}public void setMemo(String memo) {this.memo = memo;}public String getPkAccount() {return pkAccount;}public void setPkAccount(String pkAccount) {this.pkAccount = pkAccount;}}public Date getBillDate() {return billDate;}public void setBillDate(Date billDate) {this.billDate = billDate;}public String getBillmaker() {return billmaker;}public void setBillmaker(String billmaker) {this.billmaker = billmaker;}public Date getBillmakerDate() {return billmakerDate;}public void setBillmakerDate(Date billmakerDate) {this.billmakerDate = billmakerDate;}public String getCreator() {return creator;}public void setCreator(String creator) {this.creator = creator;}public String getPkCurrtype() {return pkCurrtype;}public void setPkCurrtype(String pkCurrtype) {this.pkCurrtype = pkCurrtype;}public String getPkGroup() {return pkGroup;}public void setPkGroup(String pkGroup) {this.pkGroup = pkGroup;}public String getPkOrg() {return pkOrg;}public void setPkOrg(String pkOrg) {this.pkOrg = pkOrg;}public List<RecSettleBIillDetail> getItems() {return items;}public void setItems(List<RecSettleBIillDetail> items) {this.items = items;}
}
工具类
package com.zxw.xml.util;import cn.hutool.core.date.DateUtil;
import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.util.ObjectUtils;import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;/*** @projectName: ruoyi* @package: com.ruoyi.common.utils.xml* @className: ObjectToXmlConverter* @author: zhangxuewei* @description: TODO* @date: 2023/7/6 13:15* @version: 1.0*/
public class ObjectToXmlConverter {public static String convertToXml(Object object) {Document document = DocumentHelper.createDocument();XmlRootElementName an = object.getClass().getDeclaredAnnotation(XmlRootElementName.class);Element rootElement = document.addElement(ObjectUtils.isEmpty(an.tagName()) ? object.getClass().getSimpleName() : an.tagName());convertObjectToElements(object, rootElement, document);return document.asXML();}private static void convertObjectToElements(Object object, Element parentElement, Document document) {for (Field field : object.getClass().getDeclaredFields()) {try {field.setAccessible(true);Object value = field.get(object);// 如果为空,给个空字符串,这样即使 属性为null 也会生成标签if (value == null) {value = "";}if (!(field.getName().indexOf("this") > -1)) {if (!ObjectUtils.isEmpty(field.getAnnotation(XmlAttributeName.class))) {parentElement.addAttribute(ObjectUtils.isEmpty(field.getAnnotation(XmlAttributeName.class)) ? field.getName() : field.getAnnotation(XmlAttributeName.class).tagName(), value.toString());} else {Element element = parentElement.addElement(ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class)) ? field.getName() : field.getAnnotation(XmlTagName.class).tagName());if (value instanceof String || value instanceof Integer || value instanceof Boolean || value instanceof Long || value instanceof BigDecimal) {element.setText(String.valueOf(value));} else if (value instanceof Double || value instanceof Float) {element.setText(Double.toString(Double.valueOf(value.toString())));} else if (value instanceof Date) {element.setText(DateUtil.format((Date) value, "yyyy-MM-dd HH:mm:ss"));} else if (value instanceof List) {for (Object listValue : (List) value) {Element elementL;if (!ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class)) && !ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class).arrayObjTagName()))elementL = element.addElement(field.getAnnotation(XmlTagName.class).arrayObjTagName());elseelementL = element.addElement("item");convertObjectToElements(listValue, elementL, document);}} else if (value instanceof Map) {for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) value).entrySet()) {Element mapElement = element.addElement(mapEntry.getKey());convertObjectToElements(mapEntry.getValue(), mapElement, document);}} else {convertObjectToElements(value, element, document);}}}} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (NullPointerException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}}
}
测试
package com.zxw.xml.test;import com.zxw.xml.domain.vo.SyncNcRecSettleBIillVO;
import com.zxw.xml.domain.vo.SyncNcUfinterface;
import com.zxw.xml.util.ObjectToXmlConverter;
import org.apache.tools.ant.util.DateUtils;import java.util.ArrayList;
import java.util.Date;/*** @projectName: util-cloud* @package: com.zxw.xml.test* @className: Test* @author: zhangxuewei* @description: TODO* @date: 2023/7/6 17:07* @version: 1.0*/
public class Test {public static void main(String[] args) {SyncNcRecSettleBIillVO s = new SyncNcRecSettleBIillVO();s.setBillDate(new Date());s.setPkCurrtype("10001kjhhj1232321");s.setItems(new ArrayList<SyncNcRecSettleBIillVO.RecSettleBIillDetail>() {{SyncNcRecSettleBIillVO.RecSettleBIillDetail detail = new SyncNcRecSettleBIillVO.RecSettleBIillDetail();SyncNcRecSettleBIillVO.RecSettleBIillDetail detail2 = new SyncNcRecSettleBIillVO.RecSettleBIillDetail();add(detail);add(detail2);}});SyncNcUfinterface syncNcUfinterface = new SyncNcUfinterface();syncNcUfinterface.setBilltype("RecSettleBillFromBmp").setSender("Bmp").setBill(s);System.out.println(ObjectToXmlConverter.convertToXml(syncNcUfinterface));}}
测试结果
D:\mcdev\jdk8\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53019,suspend=y,server=n -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2020.1\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\mcdev\jdk8\jre\lib\charsets.jar;D:\mcdev\jdk8\jre\lib\deploy.jar;D:\mcdev\jdk8\jre\lib\ext\access-bridge-64.jar;D:\mcdev\jdk8\jre\lib\ext\cldrdata.jar;D:\mcdev\jdk8\jre\lib\ext\dnsns.jar;D:\mcdev\jdk8\jre\lib\ext\jaccess.jar;D:\mcdev\jdk8\jre\lib\ext\jfxrt.jar;D:\mcdev\jdk8\jre\lib\ext\localedata.jar;D:\mcdev\jdk8\jre\lib\ext\nashorn.jar;D:\mcdev\jdk8\jre\lib\ext\sunec.jar;D:\mcdev\jdk8\jre\lib\ext\sunjce_provider.jar;D:\mcdev\jdk8\jre\lib\ext\sunmscapi.jar;D:\mcdev\jdk8\jre\lib\ext\sunpkcs11.jar;D:\mcdev\jdk8\jre\lib\ext\zipfs.jar;D:\mcdev\jdk8\jre\lib\javaws.jar;D:\mcdev\jdk8\jre\lib\jce.jar;D:\mcdev\jdk8\jre\lib\jfr.jar;D:\mcdev\jdk8\jre\lib\jfxswt.jar;D:\mcdev\jdk8\jre\lib\jsse.jar;D:\mcdev\jdk8\jre\lib\management-agent.jar;D:\mcdev\jdk8\jre\lib\plugin.jar;D:\mcdev\jdk8\jre\lib\resources.jar;D:\mcdev\jdk8\jre\lib\rt.jar;C:\workspace\program\util-cloud\target\classes;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-web\2.7.9\spring-boot-starter-web-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter\2.7.9\spring-boot-starter-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot\2.7.9\spring-boot-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-autoconfigure\2.7.9\spring-boot-autoconfigure-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-logging\2.7.9\spring-boot-starter-logging-2.7.9.jar;C:\workspace\mavenRepository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;C:\workspace\mavenRepository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;C:\workspace\mavenRepository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;C:\workspace\mavenRepository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;C:\workspace\mavenRepository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;C:\workspace\mavenRepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\workspace\mavenRepository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-json\2.7.9\spring-boot-starter-json-2.7.9.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-databind\2.13.5\jackson-databind-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-annotations\2.13.5\jackson-annotations-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-core\2.13.5\jackson-core-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.5\jackson-datatype-jdk8-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.5\jackson-datatype-jsr310-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.5\jackson-module-parameter-names-2.13.5.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-tomcat\2.7.9\spring-boot-starter-tomcat-2.7.9.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.71\tomcat-embed-core-9.0.71.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.71\tomcat-embed-el-9.0.71.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.71\tomcat-embed-websocket-9.0.71.jar;C:\workspace\mavenRepository\org\springframework\spring-web\5.3.25\spring-web-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-beans\5.3.25\spring-beans-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-webmvc\5.3.25\spring-webmvc-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-aop\5.3.25\spring-aop-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-context\5.3.25\spring-context-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-expression\5.3.25\spring-expression-5.3.25.jar;C:\workspace\mavenRepository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar;C:\workspace\mavenRepository\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;C:\workspace\mavenRepository\org\projectlombok\lombok\1.18.26\lombok-1.18.26.jar;C:\workspace\mavenRepository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;C:\workspace\mavenRepository\org\springframework\spring-core\5.3.25\spring-core-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-jcl\5.3.25\spring-jcl-5.3.25.jar;C:\workspace\mavenRepository\org\jsoup\jsoup\1.13.1\jsoup-1.13.1.jar;C:\workspace\mavenRepository\org\apache\poi\poi\3.10-beta2\poi-3.10-beta2.jar;C:\workspace\mavenRepository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\workspace\mavenRepository\org\apache\poi\poi-ooxml\3.10-beta2\poi-ooxml-3.10-beta2.jar;C:\workspace\mavenRepository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;C:\workspace\mavenRepository\xml-apis\xml-apis\1.0.b2\xml-apis-1.0.b2.jar;C:\workspace\mavenRepository\org\apache\poi\poi-ooxml-schemas\3.10-beta2\poi-ooxml-schemas-3.10-beta2.jar;C:\workspace\mavenRepository\org\apache\xmlbeans\xmlbeans\2.3.0\xmlbeans-2.3.0.jar;C:\workspace\mavenRepository\stax\stax-api\1.0.1\stax-api-1.0.1.jar;C:\workspace\mavenRepository\org\apache\poi\poi-scratchpad\3.0.2-FINAL\poi-scratchpad-3.0.2-FINAL.jar;C:\workspace\mavenRepository\commons-logging\commons-logging\1.1\commons-logging-1.1.jar;C:\workspace\mavenRepository\log4j\log4j\1.2.13\log4j-1.2.13.jar;C:\workspace\mavenRepository\cn\hutool\hutool-all\5.8.15\hutool-all-5.8.15.jar;C:\workspace\mavenRepository\cglib\cglib\3.2.5\cglib-3.2.5.jar;C:\workspace\mavenRepository\org\ow2\asm\asm\6.0_ALPHA\asm-6.0_ALPHA.jar;C:\workspace\mavenRepository\org\apache\ant\ant\1.9.6\ant-1.9.6.jar;C:\workspace\mavenRepository\org\apache\ant\ant-launcher\1.9.6\ant-launcher-1.9.6.jar;C:\workspace\mavenRepository\commons-io\commons-io\2.6\commons-io-2.6.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar" com.zxw.xml.test.Test
Connected to the target VM, address: '127.0.0.1:53019', transport: 'socket'
<?xml version="1.0" encoding="UTF-8"?>
<ufinterface account="develop" billtype="RecSettleBillFromBmp" filename="" groupcode="" isexchange="Y" replace="Y" roottag="" sender="Bmp"><bill id=""><billhead><bill_date>2023-07-06 17:40:45</bill_date><billmaker></billmaker><billmaker_date></billmaker_date><creator></creator><pk_currtype>10001kjhhj1232321</pk_currtype><pk_group></pk_group><pk_org></pk_org><items><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item></items></billhead></bill></ufinterface>
Disconnected from the target VM, address: '127.0.0.1:53019', transport: 'socket'Process finished with exit code 0
格式化后的结果
<?xml version="1.0" encoding="UTF-8"?>
<ufinterface account="develop" billtype="RecSettleBillFromBmp" filename="" groupcode="" isexchange="Y" replace="Y" roottag="" sender="Bmp"><bill id=""><billhead><bill_date>2023-07-06 17:40:45</bill_date><billmaker></billmaker><billmaker_date></billmaker_date><creator></creator><pk_currtype>10001kjhhj1232321</pk_currtype><pk_group></pk_group><pk_org></pk_org><items><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item></items></billhead></bill>
</ufinterface>