在开发中,经常遇到JavaBean (Java对象)转换成xml格式的字符串,或者xml格式转换为JavaBean,如果我们手动解析的话,极大影响我们的开发效率,所以借助com.fasterxml.jackson.dataformat.xml.XmlMapper实现互转。
引入依赖
2.1.1
2.10.1
......
org.dom4j
dom4j
${dom4j.version}
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
${jackson.version}
工具类XMLUtil
几个static方法实现核心的几个功能:
将xml转为bean对象
将bean转为xml字符串,bean需要配置注解@JacksonXmlProperty等
将bean的xml字符串转为map,bean需要配置注解@JacksonXmlProperty等
读取文件成XML格式
字符串输出到XML文件
package com.pay.common.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
/**
* @ClassName: XMLUtil
* @Description:生成XML文件,使用Jdom2进行节点的拼装,写入xml文件,注意添加outStream.close();防止java占用文件不释放,导致内存溢出。 实现java对象和xml的互转操作。
* @author: 郭秀志 jbcode@126.com
* @date: 2020年1月8日 上午10:47:31
* @Copyright:
*/
@Slf4j
public class XMLUtil {
public static XmlMapper xmlMapper = new XmlMapper();
static {
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
}
/**
* 将xml转为bean对象
*
* @param input
* @return
* @throws IOException
*/
public static T xmlToBean(String input, Class cls) throws IOException {
return xmlMapper.readValue(input, cls);
}
/**
* 将bean转为xml字符串,bean需要配置注解@JacksonXmlProperty等。
*
* @param input
* @return
* @throws IOException
*/
public static String beanToXmlStr(Object input) throws IOException {
String xmlStr = xmlMapper.writeValueAsString(input);
return xmlStr;
}
/**
* 将bean的xml字符串转为map,bean需要配置注解@JacksonXmlProperty等。
*
* @param input
* @return
* @throws IOException
*/
public static Map beanToXmlStrToMap(Object input) throws IOException {
String xmlStr = xmlMapper.writeValueAsString(input);
Map map = xmlMapper.readValue(xmlStr, Map.class);
return map;
}
/*
* @Description 读取文件成XML格式。
* @Param [fileName]
* @return java.lang.String
*/
public static String xmlFileToString(String fileName) {
try {
SAXReader saxReader = new SAXReader();//新建一个解析类
org.dom4j.Document tempDocument = saxReader.read(fileName);//读入一个文件
return tempDocument.asXML();
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
/**
* @Description 字符串输出到XML文件。
* @return void
* @Param [str, fileName]
*/
public static void strToXmlFile(String str, File fileName) throws IOException {
SAXReader saxReader = new SAXReader();
org.dom4j.Document document;
XMLWriter writer = null;
try {
document = saxReader.read(new ByteArrayInputStream(str.getBytes("UTF-8")));
OutputFormat format = OutputFormat.createPrettyPrint();
/** 将document中的内容写入文件中 */
writer = new XMLWriter(new FileWriter(fileName), format);
writer.write(document);
} catch (DocumentException e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
}
XmlMapper属性配置说明
ObjectMapper xmlMapper = new XmlMapper();
//反序列化时,若实体类没有对应的属性,是否抛出JsonMappingException异常,false忽略掉
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//序列化是否绕根元素,true,则以类名为根元素
xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
//忽略空属性
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//XML标签名:使用骆驼命名的属性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
//设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
数据模型类
该对象保存待生成XML的数据信息。
package com.pay.payee.model;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.pay.payee.entity.BzPayeelistBankexecut;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* @ClassName: XmlSendFileModel
* @Description: 发送给银行的数据模型,通过注解生成XML,参考:https://blog.youkuaiyun.com/qq_27569237/article/details/86678979
* @author: 郭秀志 jbcode@126.com
* @date: 2020/5/11 16:57
* @Copyright:
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JacksonXmlRootElement(localName = "TransferDataRoot")
public class XmlSendFileModel {
@JacksonXmlProperty(localName = "BankType", isAttribute = true)
@ApiModelProperty("*银行类型")
private String bankType;
@JacksonXmlProperty(localName = "TotalItems")
@ApiModelProperty("*信息总条数")
private BigDecimal totalIty;
@JacksonXmlProperty
@JacksonXmlCData
@ApiModelProperty("*金额总数")
private BigDecimal moneySum;
@JacksonXmlElementWrapper(localName = "List")
private List executeList;
}
XML相关几个注解说明:
@JacksonXmlRootElement用于类名,是xml最外层的根节点。注解中有localName属性,该属性如果不设置,那么生成的XML最外面就是Clazz.
@JacksonXmlCData注解是为了生成
@JacksonXmlProperty注解通常可以不需要,若不用,生成xml标签名称就是实体类属性名称。但是如果你想要你的xml节点名字,首字母大写。比如例子中的TotalItems,那么必须加这个注解,并且注解的localName填上你想要的节点名字。最重要的是!实体类原来的属性totalIty必须首字母小写!否则会被识别成两个不同的属性。注解的isAttribute,确认是否为节点的属性,如上面BankType,效果见后续生成的XML文件。
@JacksonXmlElementWrapper一般用于list,list外层的标签。若不用的话,useWrapping =false
@JacksonXmlText,用实体类属性上,说明该属性是否为简单内容,如果是,那么生成xml时,不会生成对应标签名称。也就是只要值没有子标签。
@JsonIgnore,忽略该实体类的属性,该注解是用于实体类转json的,但用于转xml一样有效。
业务逻辑生成xml文件
代码功能见注解
//构造数据模型实例并赋值
XmlSendFileModel xmlSendFileModel = XmlSendFileModel.builder().
executeList((List) t).
bankType("SELF").
moneySum(new BigDecimal(20)).
totalIty(new BigDecimal(((List) t).size())).build();
//调用util类把bean对象转换成XML字符串
String xmlStr = XMLUtil.beanToXmlStr(xmlSendFileModel);
// 写入xml字符串到文件。
XMLUtil.strToXmlFile(xmlStr, file);
log.info("xml文件生成完毕");
//读取一个XML文件成XML字符串格式。
log.info("输出XML文件的字符串 = " + XMLUtil.xmlFileToString(file.getAbsolutePath()));
生成的XML文件内容
20
1733703118633937410
BZ-20191231000005
2323
01
长安22
01
2.00
1585670400000
8814652931605334136
01
银行附言
interface0001
1589200140514
银行返回码
1586140240000
21.22
4050158779746406646
BZ-20191231000005
1212
01
长安11
01
5.00
1585670400000
8814652931605334136
01
interface0001
1589200141229
渠道返回成功
1586373649000
2
XML字符串转化为对象
Java功能代码
//读取一个XML文件成XML字符串格式。
String xmlFileToString = XMLUtil.xmlFileToString(file.getAbsolutePath());
log.info("输出XML文件的字符串 = " + xmlFileToString);
控制台输出XML文件的字符串
2020-05-11 20:44:05 [pool-3-thread-1] INFO com.pay.payee.xml.XmlBzHelper -输出XML文件的字符串 = <?xml version="1.0" encoding="UTF-8"?>
20
5151934541892953312
BZ-20200107000005
62212131
01
长安2
01
2.00
1585670400000
8814652931605334136
01
interface0001
1589201045680
渠道返回成功
1586373649000
1
XML字符串反序列化后的Java对象
Java功能代码
//读取一个XML文件成XML字符串格式。
String xmlFileToString = XMLUtil.xmlFileToString(file.getAbsolutePath());
XmlSendFileModel model = XMLUtil.xmlToBean(xmlFileToString, XmlSendFileModel.class);
log.info(String.valueOf(model));
控制台输出反序列化后的Java对象
20:49:22.494 [main] INFO com.pay.payee.xml.XmlBzHelper - XmlSendFileModel(bankType=SELF, totalIty=1, moneySum=20, executeList=[com.pay.payee.entity.BzPayeelistBankexecut@ec87eeba])