初识模板框架【Velocity】

因最近项目中涉及到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 ""; } }
  • Velocity依赖
	
	  
		  org.apache.velocity
		  velocity
		  1.7
	  
	  
		  org.apache.velocity
		  velocity-tools
		  2.0
	  

你可能感兴趣的:(java,Velocity)