基于tkmybatis封装常用的增删改查接口
一、背景
2019年偶然的机会了解到Agilebpm开源工作流项目,当然我不是要给他们打广告哦,真的觉得这个项目代码写得挺好的,扩展性很强。看它们的前端后端代码,我也可以学到一些设计思想什么的。不扯其它的,他们团队也封装了一套增删改查接口。看了他们的代码之后,当时我们项目用的是tk-mybatis组件,那么就想着基于tk-mybatis组件稍微封装一下这个接口,这个查询接口就会变得很灵活,当然你们用的mybatis-plus组件也是一样的。
二、代码封装
2.1 Pom
pom文件引入相关的依赖,数据源是MySQL还是PostgreSQL,可根据自己的情况添加相应的依赖。
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
2.2 Entity
2.2.1 BaseModel
实体类父类,非必须,不需要的话可忽略,也可以根据自己的需要修改父类字段,这里只是做个示范。
@Data
public class BaseModel implements Serializable {
@Column(name = "create_user")
private Integer createUser;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_user")
private Integer updateUser;
@Column(name = "update_time")
private Date updateTime;
@LogicDelete
@Column(name = "is_delete")
private Boolean isDelete;
}
2.2.2 QueryOP
查询操作符枚举类,后面接口调用会根据这个类来处理查询逻辑。
public enum QueryOP {
EQUAL("EQ", "=", "等于", new String[]{"V", "N", "D"}),
LESS("LT", "<", "小于", new String[]{"V","N", "D"}),
GREAT("GT", ">", "大于", new String[]{"V","N", "D"}),
LESS_EQUAL("LTE", "<=", "小于等于", new String[]{"V","N", "D"}),
GREAT_EQUAL("GTE", ">=", "大于等于", new String[]{"V","N", "D"}),
NOT_EQUAL("NE", "!=", "不等于", new String[]{"V", "N", "D"}),
LIKE("LK", "like", "相似", new String[]{"V"}),
LEFT_LIKE("LFK", "like", "左相似", new String[]{"V"}),
RIGHT_LIKE("RHK", "like", "右相似", new String[]{"V"}),
IS_NULL("INL", "is null", "为空", new String[]{"V", "N", "D"}),
NOTNULL("NNL", "is not null", "非空", new String[]{"V", "N", "D"}),
IN("IN", "in", "在...中", new String[]{"V", "N", "D"}),
NOT_IN("NI", "not in", "不在...中", new String[]{"V", "N", "D"}),
BETWEEN("BT", "between", "在...之间", new String[]{"N", "D"}),
NOT_BETWEEN("NBT", "not between", "不在...之间", new String[]{"N", "D"});
private String val;
private String op;
private String desc;
private String[] supports;//V->varchar N->number D->date
private QueryOP(String val, String op, String desc, String[] supports) {
this.val = val;
this.op = op;
this.desc = desc;
this.supports = supports;
}
public String value() {
return val;
}
public String op() {
return op;
}
public String desc() {
return desc;
}
public String[] supports() {
return supports;
}
public static QueryOP getByVal(String val) {
for (QueryOP queryOP : values()) {
if (queryOP.val.equals(val)) {
return queryOP;
}
}
return null;
}
}
2.3 Mapper
2.3.1 BaseMapper
public interface BaseMapper<T> extends Mapper<T>, MySqlMapper<T> {
//TODO
//FIXME 特别注意,该接口不能被扫描到,否则会出错
}
2.4 Service
2.4.1 IBaseService
Service层接口类父类,可根据需要自行添加其它方法。
public interface IBaseService<T> {
/**
* 添加记录
* @param entity
* @return
*/
int save(T entity);
/**
* 批量添加记录 只适合主键为数值类型且自增的情况
* @param list
* @return
*/
int saveList(List<T> list);
/**
* 批量添加记录 主键为UUID
* @param list
* @return
*/
int saveListNoUseGeneratedKeysAndUuid(List<T> list);
/**
* 根据主键删除记录
* @param key
* @return
*/
int delete(Object key);
/**
* 根据实体删除记录
* @param entity 删除条件:实体类不为空的字段
* @return
*/
int deleteByEntity(T entity);
/**
* 批量删除记录
* @param keys 属性集合
* @param clazz
* @param idName 为空此属性默认为“id”
* @return
*/
int deleteByKeys(List keys, Class clazz, String idName);
/**
* 更新记录
* @param entity 实体类所有字段
* @return
*/
int updateAll(T entity);
/**
* 更新记录
* @param entity 实体类不为空的字段
* @return
*/
int updateNotNull(T entity);
/**
* 批量更新记录
* @param list
* @return
*/
int updateAllList(List<T> list);
/**
* 批量更新记录
* @param list
* @return
*/
int updateNotNullList(List<T> list);
/**
* 批量更新记录【属性集合】(只适合于多条记录更改成一样的情况)
* 例如 我需要把这一批设备的状态全部更改为“在线”
* @param keys
* @param t
* @param idName
* @return
*/
int updateByKeys(List keys, T t, String idName);
/**
* 批量更新记录【表达式】
* @param t
* @param example
* @return
*/
int updateByExampleSelective(T t, Example example);
/**
* 根据主键查找记录
* @param key 主键
* @return
*/
T selectByKey(Object key);
/**
*批量查找记录
* @param keys 某属性集合
* @param clazz
* @param idName 为null此属性默认为“id”
* @return
*/
List<T> selectByKeys(List keys, Class clazz, String idName);
/**
* 查找某一记录 必须保证唯一
* @param t 筛选条件:实体类不为空的字段
* @return
*/
T selectOne(T t);
/**
* 根据实体类查找对象
* @param t
* @return
*/
List<T> selectByEntity(T t);
/**
* 查找对象
* @param example 【tk表达式】
* @return
*/
List<T> selectByExample(Example example);
/**
* 分页查找对象
* @param t
* @param pageNum
* @param pageSize
* @return
*/
PageInfo<T> selectPageByEntity(T t, int pageNum, int pageSize);
/**
* 分页查找对象
* @param example 【tk表达式】
* @param pageNum
* @param pageSize
* @return
*/
PageInfo<T> selectPageByExample(Example example, int pageNum, int pageSize);
//TODO 其他...
}
2.4.2 BaseService
Service层接口实现类父类。
public abstract class BaseService<T> implements IBaseService<T> {
private static final Logger LOG = Logger.getLogger(BaseService.class);
@Autowired
protected Mapper<T> mapper;
@Autowired
protected MySqlMapper<T> mySqlMapper;
@Autowired
protected MyDefineUpdateMapper<T> myDefineUpdateMapper;
public Mapper<T> getMapper() {
return mapper;
}
@Override
public T selectByKey(Object key) {
return mapper.selectByPrimaryKey(key);
}
@Override
public List<T> selectByKeys(List keys, Class clazz, String idName) {
if(keys == null || keys.size() == 0){
return Collections.emptyList();
}
Example example = new Example(clazz);
Example.Criteria criteria = example.createCriteria();
criteria.andIn(StringUtils.isEmpty(idName) ? "id" : idName, keys);
return selectByExample(example);
}
@Override
public T selectOne(T t) {
return mapper.selectOne(t);
}
@Override
@Transactional
public int save(T t) {
return mapper.insertSelective(t);
}
@Override
@Transactional
public int delete(Object key) {
return mapper.deleteByPrimaryKey(key);
}
@Override
public int deleteByKeys(List keys, Class clazz, String idName) {
if(keys == null || keys.size() == 0){
return 0;
}
Example example = new Example(clazz);
Example.Criteria criteria = example.createCriteria();
criteria.andIn(StringUtils.isEmpty(idName) ? "id" : idName, keys);
return mapper.deleteByExample(example);
}
@Override
@Transactional
public int updateByKeys(List keys, T t, String idName) {
if(keys == null || keys.size() == 0){
return 0;
}
Example example = new Example(t.getClass());
Example.Criteria criteria = example.createCriteria();
criteria.andIn(StringUtils.isEmpty(idName) ? "id" : idName, keys);
updateByExampleSelective(t, example);
return 0;
}
@Override
@Transactional
public int deleteByEntity(T t) {
return mapper.delete(t);
}
@Override
@Transactional
public int updateAll(T t) {
return mapper.updateByPrimaryKey(t);
}
@Override
@Transactional
public int updateNotNull(T t) {
return mapper.updateByPrimaryKeySelective(t);
}
@Override
public List<T> selectByEntity(T t) {
return mapper.select(t);
}
@Override
public List<T> selectByExample(Example example) {
return mapper.selectByExample(example);
}
@Override
public PageInfo<T> selectPageByEntity(T t, int pageNum, int pageSize) {
//分页查询
PageHelper.startPage(pageNum, pageSize); // , true
List<T> list = selectByEntity(t);
return new PageInfo<>(list);
}
@Override
public PageInfo<T> selectPageByExample(Example example, int pageNum, int pageSize) {
//分页查询
PageHelper.startPage(pageNum, pageSize); // , true
List<T> list = selectByExample(example);
return new PageInfo<>(list);
}
//TODO 其他...
@Override
@Transactional
public int saveList(List<T> list) {
if(list != null && list.size() > 0){
return mySqlMapper.insertList(list);
}
return 0;
}
@Override
@Transactional
public int saveListNoUseGeneratedKeysAndUuid(List<T> list) {
if(list != null && list.size() > 0) {
return mySqlMapper.insertListNoUseGeneratedKeys(list);
}
return 0;
}
@Override
@Transactional
public int updateByExampleSelective(T t, Example example) {
return mapper.updateByExampleSelective(t,example);
}
@Override
@Transactional
public int updateAllList(List<T> list) {
if(list != null && list.size() > 0) {
for(T t : list){
setTimeAndUser(t,false);
}
return myDefineUpdateMapper.batchUpdateByPrimaryKey(list);
}
return 0;
}
@Override
@Transactional
public int updateNotNullList(List<T> list) {
if(list != null && list.size() > 0) {
return myDefineUpdateMapper.batchUpdateByPrimaryKeySelective(list);
}
return 0;
}
}
需要注意的是:
1)批量添加方法:tkmybatis只提供了insertList方法,主键为UUID类型的话,即便是你指定了生成主键方式为UUID,它也会报ID不能为空错,看源码不难发现,insertList忽略了ID的值,所以此方法只适应自增的主键,你把insertList复制出来需要稍微修改即可。
2)批量更新方法:tkmybatis没有提供批量更新方法,需要实现手动实现。
@RegisterMapper
public interface MyDefineUpdateMapper<T> {
/**
* 根据Example条件批量更新实体`record`包含的不是null的属性值
*
* @return
*/
@UpdateProvider(type = MyDefineUpdateProvider.class, method = "dynamicSQL")
int batchUpdateByPrimaryKeySelective(List<? extends T> recordList);
/**
* 根据Example条件批量更新实体`record`的属性值
*
* @return
*/
@UpdateProvider(type = MyDefineUpdateProvider.class, method = "dynamicSQL")
int batchUpdateByPrimaryKey(List<? extends T> recordList);
}
注意MyDefineUpdateProvider 类getSql方法,根据不同的数据源稍微修改一下。
public class MyDefineUpdateProvider extends ExampleProvider {
public MyDefineUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
}
/**
* 拼update sql, 使用case when方式,id为主键
*
* @param ms
* @return
*/
public String batchUpdateByPrimaryKeySelective(MappedStatement ms) {
final Class<?> entityClass = getEntityClass(ms);
//开始拼sql
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass)));
sql.append("<trim prefix=\"set\" suffixOverrides=\",\">");
//获取全部列
Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
for (EntityColumn column : columnList) {
if (!column.isId() && column.isUpdatable()) {
sql.append(" <trim prefix=\""+column.getColumn()+" =case\" suffix=\"end,\">");
sql.append(" <foreach collection=\"list\" item=\"i\" index=\"index\">");
if(column.getJavaType().equals(String.class)){
sql.append(" <if test=\"i."+column.getEntityField().getName()+"!=null and i."+column.getEntityField().getName()+"!='' \">");
}else{
sql.append(" <if test=\"i."+column.getEntityField().getName()+"!=null\">");
}
sql.append(getSql(column));
sql.append(" </if>");
sql.append(" </foreach>");
sql.append(" </trim>");
}
}
sql.append("</trim>");
sql.append("WHERE");
sql.append(" id IN ");
sql.append("<trim prefix=\"(\" suffix=\")\">");
sql.append("<foreach collection=\"list\" separator=\", \" item=\"i\" index=\"index\" >");
sql.append("#{i.id}");
sql.append("</foreach>");
sql.append("</trim>");
return sql.toString();
}
/**
* 拼update sql, 使用case when方式,id为主键
*
* @param ms
* @return
*/
public String batchUpdateByPrimaryKey(MappedStatement ms) {
final Class<?> entityClass = getEntityClass(ms);
//开始拼sql
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass)));
sql.append("<trim prefix=\"set\" suffixOverrides=\",\">");
//获取全部列
Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
for (EntityColumn column : columnList) {
if (!column.isId() && column.isUpdatable()) {
sql.append(" <trim prefix=\""+column.getColumn()+" =case\" suffix=\"end,\">");
sql.append(" <foreach collection=\"list\" item=\"i\" index=\"index\">");
sql.append(getSql(column));
sql.append(" </foreach>");
sql.append(" </trim>");
}
}
sql.append("</trim>");
sql.append("WHERE");
sql.append(" id IN ");
sql.append("<trim prefix=\"(\" suffix=\")\">");
sql.append("<foreach collection=\"list\" separator=\", \" item=\"i\" index=\"index\" >");
sql.append("#{i.id}");
sql.append("</foreach>");
sql.append("</trim>");
return sql.toString();
}
//MySQL直接获取就行,PostgreSQL需要类型严格一致,需要转换一下数据类型。
private String getSql(EntityColumn column){
if(column.getEntityField().getJavaType().equals(Date.class)){
return " when id=#{i.id} then cast("+column.getColumnHolder("i") +"as timestamp) ";
}else if(column.getEntityField().getJavaType().equals(String.class)){
JSONAnno jsonAnno = column.getEntityField().getAnnotation(JSONAnno.class);
if(jsonAnno != null){
return " when id=#{i.id} then "+column.getColumnHolder("i") +"::"+jsonAnno.value();
}else{
return " when id=#{i.id} then "+column.getColumnHolder("i");
}
}else{
return " when id=#{i.id} then "+column.getColumnHolder("i") +"::numeric";
}
}
}
3)插入和更新:比如需要给创建用户/时间、更新用户/时间赋值,可在实体类增加相应的注解再通过反射方式实现,因为这个涉及到用户的获取,这里就把这块的代码删除了,注解类参考如下。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeAndUserAnno {
boolean createTimeExist() default true;
String createTimeType() default "D";
String createTimeSetMethod() default "setCreatetime";
String createTimeGetMethod() default "getCreatetime";
boolean updateTimeExist() default true;
boolean updateTimeType() default "D";
String updateTimeSetMethod() default "setUpdateTime";
String updateTimeGetMethod() default "getUpdateTime";
boolean createUserExist() default true;
String createUserSetMethod() default "setCreateUser";
String createUserGetMethod() default "getCreateUser";
boolean updateUserExist() default true;
String updateUserSetMethod() default "setUpdateUser";
String updateUserGetMethod() default "getUpdateUser";
}
2.5 Controller
2.5.1 RequestParamUtils
查询接口请求参数处理工具类,注意RequestParamUtils 类getValue方法,根据不同的数据源稍微修改一下。
@Slf4j
public class RequestParamUtils {
private static final String FIELD_SPILT = "_";
private static final String SQL_LIKE_CONTACT_STR = "%";
private static final String REQUEST_PARAM_ERROR = "请求参数格式无效";
/**
* 处理请求参数
* @param obj
* @return
*/
public static Example handlerRequestParam(Object obj) {
Example example = new Example(obj.getClass());
Example.Criteria criteria = example.createCriteria();
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, String[]> parameterMap = new HashMap(request.getParameterMap());
String[] orders = parameterMap.remove("order");
String[] isAscs = parameterMap.remove("isAsc");
boolean flag = false;
for (Iterator iter = parameterMap.entrySet().iterator(); iter.hasNext();) {
Map.Entry element = (Map.Entry) iter.next();
String key = String.valueOf(element.getKey());
String[] values = (String[])element.getValue();
if(key.contains(FIELD_SPILT) && handlerRequestParam(key, values, criteria)){
flag = true;
}
}
if(!flag){
example = new Example(obj.getClass());
}
orderRequestParam(example, orders, isAscs);
return example;
}
public static void orderRequestParam(Example example,String[] orders,String[] isAscs){
if(Optional.ofNullable(isAscs).isPresent() && "false".equals(isAscs[0])){
Optional.ofNullable(orders).ifPresent(val ->example.orderBy(val[0]).desc());
}else{
Optional.ofNullable(orders).ifPresent(val ->example.orderBy(val[0]).asc());
}
}
private static boolean handlerRequestParam(String key, String[] values,Example.Criteria criteria){
try {
int index = key.lastIndexOf(FIELD_SPILT);
String field = key.substring(0,index);
String opVal = key.substring(index + 1);
int size = criteria.getCriteria().size();
if(opVal.length() > 1){
String type = opVal.substring(0, 1);
opVal = opVal.substring(1);
QueryOP queryOP = QueryOP.getByVal(opVal);
Optional<List<String>> lists = Optional.ofNullable(queryOP)
.map(QueryOP::supports)
.map(Arrays::asList);
if(lists.isPresent() && lists.get().contains(type)){
if(queryOP != QueryOP.IS_NULL && queryOP != QueryOP.NOTNULL){
if(!isNotNull(values)){
return false;
}
}
switch (queryOP){
case EQUAL:
criteria.andEqualTo(field, getValue(values[0], type));
break;
case NOT_EQUAL:
criteria.andNotEqualTo(field, getValue(values[0], type));
break;
case LESS:
criteria.andLessThan(field, getValue(values[0], type));
break;
case GREAT:
criteria.andGreaterThan(field, getValue(values[0], type));
break;
case LESS_EQUAL:
criteria.andLessThanOrEqualTo(field, getValue(values[0], type));
break;
case GREAT_EQUAL:
criteria.andGreaterThanOrEqualTo(field, getValue(values[0], type));
break;
case LIKE:
criteria.andLike(field,SQL_LIKE_CONTACT_STR+getValue(values[0], type)+SQL_LIKE_CONTACT_STR);
break;
case LEFT_LIKE:
criteria.andLike(field,SQL_LIKE_CONTACT_STR+getValue(values[0], type));
break;
case RIGHT_LIKE:
criteria.andLike(field,getValue(values[0], type)+SQL_LIKE_CONTACT_STR);
break;
case IS_NULL:
criteria.andIsNull(field);
break;
case NOTNULL:
criteria.andIsNull(field);
break;
case IN:
criteria.andIn(field,getValues(values,type));
break;
case NOT_IN:
criteria.andNotIn(field,getValues(values,type));
break;
case BETWEEN:
criteria.andBetween(field, getValue(values[0], type), getValue(values[1], type));
break;
case NOT_BETWEEN:
criteria.andNotBetween(field, getValue(values[0], type), getValue(values[1], type));
break;
default:
}
}
}
return criteria.getCriteria().size() > size;
}catch (Exception e){
log.error(REQUEST_PARAM_ERROR,e);
return false;
}
}
//MySQL可忽略此方法,PostgreSQL需要类型严格一致,需要转换一下数据类型。
private static Object getValue(String val , String type){
switch (type){
case "N":
return Long.parseLong(val);
case "D":
return DateUtil.parse(val).toJdkDate();
}
return val;
}
private static List getValues(String[] values , String type){
List list = new ArrayList();
for(String str : values){
list.add(getValue(str, type));
}
return list;
}
public static boolean isNotNull(String[] values){
if(values == null || values.length == 0 || (values.length == 1 && values[0].equals(""))){
return false;
}
return true;
}
}
2.5.2 BaseController
public class BaseController<T> extends RequestParamUtils {
@Autowired
protected IBaseService<T> baseService;
@ApiOperation("添加记录")
@PostMapping("/add")
public RestResponse<Void> add(@Valid @RequestBody T t) {
int num = baseService.save(t);
if(num == 0){
return RestResponse.buildFailed("添加失败");
}
return RestResponse.buildSuccessMsg("添加成功");
}
@ApiOperation("批量添加记录")
@PostMapping("/batchAdd")
public RestResponse<Void> batchAdd(@Valid @RequestBody ValidableList<T> list) {
int num = baseService.saveList(list);
if(num == 0){
return RestResponse.buildFailed("添加失败");
}
return RestResponse.buildSuccessMsg("添加成功");
}
@ApiOperation("更新记录(更新所有字段)")
@PutMapping("/updateAll")
public RestResponse<Void> updateAll(@Valid @RequestBody T t){
int num = baseService.updateAll(t);
return RestResponse.buildSuccessMsg("修改成功");
}
@ApiOperation("批量更新记录(更新所有字段)")
@PutMapping("/batchUpdateAll")
public RestResponse<Void> batchUpdateAll(@Valid @RequestBody ValidableList<T> list){
int num = baseService.updateAllList(list);
return RestResponse.buildSuccessMsg("修改成功");
}
@ApiOperation("更新记录(更新不为空的字段)")
@PutMapping("/updateNotNull")
public RestResponse<Void> updateNotNull(@Valid @RequestBody T t){
int num = baseService.updateNotNull(t);
return RestResponse.buildSuccessMsg("修改成功");
}
@ApiOperation("批量更新记录(更新不为空的字段)")
@PutMapping("/batchUpdateNotNull")
public RestResponse<Void> updateNotNull(@Valid @RequestBody ValidableList<T> list){
int num = baseService.updateNotNullList(list);
return RestResponse.buildSuccessMsg("修改成功");
}
@ApiOperation("根据ID删除记录")
@DeleteMapping("/{id}")
public RestResponse<Void> delete(@PathVariable Object id){
int num = baseService.delete(id);
if(num == 0){
return RestResponse.buildFailed("没有查到记录");
}
return RestResponse.buildSuccessMsg("删除成功");
}
@ApiOperation("根据ID查询详情")
@GetMapping("/{id}")
public RestResponse find(@PathVariable Object id){
T t = baseService.selectByKey(id);
if(t == null){
return RestResponse.buildNotFound();
}
return RestResponse.buildSuccessData(t);
}
@ApiOperation("根据表达式分页查找记录(等值、模糊、范围等)")
@PostMapping("/findByPageAndExample")
public RestResponse findByPageAndExample(T t, @RequestParam(required = false, defaultValue = "1") int pageNumber,
@RequestParam(required = false, defaultValue = "10") int pageSize) {
Example example = handlerRequestParam(t);
PageInfo<T> pageInfo = baseService.selectPageByExample(example,pageNumber,pageSize);
return RestResponse.buildSuccessData(pageInfo);
}
@ApiOperation("根据实体类属性分页查找记录(等值查找)")
@PostMapping("/findByPageAndObject")
public RestResponse findByPageAndObject(T t, @RequestParam(required = false, defaultValue = "1") int pageNumber,
@RequestParam(required = false, defaultValue = "10") int pageSize) {
PageInfo<T> pageInfo = baseService.selectPageByEntity(t,pageNumber,pageSize);
return RestResponse.buildSuccessData(pageInfo);
}
@ApiOperation("根据表达式查找记录(等值、模糊、范围等)")
@PostMapping("/findByExample")
public RestResponse findByExample(T t) {
Example example = handlerRequestParam(t);
List<T> list = baseService.selectByExample(example);
return RestResponse.buildSuccessData(list);
}
@ApiOperation("根据实体类属性查找记录(等值查找)")
@PostMapping("/findByObject")
public RestResponse findByObject(T t) {
List<T> list = baseService.selectByEntity(t);
return RestResponse.buildSuccessData(list);
}
}
三、后端使用说明(生成代码)
3.1 Pom文件引入依赖
项目中记得引入封装好的架包
<dependency>
<groupId>com.xxx.xxx</groupId>
<artifactId>xxx_tkmybatis</artifactId>
<version>1.0.0</version>
</dependency>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.6</version>
</dependency>
<!--
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
</dependencies>
</plugin>
3.2 修改generatorConfig.xml的表名和实体类名
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<properties resource="gennerator-tools-pgsql.properties"/>
<context id="pgsql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<!--处理sql中的`符号-->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!--添加自定义的继承接口-->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.xxx.utils.BaseMapper"/>
</plugin>
<!--数据源配置-->
<jdbcConnection driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
</jdbcConnection>
<!--model包路径-->
<javaModelGenerator targetPackage="com.xxx.model" targetProject="src/main/java">
<property name="immutable" value="false"/>
<!-- 给Model添加一个父类 -->
<property name="rootClass" value="com.xxx.model.BaseModel"/>
</javaModelGenerator>
<!--mapper.xml包路径-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>
<!--mapper包路径-->
<javaClientGenerator targetPackage="com.xxx.mapper" targetProject="src/main/java"
type="XMLMAPPER"/>
<!--表配置,tableName支持%,表示全部生成-->
<table tableName="t_sys_user" domainObjectName="SysUser">
<!--mysql 配置-->
<generatedKey column="id" identity="true"/>
</table>
</context>
</generatorConfiguration>
3.3 点击生成代码
这里会生成对应的实体类和Mapper类
3.4 修改实体类
如果实体类继承了BaseModel,这里没有对父类做判断,需要手动去掉创建用户时间等字段。
@Data
@Table(name="t_sys_user")
public class SysUser extends BaseModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@NotNull(message="账户不能为空")
private String account;//账户
@NotNull(message="密码不能为空")
private String password;//密码
private Boolean gender; //性别(0:男;1::女)
}
3.5 新建Service接口继承IBaseService
public interface SysUserService extends IBaseService<SysUser> {
}
3.6 新建Service实现类继承BaseService
@Service("sysUserService")
public class SysUserServiceImpl extends BaseService<SysUser> implements SysUserService {
}
3.7 新建Controller类继承BaseController
@RestController
@RequestMapping("/sysUser")
@TableModule("用户模块")
public class SysUserController extends BaseController<SysUser> {
}
四、前端使用说明(调用接口)
添加、修改、删除等接口跟平常一样,下面重点说明下查询接口使用注意事项:
- findByObject:根据实体类不为空的字段进行等值查询,ftime=20200818。
- findByExample:根据tk表达式进行查询,组成格式:字段名_字段类型匹配类型。
-
字段名:实体类属性值。
-
字段类型:V(Varchar:字符串);N(Numbe:数字类型);D(Date:日期类型)。
-
匹配类型:参考下图:
-
例子1:查询时间在20200801和20200820之间的数据
ftime_DGTE=20200801,ftime_DLTE=20200820 -
例子2:查询名称为小明的数据
name_VEQ=小明 -
例子3:模糊查询名称包含小的数据
name_VLK=小
3.findByPageAndExample/findByPageAndObject同上,只是加了分页功能。
五 小结
到这里所有步骤就全部完成了,单表的增删改查基本几分钟就可以搞定了,而且查询接口参数也很灵活。如有错误,请批评指教。只是提供一个思路,大家根据需要修改。