適用於通用mapper的BaseService升級版
上次寫了一篇部落格適用於Generator mybatis 生成器的通用BaseService
這次是上次的升級版,因為在開發的過程中發現,mybatisGenerator生成器生成的程式碼有個弊端,雖然大大解放了我們雙手,減少了CURD的程式碼的編寫,但是當我們業務需求發生變動的時候,如資料庫新增一條欄位,這樣我們必須重新在使用MG(mybatisGenerator )生成一次非常麻煩,而這次是通過引入通用mapper來解決此問題,通用mapper外掛。通用mapper它只生成mapper.xml的實體類對映和一個繼承自己的專屬mapper,生成的mapper介面沒有方法,因為所有的CURD方法都繼承了父類,所以當我們如資料庫新增一個欄位的時候,我們只需要修改po類和mapper.xml對映欄位,很方便,CURD操作也非常多,基本上解決了90%的CURD操作,還沒學過使用通用mapper的可以下面連結學習。
通用mapper學習通用mapper學習
這次封裝的BaseService的底層用的是通用mapper,只需要自己的service繼承該service,就實現了各種CURD操作,後期在藉助我將要公佈的BaseController和通用mapper,po,service,controller生成器,基本上不用手寫一行程式碼,可以完成90%的單表操作,你只需要專注前端的介面呼叫設計就行了,BaseService程式碼如下。
/** * 基本Service * * @auther ny by:dbw * @create 2018-06-09 */ public class BaseService<T> { private Class<T> cache=null; //快取子類泛型型別 @Autowired Mapper<T> mapper; T clazz; /** * 新增 * @param t * @return */ public T add(T t){ System.out.println(t); int i = mapper.insertSelective(t); if(i>0) return t; else return null; } /** * 刪除 by 主鍵key * @param t */ public void delete(T t){ mapper.deleteByPrimaryKey(t); } /** * 通過主鍵集合批量刪除 * 資料庫主鍵名必須為id * @param ids */ public int deleteByIds(List<Integer> ids){ Example example=Example.builder(getTypeArguement()).where(Sqls.custom().andIn("id",ids)).build(); return mapper.deleteByExample(example); } /** * 更新 * @param t * @return */ public int update(T t){ return mapper.updateByPrimaryKeySelective(t); } public int batchUpdate(T record,Integer[] ids,Object properties){ Example example=Example.builder(getTypeArguement()).where(Sqls.custom().andIn("id", Arrays.asList(ids))).build(); return mapper.updateByExample(record,example); } /** * 查詢一條資料 * @param t * @return */ public T queryOne(T t){ return mapper.selectOne(t); } /** * 通用查詢指定欄位service * @param where 查詢條件 * @param orderByField 排序欄位 * @param fields 實體類名 * @return */ public T queryOneByFiled(Sqls where,String orderByField, String ...fields){ return (T) queryByFiledBase(null,null,where,orderByField,fields).get(0); } /** * 通過查詢欄位獲取集合 * @param where where查詢條件 * @param orderByField 排序欄位 * @param fields 檢索欄位 * @return List<T> */ public List<T> queryListByFiled(Sqls where,String orderByField, String ...fields){ return queryByFiledBase(null,null,where,orderByField,fields); } /** * 通過欄位查詢分頁 * @param pageNo 起始頁 * @param pageSize 頁大小 * @param where 查詢條件 * @param orderByField 排序欄位 * @param fields 查詢欄位 * @return pageInfo 分頁物件 */ public PageInfo<T> queryListByPageAadFiled(Integer pageNo,Integer pageSize,Sqls where,String orderByField, String ...fields){ return new PageInfo<T>(queryByFiledBase(pageNo,pageSize,where,orderByField,fields)); } /** * 通過欄位查詢依託通用方法 * @param pageNo 起始頁 * @param pageSize * @param where * @param orderByField * @param fields * @return */ private List<T> queryByFiledBase(Integer pageNo,Integer pageSize,Sqls where,String orderByField, String ...fields){ Example.Builder builder=null; if(null==fields||fields.length==0){ //查詢所有 builder = Example.builder(getTypeArguement()); }else{ //查詢指定欄位 builder= Example.builder(getTypeArguement()) .select(fields); } if(where!=null){ builder=builder.where(where); } if(orderByField!=null){ builder= builder .orderByDesc(orderByField); } Example example=builder.build(); if(pageNo!=null&&pageSize!=null) { PageHelper.startPage(pageNo, pageSize); //分頁外掛 } List list = getMapper().selectByExample(example); return list; } /** * 查詢多條結果 * @param t 查詢條件 * @return */ public List<T> queryList(T t){ return mapper.select(t); } /** * 分頁查詢 * @param t 條件 * @param pageNo 當前頁 * @param pageSize 頁大小 * @return */ public PageInfo<T> queryListByPage(T t,int pageNo,int pageSize){ PageHelper.startPage(pageNo,pageSize); List<T> select = mapper.select(t); PageInfo<T> pageInfo = new PageInfo<>(select); return pageInfo; } /** * 反射例項 * @param map * @return */ public T newinstance(Map map){ //自定義反射效能更高 return (T) Bean2MapUtil.map2Bean(map,getTypeArguement()); // JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(map)); // return jsonObject.toJavaObject(getTypeArguement()); } /** * 獲取子類泛型型別 * @return */ public Class<T> getTypeArguement() { if(cache==null) cache= (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; return cache; } /** * 獲取spring容器 * @return */ public ApplicationContext getApplicationContext(){ return SpringContextUtils.getApplicationContext(); } protected Mapper getMapper(){ return mapper; } }
優化部分:
1. cache= (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
這裡使用了快取,快取當前的子類泛型,不然每次都需要重新獲取子類泛型結果,非常耗時,所以在這裡進行了優化。
2. return (T) Bean2MapUtil.map2Bean(map,getTypeArguement());
// JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(map));
// return jsonObject.toJavaObject(getTypeArguement());以前用的是alibabaFastJson的Map轉PO的方法,但是發現該框架的效能基本上都集中於反射這裡,後來通過自己寫的Map轉Bean的方法,用了兩個工具 :objenesis,reflectasm,都是增強發射效能的。具博主測試,比原先方法效能提高了2.5倍其具體實現程式碼如下:
/**
* bean與map互相轉化工具
* @author dbw
*/
public class Bean2MapUtil {
//高效能java例項化工具
private final static Objenesis objenesis = new ObjenesisStd(true);
private final static StringBuilder stringBuilder=new StringBuilder();
//快取reflectASM的反射位元組集
private final static ConcurrentHashMap<Class,MethodAccess> CONCURRENT_HASH_MAP=new ConcurrentHashMap<Class,MethodAccess>(16);
/**
* map轉java bean工具類
* @param map
* @param clazz
* @param <T>
* @return
*/
public static <T> T map2Bean(Map<String,Object> map, Class<T> clazz){
T instance = objenesis.newInstance(clazz);
MethodAccess methodAccess = CONCURRENT_HASH_MAP.get(clazz);
if(methodAccess==null){
methodAccess=MethodAccess.get(clazz);
CONCURRENT_HASH_MAP.putIfAbsent(clazz,methodAccess);
}
for(Map.Entry<String,Object> entry:map.entrySet()){
String setMethodName = getSetMethodName(entry.getKey());
int index = methodAccess.getIndex(setMethodName,entry.getValue().getClass());
methodAccess.invoke(instance,index,entry.getValue());
}
return instance;
}
/**
*
* @Title: fristToUpperCase
* @Description: 首字母變大寫
* @param @param str
* @param @return 設定引數
* @return String 返回型別
* @since 1.0.0
* @author dbw
* @throws
*/
private static String fristToUpperCase(String str){
return str.substring(0,1).toUpperCase()+str.substring(1,str.length());
}
/**
* 通過欄位獲取方法名字
* @param filedName
* @return
*/
private static String getSetMethodName(String filedName){
stringBuilder.setLength(0);
return stringBuilder.append("set").append(fristToUpperCase(filedName)).toString();
}
}
其中兩個工具用到的maven座標如下:
<!-- Objenesis -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.1</version>
</dependency>
<!--高效能反射工具-->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.0</version>
</dependency>
後續等博主有時間了,再來寫一寫後續程式碼,博主也是小白,也是不斷的學習,如果大家有什麼需要指點的,積極在下面評論哦,我也會積極抽出耐心汲取大家寶貴的經驗。謝謝啦!