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