练习解析配置文件,所以找了个真实的配置文件来进行解析,突然发现自己面向对象的思维欠缺,结果写成面向过程的了,哈哈。用到的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