`

实现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>
0
5
分享到:
评论

相关推荐

    根据MyBatis或iBatis的SQLMapper文件反向生成数据库表

    解析SQLMapper文件: 首先需要解析SQLMapper文件,提取其中定义的SQL语句,包括创建表、修改表结构、插入数据等相关SQL语句。 解析SQL语句: 对于每一条SQL语句,需要解析其中的表名、字段名、数据类型、约束条件等...

    ibatis的dynamicSQL中,关于prepend的使用

    ibatis在解析动态SQL时,会执行一系列逻辑判断来确定如何构建最终的SQL语句。例如,在给定的Java代码片段中,`public void pushRemoveFirstPrependMarker(SqlTag tag)`方法用于处理`prepend`属性的逻辑。其中,`tag....

    ibatis实现原理解析

    在本篇文章中,我们将深入解析Ibatis的实现原理,探讨其核心功能、工作流程以及优势。 一、Ibatis的核心概念 1. SQL映射文件:Ibatis通过XML或注解方式定义SQL语句,这些语句被封装在SQL映射文件中。映射文件包含...

    ibatis 开发指南 和 iBATIS-SqlMaps两本图书

    4. **Mapper XML文件**:解析SQL映射文件的结构,包括定义SQL语句、结果映射、参数映射等。 5. **动态SQL**:讲解如何使用iBATIS的动态元素来构建灵活的SQL语句,以应对复杂的查询需求。 6. **API使用**:介绍...

    ibatis常用的sql

    通过传入的`HashMap`对象,可以实现动态设置更新字段及其对应的值,从而实现批量更新的功能。 综上所述,ibatis框架通过XML配置文件中的SQL语句模板和参数化处理,极大地简化了数据库操作的过程,提高了代码的安全...

    iBATIS-SqlMaps-中文教程

    5. **动态SQL**:iBATIS的一大亮点是其强大的动态SQL能力,可以实现条件查询、循环拼接SQL等复杂逻辑,无需编写大量Java代码。 6. **Mapper接口**:iBATIS 2.3版本引入了Mapper接口,将XML配置与Java代码更好地结合...

    ibatis UPDATE 动态XML与insert

    标签 "源码" 暗示我们可能需要关注MyBatis的内部实现,理解其如何解析和执行这些动态SQL。MyBatis通过`SqlSourceBuilder`和`BoundSql`等类解析XML中的动态元素,并在运行时构建出实际的SQL语句。而"工具"则可能意味...

    [iBATIS]sql转换工具

    3. **工具功能解析** 这个[iBATIS]sql转换工具,可能是针对iBATIS框架的SQL语句进行优化和转换,比如: - **语法转换**:将特定数据库的SQL语法转换为兼容其他数据库的语法。 - **方言支持**:识别并处理各种...

    根据mybatis/ibatis sqlmapper文件解析生成数据库表

    标题 "根据mybatis/ibatis sqlmapper文件解析生成数据库表" 暗示了我们将会探讨一个关于MyBatis或iBatis框架的工具,它能够解析SQL映射文件并根据这些文件自动生成数据库表。这个过程对于快速构建数据库模型,尤其是...

    ibatis的sql-map dtd

    Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将SQL语句与Java代码分离,从而更好地管理数据库操作。在Ibatis中,`sql-map`和`sql-map-config`是两个重要的XML配置文件,...

    ibatis sql语句对条件中特殊字符% # 处理

    ibatis支持动态SQL的功能,这使得在构建SQL语句时可以更加灵活。在提供的代码片段中,使用了`&lt;isNotEmpty&gt;`标签来动态判断条件是否为空,并且通过`&lt;CDATA&gt;`标签来编写SQL片段。这种方式可以避免硬编码SQL语句,提高...

    Mygeneration_1309_20081006—IBatis_SQL映射+实体模板

    IBatis.NET是SQL Map的一种实现,它是一个持久层框架,用于将SQL查询与.NET应用中的业务逻辑分离。 在Mygeneration_1309_20081006中,内置了IBatisObject模板,这是Mygeneration的一个重要功能。这个模板允许用户...

    iBATIS-SqlMaps中文教程集合

    - 动态SQL:讲解iBATIS的动态SQL功能,如if、choose、where、trim等标签,实现灵活的SQL构建。 - ResultMap与AutoMapping:探讨ResultMap如何映射复杂的结果集,以及自动映射机制的使用。 - ParameterMap与参数...

    ibatis实现增删改查功能demo

    此外,Ibatis支持动态SQL,使得查询条件可以根据业务需求灵活变化。 3. **多参数传递**: 在Ibatis中,如果一个方法需要接收多个参数,可以使用@Param注解为每个参数命名,然后在SQL语句中通过占位符引用它们。...

    Ibatis常用sql语句

    根据给定的文件信息,以下是对“Ibatis常用SQL语句”的详细解析,涵盖了一系列Ibatis在数据操作中的应用实例。 ### Ibatis简介 Ibatis是一个支持普通SQL查询、存储过程以及高级映射的优秀持久层框架。Ibatis可以让...

    ibatis-SqlMaps-开发指南-version 1.0 及 ibatis-SqlMaps-开发指南-version 2

    5. **动态SQL的增强**:version 2提供了更强大的动态SQL功能,如`&lt;bind&gt;`标签用于动态设置SQL参数,`&lt;foreach&gt;`标签用于循环生成SQL片段。 6. **Mapper接口**:版本2中提倡使用Mapper接口,使得业务逻辑更简洁,...

    ibatis源码,ibatis源码 ibatis源码 ibatis源码

    iBatis的动态SQL功能是其一大亮点,它允许在映射文件中编写条件语句,大大提高了SQL的灵活性。这部分源码主要在`org.apache.ibatis.builder.xml.XMLMapperBuilder`和`org.apache.ibatis.scripting.xmltags....

    IBATIS动态查询语句.doc

    IBATIS,现在更广为人知的名字为MyBatis,是一种半自动映射的持久层框架,它允许开发者以声明的方式进行SQL语句的编写,同时提供了动态SQL的功能,这使得SQL语句可以在运行时根据条件动态生成,极大地提高了SQL的...

Global site tag (gtag.js) - Google Analytics