xml解析Student.jpa.xml

以下是对配置文件的解析过程

Student.jpa.xml配置文件主要描述dao接口方法的hql语句:

<?xml version="1.0" encoding="UTF-8"?>

<!-- 对StudentDaoi接口中的所有方法进行外置命名实现 -->
<hqlMap namespace="Student">
	
	<!-- jpa查询语句 -->
	<select id="findAllStudent">
		SELECT mode FROM Student mode
	</select>
	
	<!-- jpa根据id查询 ,参数类型为Integer,如果不写parameterClass,则默认为语句里面只有一个参数-->
	<select id="findByIdStudent">
		SELECT mode FROM Student mode WHERE mode.stuId=?
	</select>
	
	<!-- jpa根据name查询,参数类型为String -->
	<select id="findByNameStudent">
		SELECT mode FROM Student mode WHERE mode.stuName=?
	</select>
	
	<!-- 多个参数封装成map形式的 -->
	<select id="findByMap">
		SELECT mode FROM Student mode WHERE mode.stuName=:stuName AND mode.stuSex=:stuSex
	</select>
	
	<!-- 多个参数封装成list形式的 -->
	<select id="findByList">
		SELECT mode FROM Student mode WHERE mode.stuName=? AND mode.stuSex=?
	</select>
	
	<!-- 保存单个实体方法 -->
	<insert id="saveStudent"></insert>
	
	<!-- 更新单个实体 -->
	<update id="updateStudent"></update>
	
	<!-- 根据id删除数据 -->
	<delete id="deleteStudent">
		DELETE Student mode WHERE mode.stuId=?
	</delete>
	
	
	<!-- 批量删除操作 -->
	<delete id="batchDelete">
		<![CDATA[
			DELETE Student mode WHERE 1=1 where mode.stuId IN
		]]>
		<!-- 
			使用iterate标签,目前参数只支持list类型
			当迭代的时候,里面自动获取具体的参数对象
			下面解析出来的结果是(?,?,?,?),里面支持无限级嵌套
		 -->
		<iterate conjunction="," open="(" close=")">
			#value#
		 </iterate>
	</delete>
	
	<!-- 统计操作(不带条件的) -->
	<select id="count">
		SELECT COUNT(mode) FROM Student mode
	</select>
	
	
	<!-- 处理条件的模板ql语句 -->
	<hql id="condition_hql">
			<iterate property="conditions" prepend=" AND " conjunction=" AND ">
				<isEqual property="operation" compareValue="EQ">
					<![CDATA[
					($propertyName$ = #propertyValue#)
					]]>
				</isEqual>
				<isEqual property="operation" compareValue="GE">
					<![CDATA[
					($propertyName$ >= #propertyValue#)
					]]>
				</isEqual>
				<isEqual property="operation" compareValue="LE">
					<![CDATA[
					($propertyName$ <= #propertyValue#)
					]]>
				</isEqual>
				<isEqual property="operation" compareValue="LIKE">
					<![CDATA[
					($propertyName$ LIKE #propertyValue#)
					]]>
					
				</isEqual>
				<isEqual property="operation" compareValue="BETWEEN">
					<![CDATA[
					($propertyName$ BETWEEN #propertyValue[0]# AND #propertyValue[1]#)
					]]>
				</isEqual>
				<isEqual property="operation" compareValue="IN">
					<![CDATA[
					($propertyName$ IN
					]]>
					<iterate open="(" close="))" conjunction=","
						property="propertyValue">
						#value#
					</iterate>
				</isEqual>
			</iterate>
	</hql>
	
	<!--多属性排序模板-->
	<hql id="order_hql">
			<iterate property="orders" prepend=" ORDER BY " conjunction=",">
				<isEqual property="orderType" compareValue="ASC">
					<![CDATA[$propertyName$ ASC]]>
				</isEqual>
				<isEqual property="orderType" compareValue="DESC">
					<![CDATA[$propertyName$ DESC]]>
				</isEqual>
			</iterate>
	</hql>
	
	<!-- 统计操作(带条件的) -->
	<select id="countByCondition">
		<![CDATA[
			SELECT COUNT(mode) FROM Student mode WHERE 1=1
		]]>
		<!--支持模板hql语句-->
		<include refid="condition_hql"/>
	</select>
	
	<!-- 分页结果集查询 -->
	<select id="findByPageStudent">
		<![CDATA[
			SELECT mode FROM Student mode WHERE 1=1 
		]]>
		<include refid="condition_hql"/>
		<include refid="order_hql"/>
	</select>
	
</hqlMap>

  StudentJpaXml.java是模拟解析配置文件全过程:

package org.forever.xml;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultCDATA;
import org.dom4j.tree.DefaultText;
import org.forever.pagination.Condition;
import org.forever.pagination.Operation;
import org.forever.pagination.Order;
import org.forever.pagination.OrderType;
import org.forever.xxxx.domain.Student;


public class StudentJpaXml {
	private static Log log = LogFactory.getLog(StudentJpaXml.class);
	private static Document doc;
	private static StringBuffer hql;
	private static List<Object> param_list;
	
	public static void main(String[] args) throws Exception {
		SAXReader reader = new SAXReader();
		InputStream in = StudentJpaXml.class.getClassLoader()
		.getResourceAsStream("org/forever/xxxx/domain/Student.jpa.xml");
		doc = reader.read(in);
		param_list = new ArrayList<Object>();//搜集参数值的list
		Object param = null;//模拟dao接口方法的参数
		
		//findAllStudent();
		Element element = getSingleNode("/hqlMap/select[@id='findAllStudent']");
		//findByIdStudent(int id);
		element = getSingleNode("/hqlMap/select[@id='findByIdStudent']");
		param = 2;
		//findByNameStudent(String name);
		element = getSingleNode("/hqlMap/select[@id='findByNameStudent']");
		param = "陈均";
		//findByMap(Map map);
		element = getSingleNode("/hqlMap/select[@id='findByMap']");
		Map<String, Object> param_map = new HashMap<String, Object>();
		param_map.put("stuName", "chenjun");
		param_map.put("stuSex", "男");
		param = param_map;
		//findByList(List list);
		element = getSingleNode("/hqlMap/select[@id='findByList']");
		List<Object> list = new ArrayList<Object>();
		list.add("chenjun");
		list.add("男");
		param = list;
		//countByCondition(Student student);
		element = getSingleNode("/hqlMap/select[@id='countByCondition']");
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		Date startTime = dateFormat.parse("2010-02-01");
		Date endTime = dateFormat.parse("2010-03-02");
		List<Condition> conditions = Arrays.asList(
			new Condition("stuGrade", "一年级",Operation.EQ),
			new Condition("stuAge",12,Operation.GE),
			new Condition("stuAge",19,Operation.LE),
			new Condition("stuClass", "二班", Operation.EQ),
			new Condition("stuName", "%stor%", Operation.LIKE), 
			new Condition("stuAge", new Object[] { 14, 18 }, Operation.BETWEEN),
			new Condition("stuSex", Arrays.asList("男","女"),Operation.IN),
			new Condition("stuTime",new Object[]{startTime,endTime},Operation.BETWEEN)
		);
		Student student = new Student();
		student.setConditions(conditions);
		param = student;
		//findByPageStudent(Student student);
		element = getSingleNode("hqlMap/select[@id='findByPageStudent']");
		List<Order> orders = Arrays.asList(
				new Order("stuName", OrderType.ASC),
				new Order("stuAge", OrderType.DESC)
		);
		student.setOrders(orders);
		
		hql = new StringBuffer();
		
		//动态hql解析
		parseHQL(element,param);
		//解析参数
		parseParam(param);
		
		
		log.info("解析后的hql语句:" + hql.toString());
		log.info("参数个数:"+param_list.size()+"个------>");
		for (int i = 0; i < param_list.size(); i++) {
			log.info("第" + (i+1) + "个参数值:" + param_list.get(i)); 
		}
		
	}
	
	//解析非引用类型参数
	private static void parseParam(Object param) {
		if (isPrimitive(param)) {
			param_list.add(param);
		} else if (param instanceof List<?>) {
			param_list = (List) param;
		} else if (param instanceof Map<?, ?>) {
			Map<String,Object> map = (Map) param;
			for (String key : map.keySet()) {
				String name = ":" + key;
				int start = hql.indexOf(name);
				int end = start + name.length();
				hql.replace(start, end, "?");
				param_list.add(map.get(key));
			}
		}		
		
	}

	/**
	 * 解析元素
	 * 该内容可能是以下几种情况:文本、元素、文档注释,CDATA
	 * 元素可能又会有上面的情况,所以是递归的解析
	 * 参数有以下3种:基本类型,集合类型(Map,List),引用类型
	 * 该递归方法只考虑引用类型
	 * @param element 待解析的标签元素
	 * @param param 接口方法的参数
	 * @param hql hql字符串
	 * @param param_list 存放参数集合
	 * @throws Exception 
	 */
	public static void parseHQL(Element element,Object param) throws Exception{
		
		for (Object item : element.content()) {
			if(item instanceof DefaultText){
				parseText(item,param);
			}else if(item instanceof DefaultCDATA){
				parseCDATA(item,param);
			}else if(item instanceof Element){
				parseElement(item,param);
			}
		}
	}
	
	//解析元素标签
	private static void parseElement(Object item, Object param) throws Exception {
		//元素有以下几种:
		//include,isEqual,iterate
		Element element = (Element)item;
		String name = element.getName();
		if("include".equals(name)){//模板标签
			String refid = element.attributeValue("refid");//获取引用的sqlid
			//找到该元素的模板进行解析,递归操作
			Element hqlE = getSingleNode("/hqlMap/hql[@id='"+refid+"']");
			if(hqlE==null){
				throw new RuntimeException("配置文件不存在id="+refid+"的标签!");
			}
			parseHQL(hqlE, param);
		}else if("iterate".equals(name)){
			String property = element.attributeValue("property");//参数的属性
			String prepend = element.attributeValue("prepend");//开始字符串
			String conjunction = element.attributeValue("conjunction");//迭代一次所加字符串
			String open = element.attributeValue("open");
			String close = element.attributeValue("close");
			if(null != prepend){
				hql.append(prepend);
			}
			if(null != open){
				hql.append(open);
			}
			
			//目前迭代标签只支持List类型的
			Field field = getField(param, property);
			field.setAccessible(true);
			List list = new ArrayList<Object>();
			try {
				list = (List)field.get(param);
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("获取迭代标签属性值失败!");
			} 
			if(conjunction==null){
				conjunction = " ";
			}
			
			for (Object object : list) {
				parseHQL(element, object);
				hql.append(conjunction);
			}
			
			hql.delete(hql.lastIndexOf(conjunction), hql.length());
			if(null != close){
				hql.append(close);
			}
			
		} else if("isEqual".equals(name)){
			String property = element.attributeValue("property");//属性
			String compareValue = element.attributeValue("compareValue");//比较的值
			Field field = getField(param, property);
			try {
				field.setAccessible(true);
				Object value = field.get(param);
				if(compareValue!=null && compareValue.equals(value.toString())){//满足条件
					parseHQL(element, param);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("获取迭代标签属性值失败!");
			} 
			
		}
		
		
		
	}
	
	//反射获取属性字段
	private static Field getField(Object param, String property){
		Field field = null;
		try {
			field = param.getClass().getDeclaredField(property);
		} catch (Exception e1) {
			// 去父类中找寻,在此支持一级父类找寻,如果多级,那就递归呗
			try {
				field = param.getClass().getSuperclass().getDeclaredField(property);
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("反射获取属性字段失败!");
			} 
		}
		return field;
	}

	//解析元素据类型
	private static void parseCDATA(Object element, Object param) throws Exception {
		DefaultCDATA cdata = (DefaultCDATA)element;
		String text = cdata.getText().trim();
		log.info("CDATA文本内容:" + text);
		if("".equals(text)){
			return;
		}
		
		hql.append(" " + text + " ");
		parseJH(param);
		parse$(param);
		
	}

	/**
	 * 是否是基本类型(8种基本类型和包装类型)
	 * @param param
	 * @return
	 */
	public static boolean isPrimitive(Object param) {
		// 等等....
		if (param == null)
			return false;

		if (param.getClass().isPrimitive() || param instanceof Integer
				|| param instanceof String || param instanceof Long
				|| param instanceof Short || param instanceof Double
				|| param instanceof Float || param instanceof Byte
				|| param instanceof Boolean) {
			return true;	
		}

		return false;
	}
	
	
	
	
	//解析文本类型
	public static void parseText(Object element,Object param) throws Exception{
		DefaultText dt = (DefaultText)element;
		String text = dt.getText().trim();
		log.info("text文本内容:" + text);
		if("".equals(text)){
			return;
		}
		
		hql.append(" " + text + " ");
		parseJH(param);
		parse$(param);
		
	}
	
	//解析$符号的表达式
	private static void parse$(Object param) throws Exception {
		log.info("解析$号.........");
		String str = "$";// $?$形式的解析
		int start = hql.indexOf(str,0);// 第一次$号出现的起始位置
		int end = hql.indexOf(str,start+1);// 第一次$号出现的结束位置
		while(start !=-1 && end != -1){// 可能有多个$号
			String property = hql.substring(start+1, end);
			//propertyValue[0]这种情况
			int start_ = property.indexOf("[");
			Object value = null;
			if(start_!=-1){//数组的情况
				int index = Integer.parseInt(property.substring(start_+1, start_+2));//获取下标
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
				value = ((Object[])value)[index];
				
			} else if(isPrimitive(param)){
				value = param;
			}
			else{// 普通属性
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
			}
			
			hql.replace(start, end + 1, value.toString());// 把语句中的$?$符号替换成?号
			start = hql.indexOf(str, start);// 获取下一次$号出现的起始位置
			end = hql.indexOf(str, start + 1);// 获取下一次$号出现的结束位置
		}//end while
	}

	//解析#符号的表达式
	public static void parseJH(Object param) throws Exception{
		log.info("解析#号.........");
		String str = "#";// #?#形式的解析
		int start = hql.indexOf(str,0);// 第一次#号出现的起始位置
		int end = hql.indexOf(str,start+1);// 第一次#号出现的结束位置
		while(start !=-1 && end != -1){// 可能有多个#号
			String property = hql.substring(start+1, end);
			//propertyValue[0]这种情况
			int start_ = property.indexOf("[");
			Object value = null;
			if(start_!=-1){//数组的情况
				int index = Integer.parseInt(property.substring(start_+1, start_+2));//获取下标
				Field field = getField(param, property.replaceFirst("\\["+index+"\\]", ""));
				field.setAccessible(true);
				value = field.get(param);
				param_list.add(((Object[])value)[index]);
				
			} else if(isPrimitive(param)){
				param_list.add(param);
			}
			else{// 普通属性
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
				param_list.add(value);
			}
			
			hql.replace(start, end + 1, "?");// 把语句中的#?#符号替换成?号
			start = hql.indexOf(str, start);// 获取下一次#号出现的起始位置
			end = hql.indexOf(str, start + 1);// 获取下一次#号出现的结束位置
		}//end while
		
		
		
	}
	
	//根据xpath获取单节点元素
	public static Element getSingleNode(String xpathExpression){
		return (Element)doc.selectSingleNode(xpathExpression);
	}

}

 

 涵盖了对单对象的所有情况的一个操作。当然这种通用写法肯定会降低效率的哈.

以上依赖的jar包:dom4j-1.6.1.jar,jaxen-1.1.1.jar,pagination.jar,commons-logging.jar

log4j.properties:

##LOGGERS##
log4j.rootLogger=INFO,console
##APPENDERS##
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=d\:\\log.txt
log4j.appender.file.MaxFileSize=1024KB
##LAYOUTS##
log4j.appender.console.layout=org.apache.log4j.SimpleLayout
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm} %t %p- %m%n

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值