通用Mapper和通用Service,基于mybatis

对于SERVICE层有哪些是可以被公共出来的东西?
1.对于单张表的增、删、改、查(单条查、批量查、分页查)功能


1.通用Mapper

作用: 所有对单张表的crud操作,都可以通过通用Mapper来简化代码

可参考day98_ssm中第五天和第六天

讲通用Mapper之前我们先讲动态代理Mapper,动态代理Mapper就是不需要再写具体的Mapper接口实现了,直接通过Mapper接口+方法和Mapper映射文件相关联

Mapper接口的动态代理实现,需要满足以下条件:

  • 1.映射文件中命名空间和Mapper接口的全路径一致
  • 2映射文件中的statementId与Mapper接口的方法名保持一致
  • 3.映射文件中的statement的ResultType必须和mapper接口方法的返回类型一致(即使不采用动态代理,也要一致)
  • 4.映射文件中的statement的parameterType必须和mapper接口方法的参数类型一致(不一定,该参数可省略)

而通用Mapper则更简单,只有自定义的Mapper接口实现了Mapper接口即可,连Mapper映射文件都不用写,在父类的Mapper接口已经定义了一些通用方法,但是这些方法仅是对单张表的crud,如果要写复杂的crud,就不能用通用Mapper了

2.通用Service

功能: 对于单张表的增、删、改、查(单条查、批量查、分页查)功能
两个点需要注意:

  • (1)通过定义抽象的getMapper()方法,再由子类实现的方式,实现对Mapper的注入
  • (2)通过反射来获取BaseService中的泛型类型

在通用service中,我们并不知道返回值具体是什么,那怎么办?写Object,太原始了,之后还要强转,对了.我们可以使用泛型,那么我们应该是定义泛型类还是单独定义泛型方法,答案是泛型类,所有方法都能用这个泛型

@SuppressWarnings("unchecked")
public abstract class BaseService {
    
    public abstract Mapper getMapper();
    
    // 当前Service上泛型的字节码对象
    private Class clazz;
    {
        // 读取当前类上的泛型
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        clazz = (Class) type.getActualTypeArguments()[0];
    }
    
    /**
     * 根据主键进行查询
     * @param id
     * @return
     */
    public T queryById(Long id){
        return this.getMapper().selectByPrimaryKey(id);
    }
    
    /**
     * 查询全部
     * @return
     */
    public List queryAll(){
        return this.getMapper().select(null);
    }
    
    /**
     * 根据条件查询1条数据。
     * @param record
     * @return
     */
    public T queryOne(T record){
        return this.getMapper().selectOne(record);
    }
    
    /**
     * 根据条件查询多条数据
     * @param record
     * @return
     */
    public List queryListByWhere(T record){
        return this.getMapper().select(record);
    }
    
    /**
     * 根据条件分页查询
     * @param record
     * @return
     */
    public PageInfo queryPageListByWhere(T record, Integer page, Integer rows){
        PageHelper.startPage(page, rows);
        List list = this.getMapper().select(record);
        return new PageInfo<>(list);
    }
    
    /**
     * 插入数据
     * @param record
     * @return
     */
    public Integer save(T record){
        record.setCreated(new Date());
        record.setUpdated(record.getCreated());
        return this.getMapper().insert(record);
    }
    
    /**
     * 插入数据,只操作record中的非空属性
     * @param record
     * @return
     */
    public Integer saveSelective(T record){
        record.setCreated(new Date());
        record.setUpdated(record.getCreated());
        return this.getMapper().insertSelective(record);
    }
    
    
    /**
     * 更新数据
     * @param record
     * @return
     */
    public Integer update(T record){
        record.setUpdated(new Date());
        // TODO 这里如何解决用户传入的created属性的问题?
        return this.getMapper().upateByPrimaryKey(record);
    }
    
    /**
     * 更新数据,只操作record中的非空属性
     * @param record
     * @return
     */
    public Integer updateSelective(T record){
        record.setUpdated(new Date());
        // 保证created字段不会被修改
        record.setCreated(null);
        return this.getMapper().updateByPrimaryKeySelective(record);
    }
    
    /**
     * 根据主键进行删除
     * @param id
     * @return
     */
    public Integer deleteById(Long id){
        return this.getMapper().deleteByPrimaryKey(id);
    }
    
    /**
     * 批量删除
     * @param id
     * @return
     */
    public Integer deleteByIds(String property, List ids){
        Example example = new Example(clazz);
        example.createCriteria().andIn(property, ids);
        return this.getMapper().deleteByExample(example);
    }
    
    /**
     * 根据条件删除
     * @param id
     * @return
     */
    public Integer deleteByWhere(T record){
        return this.getMapper().delete(record);
    }
    
}

我们可以在自己的service子类中定义对应的Mapper,当然既然用了通用Mapper,我们可以更简洁的,在通用service中注入Mapper,那怎么注入呢,因为@Autowired是通过类型和id注入,如果没有类型压根无法注入

所有的通用Mapper都实现了Mapper接口,我们能不能直接定义一个了Mapper类型的成员?

public class BaseService {
	
	@Autowired
	public Mapper service;
	
}

想法固然是美好的,但是当之后我们自定义的Mapper越来越多后,同一个接口下可能有很多子类,Spring无法自我判断,所以我们得想个更好的方法

既然在父类中,我们并不知道Mapper应该是什么泛型,但是我们在子类实现时,是指定应该用什么Mapper,所以我们可以在通用service中定义一个抽象方法,当子类调用父类方式时,因为是抽象方法,所以实际上还是调用子类中的提供的Mapper,但优点是父类中方法能引用这个Mapper

public abstract class BaseService {
	
	public abstract Mapper getMapper();
	......
	
}

注意哦,抽象方法的存在是为了让人实现的,所以必须是public

其中在save方法时,我们除了用户添加的信息外,还有设计Updated和Created的时间,这两个值也应该写在通用service中,此时是要我们T extends BasePojo就能使用BasePojo中方法设置值

你可能感兴趣的:(通用Mapper和通用Service,基于mybatis)