到目前爲止,咱們已經寫了三個模塊的開發了。咱們已經抽取過了BaseAction、BaseDao,咱們此次來看看咱們的Service接口。php
/** * created by ozc on 2017/5/23. */ public interface UserService { //新增 void save(User user); //更新 void update(User user); //根據id刪除 void delete(Serializable id); //根據id查找 User findObjectById(Serializable id); //查找列表 List<User> findObjects() throws ServiceException; //導出用戶列表 void exportExcel(List<User> userList, ServletOutputStream outputStream); //導入用戶列表 void importExcel(File userExcel, String userExcelFileName); /** * 根據賬號和用戶id查詢用戶 * * @param id 用戶ID * @param account 用戶賬號 * @return 用戶列表 */ List<User> findAccount(String id, String account); void saveUserAndRole(User user, String[] userRoleIds); //經過用戶id獲得該用戶的角色 List<UserRole> findRoleById(String id); void deleteUserRoleById(String[] userRoleIds); List<User> findUserByAccountAndPassword(String account, String password); }
/** * created by ozc on 2017/5/23. */ public interface InfoService { //新增 public void save(Info info); //更新 public void update(Info info); //根據id刪除 public void delete(Serializable id); //根據id查找 public Info findObjectById(Serializable id); //查找列表 public List<Info> findObjects() ; }
/** * Created by ozc on 2017/5/26. */ public interface RoleService { //新增 void save(Role role); //更新 void update(Role role); //根據id刪除O void delete(Serializable id); //根據id查找 Role findObjectById(Serializable id); //查找列表 List<Role> findObjects() ; }
咱們能夠發現,三個Service接口中都存在着增刪改查的方法,這明顯就是重複的代碼。所以,咱們須要將他們進行抽取成一個BaseService。java
在core模塊中添加service包,抽取BaseServicesql
package zhongfucheng.core.service; import java.io.Serializable; import java.util.List; /** * Created by ozc on 2017/6/7. */ interface BaseService<T> { //新增 void save(T entity); //更新 void update(T entity); //根據id刪除 void delete(Serializable id); //根據id查找 T findObjectById(Serializable id); //查找列表 List<T> findObjects(); }
咱們的Sercive是調用dao層的對象來實現方法的,由於這個Service是表明整個項目的Service,因而應該使用BaseDao數據庫
package zhongfucheng.core.service.impl; import zhongfucheng.core.dao.BaseDao; import zhongfucheng.core.service.BaseService; import java.io.Serializable; import java.util.List; /** * Created by ozc on 2017/6/7. */ public abstract class BaseServiceImpl <T> implements BaseService <T>{ //經過BaseDao來操做數據庫 private BaseDao<T> baseDao; @Override public void save(T entity) { baseDao.save(entity); } @Override public void update(T entity) { baseDao.update(entity); } @Override public void delete(Serializable id) { baseDao.delete(id); } @Override public T findObjectById(Serializable id) { return baseDao.findObjectById(id); } @Override public List<T> findObjects() { return baseDao.findObjects(); } }
InfoService繼承了BaseService接口,因而就有了增刪改查的方法。同時把泛型T的類型肯定下來。markdown
/** * created by ozc on 2017/5/23. */ public interface InfoService extends BaseService<Info> { }
繼承了InfoService,有了增刪該查的方法,然而具體的操做是BaseServiceImpl中實現的。咱們繼承它,並給出泛型T對應的類型。ide
@Service public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService { }
如今的問題是什麼呢???咱們在BaseServiceImpl中使用了BaseDao這個變量來對數據庫進行操做。但是在BaseServiceImpl中是沒有BaseDao這個變量的。工具
首先,要明確的是,咱們不能在BaseServiceImpl中注入BaseDao,由於BaseServiceImpl自己就是一個抽象類。那咱們怎麼對BaseDao進行實例化呢???優化
咱們能夠這樣作:this
最後,咱們在BaseServiceImpl中就有了baseDao這個變量了。spa
InfoServiceImpl獲得InfoDao對象,並把InfoDao對象設置到BaseServiceImpl中。
@Service public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService { private InfoDao infoDao; @Resource public void setInfoDao(InfoDao infoDao) { super.setBaseDao(infoDao); this.infoDao = infoDao; } }
//經過BaseDao來操做數據庫 private BaseDao<T> baseDao; public void setBaseDao(BaseDao<T> baseDao) { this.baseDao = baseDao; }
咱們來實現下面的功能:
其實也是一個查詢,只不過查詢多了一個條件罷了。按照傳統的方式咱們能夠這樣作:
//根據條件查詢列表 List<T> findObjects(String sql, List<Object> objectList);
@Override public List<T> findObjects(String sql, List<Object> objectList) { Query query = getSession().createQuery(sql); if (objectList != null) { int i =0; for (Object o : objectList) { query.setParameter(i, o); i++; } return query.list(); } return query.list(); }
//根據條件查詢列表 List<T> findObjects(String sql, List<Object> objectList);
@Override public List<T> findObjects(String sql, List<Object> objectList) { return baseDao.findObjects(sql, objectList); }
咱們仍是用着listUI這個方法,由於它僅僅是參數可能不一樣。
public String listUI() { //查詢語句 String hql = "FROM Info i "; List<Object> objectList = new ArrayList<>(); //根據info是否爲null來判斷是不是條件查詢。若是info爲空,那麼是查詢全部。 if (info != null) { if (StringUtils.isNotBlank(info.getTitle())) { hql += "where i.title like ?"; objectList.add("%" + info.getTitle() + "%"); } } infoList = infoServiceImpl.findObjects(hql,objectList); ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP); return "listUI"; }
看回咱們Action中的代碼,咱們能夠看出一些不夠優雅的地方:
因而,咱們想要用一個工具類來把上面的代碼進行優化。
針對上面的問題,咱們發現手寫拼接SQL很容易出錯。那咱們能夠在工具類裏面拼接,使用的時候調用方法獲取就行啦。查詢的對象寫死了,咱們要能夠處理任何的查詢。。
咱們可以找到以下的規律:
FROM Info WHERE title like ? and state = ? order by createTime,state 條件查詢(QueryHelper): 1、查詢條件語句hql: from 子句:一定出現;並且只出現一次 where 子句:可選;但關鍵字where 出現一次;可添加多個查詢條件 order by子句:可選;但關鍵字order by 出現一次;可添加多個排序屬性 2、查詢條件值集合: 出現時機:在添加查詢條件的時候,?對應的查詢條件值
package zhongfucheng.core.utils; import java.util.ArrayList; import java.util.List; /** * Created by ozc on 2017/6/7. */ public class QueryHelper { private String fromClause = ""; private String whereClause = ""; private String orderbyClause = ""; private List<Object> objectList; public static String ORDER_BY_ASC = "asc"; public static String ORDER_BY_DESC = "desc"; //FROM子句只出現一次 /** * 構建FROM字句,並設置查詢哪張表 * @param aClass 用戶想要操做的類型 * @param alias 別名 */ public QueryHelper(Class aClass, String alias) { fromClause = " FROM " + aClass.getSimpleName() + " " + alias; } //WHERE字句能夠添加多個條件,但WHERE關鍵字只出現一次 /** * 構建WHERE字句 * @param condition * @param objects * @return */ public QueryHelper addCondition(String condition, Object... objects) { //若是已經有字符了,那麼就說明已經有WHERE關鍵字了 if (whereClause.length() > 0) { whereClause += " AND " + condition; } else { whereClause += " WHERE" + condition; } //在添加查詢條件的時候,?對應的查詢條件值 if (objects == null) { objectList = new ArrayList<>(); } for (Object object : objects) { objectList.add(object); } return this; } /** * * @param property 要排序的屬性 * @param order 是升序仍是降序 * @return */ public QueryHelper orderBy(String property, String order) { //若是已經有字符了,那麼就說明已經有ORDER關鍵字了 if (orderbyClause.length() > 0) { orderbyClause += " , " + property +" " + order; } else { orderbyClause += " ORDER BY " + property+" " + order; } return this; } /** * 返回HQL語句 */ public String returnHQL() { return fromClause + whereClause + orderbyClause; } /** * 獲得參數列表 * @return */ public List<Object> getObjectList() { return objectList; } }
public String listUI() { QueryHelper queryHelper = new QueryHelper(Info.class, "i"); //根據info是否爲null來判斷是不是條件查詢。若是info爲空,那麼是查詢全部。 if (info != null) { if (StringUtils.isNotBlank(info.getTitle())) { queryHelper.addCondition(" i.title like ? ", "%" + info.getTitle() + "%"); } } queryHelper.orderBy("i.createTime", QueryHelper.ORDER_BY_DESC); infoList = infoServiceImpl.findObjects(queryHelper); //infoList = infoServiceImpl.findObjects(hql,objectList); ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP); return "listUI"; }