com.poyee.base.mapper.provider 包是一个用于动态构建 SQL 语句的工具包,它基于注解驱动,通过解析实体类和 DTO 上的注解来自动生成 SQL 查询语句。该包主要用于简化数据库操作,支持复杂的查询条件、连接查询、排序、分页等功能,使开发者能够以更加面向对象的方式编写数据库访问代码。
BaseProvider 是整个包的核心抽象类,提供了基础的 SQL 构建功能,包括左连接和 WHERE 条件的处理。它维护了一系列线程安全的集合来存储 SQL 构建过程中的各种信息:
public abstract class BaseProvider {
// 数据库操作类型
public DbMethodEnums dbMethod;
// 表计数器
public int tableCount = 0;
// 是否分页
public boolean isPage = false;
// 存储 insert
public Object insert;
// 记录 UPDATE
public Object update;
// 记录 SELECT
public Object select;
// 主表信息
public TableInfo superTable;
// 分页查询
public MPage mPage;
// 标记是否前端传排序字段
public boolean isFrontSort = false;
// 分页查询SQL
public String pageCountSql;
// 记录 INSERT key-value(线程安全)
public final Map<String, Object> insertMap = new HashMap<>();
// 记录 UPDATE key-value(线程安全)
public final Map<String, Object> updateMap = new HashMap<>();
// 存储表信息的映射(线程安全)
public final Map<String, TableInfo> tableInfos = new ConcurrentHashMap<>();
// 记录 WHERE 条件(线程安全)
public final List<WhereInfo> whereInfos = new CopyOnWriteArrayList<>();
// 记录 SELECT 列(线程安全)
public final List<String> selectColumns = new CopyOnWriteArrayList<>();
// 记录 LEFT JOIN 信息(线程安全)
public final List<LeftJoinInfo> leftJoinInfos = new CopyOnWriteArrayList<>();
// 记录 ORDER BY 信息(线程安全)
public final Map<Integer,String> orderByMap = new HashMap<>();
// 各种SQL构建方法...
}
BaseProvider 提供了以下主要方法:
selectById: 根据ID查询单条记录selectOne: 查询单条记录selectSum: 聚合查询(求和)save: 插入记录update: 更新记录pageWrapper: 分页查询leftJoinWrapper: 左连接查询mPage: 分页查询(返回MPage对象)IBaseProvider 是一个接口,定义了基础的数据库操作方法,并通过 MyBatis 的 @SelectProvider、@InsertProvider 和 @UpdateProvider 注解将这些方法与 BaseProvider 的实现关联起来。
public interface IBaseProvider<T extends BaseReq, R extends BaseDto> {
@SelectProvider(type = FinalProviderSql.class, method = "leftJoinWrapper")
List<Map<String, Object>> selectListMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
@SelectProvider(type = FinalProviderSql.class, method = "pageCountSql")
long pageCount(String sql);
@SelectProvider(type = FinalProviderSql.class, method = "pageSql")
List<Map<String, Object>> page(String sql);
@SelectProvider(type = FinalProviderSql.class, method = "selectOne")
Map<String, Object> selectOneMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
@SelectProvider(type = FinalProviderSql.class, method = "selectById")
Map<String, Object> selectByIdMap(@Param("id") Serializable id, @Param("clazz") Class<R> clazz);
@SelectProvider(type = FinalProviderSql.class, method = "selectSum")
Map<String, Object> selectSumMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
@InsertProvider(type = FinalProviderSql.class, method = "save")
@Options(useGeneratedKeys = true, keyProperty = "id")
int save(T req);
@UpdateProvider(type = FinalProviderSql.class, method = "update")
int update(T req);
// 默认方法实现...
}
IBaseProvider 还提供了一些默认方法,如 selectByPrimaryKey、selectOne、sum、selectList 和 selectPage 等,这些方法封装了对 MyBatis 返回结果的处理逻辑。
SqlUtil 是 SQL 生成工具类,负责将 BaseProvider 中收集的各种信息转换为最终的 SQL 字符串。它提供了以下主要方法:
buildPage: 构建分页查询buildOne: 构建单条记录查询buildSum: 构建聚合查询toSql: 生成最终的 SQL 字符串SelectUtil 负责处理 SELECT 语句的构建,包括解析实体类上的注解、处理字段映射、构建查询条件等。
UpdateUtil 负责处理 UPDATE 语句的构建,包括解析实体类上的注解、处理字段映射等。
InsertUtil 负责处理 INSERT 语句的构建,包括解析实体类上的注解、处理字段映射等。
JoinUtil 负责处理 JOIN 语句的构建,包括解析 @LeftJoin 注解、构建连接条件等。
WhereUtil 负责处理 WHERE 条件的构建,包括解析 @Where 注解、构建查询条件等。
TableInfoUtil 负责处理表信息的初始化,包括解析 @TableName 注解、构建表信息对象等。
TableInfo 表示数据库表的信息,包括表名、别名、主键等。
public class TableInfo {
// 实体类名
private String className;
// 实体类
private Class<?> clazz;
// 表名
private String tableName;
// 别名
private String alias;
// 索引
private Integer idx;
// 主键
private String primaryKey;
}
WhereInfo 表示 WHERE 条件的信息,包括表信息、字段名、操作符、值等。
public class WhereInfo {
// 表信息
private TableInfo tableInfo;
// 字段
private String column;
// or 条件
private List<String> orColumn;
// 值
private Object value;
// 结束值 (between 时使用)
private Object endValue;
// 操作符
private FieldOperator operator;
// 字段类型
private FieldType fieldType;
}
LeftJoinInfo 表示左连接的信息,包括表信息、关联表信息、关联条件等。
public class LeftJoinInfo {
// 表信息
private TableInfo tableInfo;
// 关联表信息
private TableInfo leftTableInfo;
// 关联条件
private String fieldName;
// 关联字段
private String leftFieldName;
// 别名
private String alias;
}
MPage 表示分页查询的信息,包括当前页、每页大小、总记录数等。
public class MPage<T> {
// 当前页
private long current;
// 每页大小
private long size;
// 总记录数
private long total;
// 记录列表
private List<T> records;
// 分页SQL
private String pageSql;
// 计数SQL
private String countSql;
// 排序信息
private List<OrderItem> orders;
// 是否优化计数SQL
private boolean optimizeCountSql;
// 是否查询总记录数
private boolean searchCount;
// 是否优化连接查询的计数SQL
private boolean optimizeJoinOfCountSql;
}
@Select 注解用于指定查询字段,可以应用在实体类或 DTO 的字段上。
public @interface Select {
// 表名
Class<?> table();
// 别名
String alias() default "";
// 字段名
String fieldName() default "";
// 聚合等条件取值
CaseWhen[] caseWhen() default {};
// 是否去重
boolean distinct() default false;
}
@Where 注解用于指定查询条件,可以应用在实体类或 DTO 的字段上。
public @interface Where {
// 表名
Class<?> table();
// 别名
String alias() default "";
// 字段名
String field() default "";
// 字段名数组(用于 OR 条件)
String[] orFields() default {};
// 字段类型
FieldType columnType() default FieldType.STRING;
// 操作符
FieldOperator operator() default FieldOperator.EQ;
// 是否为空
boolean isNull() default false;
// 是否结束(用于 BETWEEN 条件)
boolean isEnd() default false;
}
@LeftJoin 注解用于指定左连接,可以应用在实体类或 DTO 的字段上。
public @interface LeftJoin {
// 关联表
Class<?> table();
// 关联表(左表,主表)
Class<?> leftTable() default void.class;
// 关联字段
String fieldName() default "";
// 关联字段(左表关联字段)
String leftFieldName() default "";
}
@OrderBy 注解用于指定排序,可以应用在实体类或 DTO 的字段上。
public @interface OrderBy {
// 排序方式
OrderBySortEnums sortType() default OrderBySortEnums.ASC;
// 顺序
int index() default 1;
}
@Count 注解用于指定计数查询,可以应用在实体类或 DTO 的字段上。
public @interface Count {
// 是否去重
boolean distinct() default false;
// 条件
CaseWhen[] caseWhen() default {};
}
@Sum 注解用于指定求和查询,可以应用在实体类或 DTO 的字段上。
public @interface Sum {
// 条件
CaseWhen[] caseWhen() default {};
}
// 实体类
@Data
@TableName("user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("name")
private String name;
@TableField("age")
private Integer age;
@TableField("email")
private String email;
@TableField("create_time")
private Date createTime;
}
// 请求DTO
@Data
public class UserReq extends BaseReq {
@Where(table = User.class, field = "name")
private String name;
@Where(table = User.class, field = "age", operator = FieldOperator.GE)
private Integer minAge;
@Where(table = User.class, field = "age", operator = FieldOperator.LE)
private Integer maxAge;
@Where(table = User.class, field = "email", operator = FieldOperator.LIKE)
private String email;
@LeftJoin(table = Department.class, leftTable = User.class, fieldName = "id", leftFieldName = "dept_id")
private String departmentJoin;
}
// 响应DTO
@Data
public class UserDto extends BaseDto {
private Long id;
private String name;
private Integer age;
private String email;
private Date createTime;
@Select(table = Department.class, fieldName = "name")
private String departmentName;
@Count(distinct = true)
@TableField("id")
private Long userCount;
@Sum
@TableField("age")
private Long totalAge;
}
@Mapper
public interface UserMapper extends IBaseMapper<UserDto> {
// 可以添加自定义方法
}
@Service
public class UserService extends BaseServiceImpl<UserReq, User, UserDto> {
@Autowired
private UserMapper userMapper;
// 查询单条记录
public UserDto getUser(Long id) {
return userMapper.selectByPrimaryKey(id, UserDto.class);
}
// 条件查询
public List<UserDto> getUserList(UserReq req) {
return userMapper.selectList(req, UserDto.class);
}
// 分页查询
public Page<UserDto> getUserPage(UserReq req) {
return userMapper.selectPage(req, UserDto.class);
}
// 统计查询
public UserDto getUserStats(UserReq req) {
return userMapper.sum(req, UserDto.class);
}
// 保存
public int saveUser(UserReq req) {
return userMapper.save(req);
}
// 更新
public int updateUser(UserReq req) {
return userMapper.update(req);
}
}
@Data
public class ComplexUserReq extends BaseReq {
// 多字段OR条件
@Where(table = User.class, orFields = {"name", "email"}, operator = FieldOperator.LIKE)
private String keyword;
// BETWEEN条件
@Where(table = User.class, field = "create_time", operator = FieldOperator.BETWEEN)
private Date startTime;
@Where(table = User.class, field = "create_time", operator = FieldOperator.BETWEEN, isEnd = true)
private Date endTime;
// IN条件
@Where(table = User.class, field = "status", operator = FieldOperator.IN)
private List<Integer> statusList;
}
@Data
public class UserWithDeptReq extends BaseReq {
@Where(table = User.class, field = "name", operator = FieldOperator.LIKE)
private String userName;
@LeftJoin(table = Department.class, leftTable = User.class, fieldName = "id", leftFieldName = "dept_id")
private String deptJoin;
@Where(table = Department.class, field = "name", operator = FieldOperator.LIKE)
private String deptName;
@LeftJoin(table = Company.class, leftTable = Department.class, fieldName = "id", leftFieldName = "company_id")
private String companyJoin;
@Where(table = Company.class, field = "name", operator = FieldOperator.LIKE)
private String companyName;
}
@Data
public class UserWithDeptDto extends BaseDto {
private Long id;
private String name;
private Integer age;
@Select(table = Department.class, fieldName = "name")
private String departmentName;
@Select(table = Company.class, fieldName = "name")
private String companyName;
}
@Data
public class UserStatsDto extends BaseDto {
@Count(distinct = true)
@TableField("id")
private Long userCount;
@Sum
@TableField("age")
private Long totalAge;
@Select(table = Department.class, fieldName = "name")
private String departmentName;
// CASE WHEN 条件
@Sum(caseWhen = {
@CaseWhen(when = "age > 30", then = "1", elseThen = "0")
})
@TableField("id")
private Long seniorUserCount;
}
Class<R> clazz 参数,用于指定返回的 DTO 类型。@Where 注解时,需要指定 table 属性,用于确定查询条件所属的表。@LeftJoin 注解时,需要指定 table 和 leftTable 属性,用于确定连接的两个表。@Select 注解时,需要指定 table 和 fieldName 属性,用于确定查询的字段。@OrderBy 注解时,可以指定 sortType 和 index 属性,用于确定排序方式和顺序。@Count 和 @Sum 注解时,需要与 @TableField 注解一起使用,用于确定聚合的字段。@CaseWhen 注解时,需要指定 when 和 then 属性,用于构建 CASE WHEN 语句。com.poyee.base.mapper.provider 包提供了一种基于注解的方式来构建 SQL 语句,使开发者能够以更加面向对象的方式编写数据库访问代码。通过使用这些注解,开发者可以轻松实现复杂的查询条件、连接查询、排序、分页等功能,而无需手动编写 SQL 语句。
这种方式的优点是:
缺点是:
总体来说,这个包是一个非常有用的工具,特别适合于需要频繁进行数据库操作的项目。
SELECT *