上次写了一篇博客适用于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>
后续等博主有时间了,再来写一写后续代码,博主也是小白,也是不断的学习,如果大家有什么需要指点的,积极在下面评论哦,我也会积极抽出耐心汲取大家宝贵的经验。谢谢啦!