tk.mybatis扩展通用接口使用详解
一.tk.mybatis已经为我们封装好了许多拆箱即用的通用mapper,但在实际的项目开发中想必不少小伙伴在数据库设计中都会采用逻辑删除这种方案,再去使用通用的mapper接口就不行了。
这时候就需要我们封装一些扩展的通用Mapper接口。
二.项目中提供了大量现成的方法,这些方法可以作为扩展时的参考。
例如 selectAll 方法。
首先定义接口:
@RegisterMapper public interface SelectAllMapper<T> { /** * 查询全部结果 * * @return */ @SelectProvider(type = MySelectProvider.class, method = "dynamicSQL") List<T> selectAll(); }
其中 MySelectProvider 是你要实现的一个类,该类需要继承 MapperTemplate。@RegisterMapper 注解可以避免 mappers 参数配置,通用 Mapper 检测到该接口被继承时,会自动注册。
import org.apache.ibatis.mapping.MappedStatement; import tk.mybatis.mapper.mapperhelper.MapperHelper; import tk.mybatis.mapper.mapperhelper.MapperTemplate; import tk.mybatis.mapper.mapperhelper.SqlHelper; public class MySelectProvider extends MapperTemplate { public BaseSelectProvider(Class<?> mapperClass, MapperHelper mapperHelper) { super(mapperClass, mapperHelper); } /** * 查询全部结果 * * @param ms * @return */ public String selectAll(MappedStatement ms) { final Class<?> entityClass = getEntityClass(ms); //修改返回值类型为实体类型 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder(); sql.append(SqlHelper.selectAllColumns(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.orderByDefault(entityClass)); return sql.toString(); } }
其中 selectAll 方法名要和接口中定义的方法名一致。其次就是该方法的参数为 MappedStatement类型。
在 selectAll 方法中,首先是获取了当前接口的实体类型:
final Class<?> entityClass = getEntityClass(ms);
因为接口返回值类型为 List<T>,MyBatis 会认为返回值类型为 List<Object>,这和我们想要的实体类型不一样,所以下一行代码就是设置返回值类型:
setResultType(ms, entityClass);
注意,只有返回 T 或者 List 时需要设置,返回 int 类型时不需要设置。
接下来就是纯粹的拼接 XML 形式的 SQL 了。
/select col1,col2... sql.append(SqlHelper.selectAllColumns(entityClass)); //from tablename - 支持动态表名 sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); //order by xxx sql.append(SqlHelper.orderByDefault(entityClass));
当你想要实现某种方法时,可以从已有的例子中找一个最接近的方法,在此基础上进行修改
三.例:根据主键查询单个实体对象(过滤掉逻辑删除的实体,注:我的数据表逻辑删除字段定义为enabled_status)
首先定义mapper
@RegisterMapper public interface SelectByKeyAndNotDeletedMapper<T> { /** * 根据主键查询没有被逻辑删除的实体 * * @return */ @SelectProvider(type = SelectByKeyNotDeletedProvider.class, method = "dynamicSQL") T selectByKeyNotDeleted(Object key); }
其次定义SelectByKeyNotDeletedProvider
public class SelectByKeyNotDeletedProvider extends MapperTemplate { public SelectByKeyNotDeletedProvider(Class<?> mapperClass, MapperHelper mapperHelper) { super(mapperClass, mapperHelper); } public String selectByKeyNotDeleted(MappedStatement ms) { final Class<?> entityClass = getEntityClass(ms); //将返回值修改为实体类型 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder(); sql.append(SqlHelper.selectAllColumns(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(wherePKColumns(entityClass, false)); return sql.toString(); } private String wherePKColumns(Class<?> entityClass, boolean useVersion) { StringBuilder sql = new StringBuilder(); sql.append("<where>"); //获取全部列 Set<EntityColumn> columnSet = EntityHelper.getPKColumns(entityClass); //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值 for (EntityColumn column : columnSet) { sql.append(" AND " + column.getColumnEqualsHolder()); } if (useVersion) { sql.append(whereVersion(entityClass)); } //过滤被逻辑删除的数据 sql.append(" AND enabled_status = 1 "); sql.append("</where>"); return sql.toString(); } }
然后定义BasicMapper,让其继承通用Mapper接口以及上面自定义的SelectByKeyAndNotDeletedMapper接口。
@tk.mybatis.mapper.annotation.RegisterMapper public interface BasicMapper<T> extends Mapper<T>, SelectByKeyAndNotDeletedMapper<T> { }
最后在通用service中引入,
@Autowired private BasicMapper<T> mapper;
自定义*.Mapper都去继承BasicMapper<T>即可
public interface UserPOMapper extends BasicMapper<UserPO> {}
注意:最新版本的tk已经支持根据注解@LogicDelete实现逻辑删除
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。