告别繁琐的业务层代码,MyBatis-Plus带你飞~

  • Post author:
  • Post category:其他



学习要求

良好的java基础, 熟悉SpringBoot框架,熟悉Mybatis框架



教学目标

了解并掌握MyBatis-Plus业务层的实现

视频教程


MyBatisPlus实战教程与开发建议

概念

Java项目一般使用三层结构开发:

表现层:接收请求,调用业务方法处理请求,响应请求

业务层:也叫服务层,实现业务逻辑,调用持久层实现数据组合操作

持久层:完成数据的CRUD操作

前面讲的Mapper接口操作属于持久层,如果项目加入服务层,那代码该如何构建呢?

传统的业务层

使用MyBatis-Plus之前,传统业务层构建方式:以员工操作为例子

步骤1:构建员工业务层服务接口

public interface IEmployeeService {
    void save(Employee employee);
    void update(Employee employee);
    void delete(Long id);
    Employee get(Long id);
    List<Employee> list();
}

步骤2:实现员工业务层接口

@Service
public class EmployeeServiceImpl implements IEmployeeService {
    @Autowired
    private EmployeeMapper mapper;

    @Override
    public void save(Employee employee) {
        mapper.insert(employee);
    }

    @Override
    public void update(Employee employee) {
        mapper.updateById(employee);  //必须全量更新
    }

    @Override
    public void delete(Long id) {
        mapper.deleteById(id);
    }

    @Override
    public Employee get(Long id) {
        return mapper.selectById(id);
    }
    @Override
    public List<Employee> list() {
        return mapper.selectList(null);
    }
}

步骤3:实现服务方法测试

传统业务层服务方法需要自己调用Mapper接口方法去实现,相对麻烦。再看MyBatis-Plus提供简化操作

MyBatis-Plus业务层

步骤1:构建员工业务层服务接口

/**
*1>自定义一个业务服务接口:IEmployeeService,继承父接口:IService
*2>明确指定父接口泛型:当前接口操作实体对象:Employee
*/
public interface IEmployeeService extends IService<Employee> {
}

步骤2:实现员工业务层接口

/**
*1>定义服务接口实现类,实现IEmployeeService接口
*2>继承通用的父接口实现类:ServiceImpl
*3>明确指定通用的父接口实现类2个泛型:
*    1:当前服务类操作的实体对象对应的Mapper接口:EmployeeMapper
*    2:当前服务类操作的实体对象:Employee
*/
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}

步骤3:实现服务方法测试

@SpringBootTest
public class ServiceTest {
    @Autowired
    private IEmployeeService employeeService;
    @Test
    public void testSave(){
        Employee employee = new Employee();
        employee.setAdmin(1);
        employee.setAge(18);
        employee.setDeptId(1L);
        employee.setEmail("zhangsan@163.com");
        employee.setName("zhangsan");
        employee.setPassword("111");
        employeeService.save(employee);
    }

    @Test
    public void testUpdate(){
        Employee employee = new Employee();
        employee.setId(1327139013313564673L);
        employee.setAdmin(1);
        employee.setAge(18);
        employee.setDeptId(1L);
        employee.setEmail("zhangsan@163.com");
        employee.setName("zhangxiaosan");
        employee.setPassword("111");
        employeeService.updateById(employee);
    }
    @Test
    public void testDelete(){
        employeeService.removeById(11L);
    }
    @Test
    public void testGet(){
        System.out.println(employeeService.getById(11L));
    }

    @Test
    public void testList(){
        List<Employee> employees = employeeService.list();
        employees.forEach(System.err::println);
    }

}

常用服务层api

上面就是IService接口提供的实现方法,几乎涵盖了数据库常规操作。

方法解析

思考一个问题,IService接口是怎么实现的?

以IEmployeeService 接口中的getById() 方法为例子

/**
* 根据 ID 查询
*
* @param id 主键ID
*/
default T getById(Serializable id) {
    return getBaseMapper().selectById(id);
}

源码上,getById是一个接口默认方法,默认实现是调用getBaseMapper()对象去执行selectById方法

/**
* 获取对应 entity 的 BaseMapper
*
* @return BaseMapper
*/
BaseMapper<T> getBaseMapper();

getBaseMapper方法也是IService接口定义的方法,继续追踪其接口实现:

ServiceImpl类的getBaseMapper方法

public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

    @Autowired
    protected M baseMapper;

    @Override
    public M getBaseMapper() {
        return baseMapper;
    }
}

从上面代码可以看到baseMapper是使用@Autowired 方式从spring容器中注入的,具体类型是泛型对象M, 而在定义EmployeeServiceImpl类时,具体代码:

@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}

可以确认,以EmployeeServiceImpl为例子, 那么ServiceImpl中M的泛型就是EmployeeMapper类型,那么ServiceImpl可以等价

public class ServiceImpl<EmployeeMapper extends BaseMapper<T>, T> implements IService<T> {

    @Autowired
    protected EmployeeMapper baseMapper;

    @Override
    public EmployeeMapper getBaseMapper() {
        return baseMapper;
    }
}

最后IService方法中getById

/**
* 根据 ID 查询
*
* @param id 主键ID
*/
default T getById(Serializable id) {
    return getBaseMapper().selectById(id);
}

等价于:

/**
* 根据 ID 查询
*
* @param id 主键ID
*/
default T getById(Serializable id) {
    //其中的baseMapper就是employeeMapper
    return baseMapper.selectById(id);
}

到这,可以确定IService接口中方法底层都是使用Mapper接口方法实现,那么IService 接口方法操作就可以同理可得啦。

总结

MyBatis-Plus Service层编写得益于IService接口与ServiceImpl接口实现,能满足大部分常规的CRUD操作需求,后续如果业务复杂后,可以自己去拓展接口。

MyBatis-Plus Service层这种操作模式相对简单,在中小型项目中使用非常推荐,如果在复杂项目需要酌情考虑,Service层通过继承方式实现便利,同时也引入很多不必要的方法,同时让代码结构复杂话,后期维护是个麻烦。



版权声明:本文为langfeiyes原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。