dom4j-xpath解析ibatis配置文件

练习解析配置文件,所以找了个真实的配置文件来进行解析,突然发现自己面向对象的思维欠缺,结果写成面向过程的了,哈哈。用到的jar包dom4j-1.6.1.jar和jaxen-1.1.1.jar,commons-logging.jar,log4j-1.2.15.jar

ibatis配置文件:

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

<!DOCTYPE sqlMap      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">

	<!-- 学生实体 -->
<sqlMap namespace="Student">

	<typeAlias alias="Student" type="org.forever.xxxx.domain.Student" />

	<!-- 可以配置多个结果映射信息描述 -->
	<resultMap id="StudentResult" class="Student">
		<result property="id" column="ID_" />
		<result property="name" column="NAME_" />
		<result property="sex" column="SEX_" />
		<result property="age" column="AGE_" />
		<result property="grade" column="GRADE_" />
		<result property="clazz" column="CLASS_" />
	</resultMap>

	<!-- 多条件查询 -->
	<select id="findByMap" parameterClass="java.util.Map" resultMap="StudentResult">
		SELECT * FROM STUDENT_
		WHERE STUDENT_.GRADE_=#grade#
		AND
		STUDENT_.CLASS_=#class#
		AND STUDENT_.NAME_ LIKE '%$name$%'
		AND
		STUDENT_.AGE_ BETWEEN #start_age# AND #end_age#
		AND STUDENT_.SEX_ IN
		('男','女')
		ORDER BY STUDENT_.NAME_ ASC,STUDENT_.AGE_ ASC

	</select>
	
	<!-- 处理条件的模板sql语句 -->
	<sql id="condition_sql">
		<!-- 条件集合不为null时说明有附加条件 -->
		<isNotNull property="conditions">
			<!-- 迭代条件集合,还有其他条件的解析,自己补充吧 ,这种条件可以写成模板sql,让统计语句重复使用-->
			<iterate property="conditions" prepend=" AND " conjunction=" AND ">
				<!-- 等于条件解析 -->
				<isEqual property="${conditions[].operation}" compareValue="EQ">
					<![CDATA[
					($conditions[].propertyName$ = #conditions[].propertyValue#)
					]]>
				</isEqual>
				<!-- 大于等于-->
				<isEqual property="${conditions[].operation}" compareValue="GE">
					<![CDATA[
					($conditions[].propertyName$ >= #conditions[].propertyValue#)
					]]>
				</isEqual>
				<!-- 小于等于-->
				<isEqual property="${conditions[].operation}" compareValue="LE">
					<![CDATA[
					($conditions[].propertyName$ <= #conditions[].propertyValue#)
					]]>
				</isEqual>
				<!-- 模糊条件解析 -->
				<isEqual property="${conditions[].operation}" compareValue="LIKE">
					<![CDATA[
					($conditions[].propertyName$ LIKE
					'%'||#conditions[].propertyValue#||'%')
					]]>
					
				</isEqual>
				<!-- 范围条件解析 -->
				<isEqual property="${conditions[].operation}" compareValue="BETWEEN">
					<![CDATA[
					($conditions[].propertyName$ BETWEEN
					#conditions[].propertyValue[0]# AND
					#conditions[].propertyValue[1]#)
					]]>
					
				</isEqual>
				<!-- in条件解析 -->
				<isEqual property="${conditions[].operation}" compareValue="IN">
					<![CDATA[
					($conditions[].propertyName$ IN
					]]>
					<iterate open="(" close="))" conjunction=","
						property="${conditions[].propertyValue}">
						#conditions[].propertyValue[]#
					</iterate>
				</isEqual>
			</iterate>
		</isNotNull>
	</sql>
	
	<!-- 分页查询单个对象的信息 -->
	<select id="queryByStudent" parameterClass="Student" resultMap="StudentResult">
		<![CDATA[
			SELECT * FROM 
			(
				SELECT ROWNUM NUM,STUDENT_.* FROM STUDENT_
				WHERE 1=1 AND (ROWNUM<=#currentPage#*#pageSize#)
		]]>
		<include refid="condition_sql"/>
		<!-- 排序条件处理 -->	
		$orderSql$
		<![CDATA[
			)
			WHERE NUM >(#currentPage#-1)*#pageSize#
		]]>
	</select>

	<!-- 分页统计查询 -->
	<select id="queryPageCount" parameterClass="Student"
		resultClass="int">
		SELECT COUNT(*) FROM STUDENT_ WHERE 1=1 
		<include refid="condition_sql"/>
	</select>


	<!-- 单个参数配置 -->
	<select id="findByNameStudent" parameterClass="string"
		resultMap="StudentResult">
		SELECT * FROM STUDENT_ WHERE STUDENT_.NAME_=#name#
	</select>

	<!-- 根据学生id查询 -->
	<select id="findByIdStudent" parameterClass="int" resultMap="StudentResult">
		SELECT * FROM STUDENT_ WHERE STUDENT_.ID_=#id#
	</select>

	<!-- 更新一条记录 -->
	<update id="updateStudent" parameterClass="Student">
		UPDATE STUDENT_ SET
		STUDENT_.AGE_=#age#,STUDENT_.NAME_=#name#,STUDENT_.CLASS_=#clazz#,STUDENT_.GRADE_=#grade#,STUDENT_.SEX_=#sex#
		WHERE STUDENT_.ID_ = #id#
	</update>

	<!-- 删除一条记录 -->
	<delete id="deleteStudent" parameterClass="int">
		DELETE STUDENT_ WHERE
		STUDENT_.ID_ = #id#
	</delete>

	<!-- 批量删除 -->
	<delete id="batchDelete" parameterClass="java.util.List">
		DELETE STUDENT_ WHERE STUDENT_.ID_ IN
		<iterate conjunction="," open="(" close=")">
			#value[]#
		 </iterate>
	</delete>

	<!-- 添加一条记录,参数类型为Student -->
	<insert id="saveStudent" parameterClass="Student">
		<!-- 获取序列的下一个值 keyProperty为实体的属性-->
		<selectKey keyProperty="id" resultClass="int">
			SELECT
			SEQ_STUDENT_ID.NEXTVAL AS SID FROM DUAL
		</selectKey>
		<!-- #属性#字段 -->
		<![CDATA[
			INSERT INTO STUDENT_(
				ID_,
				NAME_,
				SEX_,
				AGE_,
				GRADE_,
				CLASS_
			)
			VALUES(
				#id#,
				#name#,
				#sex#,
				#age#,
				#grade#,
				#clazz#
			)
		]]>
	</insert>

	<!-- 查询所有信息 -->
	<select id="findAllStudent" resultMap="StudentResult">
		SELECT * FROM STUDENT_
	</select>

</sqlMap>

 代码没有经过优化的:

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 StudentXml {
	
	private static Log log = LogFactory.getLog(StudentXml.class);
	private static Document doc;

	public static void main(String[] args) throws Exception {
		// 以下是解析ibatis的一个xml配置文件
		SAXReader reader = new SAXReader();
		InputStream inputStream = StudentXml.class.getClassLoader()
				.getResourceAsStream(
						"org/forever/xxxx/domain/Student.ibatis.xml");
		doc = reader.read(inputStream);// 获取文档对象
		// 以下是对各个方法的解析
		List<Object> param_list = new ArrayList<Object>();// 搜集参数值的集合
		Object param;// 单个参数声明
		// 查询id为findAllStudent的元素
		Element element = getSingleNode("/sqlMap/select[@id='findAllStudent']");

		element = getSingleNode("/sqlMap/select[@id='findByIdStudent']");
		param = 2;// 模拟findByIdStudent方法的参数

		element = getSingleNode("/sqlMap/select[@id='findByNameStudent']");
		param = "admin";// 模拟findByNameStudent方法的参数

		element = getSingleNode("/sqlMap/select[@id='findByMap']");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("grade", "一年级");
		map.put("class", "二班");
		map.put("start_age", 14);
		map.put("end_age", 18);
		map.put("name", "陈均");
		param = map;// 模拟findByMap方法的参数
		
		element = getSingleNode("/sqlMap/select[@id='queryByStudent']");
		
		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.setPageSize(2);//每页2条
			student.setCurrentPage(2);//查看第2页
			
			student.setConditions(conditions);
			
			List<Order> orders = Arrays.asList(
					new Order("stuName", OrderType.ASC),
					new Order("stuAge", OrderType.ASC)
			);
			student.setOrders(orders);
			
			param = student;//模拟queryByStudent方法的参数
			
		//模拟批量删除	
//		element = getSingleNode("/sqlMap/delete[@id='batchDelete']");	
//		param = Arrays.asList(2,3,4,5);	

		//动态sql解析
		//元素、属性、文本、命名空间、处理指令、注释以及文档
		StringBuffer qlString = new StringBuffer();
		
		
		parseEC(element, qlString,param,param_list);
		
		
		log.info(qlString.toString());
		
		log.info(param_list.size());
		
		
	}
	
	//解析#号
	private static void parseJH(StringBuffer sb,Object param,List<Object> p_list) throws Exception{
		String str = "#";// #?#形式的解析
		int start = sb.indexOf(str, 0);// 第一次#号出现的起始位置
		int end = sb.indexOf(str, start + 1);// 第一次#号出现的结束位置
		while (start != -1 && end != -1) {// 可能有多个#号
			String property = sb.substring(start + 1, end);// 提取##之间的名字
			//可能出现conditions[].propertyValue这种写法
			
			//去掉即可
			//首先用.进行分割
			String[]p = property.split("\\.");
			if(p.length>1){//说明存在.
				//取第二个单元的内容,这里假设不会出现conditions[].propertyValue.?这种,也没意义
				property = p[1];
			}
			//还可能出现property = propertyValue[0]这种
			int start_ = property.indexOf("[");
			Object value = null;
			if(isPrimitive(param)){//如果是基本类型
				value = param;
			}else if(param instanceof Map<?,?>){
				value = ((Map)param).get(property);
			}else if(start_!=-1){
				int index = Integer.parseInt(property.substring(start_+1, start_+2));//获取下标
				property = property.replaceAll("\\["+index+"\\]", "");//去掉[?]
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
				p_list.add(((Object[])value)[index]);
				
			}else{
				//反射获取值
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
				p_list.add(value);
			}
			
	
			sb.replace(start, end + 1, "?");// 把语句中的#?#符号替换成?号
			start = sb.indexOf(str, start);// 获取下一次#号出现的起始位置
			end = sb.indexOf(str, start + 1);// 获取下一次#号出现的结束位置
		}//end
	}
	
	//解析$符号
	private static void parse$(StringBuffer sb,Object param,List<Object> p_list) throws Exception{
		String str = "$";
		int start = sb.indexOf(str, 0);// 第一次$号出现的起始位置
		int end = sb.indexOf(str, start + 1);// 第一次$号出现的结束位置
		while (start != -1 && end != -1) {// 可能有多个$号
			String property = sb.substring(start + 1, end);// 提取$$之间的名字
			//可能出现$conditions[].propertyName$这种写法
			//去掉即可
			//首先用.进行分割
			String[]p = property.split("\\.");
			if(p.length>1){//说明存在.
				//取第二个单元的内容,这里假设不会出现conditions[].propertyValue.?这种,也没意义
				property = p[1];
			}
			Object value = null;
			if(isPrimitive(param)){//如果是基本类型
				value = param;
			}else if(param instanceof Map<?,?>){
				value = ((Map)param).get(property);
			}else{
				//反射获取值
				Field field = getField(param, property);
				field.setAccessible(true);
				value = field.get(param);
			}
			
			sb.replace(start, end + 1, value.toString());// 把语句中的$?$符号替换成具体的值
			start = sb.indexOf(str, start);// 获取下一次$号出现的起始位置
			end = sb.indexOf(str, start + 1);// 获取下一次$号出现的结束位置
		}//end
	}
	
	//递归解析
	private static void parseEC(Element element, StringBuffer sb,Object param,List<Object> p_list) throws Exception {
		for (Object obj : element.content()) {
			if(obj instanceof DefaultText){
				DefaultText dt = (DefaultText)obj;
				log.info("文本元素:" + dt.getNodeTypeName());
				log.info("文本内容:" + dt.getText());
				sb.append(" " + dt.getText().trim() + " ");
				//如果是空文本,本次操作是可以略过的
				if("".equals(dt.getText().trim())){
					continue;
				}
				parseJH(sb, param, p_list);
				
				// 还有种$?$形式的解析,这种解析直接将值赋予语句中,和##的解析差不多
				parse$(sb, param, p_list);
				

			}else if(obj instanceof Element){
				Element e = (Element)obj;
				log.info("元素标签:"+e.getNodeTypeName());
				String name = e.getName();
				if(name.equals("include")){//如果是include
					String refid = e.attributeValue("refid");//获取引用的sqlid
					//找到该元素的模板进行解析,发现是个递归操作
					Element sql_e = getSingleNode("/sqlMap/sql[@id='"+refid+"']");
					parseEC(sql_e, sb,param,p_list);//递归处理该元素
				}else if("isNotNull".equals(name)){//如果是不为null标签元素
					String property = e.attributeValue("property");
					//反射获取指定的属性
					Field field = getField(param, property);
					field.setAccessible(true);
					Object value = field.get(param);
					log.info("属性"+property + (value==null?"为空,不满足条件":"不为空,满足条件"));
					if(value!=null){
						//递归遍历子元素
						parseEC(e, sb, param,p_list);
					}
				}else if("iterate".equals(name)){//如果遇到迭代标签
					String property = e.attributeValue("property");//获取迭代的属性
					String prepend = e.attributeValue("prepend");//获取迭代前缀字符串
					String open = e.attributeValue("open");
					String close = e.attributeValue("close");
					String conjunction = e.attributeValue("conjunction");
					if(property==null){
						property = "";
					}
					//去掉${,},[]
					property = property.replace("$", "")
										.replace("{", "")
										.replace("}", "")
										.replace("[", "")
										.replace("]", "");
					//以.分割数组
					String[]nameArray = property.split("\\.");
					//从第二个名字开始
					String pn1 = property;
					if(nameArray.length>1){
						pn1 = nameArray[1];
					}
					List list = null;
					if(param instanceof java.util.List<?>){
						list = (List) param;
					}else{
						Field field = getField(param, pn1);
						//假设迭代标签只支持list类型的
						field.setAccessible(true);
						list = (List) field.get(param);
					}
					
					log.info(list.size());
					
					if(open!=null && close!=null && conjunction!=null){
						sb.append(open);
						for (Object object : list) {
							sb.append("?" + conjunction);
							p_list.add(object);
							
							
						}
						sb.delete(sb.length()-1,sb.length());//去掉最后一个多余的
						sb.append(close);
					}else{
						//遍历list
						for (Object object : list) {
							sb.append(prepend);
							parseEC(e, sb, object, p_list);
							
						}
					}
					
					
				}else if("isEqual".equals(name)){//如果是比较标签
					String property = e.attributeValue("property");//获取比较的属性
					String compareValue = e.attributeValue("compareValue");//比较的值
					//去掉${,},[]
					
					property = property.replace("$", "")
										.replace("{", "")
										.replace("}", "")
										.replace("[", "")
										.replace("]", "");
					//以.分割数组
					String[]nameArray = property.split("\\.");
					//从第二个名字开始
					String pn1 = nameArray[1];
					//反射获取改字段的值
					Field field = getField(param, pn1);
					//假设迭代标签只支持list类型的
					field.setAccessible(true);
					if(compareValue.equals(field.get(param).toString())){//如果满足等于条件
						//递归解析里面的内容
						parseEC(e, sb, param, p_list);
					}
					
					
				}
				
			}else if(obj instanceof DefaultCDATA){
				
				DefaultCDATA cdata = (DefaultCDATA)obj;
				log.info("cdata元素:"+cdata.getNodeTypeName());
				log.info("cdata的内容为:" + cdata.getText().trim());
				sb.append(" " + cdata.getText().trim() + " ");
				
				parseJH(sb, param, p_list);
				
				// 还有种$?$形式的解析,这种解析直接将值赋予语句中,和##的解析差不多
				parse$(sb, param, p_list);
				
			}
		}
	}

	
	
	
	private static Field getField(Object param, String property)
			throws NoSuchFieldException {
		Field field;
		try {
			field = param.getClass().getDeclaredField(property);
		} catch (Exception e1) {
			//去父类中找寻,在此支持一级父类找寻,如果多级,那就递归呗
			field = param.getClass().getSuperclass().getDeclaredField(property);
		}
		return field;
	}
	
	//是否是基本类型
	public static boolean isPrimitive(Object param){
		//等等.....
		if(param.getClass().isPrimitive() || param instanceof String || param instanceof Integer){
			return true;
		}
		return false;
	}
	


	public static Element getSingleNode(String xpath) {
		return (Element) doc.selectSingleNode(xpath);
	}

}

 

 

 log4j配置文件:

##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

 

例子中所用到的其他类:

PageInfo

package org.forever.pagination;

import java.io.Serializable;
import java.util.List;

//分页信息
public class PageInfo implements Serializable {

	private static final long serialVersionUID = -2013522911148457717L;
	private int currentPage = 1;// 当前页
	private int totalPage = 0;// 总页数
	private int totalItems = 0;// 总条数
	private int pageSize = 10;// 每页显示多少条
	protected List<Condition> conditions;// 条件集合
	protected List<Order> orders;// 排序集合
	private String orderSql="";// 排序拼接语句
	
	public PageInfo() {

	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

	public int getTotalItems() {
		return totalItems;
	}

	public void setTotalItems(int totalItems) {
		this.totalItems = totalItems;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public List<Condition> getConditions() {
		return conditions;
	}

	public void setConditions(List<Condition> conditions) {
		this.conditions = conditions;
	}

	public List<Order> getOrders() {
		return orders;
	}

	public void setOrders(List<Order> orders) {
		this.orders = orders;
		StringBuffer order = new StringBuffer();
		if (orders != null && orders.size() > 0) {
			order.append(" ORDER BY ");
			for (Order item : orders) {
				String propertyName = item.getPropertyName();
				switch (item.getOrderType()) {
				case ASC:
					order.append(propertyName + " ASC,");
					break;
				case DESC:
					order.append(propertyName + " DESC,");
					break;
				default:
					break;
				}
			}
			//去掉多余的逗号
			order.replace(order.length() - 1, order.length(), "");
		}
		setOrderSql(order.toString());
	}

	public String getOrderSql() {
		return orderSql;
	}

	public void setOrderSql(String orderSql) {
		this.orderSql = orderSql;
	}

	
}

 条件Condition类:

package org.forever.pagination;

//条件操作
public class Condition {

	private String propertyName;// 属性名
	private Object propertyValue;// 属性值
	private Operation operation;// 操作符号

	public Condition() {
	}

	public String getPropertyName() {
		return propertyName;
	}

	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}

	public Object getPropertyValue() {
		return propertyValue;
	}

	public void setPropertyValue(Object propertyValue) {
		this.propertyValue = propertyValue;
	}

	public Operation getOperation() {
		return operation;
	}

	public void setOperation(Operation operation) {
		this.operation = operation;
	}

	public Condition(String propertyName, Object propertyValue, Operation operation) {
		this.propertyName = propertyName;
		this.operation = operation;
		this.propertyValue = propertyValue;
		// 在这里处理属性值
	}

}

 

package org.forever.pagination;
//操作类型
public enum Operation {
	IN,
	EQ,
	GT,
	LT,
	NE,
	GE,
	LE,
	BETWEEN,
	LIKE
}

 

package org.forever.pagination;

public class Order {

	private String propertyName;// 属性名
	private OrderType orderType;// 排序类型

	public Order() {

	}

	public Order(String propertyName, OrderType orderType) {
		super();
		this.propertyName = propertyName;
		this.orderType = orderType;
	}

	public String getPropertyName() {
		return propertyName;
	}

	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}

	public OrderType getOrderType() {
		return orderType;
	}

	public void setOrderType(OrderType orderType) {
		this.orderType = orderType;
	}

}

 

package org.forever.pagination;

public enum OrderType {

	ASC,
	DESC
	
}

解析queryByStudent方法的结果:

INFO -    SELECT * FROM 
			(
				SELECT ROWNUM NUM,STUDENT_.* FROM STUDENT_
				WHERE 1=1 AND (ROWNUM<=?*?)            AND        (stuGrade = ?)                          AND            (stuAge >= ?)                      AND                (stuAge <= ?)                  AND        (stuClass = ?)                          AND                    (stuName LIKE
					'%'||?||'%')              AND                        (stuAge BETWEEN
					? AND
					?)          AND                            (stuSex IN   (?,?))     AND                        (stuTime BETWEEN
					? AND
					?)                 ORDER BY stuName ASC,stuAge ASC    )
			WHERE NUM >(?-1)*?   
INFO - 15

  

你可能感兴趣的:(apache,sql,log4j,ibatis)