J2EE开发框架搭建(7) - 用hibernate实现类似mybaits把sql写在配置文字中

为了避免sql编写在Java代码里面,所以实现类型mybaits的功能,把sql语句编写在xml文件中,这样可以统一管理sql语句,维护更加容易。

1. 首先编写配置sql语句的xml的dtd文件,dtd文件主要是规范xml的,在编写sql语句的配置文件中主要有五个标签:select , update , insert , delete , import

其中select有两个属性id(保证所有的sql语句id唯一),resultClass(查询语句返回的对象,可以使具体的实体类,也可以是Map,List);import只有一个resource属性,指定导入的xml的位置,其他的标签都只有一个id属性。dtd文件如下,存放在hqhop-framework-common项目的/src/main/resources/META-INF下:

</pre><pre name="code" class="html"><!ELEMENT sqls-configs (import | insert | delete | update | select )*>

<!ELEMENT insert (#PCDATA)>
<!ATTLIST insert id ID #REQUIRED>

<!ELEMENT delete (#PCDATA)>
<!ATTLIST delete id ID #REQUIRED>

<!ELEMENT update (#PCDATA)>
<!ATTLIST update id ID #REQUIRED>

<!ELEMENT select (#PCDATA)>
<!ATTLIST select resultClass CDATA #REQUIRED>
<!ATTLIST select id ID #REQUIRED>

<!ELEMENT import EMPTY>
<!ATTLIST import resource CDATA #REQUIRED>

2. sql配置文件的参考事例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqls-configs PUBLIC "-//SQLS//MAIN CONFIG DTD//EN" "http://kf.hqhop.com:8888/hqhop-framework-sqls.dtd">
<sqls-configs>
	<select <span style="color:#ff0000;">id="select1"</span> resultClass="<span style="color:#ff0000;">com.hqhop.framework.shiro.entity.User</span>">
		select * from t_base_user where id =:id
	</select><pre name="code" class="html"><span style="white-space:pre">	</span><select <span style="color:#ff0000;">id="select2"</span> resultClass="<span style="color:#ff0000;">java.util.Map</span>">
		select * from t_base_user where id = ?
	</select>
<pre name="code" class="html"><span style="white-space:pre">	</span><select <span style="color:#ff0000;">id="select3" </span>resultClass="<span style="color:#ff0000;">java.util.List</span>">
		select * from t_base_user where id = ?
	</select>

<update id="update"></update><insert id="insert"></insert><delete id="delete"></delete><import resource="classpath:sql/test.xml" /></sqls-configs>


3. 解析sql的配置文件,类目录结构

实现主要就用到了这4个类,首先把每一条sql语句的信息存放到SQL对象中,然后在把SQL对象和配置的sql的id对应存放到SQLContext,当我们在使用的时候就直接去SQLContext中去取。

SQL.java

public class SQL {
	private String id;               //sql的id
	private String sql;              //具体的sql
	private Class resultClass;       //返回的实体类,只对select标签有效

	public SQL(String id, String sql, String resultClass) {
		this.id = id;
		this.sql = sql;
		try {
			if (Utils.isNotEmpty(resultClass))
				this.resultClass = Class.forName(resultClass);
			else
				this.resultClass = null;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}<pre name="code" class="java">        //get set....

}


SQLContext.java

public class SQLContext {
<span style="white-space:pre">	</span>//仅仅一个属性,使用map存放每一个sql语句,使用的时候更加key来找到sql
	private Map<String, SQL> sqls = new HashMap<>();
	public SQL getSQL(String sqlKey) {
		return sqls.get(sqlKey);
	}
	public Set<String> getKeys() {
		return sqls.keySet();
	}
	public void put(String sqlKey, SQL sql) {
		this.sqls.put(sqlKey, sql);
	}
	public boolean checkKeyIsExist(String key) {
		return this.sqls.containsKey(key);
	}
}

4. 解析sql的xml文件主要是在SQLContextFileBuilder中完成的,是一个的单例模式

1) 首先解析import标签,使用递归的方式把所有import的xml加载到一个document,实现的方法是public Document loadFullConfigFile(Resource resource, String encoding)

// 解析import包含的子配置文件
public Document loadFullConfigFile(Resource resource, String encoding) throws UnsupportedEncodingException, IOException, DocumentException {
	SAXReader reader = null;
	Document document = null;
	reader = new SAXReader();
	InputStreamReader isr = null;
	try {
		isr = new InputStreamReader(resource.getInputStream(), encoding);
		document = reader.read(isr);
	} finally {
		CloseUtil.close(isr);
	}
	final Element root = document.getRootElement();
	List list = document.selectNodes("//import");
	for (int i = 0; i < list.size(); i++) {
		Element n = (Element) list.get(i);
		String file = n.attribute("resource").getValue();
		Resource fr = SpringUtils.getResource(file);
		<span style="color:#ff0000;">Document includedDoc = loadFullConfigFile(fr, encoding);</span>
		List content = root.content();
		int indexOfPos = content.indexOf(n);
		content.remove(indexOfPos);
		Element ie = includedDoc.getRootElement();
		List ie_children = ie.content();
		for (int k = ie_children.size() - 1; k >= 0; k--) {
			content.add(indexOfPos, ie_children.get(k));
		}
	}
	this.rootDoc = document.getRootElement();
	return document;
}

2) 再从document中解析出所有的sql语句,创建SQL对象,存放到SQLContext中

public SQLContext loadSQLContext() {
	SQLContext sqlContext = new SQLContext();
	List els = rootDoc.elements();
	for (Object o : els) {
		Element element = (Element) o;
		String idKey = element.attribute("id").getValue();
		String sql = element.getTextTrim();
		Attribute attribute = element.attribute("resultClass");
		String resultClass = Utils.isNotEmpty(attribute) ? attribute.getValue() : null;
                <span style="color:#ff0000;">//判断sql的id是否已经存在 ,若存在就抛出异常</span>
	        if (<span style="color:#ff0000;">!sqlContext.checkKeyIsExist(idKey)</span>) {
			sqlContext.put(idKey, new SQL(idKey, sql, resultClass));
		} else {
			throw new RuntimeException("请检查sql的配置文件,sql的key已经存在(key=" + idKey + ")!");
		}
	}
	return sqlContext;
}

5. 让spring容器启动就去加载sql的xml文件:SQLContextFactory.java   只有一个方法,

public static SQLContext createSQLContext(Resource springResource){......}        完成解析xml文件,返回sqlContext

在spring的xml配置文件中添加如下代码来完成SQLContext的创建:

<bean id="sqlContext" class="com.hqhop.framework.common.orm.sql.SQLContextFactory" factory-method="createSQLContext">
        <constructor-arg>
                 <!-- 指定sql文件的位置 -->
	         <value><span style="color:#ff0000;">classpath:sqls/sql.xml</span></value>
	</constructor-arg>
</bean>

6. 到此为止sqlContext已经存在了spring容器中了,接下来就在 BaseRepoitoryImpl中来使用sqlContext,在BaseRepoitory中定义了几个使用sql的xml的接口,这里就只说明一个接口就行了:

public List<T> findAll(String sqlKey, Object... params) {....}

@Autowired
private SQLContext sqlContext;
public List<T> findAll(String sqlKey, Object... params) {
	SQL sql = this.sqlContext.getSQL(sqlKey);
	SQLQuery sqlQuery = this.getSession().createSQLQuery(sql.getSql());
	RepositoryHelper.setValues(sqlQuery, params);
	RepositoryHelper.setResultTransformer(sqlQuery, sql.getResultClass());
	return sqlQuery.list();
}

1) 传入一个sql的id,然后通过sqlContext来获取对应的SQL对象,通过RepoitoryHelper.setValues(...)来设置参数的值,这里传入的params可以使多个参数值,也可以是一个map对象,具体使用什么就要根据编写的sql来决定

select * from t_base_user where id =:id                  这种方式只能传入map对象

select * from t_base_user where id = ?                   这种方式只能传入对个参数值

RepositoryHelper.setValues(.....)代码如下:

public static void setValues(Query query, Object... params) {
	if (params[0] instanceof Map) {
		Map mapParams = (Map) params[0];
		Set<String> keys = mapParams.keySet();
		for (String key : keys) {
			query.setParameter(key, mapParams.get(key));
		}
	} else {
		int paramIndex = 0;
		for (Object o : params) {
			query.setParameter(paramIndex++, o);
		}
	}
}

2) 绑定查询出来的数据应该转化成什么对象,使用RepositoryHelper.setResultTransformer(...)来完成的,这里的resultClass是在sql的xml文件中指定的,只对select标签有效:

public static void setResultTransformer(SQLQuery query, Class resultClass) {
	if (Utils.isNotEmpty(resultClass)) {
		if (<span style="color:#ff0000;">resultClass.equals(List.class)</span>) {
			query.setResultTransformer(Transformers.TO_LIST);
		} else if (<span style="color:#ff0000;">resultClass.equals(Map.class)</span>) {
			query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		} else {
			query.addEntity(resultClass);
		}
	}
}

其他使用sql的xml接口的实现方式都类似。

时间: 2024-10-08 06:04:44

J2EE开发框架搭建(7) - 用hibernate实现类似mybaits把sql写在配置文字中的相关文章

J2EE开发框架搭建目录

搭建的一个简单的J2EE开发框架 框架使用到的Java技术: 1. springmvc4   spring4 2. orm使用hibernate4 3. 安全框架使用shiro 4. 数据源使用druid 5. 整个框架使用maven管理 6. 缓存可以使用memcached,ehcached 7. 日志使用slf4j+log4j 项目下载地址:http://pan.baidu.com/s/1sjPSxtj J2EE开发框架搭建(1) - maven搭建多项目 J2EE开发框架搭建(2) - s

J2EE开发框架搭建(6) - 使用hibernate4完成基本Dao的封装

现在orm框架有很多,比如说guzz,hibernate,mybaits....,在封装一个框架的时候我们可以选择一种,也可以选择多种实现,供以后使用选择,这里我只实现了hibernate,目录结构图如下: 1. 首先查询BaseRepository这个接口,该接口泛型 :T 表示实体类型:ID表示主键类型:虽然在框架里面已经提供了查询的结构Searchable,但是Searchable也不能做到无限强大,比如一个多变关联查询,嵌套查询是没有办法完成的,所有只能自己编写sql语句,但是hiber

J2EE开发框架搭建(2) - springmvc4 + spring4 + hibernate4 整合

1. 打开hqhop-framework-parent项目下的pom.xml文件,添加springmvc4 , spring4 , hibernate4 ,以及数据源druid的依赖包,插件,依赖包版本号 <!-- data source 相关jar? --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version&g

J2EE开发框架搭建(1) - maven搭建多项目

如何使用maven搭建多个项目 1. 创建一个maven project 2. 在frame-parent项目上面点击右键,新建Maven Module 3. 完成之后再建立一个web项目 4. 按照是以上的步骤建立,最后我建立的项目目录结构 框架使用到的Java技术: 1. springmvc4   spring4 2. orm使用hibernate4 3. 安全框架使用shiro 4. 数据源使用druid 5. 整个框架使用maven管理 6. 缓存可以使用memcached,ehcach

J2EE开发框架搭建(5) - Java项目开发常用工具类

工具类下项目中的目录位置: 1. 中文转化成拼音.首字母  ,ChineseCharToPinYin,使用这个类的时候必须要加入pinyin.jar,pinyin.jar已经放到hqhop-framework-web项目的lib目录中: 使用方式: ChineseCharToPinYin只提供了两个方法: public static String getPinYin(String src) {.....}      将汉字转换为全拼 public static String getPinYinH

J2EE开发框架搭建(9) - memcached与spring提供的cache接口整合

spring 从3.x就提供了cache接口,spring默认实现的缓存是ehcache,spring的cache接口: public interface Cache { String getName(); Object getNativeCache(); ValueWrapper get(Object key); <T> T get(Object key, Class<T> type); void put(Object key, Object value); void evict

J2EE开发框架搭建(3) - 查询条件封装

这一节主要想要说明一下框架中的查询条件接口 1. 条件查询的整个类结构图 2. 在hqhop-framework-common项目下面查询条件的的目录结构: 3. 打开SearchOperator.java , 该类包含了所有的查询操作符,是一个枚举类型: public enum SearchOperator { eq("等于", "="), ne("不等于", "!="), gt("大于", "

ONVIF学习-ONVIF开发框架搭建(C++)

第一步.下载gsoap 从gsoap官网(http://www.genivia.com/products.html#notice)下载最新版gsoap(博主用的是gsoap_2.8.45).gsoap有三个版本:Open Source gSOAP.Commercial gSOAP Edition.Commercial gSOAP Edition.我们下载开源版本即可. 第二步.解压gsoap并建立文件夹层次    新建一个文件夹,命名为OnvifFramework,将下载下来的gsoap_x.x

C# 快速开发框架搭建—开发工具介绍

C# 快速开发框架搭建-开发工具介绍 一.VS2013,SQL SERVER R22008 以上两种工具如有不会者自行百度学习下. 二.动软代码生成器 对于经典的三层架构框架来说,使用动软代码生成器会起到事半功倍的效果.链接(http://www.maticsoft.com/download.aspx) 三.如何使用 1.打开工具,点击如下图的连接SQL Server数据库服务器 2.如图,填写好数据库相关配置,点击连接测试,可以看到你的数据库出现在了下拉列表中,点击选择你的数据库,点击下一步: