初始模板框架【Velocity】
阿新 • • 發佈:2018-12-19
因最近專案中涉及到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> T convert(String xml,Class<T> 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> T convert(String xml,Class<T> 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> T convert(InputStream in,Class<T> 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> T convert(InputStream in,Class<T> clz,String ns,String alisa) throws Exception { SAXReader saxReader = new SAXReader(); Document doc = saxReader.read(in); Map<String,String> 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> T convert(Document doc,Class<T> 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<Field,XmlField> 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<Node> 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<Node> 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<Class<?>, Map<Field,XmlField>> xmlTypeMap = new ConcurrentHashMap<Class<?>,Map<Field,XmlField>>(); public static Map<Field,XmlField> getForClass(Class<?> type){ Map<Field,XmlField> xmlType = xmlTypeMap.get(type); if(xmlType == null) { xmlType = getXmlType(type); xmlTypeMap.put(type, xmlType); } return xmlType; } private static Map<Field,XmlField> getXmlType(Class<?> type){ Map<Field,XmlField> 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;
/**
* <pre>
* <b>JavaBean convert to xml by VelocityEngine</b>
* <b>Description:</b>
*
* <b>Author:</b> Mike•Tran
* <b>Date:</b> 2018年10月10日 17:52
* <b>Copyright:</b> Copyright 2018 xxx-xxxx.com.cn. All rights reserved.
* <b>Changelog:</b>
* Ver Date Author Detail
* ----------------------------------------------------------------------
* 1.0 2018年10月10日 17:52 Mike new file.
*
* </pre>
*/
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<String, Object> 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<String, Object> 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 "";
}
}
- Velocity依賴
<!--velocity start-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>