tk.mybatis提供了针对单表的一些常规增删改查以及Example相关的操作,我们能够简单方便的使用其提供的接口方法进行开发,下面我们将结合tk.mybatis提供的通用方法抽取dao和service层base接口。
首先需要导入tk.mybatis依赖,版本视springboot版本而定
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${tk.mybatis.version}</version>
</dependency>
1、对dao层进行基类抽取
/**
* @param <T>
* @description Dao层基类
*/
public interface MyMapper<T> extends Mapper<T>, InsertListMapper<T> {
}
抽取MyMapper接口继承通用Mapper和通用InsertListMapper接口,Mapper接口中提供了对象映射增删查改方法,InsertListMapper接口提供批量插入方法,这里可以根据需要继承其他通用Mapper。
2、对service层进行基类抽取
/**
* @Description: 服务层基类
*/
public interface BaseService<T, ID, EXAMPLE> {
/**
* 单个实体对象全量字段保存
*
* @param record
* @return
*/
int save(T record);
/**
* 单个实体对象非空字段保存
*
* @param record
* @return
*/
int saveSelective(T record);
/**
* 多个实体对象保存
*
* @param list
* @return
*/
int saveList(java.util.List<? extends T> list);
/**
* 单个实体对象删除
*
* @param record
* @return
*/
int delete(T record);
/**
* 单个实体对象条件删除
*
* @param record
* @param example
* @return
*/
int deleteByExample(T record, EXAMPLE example);
/**
* 单个实体对象主键删除
*
* @param record
* @param key
* @return
*/
int deleteByPrimaryKey(T record, ID key);
/**
* 单个实体对象条件全量字段更新
*
* @param record
* @param example
* @return
*/
int updateByExample(T record, EXAMPLE example);
/**
* 单个实体对象条件非空字段更新
*
* @param record
* @param example
* @return
*/
int updateByExampleSelective(T record, EXAMPLE example);
/**
* 单个实体对象主键全量字段更新
*
* @param record
* @return
*/
int updateByPrimaryKey(T record);
/**
* 单个实体对象主键非空字段更新
*
* @param record
* @return
*/
int updateByPrimaryKeySelective(T record);
}
/**
* @Description: 服务层基类实现类
* 注:自定义需要保存对象日志的操作方法(insert,update,delete操作必须记录日志!)
*/
public abstract class BaseServiceImpl<T, ID, EXAMPLE> implements BaseService<T, ID, EXAMPLE> {
@Autowired
private ILogService logService;
// 定义抽象方法getMyMapper获取当前实体Mapper对象
protected abstract MyMapper<T> getMyMapper();
@Override
@Transactional(rollbackFor = Exception.class)
public int save(T record) {
int res = getMyMapper().insert(record);
logService.saveLogEntity(record, "insert", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int saveSelective(T record) {
int res = getMyMapper().insertSelective(record);
logService.saveLogEntity(record, "insert", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int saveList(java.util.List<? extends T> list) {
int res = getMyMapper().insertList(list);
list.forEach(record -> logService.saveLogEntity(record, "insert", record.getClass(), null));
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int delete(T record) {
int res = getMyMapper().delete(record);
logService.saveLogEntity(record, "delete", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteByExample(T record, EXAMPLE example) {
int res = getMyMapper().deleteByExample(example);
logService.saveLogEntity(record, "delete", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteByPrimaryKey(T record, ID key) {
int res = getMyMapper().deleteByPrimaryKey(key);
logService.saveLogEntity(record, "delete", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByExample(T record, EXAMPLE example) {
int res = getMyMapper().updateByExample(record, example);
logService.saveLogEntity(record, "update", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByExampleSelective(T record, EXAMPLE example) {
int res = getMyMapper().updateByExampleSelective(record, example);
logService.saveLogEntity(record, "update", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByPrimaryKey(T record) {
int res = getMyMapper().updateByPrimaryKey(record);
logService.saveLogEntity(record, "update", record.getClass(), null);
return res;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByPrimaryKeySelective(T record) {
int res = getMyMapper().updateByPrimaryKeySelective(record);
logService.saveLogEntity(record, "update", record.getClass(), null);
return res;
}
}
BaseService接口定义了一些增删改的统一方法,BaseServiceImpl实现BaseService接口接收三个泛型参数T(实体对象), ID(主键id), EXAMPLE(Example条件)。这里有一个特殊的业务逻辑,logService.saveLogEntity方法作用时当对象进行增、删、改时,记录对象字段信息,如下:
@Mapper
public interface LogEntityMapper extends MyMapper<LoggerEntity> {
}
/**
* @Description: 实体对象操作日志service接口
*/
public interface ILogService extends BaseService<LoggerEntity, String, Object> {
int saveLogEntity(Object entity, String loggerType, Class<?> entityClass, String info);
}
@Service
@Slf4j
public class LogServiceImpl extends BaseServiceImpl<LoggerEntity, String, Object> implements ILogService {
@Autowired
private LogEntityMapper logMapper;
@Override
public int saveLogEntity(Object entity, String loggerType, Class<?> entityClass, String info) {
// 组装LoggerEntity对象信息
LoggerEntity logger = new LoggerEntity();
...
logMapper.insert(logger);
}
}
3、举例使用说明实现以上抽取的MyMapper dao接口和BaseService service接口
其实上面记录对象日志的操作已经举例了用法,但是还是想举个完整的例子0_0
首先定义一个Book实体类对象:
@Data
@Builder(toBuilder = true)
@Table(name = "TEST_BOOK")
public class BookEntity {
@Id
@Column(name = "BOOK_ID")
private Integer bookId;
@Column(name = "BOOK_NAME")
private String bookName;
@Column(name = "CREATE_TIME")
private Date createTime;
@Column(name = "BOOK_CONTENT")
private String bookContent;
}
@Mapper
public interface BookEntityMapper extends MyMapper<BookEntity> {
}
public interface IBookService extends BaseService<BookEntity, Integer, Object> {
}
@Slf4j
@Service
public class BookServiceImpl extends BaseServiceImpl<BookEntity, Integer, Object> implements IBookService {
@Autowired
private BookEntityMapper bookMapper;
// 重写BaseServiceImpl抽象方法,将当前bookMapper返回
@Override
protected MyMapper<BookEntity> getMyMapper() { return bookMapper; }
}
@Api(value = "书籍管理相关API")
@RestController
@RequestMapping("/book")
@Slf4j
public class BookController {
@Autowired
private IBookService bookService;
@ApiOperation(value = "新增书籍接口", notes = "新增书籍接口", httpMethod = "POST")
@ApiImplicitParams({@ApiImplicitParam(name = "request", value = "Book参数实体", required = true, dataType = "BookRequest")})
@PostMapping(path = "/addBook")
public Object addNewBook(@RequestBody @Validated BookRequest request) {
BookEntity entity = BookEntity.builder()
.bookId(1)
.bookName(request.getBookName())
.createTime(new Date())
.bookContent(request.getBookContent())
.build();
return bookService.save(entity);
}
}
#配置mybatis实体类扫描包路径
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.web.entity
启动项目调用接口即可测试,这里解释一下为什么要自己重新封装对象操作方法,实际上直接注入对象Mapper也可以直接进行增删改查操作(就如saveLogEntity方法的具体实现)。
实际项目中一定会涉及到日志的记录,上例这种结构实际上是把通用Mapper中的对象操作方法再封装了一层,在这一层可以自己加入另外的业务逻辑,在例子中,BaseServiceImpl封装的增删改方法中均用到saveLogEntity方法来记录对象日志,而saveLogEntity方法的具体实现中直接使用未进行封装的logMapper.insert();方法,控制层增删改操作使用继承BaseServiceImpl的实体service方法,这样就达到了在增删改操作下记录日志的要求。