学习要求
良好的java基础, 熟悉SpringBoot框架,熟悉Mybatis框架
教学目标
了解并掌握MyBatis-Plus业务层的实现
视频教程
概念
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层通过继承方式实现便利,同时也引入很多不必要的方法,同时让代码结构复杂话,后期维护是个麻烦。