1. 程式人生 > >適用於通用mapper的BaseService升級版

適用於通用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>

 後續等博主有時間了,再來寫一寫後續程式碼,博主也是小白,也是不斷的學習,如果大家有什麼需要指點的,積極在下面評論哦,我也會積極抽出耐心汲取大家寶貴的經驗。謝謝啦!