源码地址

需求描述

  • 使用 QueryWrapper 对较少条件进行查询,如下:

      1. List<User> userList = userMapper.selectList(
      2. new QueryWrapper<User>()
      3. .lambda()
      4. .ge(User::getAge, 18)
      5. );
  • 而往往在真实情况下,前端一般有很多的查询条件传入后台,此时不得不手动的去包装我们的查询条件,如下:

      1. List<User> userList = this.userService.list(
      2. new QueryWrapper<User>()
      3. .lambda()
      4. .ge(User::getAge, 18)
      5. .likeLeft(User::getName, "ext")
      6. .eq(User::getEmail, "ext@baomidou.com")
      7. ...
      8. );

基础引用

mybatis-plus 3.4.0mybatis-plus 3.4.3.4 SQL注入(DefaultSqlInjector)有所不同 ,可自行更正。

  1. <!-- SpringBoot集成mybatis-plus -->
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-boot-starter</artifactId>
  5. <version>3.4.3.4</version>
  6. </dependency>>
  1. <!-- PageHelper-分页插件(非必须,可自行重写分页与排序模块) -->
  2. <dependency>
  3. <groupId>com.github.pagehelper</groupId>
  4. <artifactId>pagehelper-spring-boot-starter</artifactId>
  5. <version>1.3.0</version>
  6. </dependency

实现原理

基于自定义注解通过反射来实现。

  1. /**
  2. * 通过条件注解完成自动包装
  3. *
  4. * @param query 自定义的查询对象
  5. * @param queryWrapper 查询包装器
  6. * @param <QUERY> 自定义的查询类型
  7. * @param <ENTITY> 实体类型
  8. * @return {@link QueryWrapper}
  9. */
  10. public static <QUERY extends AbstractQuery, ENTITY> QueryWrapper<ENTITY> advise(final QUERY query, QueryWrapper<ENTITY> queryWrapper) {
  11. CriteriaFieldParser.foreachCriteriaField(query, (field, criteriaAnnotation) -> {
  12. final CriteriaAnnotationProcessor processorCached = findProcessor(criteriaAnnotation.annotationType());
  13. assert processorCached != null;
  14. return processorCached.process(queryWrapper, field, query, criteriaAnnotation);
  15. });
  16. return queryWrapper;
  17. }

查询使用

基本查询参数

  1. /**
  2. * <p>
  3. * 基本查询参数
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-03-09 14:03
  8. */
  9. public class BaseQueryParam {
  10. /**
  11. * 基本查询参数数据库字段的命名策略(默认使用小写字母 && 下划线)
  12. * [orderByColumn,isAsc,selectColumn,excludeColumn]
  13. */
  14. @ApiModelProperty(value = "数据库字段的命名策略", position = 100, example = "LOWER_CASE_UNDER_LINE")
  15. public ColumnNamingStrategy strategy = ColumnNamingStrategy.LOWER_CASE_UNDER_LINE;
  16. /** 排序列,不为空时执行排序,多个用逗号分隔 */
  17. @ApiModelProperty(value = "排序列,不为空时执行排序,多个用逗号分隔", example = "createTime", position = 101)
  18. private String orderByColumn;
  19. /** 排序方向(asc升序、desc倒序,多个用逗号分隔 */
  20. @ApiModelProperty(value = "排序方向(asc=升序,desc=倒序,多个用逗号分隔", example = "desc", position = 102)
  21. private String isAsc;
  22. /** 当前记录起始索引 */
  23. @ApiModelProperty(value = "当前记录起始索引", example = "1", position = 103)
  24. private Integer pageNum;
  25. /** 每页显示记录数(0表示查询出全部) */
  26. @ApiModelProperty(value = "每页显示记录数(0表示查询出全部)", example = "10", position = 104)
  27. private Integer pageSize;
  28. /** 指定需要查的询列(多个用逗号分隔,优先使用指定列) */
  29. @ApiModelProperty(value = "指定需要查询的列(多个用逗号分隔,优先使用指定列)", position = 105)
  30. private String selectColumn;
  31. /** 排除不需要查询的列(多个用逗号分隔,不能排除ID列) */
  32. @ApiModelProperty(value = "排除不需要查询的列(多个用逗号分隔,不能排除ID列)", position = 106)
  33. private String excludeColumn;
  34. public BaseQueryParam() {
  35. }
  36. public BaseQueryParam(Integer pageNum, Integer pageSize) {
  37. this.pageNum = pageNum;
  38. this.pageSize = pageSize;
  39. }
  40. public BaseQueryParam(String orderByColumn, String isAsc) {
  41. this.orderByColumn = orderByColumn;
  42. this.isAsc = isAsc;
  43. }
  44. public void setLimit(Integer pageNum, Integer pageSize) {
  45. this.pageNum = pageNum;
  46. this.pageSize = pageSize;
  47. }
  48. public void setOrderBy(String orderByColumn, String isAsc) {
  49. this.orderByColumn = orderByColumn;
  50. this.isAsc = isAsc;
  51. }
  52. ...
  53. /** 获取排序SQL */
  54. public String getOrderBy() {
  55. return SQLUtils.getOrderBy(this, strategy);
  56. }
  57. }

自定义查询对象

继承内置的 AbstractQuery

  1. /**
  2. * <p>
  3. * 访问日志记录 bg_visit_log
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-06-19 19:35:09
  8. */
  9. @Data
  10. @Accessors(chain = true)
  11. @TableName(value = "bg_visit_log", excludeProperty = {"updateBy", "updateTime", "remark"})
  12. @EqualsAndHashCode(callSuper = false)
  13. @ApiModel("访问日志记录")
  14. public class VisitLog extends BaseEntity {
  15. /** 日志ID */
  16. @TableId(type = IdType.AUTO)
  17. @ApiModelProperty("日志ID")
  18. private String visitId;
  19. ...
  20. /** 请求的模块 */
  21. @ApiModelProperty("请求的模块")
  22. private String title;
  23. /** 访问状态,1表示正常,0表示不正常 */
  24. @ApiModelProperty("访问状态,1表示正常,0表示不正常")
  25. private String status;
  26. }
  1. /**
  2. * <p>
  3. * 访问日志记录查询参数
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-06-19 19:35:09
  8. */
  9. @Data
  10. @Accessors(chain = true)
  11. @EqualsAndHashCode(callSuper = false)
  12. @ApiModel("访问日志记录查询参数")
  13. public class VisitLogQuery extends AbstractQuery<VisitLog> {
  14. @Eq
  15. @ApiModelProperty(value = "日志ID", position = 1)
  16. private Integer visitId;
  17. @Like
  18. @ApiModelProperty(value = "请求的模块", position = 2)
  19. private String title;
  20. @Eq
  21. @ApiModelProperty(value = "访问状态,1表示正常,0表示不正常", position = 3)
  22. private String status;
  23. @GroupBy(fieldType = HandleTypeEnum.DYNAMIC, naming = ColumnNamingStrategy.DEFAULT_COLUMN_NAMING)
  24. @ApiModelProperty(value = "分组统计(需配合selectColumn一起使用)", position = 4)
  25. private String groupBy;
  26. @JsonFormat(pattern = "yyyy-MM-dd")
  27. @Time(alias = "create_time", compare = CompareEnum.GE, format = TimeQueryFormat.DAY_BEGIN)
  28. @ApiModelProperty(value = "开始时间段", position = 10)
  29. private Date beginTime;
  30. @JsonFormat(pattern = "yyyy-MM-dd")
  31. @Time(alias = "create_time", compare = CompareEnum.LE, format = TimeQueryFormat.DAY_END)
  32. @ApiModelProperty(value = "结束时间段", position = 11)
  33. private Date endTime;
  34. }

使用案列

@Eq

  1. /**
  2. * 等于(=) 条件注解
  3. *
  4. * @author walming
  5. * @date 2020-02-15 19:45
  6. */
  7. @Documented
  8. @CriteriaQuery
  9. @Target({ElementType.FIELD})
  10. @Retention(RetentionPolicy.RUNTIME)
  11. public @interface Eq {
  12. /** 自定义的属性值(数据库字段名) */
  13. String alias() default "";
  14. /** 数据库字段命名策略(默认小写字母 && 下划线) */
  15. ColumnNamingStrategy naming() default ColumnNamingStrategy.LOWER_CASE_UNDER_LINE;
  16. }

测试代码:

  1. VisitLogQuery visitLogQuery = new VisitLogQuery().setVisitId(1);
  2. VisitLog visitLog = visitLogService.getOne(visitLogQuery.autoWrapper());

最终SQL:

  1. SELECT visit_id,ip_addr,location,browser,os,spider,request_url,error_msg,title,status,create_by,create_time FROM bg_visit_log WHERE (visit_id = 1)

@Like

  1. /**
  2. * 模糊查询(LIKE) 条件注解
  3. *
  4. * @author walming
  5. * @date 2020-02-15 19:50
  6. */
  7. @Documented
  8. @CriteriaQuery
  9. @Target({ElementType.FIELD})
  10. @Retention(RetentionPolicy.RUNTIME)
  11. public @interface Like {
  12. /** 自定义的属性值(数据库字段名) */
  13. String alias() default "";
  14. /** 匹配模式 */
  15. SqlLike like() default SqlLike.DEFAULT;
  16. /** 数据库字段命名策略(默认小写字母 && 下划线) */
  17. ColumnNamingStrategy naming() default ColumnNamingStrategy.LOWER_CASE_UNDER_LINE;
  18. }
  1. public enum SqlLike {
  2. LEFT,
  3. RIGHT,
  4. DEFAULT;
  5. ...
  6. }

测试代码:

  1. VisitLogQuery visitLogQuery = new VisitLogQuery();
  2. visitLogQuery.setTitle("首页");
  3. visitLogQuery.setOrderBy("status,create_time", "asc,desc");
  4. List<VisitLog> logList = visitLogService.list(visitLogQuery.autoWrapper());

最终SQL:

  1. SELECT visit_id, ip_addr, location, browser, os, spider, request_url, error_msg, title, status, create_by, create_time FROM bg_visit_log WHERE (title LIKE '%首页%') order by status asc,create_time desc

@Time

  1. /**
  2. * <p>
  3. * 时间模式查询,根据不同场景对时间进行处理
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-04-14 11:04
  8. */
  9. @Documented
  10. @CriteriaQuery
  11. @Target({ElementType.FIELD})
  12. @Retention(RetentionPolicy.RUNTIME)
  13. public @interface Time {
  14. /** 自定义的属性值(数据库字段名) */
  15. String alias() default "";
  16. /** 比较运行符,默认采用等于 */
  17. CompareEnum compare() default CompareEnum.EQ;
  18. /** 数据库字段命名策略(默认小写字母 && 下划线) */
  19. ColumnNamingStrategy naming() default ColumnNamingStrategy.LOWER_CASE_UNDER_LINE;
  20. /** 时间查询模式,默认不做任何处理 */
  21. TimeQueryFormat format() default TimeQueryFormat.DEFAULT;
  22. }
  1. /**
  2. * <p>
  3. * 时间查询模式
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-04-14 9:39
  8. */
  9. public enum TimeQueryFormat {
  10. /** 默认模式 */
  11. DEFAULT("yyyy-MM-dd HH:mm:ss.SSS"),
  12. /** 精确到小时 */
  13. HOUR("yyyy-MM-dd HH:00:00.0"),
  14. /** 精确到分钟 */
  15. MINUTE("yyyy-MM-dd HH:mm:00.0"),
  16. /** 精确到秒 */
  17. SECOND("yyyy-MM-dd HH:mm:ss.0"),
  18. /** 表示一天的开始 */
  19. DAY_BEGIN("yyyy-MM-dd 00:00:00.0"),
  20. /** 表示一天的结束 */
  21. DAY_END("yyyy-MM-dd 23:59:59.999");
  22. private final String format;
  23. TimeQueryFormat(String format) {
  24. this.format = format;
  25. }
  26. public String format() {
  27. return format;
  28. }
  29. }

测试代码:

  1. // 获取 2021-07-01 至 2021-07-05 期间的数据,包括 2021-07-05 这一天的数据
  2. VisitLogQuery visitLogQuery = new VisitLogQuery();
  3. visitLogQuery.setTitle("首页");
  4. visitLogQuery.setBeginTime(DateUtils.parseDate("2021-07-05"));
  5. visitLogQuery.setEndTime(DateUtils.parseDate("2021-07-11"));
  6. visitLogQuery.setOrderBy("status,create_time", "asc,desc");
  7. List<VisitLog> logList = visitLogService.list(visitLogQuery.autoWrapper());

最终SQL:

  1. SELECT visit_id, ip_addr, location, browser, os, spider, request_url, error_msg, title, status, create_by, create_time FROM bg_visit_log WHERE (title LIKE '%首页%' AND create_time >= '2021-07-05 00:00:00.0' AND create_time <= '2021-07-11 23:59:59.999') order by status asc,create_time desc

@Timestamp

一些场景下,前端时间传值,可能是采用的是时间戳 - 因此就有了 @Timestamp 的使用场景。

  1. /**
  2. * 测试 Timestamp
  3. * {@link java.time.LocalDateTime}
  4. * ==> Preparing: SELECT id,name,age,email,birth_day FROM user WHERE (age >= ? AND birth_day > ?) ORDER BY age DESC
  5. * ==> Parameters: 20(Integer), 2019-05-11T10:00(LocalDateTime)
  6. */
  7. @Test
  8. public void testQueryByTimestampGe() throws ParseException {
  9. String birthDayStr = "2019-05-12 10:00:00";
  10. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  11. Date birthDay = format.parse(birthDayStr);
  12. UserQuery userQuery = new UserQuery().setAge(20).setBirthDayGe(birthDay);
  13. List<User> users = this.userService.list(userQuery.autoWrapper());
  14. Assert.assertEquals(3, users.size());
  15. users.forEach(System.out::println);
  16. }
  17. /**
  18. * 测试 Timestamp
  19. * {@link java.time.LocalDate}
  20. * ==> Preparing: SELECT id,name,age,email,birth_day FROM user WHERE (age >= ? AND birth_day > ?) ORDER BY age DESC
  21. * ==> Parameters: 20(Integer), 2019-05-11(LocalDate)
  22. */
  23. @Test
  24. public void testQueryByCriteriaTimestampByLocalDate() {
  25. UserQuery userQuery = new UserQuery().setAge(20).setBirthDayTimestampLocalDate(1557540000000L);
  26. List<User> users = this.userService.list(userQuery.autoWrapper());
  27. users.forEach(System.out::println);
  28. }
  29. /**
  30. * 测试 Timestamp
  31. * {@link java.time.LocalTime}
  32. * ==> Preparing: SELECT id,name,age,email,birth_day FROM user WHERE (age >= ? AND birth_day > ?) ORDER BY age DESC
  33. * ==> Parameters: 20(Integer), 10:00(LocalTime)
  34. */
  35. @Test
  36. public void testQueryByCriteriaTimestampByLocalTime() {
  37. UserQuery userQuery = new UserQuery().setAge(20).setBirthDayTimestampLocalTime(1557540000000L);
  38. List<User> users = this.userService.list(userQuery.autoWrapper());
  39. users.forEach(System.out::println);
  40. }
  41. /**
  42. * 测试 Timestamp
  43. * {@link java.time.ZonedDateTime}
  44. * ==> Preparing: SELECT id,name,age,email,birth_day FROM user WHERE (age >= ? AND birth_day > ?) ORDER BY age DESC
  45. * ==> Parameters: 20(Integer), 2019-05-11T10:00+08:00[Asia/Shanghai](ZonedDateTime)
  46. */
  47. @Test
  48. public void testQueryByCriteriaTimestampByZonedDateTime() {
  49. UserQuery userQuery = new UserQuery().setAge(20).setBirthDayTimestampZonedDateTime(1557540000000L);
  50. List<User> users = this.userService.list(userQuery.autoWrapper());
  51. users.forEach(System.out::println);
  52. }

传参排序处理规则

  1. /**
  2. * 针对多字段排序规则优化
  3. *
  4. * @param queryParam 基本查询参数
  5. * @param strategy 数据库字段的命名策略
  6. * @return 排序条件语句
  7. */
  8. public static String getOrderBy(BaseQueryParam queryParam, ColumnNamingStrategy strategy) {
  9. // 排序字段为空返回空字符串
  10. if (StringUtils.isEmpty(queryParam.getOrderByColumn())) {
  11. return StringConstants.EMPTY_STRING;
  12. }
  13. String orderByColumn = StringUtils.replaceAllBlank(queryParam.getOrderByColumn());
  14. // 获取需要排序的字段
  15. String[] columns = Convert.toStrArray(NamingUtils.columnName(orderByColumn, strategy));
  16. // 若排序方向只有一个,默认所有字段均以该方向进行排序
  17. StringBuilder orderingRule = new StringBuilder();
  18. // 当排序方向为空时不做处理
  19. if (StringUtils.isEmpty(queryParam.getIsAsc())) {
  20. orderingRule.append(StringUtils.join(columns, StringConstants.COMMA));
  21. } else {
  22. String isAsc = StringUtils.replaceAllBlank(queryParam.getIsAsc());
  23. String[] directions = Convert.toStrArray(isAsc);
  24. // 当排序方向只有一个时默认所有字段均以此方向排序
  25. if (directions.length == 1) {
  26. for (int i = 0; i < columns.length; i++) {
  27. orderingRule.append(columns[i]).append(StringConstants.BLANK_SPACE).append(getIsAsc(directions[0]));
  28. if (i < columns.length - 1) {
  29. orderingRule.append(StringConstants.COMMA);
  30. }
  31. }
  32. } else {
  33. // 当排序方向有多个时按顺序匹配,若有多出或不足将不做处理
  34. for (int i = 0; i < columns.length; i++) {
  35. orderingRule.append(columns[i]);
  36. if (directions.length >= i) {
  37. orderingRule.append(StringConstants.BLANK_SPACE).append(getIsAsc(directions[i]));
  38. }
  39. if (i < columns.length - 1) {
  40. orderingRule.append(StringConstants.COMMA);
  41. }
  42. }
  43. }
  44. }
  45. return orderingRule.toString();
  46. }
  47. /** 排序方向规范,不合理默认升序 */
  48. public static String getIsAsc(String isAsc) {
  49. return (QueryConstants.ASC.equals(isAsc) || QueryConstants.DESC.equals(isAsc)) ? isAsc : QueryConstants.ASC;
  50. }

自定义模版方法

通过继承与重写 mybatis-plus 提供的 IServiceServiceImpl可以新增一些自己的模板方法。

通过mybatis-plus提供的SQL注入器(DefaultSqlInjector)也可以新增一些自己的 BaseMapper 查询模板。

IService

  1. /**
  2. * <p>
  3. * 自定义IService
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-03-09 09:53
  8. */
  9. public interface IService<T> extends com.baomidou.mybatisplus.extension.service.IService<T> {
  10. ...
  11. /**
  12. * 根据 ID 删除(物理删除,不受逻辑标识影响)
  13. *
  14. * @param id 主键ID
  15. * @return 执行结果
  16. */
  17. boolean removePhysicalById(Serializable id);
  18. ...
  19. /**
  20. * 通过 query 条件,分页查询数据,并进行排序,返回指定类型
  21. *
  22. * @param query 查询条件
  23. * @param clazz 需要转换的类型
  24. * @return {@link PageInfo<T>}
  25. */
  26. <S> PageInfo<S> query(AbstractQuery<T> query, Class<S> clazz);
  27. }

ServiceImpl

  1. /**
  2. * <p>
  3. * 自定义ServiceImpl
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-03-09 09:55
  8. */
  9. public class ServiceImpl<M extends BaseMapper<T>, T> extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<M, T> implements IService<T> {
  10. ...
  11. /**
  12. * 根据 ID 删除(物理删除,不受逻辑标识影响)
  13. *
  14. * @param id 主键ID
  15. * @return 执行结果
  16. */
  17. @Override
  18. public boolean removePhysicalById(Serializable id) {
  19. return SqlHelper.retBool(baseMapper.deletePhysicalById(id));
  20. }
  21. ...
  22. /**
  23. * 通过 query 条件,分页查询数据,返回指定类型
  24. *
  25. * @param query 查询条件
  26. * @param clazz 需要转换的类型
  27. * @return {@link PageInfo<S>}
  28. */
  29. @Override
  30. public <S> PageInfo<S> query(AbstractQuery<T> query, Class<S> clazz) {
  31. List<Map<String, Object>> maps = baseMapper.selectMaps(query.autoWrapper());
  32. List<S> list = BeanUtils.mapsToBeanList(maps, clazz);
  33. return BeanUtils.copyToCast(new PageInfo<>(maps), new PageInfo<>(list), "list");
  34. }
  35. }

BaseMapper

  1. /**
  2. * BaseMapper
  3. *
  4. * @author walming
  5. * @date 2021-03-09 9:52
  6. */
  7. public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {
  8. ...
  9. /**
  10. * 根据 ID 删除(物理删除,不受逻辑标识影响)
  11. *
  12. * @param id 主键ID
  13. * @return 执行影响行数
  14. */
  15. int deletePhysicalById(Serializable id);
  16. ...
  17. }

PhysicalDeleteById

  1. /**
  2. * <p>
  3. * 根据 ID 删除数据,<br>
  4. * 此方法慎用,绝对物理删除,不受逻辑标识影响
  5. * </p>
  6. *
  7. * @author walming
  8. * @date 2021-03-09 11:45
  9. */
  10. public class PhysicalDeleteById extends AbstractMethod {
  11. /**
  12. * 注入自定义 MappedStatement
  13. *
  14. * @param mapperClass mapper 接口
  15. * @param modelClass mapper 泛型
  16. * @param tableInfo 数据库表反射信息
  17. * @return MappedStatement
  18. */
  19. @Override
  20. public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
  21. SqlMethod sqlMethod = SqlMethod.DELETE_BY_ID;
  22. String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty());
  23. SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, Object.class);
  24. return this.addDeleteMappedStatement(mapperClass, getMethod(sqlMethod), sqlSource);
  25. }
  26. @Override
  27. public String getMethod(SqlMethod sqlMethod) {
  28. // 自定义 mapper 方法名
  29. return "deletePhysicalById";
  30. }
  31. }

PhysicalDeleteEnhance

  1. /**
  2. * <p>
  3. * 物理删除增强SQL注入器
  4. * </p>
  5. *
  6. * @author walming
  7. * @date 2021-03-09 10:19
  8. */
  9. public class PhysicalDeleteEnhance extends DefaultSqlInjector {
  10. @Override
  11. public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
  12. List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
  13. methodList.add(new PhysicalDelete());
  14. methodList.add(new PhysicalDeleteById());
  15. methodList.add(new PhysicalDeleteBatchByIds());
  16. return methodList;
  17. }
  18. }

MybatisPlusConfig

  1. /**
  2. * mybatis-plus 配置类
  3. *
  4. * @author walming
  5. * @date 2021-03-03 16:07
  6. */
  7. @Configuration
  8. public class MybatisPlusConfig {
  9. /**
  10. * SQL 自动注入器接口
  11. */
  12. @Bean
  13. public ISqlInjector sqlInjector() {
  14. return new PhysicalDeleteEnhance();
  15. }
  16. }

进阶使用

分页查询

测试代码:

  1. VisitLogQuery visitLogQuery = new VisitLogQuery();
  2. visitLogQuery.setLimit(1, 10);
  3. PageInfo<VisitLog> pageInfo = visitLogService.query(visitLogQuery);

最终SQL:

  1. SELECT visit_id,ip_addr,location,browser,os,spider,request_url,error_msg,title,status,create_by,create_time FROM bg_visit_log LIMIT 10

自定义返回列&对象

  1. @Data
  2. @Accessors(chain = true)
  3. public class VisitLogTest {
  4. /** 浏览器类型 */
  5. private String visitId;
  6. /** 操作系统 */
  7. private String os;
  8. /** 请求地址 */
  9. private String requestUrl;
  10. /** 请求的模块 */
  11. private String module;
  12. }

测试代码:

  1. VisitLogQuery visitLogQuery = new VisitLogQuery();
  2. visitLogQuery.setSelectColumn("visitId, os, requestUrl, title as module, spider");
  3. visitLogQuery.setOrderBy("create_time", "desc");
  4. visitLogQuery.setLimit(1, 10);
  5. PageInfo<VisitLogTest> pageInfo = visitLogService.query(visitLogQuery, VisitLogTest.class);

最终SQL:

  1. SELECT visit_id, os, request_url, title AS module, spider FROM bg_visit_log order by create_time desc LIMIT 10

分组统计

  1. @Data
  2. @Accessors(chain = true)
  3. public class DateGroupingStatistics {
  4. /** 时间(天) */
  5. private String createTime;
  6. /** 识别数 */
  7. private Integer count;
  8. }

测试代码:

  1. // 统计 2021-07-05 至 2021-07-11 这一周每天的日志数量
  2. VisitLogQuery visitLogQuery = new VisitLogQuery();
  3. visitLogQuery.setStrategy(ColumnNamingStrategy.DEFAULT_COLUMN_NAMING);
  4. visitLogQuery.setBeginTime(DateUtils.parseDate("2021-07-05"));
  5. visitLogQuery.setEndTime(DateUtils.parseDate("2021-07-11"));
  6. visitLogQuery.setSelectColumn("DATE_FORMAT(create_time, '%y-%m-%d') AS create_time, COUNT(*) AS count");
  7. visitLogQuery.setGroupBy("DATE_FORMAT(create_time, '%y-%m-%d')");
  8. visitLogQuery.setOrderByColumn("create_time");
  9. List<DateGroupingStatistics> logStatistics = visitLogService.list(visitLogQuery, DateGroupingStatistics.class);

最终SQL:

  1. SELECT
  2. DATE_FORMAT( create_time, '%y-%m-%d' ) AS create_time,
  3. COUNT(*) AS count
  4. FROM
  5. bg_visit_log
  6. WHERE
  7. ( create_time >= '2021-07-05 00:00:00.0' AND create_time <= '2021-07-11 23:59:59.999' )
  8. GROUP BY
  9. DATE_FORMAT( create_time, '%y-%m-%d' )
  10. ORDER BY
  11. create_time

打印日志:

  1. ==> Parameters:
  2. <== Columns: create_time, count
  3. <== Row: 21-07-07, 15
  4. <== Row: 21-07-08, 30
  5. <== Row: 21-07-09, 18
  6. <== Row: 21-07-10, 12
  7. <== Row: 21-07-11, 20
  8. <== Total: 5