J2EE開發框架搭建(6) - 使用hibernate4完成基本Dao的封裝
來源:程序員人生 發布時間:2014-09-29 08:00:01 閱讀次數:2695次
現在orm框架有很多,比如說guzz,hibernate,mybaits....,在封裝一個框架的時候我們可以選擇一種,也可以選擇多種實現,供以后使用選擇,這里我只實現了hibernate,目錄結構圖如下:

1. 首先查詢BaseRepository這個接口,該接口泛型 :T 表示實體類型;ID表示主鍵類型;雖然在框架里面已經提供了查詢的結構Searchable,但是Searchable也不能做到無限強大,比如一個多變關聯查詢,嵌套查詢是沒有辦法完成的,所有只能自己編寫sql語句,但是hibernate編寫sql語句都只能寫在java代碼里面,用過mybaits的朋友就知道sql語句可以配置在xml里面 ,這里我們就可以簡單的仿照mybaits來完成,在這個接口中就提供了調用xml中的sql語句的方法,具體怎么實現后面再說明:
package com.hqhop.framework.common.orm;
///import .....
/**
* <p>
* 抽象DAO層基類 提供一些簡便方法<br/>
* <p/>
* <span style="color:#ff0000;">泛型 :T 表示實體類型;ID表示主鍵類型</span>
* <p>
* Version: 1.0
*
* @author silentwu
*/
public interface BaseRepository<T extends AbstractEntity<ID>, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
/**
* 根據主鍵刪除
*
* @param ids
*/
public void delete(ID... ids);
/**
* 根據條件查詢所有 條件 + 分頁 + 排序
*
* @param searchable
* @return
*/
public Page<T> findAll(Searchable searchable);
/**
* 根據條件統計所有記錄數
*
* @param searchable
* @return
*/
public long count(Searchable searchable);
public void update(T entity);
/**
* 自定義sql更新
*
* @param sqlKey
* @param params
*/
public void update(String sqlKey, Object... params);
/**
* 自定義sql查詢
*
* @param sqlKey
* @param params
* @return
*/
public List<T> findAll(String sqlKey, Object... params);
public Page<T> findPage(Pageable pageable, String sqlKey, Object... params);
/**
* 自定義sql刪除
*
* @param sqlKey
* @param params
*/
public void delete(String sqlKey, Object... params);
}
該接口繼承了spring的PagingAndSortingRepository接口, 然而PagingAndSortingRepository又繼承了CrudRepository接口,所以BaseRepository就具有了基本的增刪改查以及自己定義的一些方法:
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
2. 接下來查看BaseRepository的實現類BaseRepositoryImpl,由于要使用hibernate操作數據庫,所以要提供session,在hibernate4中已經建議直接使用session操作數據庫,建議不要在使用hibernateTemplate;要使用sessionFactory.getCurrentSession()來獲取當前的線程中的session就必須開啟事物,所以在spring-config.xml中加入下代碼:
<!-- 開啟注解事務 只對當前配置文件有效 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- 配置Hibernate事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
在BaseRepositoryImpl就可以使用如下代碼了:
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
// 事務必須是開啟的(Required),否則獲取不到
return sessionFactory.getCurrentSession();
}
3. 在BaseRepositoryImpl中還必須要有一個Class 屬性,指定運行時刻BaseRepositoryImpl操作的實體類,因為在hibernate中做了sql查詢或者是hql查詢,查詢的結果通過反射轉化為實體類返回到service。那么又怎么給這個Class對象賦值呢?在這里我們需要自己定義一個注解Repository,在這個注解中就記錄了BaseRepositoryImpl要操作的實體類:
/**
*
* @author silentwu
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@org.springframework.stereotype.Repository
public @interface Repository {
/**
* Repository在spring容器中的實例名稱
*/
String value() default "";
/**
* Repository處理的實體類
*
* @return
*/
Class<?> entity();
}
接下來我們就可以直接在BaseRepositoryImpl中獲取這個注解來得到Class,在BaseRepositoryImpl中添加如下代碼:
private Class<T> clazz;
@PostConstruct
@SuppressWarnings("unchecked")
public void init() throws Exception {
<span style="color:#ff0000;">Repository repository = this.getClass().getAnnotation(Repository.class);</span>
if (Utils.isNotEmpty(repository)) {
if (Utils.isNotEmpty(repository.entity())) {
<span style="color:#ff0000;">this.clazz = (Class<T>) repository.entity();</span>
this.countAllQL = String.format(COUNT_QUERY_STRING, clazz.getName());
this.findAllQL = String.format(FIND_QUERY_STRING, clazz.getName());
} else {
throw new Exception(Repository.class + "注解的entity不能為空!");
}
} else {
throw new Exception(this.getClass() + " 必須要使用" + Repository.class + "注解!");
}
}
在init()方法上面添加了@PostConstruct注解,表示在類被spring容器實例化后要執行的方法;也可以實現spring的InitializingBean接口來達到同樣的效果(但是spring已經不推薦使用這種方式)
4. 在前面的章節中,我們提供了邏輯刪除的接口LogicDeleteable,具體實現邏輯的刪除就是在BaseRepositoryImpl中,在BaseRepositoryImpl中提供了多個刪除方法,但是主要的刪除操作只有一個delete(T entity),其他的刪除都是調用的這個:
/**
* 檢查是否實現了邏輯刪除接口
*
* @return
*/
private boolean checkLogicDeleteable() {
Class[] inters = this.clazz.getInterfaces();
boolean flag = false;
for (int i = 0; i < inters.length; i++) {
if ("LogicDeleteable".equals(inters[i].getSimpleName())) {
flag = true;
break;
}
}
return flag;
}
@Override
public void delete(T entity) {
if (Utils.isNotEmpty(entity)) {
if (entity instanceof LogicDeleteable) {
((LogicDeleteable) entity).markDeleted();
update(entity);
} else {
this.getSession().delete(entity);
}
}
}
在刪除對象的時候首先判斷是否實現了LogicDeleteable接口,若為true ==> 調用markDeleted(); 否則真實刪除。
5. BaseRepository,BaseRepositoryImpl的使用方式,操作User實體類:
接口UserDao
public interface UserDao extends BaseRepository<User, String> {
}
實現類UserDaoImpl,使用@Repository注解,指定操作的實體類
@Repository(entity = User.class)
public class UserDaoImpl extends BaseRepoitoryImpl<User, String> implements UserDao {
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈