实现Ibatis的动态解析SQL功能

曾几何时,一直想实现Ibatis的动态解析SQL功能,前些日子写了一个,基本实现(
暂不支持嵌套标签):
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 
 * @description SQL动态解析
 * @author 杨惠
 * @version 1.0
 * @date 2013-5-10
 */
public class SqlParse {

	private static Logger logger = Logger.getLogger(SqlParse.class);
	private String encoding = "UTF-8";
	private SAXReader saxReader = null;
	private Document document = null;
	// XML文件全路径
	private String filePath = "D:\\sql.xml";

	public SqlParse() {
		Init();
	}

	public SqlParse(String filePath) {
		this.filePath = filePath;
		Init();
	}

	/**
	 * 初始化
	 */
	private void Init() {
		File file = new File(filePath);
		if (file.exists() && file.isFile()) {
			try {
				saxReader = new SAXReader();
				document = saxReader.read(file);
			} catch (Exception e) {
				logger.error(e);
				document = null;
			} finally {
				saxReader = null;
				file = null;
			}
		} else {
			logger.error("指定文件不存在;");
		}
	}

	/**
	 * 根据传入参数Map,动态替换SQL标签,解析成最终执行的SQL语句
	 * 
	 * @param selectID
	 *            select元素的ID
	 * @param mapPara
	 *            SQL参数
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public final Map<String, String> parseSql(String strID,
			Map<String, String> mapPara) throws Exception {
		// 1.根据sqlID获得SQL语句元素
		Element elementParent = (Element) document
				.selectSingleNode("//select[@id='" + strID + "'] ");
		if (elementParent == null) {
			logger.info("文件名:" + filePath + ";信息:无id="
					+ strID + "的元素。");
			return null;
		}
		if (mapPara == null) {
			mapPara = new HashMap<String, String>();
		}
		// 2.解析每一个子元素标签,例如isNotEmpty,isEqual等
		List<Element> listElements = elementParent.elements();
		if (listElements != null && (!listElements.isEmpty())) {
			for (Element element : listElements) {
				parseElement(element, mapPara);
			}
		}
		// 3.解析SQL,用Map值替换SQL标签
		String strSQL = elementParent.getStringValue();
		Set<String> setKey = mapPara.keySet();
		String strProperty = null;
		for (Iterator<String> iterator = setKey.iterator(); iterator.hasNext();) {
			strProperty = (String) iterator.next();
			strSQL = strSQL.replaceAll("#" + strProperty + "#",
					mapPara.get(strProperty));
			strProperty = null;
		}
		Map<String, String> mapSQL = new HashMap<String, String>();
		mapSQL.put("sqlText", strSQL.replaceAll("\\s{2,}", " "));
		List<Attribute> listAttribute = elementParent.attributes();
		for (Attribute attribute : listAttribute) {
			mapSQL.put(attribute.getName(), attribute.getText());
		}
		// 4.释放变量
		strID = null;
		mapPara = null;
		elementParent = null;
		listElements = null;
		setKey = null;
		strSQL = null;
		return mapSQL;
	}

	/**
	 * 解析每一个标签元素
	 * 
	 * @param element
	 *            标签元素
	 * @param mapPara
	 *            SQL参数
	 * @throws Exception
	 */
	private final void parseElement(Element element, Map<String, String> mapPara)
			throws Exception {
		// 获得节点名称、属性,属性值
		String strElementName = element.getName();
		String strProperty = element.attributeValue("property").trim();
		String strPropertyValue = mapPara.get(strProperty);
		// 是否删除该节点
		boolean booDelete = false;
		// 标签处理
		if (StringUtils.equals(strElementName, "isNotEmpty")) {
			// 是否非空
			if (StringUtils.isBlank(strPropertyValue)) {
				booDelete = true;
			}
		} else if (StringUtils.equals(strElementName, "isEmpty")) {
			// 是否为空
			if (StringUtils.isNotBlank(strPropertyValue)) {
				booDelete = true;
			}
		} else {
			// 比较值
			if (StringUtils.isBlank(strPropertyValue)) {
				booDelete = true;
			} else {
				double douPropertyValue = Double.parseDouble(strPropertyValue);
				double douCompareValue = Double.parseDouble(element
						.attributeValue("compareValue").trim());
				if (StringUtils.equals(strElementName, "isGreaterThan")) {
					// 是否大于
					if (douPropertyValue <= douCompareValue) {
						booDelete = true;
					}
				} else if (StringUtils.equals(strElementName, "isGreaterEqual")) {
					// 是否大于等于
					if (douPropertyValue < douCompareValue) {
						booDelete = true;
					}
				} else if (StringUtils.equals(strElementName, "isLessThan")) {
					// 是否小于
					if (douPropertyValue >= douCompareValue) {
						booDelete = true;
					}
				} else if (StringUtils.equals(strElementName, "isEqual")) {
					// 是否等于
					if (douPropertyValue != douCompareValue) {
						booDelete = true;
					}
				} else if (StringUtils.equals(strElementName, "isNotEqual")) {
					// 是否不等于
					if (douPropertyValue == douCompareValue) {
						booDelete = true;
					}
				} else if (StringUtils.equals(strElementName, "isLessEqual")) {
					// 是否小于等于
					if (douPropertyValue > douCompareValue) {
						booDelete = true;
					}
				}
			}
		}
		if (booDelete == true) {
			element.getParent().remove(element);
		}
		// 释放变量
		element = null;
		mapPara = null;
		strElementName = null;
		strProperty = null;
		strPropertyValue = null;
	}

	/**
	 * 获得:XML文件编码
	 * 
	 * @return the encoding
	 */

	public final String getEncoding() {
		return encoding;
	}

	/**
	 * 设置:XML文件编码
	 * 
	 * @param encoding
	 *            the encoding to set
	 */

	public final void setEncoding(String encoding) {
		if (encoding != null) {
			this.encoding = encoding;
		}
	}

	/**
	 * 获得:Document
	 * 
	 * @return the document
	 */

	public final Document getDocument() {
		return document;
	}

	/**
	 * 设置:Document
	 * 
	 * @param document
	 *            the document to set
	 */

	public final void setDocument(Document document) {
		if (document != null) {
			this.document = document;
		}
	}

	/**
	 * 获得:XMl文件全路径(含文件名)
	 * 
	 * @return the filePath
	 */

	public final String getFilePath() {
		return filePath;
	}

	/**
	 * 设置:XMl文件全路径(含文件名)
	 * 
	 * @param filePath
	 *            the filePath to set
	 */

	public final void setFilePath(String filePath) {
		if (filePath != null) {
			this.filePath = filePath;
		}
	}

	public static void main(String[] args) {
		try {
			Map<String, String> mapPara = new HashMap<String, String>();
			mapPara.put("menucode", "sysAdmin");
			SqlParse sqlParse = new SqlParse("d:/sql.xml");
			System.out.println(sqlParse.parseSql(
					"queryMenuAsList", mapPara));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


上面main方法打印结果:
{id=queryMenuAsList, name=菜单表, sqlText= select menucode as 菜单编码,menuname as 菜单名称 from tb_upc_menu where 1=1 and menucode='myWork' }


Sql.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
	<select id="queryMenuAsList" name="菜单表">
		select menucode as 菜单编码,menuname as 菜单名称  from tb_upc_menu
		where 1=1
		<isNotEmpty property="menucode">
			and menucode='myWork'
		</isNotEmpty>
	</select>
	<select id="queryUserAsList" name="用户表">
		select row_number() OVER(
		order by createtime desc) as 序号,usercode as ID,username as 名称,mobile
		as 手机号 from tb_upc_user
	</select>
</root>

猜你喜欢

转载自huiy.iteye.com/blog/1866775