练习解析配置文件,所以找了个真实的配置文件来进行解析,突然发现自己面向对象的思维欠缺,结果写成面向过程的了,哈哈。用到的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
本文介绍了一种解析iBatis配置文件的方法,通过实例演示了如何解析复杂的SQL语句和参数,包括多条件查询、分页查询等,并展示了如何处理动态SQL。
2114

被折叠的 条评论
为什么被折叠?



