因最近项目中涉及到javabean 2 XML的转换,比较多,但是又不涉及具体的业务逻辑,请求系统与目标系统间进行数据透传,两个系统间的报文字段都不一致,需要进行映射转换,所以考虑再三,xml2bean选择了xpath实现,然后再把bean转换为对应的xml,此过程考虑几个不同的模板引擎:FreeMarker、Thymeleaf、Enjoy、Velocity,对比了几个的优缺点之后,选择了Velocity,比较轻巧,效率高,性能还不错,最重要是满足当前的项目需要。
【xpath】
package com.xx.xxx.api.xml.xpath;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
/**
* xml path 映射
* @author zenghaom
*
*/
public class XmlPathUtil {
/**
* xml字符串转换Object
* @param xml
* @param clz 转换对象class
* @return
* @throws Exception
*/
public static T convert(String xml,Class clz) throws Exception{
InputStream in = null;
try {
in = IOUtils.toInputStream(xml);
return convert(in,clz);
}finally {
IOUtils.closeQuietly(in);
}
}
/**
* xml字符串转换Object
* @param xml xml字符串
* @param clz 转换对象class
* @param ns 命名空间
* @param alisa 别名
* @return
* @throws Exception
*/
public static T convert(String xml,Class clz,String ns,String alisa) throws Exception{
InputStream in = null;
try {
in = IOUtils.toInputStream(xml);
return convert(in,clz,ns,alisa);
}finally {
IOUtils.closeQuietly(in);
}
}
/**
* inputStream xml转Object
* @param in
* @param clz
* @return
* @throws Exception
*/
public static T convert(InputStream in,Class clz) throws Exception {
Document doc = new SAXReader().read(in);
return convert(doc,clz);
}
/**
* inputStream xml转Object
* @param in
* @param clz
* @param ns 命名空间
* @param alisa 别名
* @return
* @throws Exception
*/
public static T convert(InputStream in,Class clz,String ns,String alisa) throws Exception {
SAXReader saxReader = new SAXReader();
Document doc = saxReader.read(in);
Map map = new HashMap<>();
map.put(alisa,ns);
saxReader.getDocumentFactory().setXPathNamespaceURIs(map);
return convert(doc,clz);
}
/**
* document 转 Object
* @param doc
* @param clz
* @return
* @throws Exception
*/
public static T convert(Document doc,Class clz) throws Exception {
T t = clz.newInstance();
getValue(doc, t, clz,"");
return t;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void getValue(Document doc,Object obj,Class clz,String parentPath) throws Exception{
Map xmlType = XmlFieldBeanFactory.getForClass(clz);
for(Field field : xmlType.keySet()) {
XmlField xmlField = xmlType.get(field);
Object value = field.getType().newInstance();
BeanUtils.setProperty(obj, field.getName(), value);
if(!xmlField.haveSon()) {
if(isCollection(field.getType())) {
Collection cl = (Collection) value;
List nodes = doc.selectNodes(parentPath+xmlField.path());
if(CollectionUtils.isNotEmpty(nodes)) {
for (Node node : nodes) {
cl.add(node.getText());
}
}
}else {
if(xmlField.isText()) {
Node node = doc.selectSingleNode(parentPath+xmlField.path());
if(node!=null) {
BeanUtils.setProperty(obj,field.getName() , node.getText());
}
}else {
BeanUtils.setProperty(obj,field.getName() , doc.valueOf(parentPath+xmlField.path()));
}
}
}else {
if(isCollection(field.getType())){
Collection cl = (Collection) value;
List nodes = doc.selectNodes(parentPath+xmlField.path());
if(CollectionUtils.isNotEmpty(nodes)) {
for (Node node : nodes) {
Type genericType = field.getGenericType();
if(genericType == null)
return; // 如果是泛型参数的类型
if(genericType instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType) genericType;//得到泛型里的class类型对象
Class> accountPrincipalApproveClazz = (Class>)pt.getActualTypeArguments()[0];
Object v = accountPrincipalApproveClazz.newInstance();
cl.add(v);
getValue(node.getDocument(), v,accountPrincipalApproveClazz,node.getUniquePath());
}
}
}
}else {
Node node = doc.selectSingleNode(xmlField.path());
if(node != null) {
Object v = field.getType().newInstance();
getValue(doc, v,field.getType(),node.getUniquePath());
}
}
}
}
}
private static boolean isCollection(Class> type) {
return Collection.class.isAssignableFrom(type);
}
}
package com.xx.xxx.api.xml.xpath;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 缓存解析过的xmlField
* @author zenghaom
*
*/
public class XmlFieldBeanFactory {
private final static ConcurrentMap, Map> xmlTypeMap = new ConcurrentHashMap,Map>();
public static Map getForClass(Class> type){
Map xmlType = xmlTypeMap.get(type);
if(xmlType == null) {
xmlType = getXmlType(type);
xmlTypeMap.put(type, xmlType);
}
return xmlType;
}
private static Map getXmlType(Class> type){
Map xmlType = new HashMap<>();
while (type != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
for (Field field : type .getDeclaredFields()) {
if(field.isAnnotationPresent(XmlField.class)){//判断成员变量是否有注解
xmlType.put(field, field.getAnnotation(XmlField.class));
}
}
type = type.getSuperclass(); //得到父类,然后赋给自己
}
return xmlType;
}
}
package com.xx.xxx.api.xml.xpath;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* 用于注解字段对应的xpath,进行解析xml
* @author zenghaom
*
*/
@Retention(RUNTIME)
@Target(FIELD)
public @interface XmlField {
/**
* xml对应的xPath路径
* @return
*/
String path();
/**
* 是否嵌套对象
* @return
*/
boolean haveSon() default false;
/**
* 取属性值
* @return
*/
boolean isText() default true;
}
【Velocity】
package com.xx.xxx.api.xml.velocity;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
*
* JavaBean convert to xml by VelocityEngine
* Description:
*
* Author: Mike•Tran
* Date: 2018年10月10日 17:52
* Copyright: Copyright 2018 xxx-xxxx.com.cn. All rights reserved.
* Changelog:
* Ver Date Author Detail
* ----------------------------------------------------------------------
* 1.0 2018年10月10日 17:52 Mike new file.
*
*
*/
public class VelocityXmlUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(VelocityXmlUtil.class);
private static final String DEFAULT_ENCODING = "UTF-8";
private static Properties p = new Properties();
static {
p.setProperty(Velocity.RESOURCE_LOADER, "class");
p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
p.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogChute");//关闭日志
}
/**
* pojo转换成xml 默认编码UTF-8
*
* @author Mike
* @date 2018/10/11 18:03
* @param map
* @param templateFilePathAndName 资源文件路径:比如模板放在resources/template/example.vm,则basePath="template/example.vm"
* @return java.lang.String
*/
public static String convertBeanToXml(Map map, String templateFilePathAndName) {
return convertBeanToXml(map, templateFilePathAndName, DEFAULT_ENCODING);
}
/**
* pojo转换成xml 自定义编码
*
* @author Mike
* @date 2018/10/11 18:03
* @param map
* @param templateFilePathAndName
* @return java.lang.String
*/
public static String convertBeanToXml(Map map, String templateFilePathAndName, String encoding) {
try {
//Velocity 引擎初始化(singleton)
Velocity.init(p);
//实例化一个VelocityContext
VelocityContext velocityContext = new VelocityContext(map);
//实例化一个StringWriter
StringWriter stringWriter = new StringWriter();
Template template = Velocity.getTemplate(templateFilePathAndName, encoding);
template.merge(velocityContext, stringWriter);
stringWriter.flush();
stringWriter.close();
return stringWriter.toString();
} catch (Exception e) {
LOGGER.error("VelocityXmlUtil_convertBeanToXml_Exception:{}", e.getMessage());
}
return "";
}
}
org.apache.velocity
velocity
1.7
org.apache.velocity
velocity-tools
2.0