检索参数

检索参数是 Bean Searcher 的重要检索信息,它们共同组成了 Searcher 接口的检索方法的 第二个 类型为 Map<String, Object> 的参数值。

分页参数

Bean Searcher 提供了两种分页:Page 分页Offset 分页

可配置项

在 Spring Boot 项目中,可在项目配置文件 application.propertiesapplication.yml 中对分页进行个性化配置:

配置键名含义可选值默认值
bean-searcher.params.pagination.type分页类型pageoffsetpage
bean-searcher.params.pagination.default-size默认每页查询条数正整数15
bean-searcher.params.pagination.max-allowed-size每页最大查询条数正整数100
bean-searcher.params.pagination.page页码参数名(在 type = page 时有效)字符串page
bean-searcher.params.pagination.size大小参数名(在 type = page 时有效)字符串size
bean-searcher.params.pagination.offset偏移参数名(在 type = offset 时有效)字符串offset
bean-searcher.params.pagination.max大小参数名(在 type = offset 时有效)字符串max
bean-searcher.params.pagination.start起始页码 或 起始偏移量自然数0

Page 分页

Page 分页提供两个分页参数(参数名可配置):

  • page: 页码
  • size: 每页查询条数

用法示例(默认配置下):

Map<String, Object> params = new HashMap<>();
params.put("page", 0);                                      // 第 0 页
params.put("size", 15);                                     // 每页 15 条
SearchResult<User> result = searcher.search(User.class, params);
1
2
3
4

使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .page(0, 15)                                        // 该方法会自动使用正确的参数名
        .build();
SearchResult<User> result = searcher.search(User.class, params);
1
2
3
4

Offset 分页

Offset 分页也提供两个分页参数(参数名可配置):

  • offset: 偏移量
  • max: 每页查询条数

用法示例(默认配置下):

Map<String, Object> params = new HashMap<>();
params.put("offset", 0);                                    // 从第 0 条开始查
params.put("max", 15);                                      // 每页 15 条
SearchResult<User> result = searcher.search(User.class, params);
1
2
3
4

使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .limit(0, 15)                                       // 该方法会自动使用正确的参数名
        .build();
SearchResult<User> result = searcher.search(User.class, params);
1
2
3
4

起始 页码/偏移量

配置项 起始页码/偏移量(bean-searcher.params.pagination.start)默认是 0,在 Page 分页机制下,page 参数为 0 表示查询第 1 页。当把 起始页码 配置为 1 时,则 page 参数为 1 才表示查询第 1 页。Offset 分页同理。

最大查询条数

配置项 最大查询条数(bean-searcher.params.pagination.max-allowed-size)默认是 100,它可以风控一些恶意查询:比如黑客想通过一次查询 1 亿 条数据从而让我们系统崩溃时,Bean Searcher 会自动把它缩小为 100

默认分页大小

配置项 默认分页大小(bean-searcher.params.pagination.default-size)默认是 15,在用户为添加分页参数时,默认每页查询 15 条数据。

TIP

Searcher 实例的 searchAll(...) 方法不受分页参数影响

排序参数

可配置项

在 Spring Boot 项目中,可在项目的 application.propertiesapplication.yml 文件中通过如下配置项对排序参数进行定制:

配置键名含义可选值默认值
bean-searcher.params.sort排序字段参数名字符串sort
bean-searcher.params.order排序方法参数名字符串order

用法示例(默认配置下):

Map<String, Object> params = new HashMap<>();
params.put("sort", "age");                                  // 按年龄字段排序
params.put("order", "desc");                                // 降序
SearchResult<User> res = searcher.search(User.class, params);
1
2
3
4

使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .orderBy(User::getAge, "desc")                      // 该方法会自动使用正确的参数名
        .build();
SearchResult<User> result = searcher.search(User.class, params);
1
2
3
4

字段参数

字段参数是根据 SearchBean (检索实体类)里被 @DbField 注解的字段衍生出来的一系列参数,它们起到对查询结果进行筛选的作用。

可配置项

在 Spring Boot 项目中,可在项目的 application.propertiesapplication.yml 文件中通过如下配置项对字段参数进行定制:

配置键名含义可选值默认值
bean-searcher.params.separator字段参数名分隔符字符串-
bean-searcher.params.operator-key字段运算符参数名后缀字符串op
bean-searcher.params.ignore-case-key是否忽略大小写字段参数名后缀字符串ic

字段衍生规则

示例,对于如下的一个 SearchBean:

@SearchBean(tables = "user") 
public class User {

    @DbField("name")
    private String name;

    // Getter and Setter ...
}
1
2
3
4
5
6
7
8

以它的 name 字段为例,可衍生出以下一系列的字段参数:

  • name-{n}: name 字段的第 n 个参数值,如:name-0name-1name-2 等等
  • name: 等价于 name-0,name 字段的第 0 个参数值
  • name-op: name 的 字段运算符,如: EqualGreaterEqualGreaterThan 等等
  • name-ic: name 字段在检索时是否应该忽略大小写

以上在衍生字段参数时,用到了中划线(-)作为连接符,如果你喜欢下划线(_),可把 bean-searcher.params.separator 配置为下划线即可。配置为下划线后,衍生出的参数就是 name_{n}namename_opname_ic 了。同理: opic 后缀您也可以自定义。

TIP

字段参数,是根据 SearchBean 里的 JAVA 字段名(不是表字段)衍生出来的,已经和数据库的表字段解耦了。

字段运算符

字段运算符是用来描述某个字段的检索方式,即:SQL 的拼接方法。Bean Searcher 共提供了 13 种不同的字段运算符,下表:

运算符全称运算符缩写SQL 片段含义
Equaleq= ?等于(是缺省默认的运算符)
GreaterEqualge>= ?大于等于
GreaterThangt> ?大于
LessEqualle<= ?小于等于
LessThanlt< ?小于
NotEqualne!= ?不等于
Emptyeyis null为空
NotEmptynyis not null不为空
Includeinlike '%?%'包含(模糊查询)
StartWithswlike '?%'以...开头(模糊查询)
EndWithewlike '%?'以...结尾(模糊查询)
Betweenbtbetween ? and ?<= ?>= ?在...之间(范围查询)
MultiValuemvin (?, ?, ...)多值查询

由于 Bean Searcher 为运算符提供了全称与缩写,所以对于每一种运算符,都有三种等效的用法,例如,查询 name 等于 Jack 的用户:

Map<String, Object> params = new HashMap<>();
params.put("name", "Jack");
// 使用枚举变量
params.put("name-op", Equal.class);
// 查询满足条件的第一个用户
User jack = searcher.searchFirst(User.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "Jack").op(Equal.class)
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11
12
13

等价于:

Map<String, Object> params = new HashMap<>();
params.put("name", 'Jack');
// 使用运算符名称
params.put("name-op", "Equal");
// 查询满足条件的第一个用户
User jack = searcher.searchFirst(User.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "Jack").op("Equal")
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11
12
13

等价于:

Map<String, Object> params = new HashMap<>();
params.put("name", 'Jack');
// 使用运算符缩写
params.put("name-op", "eq");
// 查询满足条件的第一个用户
User jack = searcher.searchFirst(User.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "Jack").op("eq")
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11
12
13

由于 Equal 是缺省默认的字段运算符,所以上述代码也等价于:

Map<String, Object> params = new HashMap<>();
params.put("name", 'Jack');
// 查询满足条件的第一个用户
User jack = searcher.searchFirst(User.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "Jack")
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11

由于字段参数 namename-0 的等价写法,所以上述代码还等价于:

Map<String, Object> params = new HashMap<>();
params.put("name-0", 'Jack');
// 查询满足条件的第一个用户
User jack = searcher.searchFirst(User.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "Jack")
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11

内嵌参数

内嵌参数,即是:嵌入到实体类注解内的参数(参见:实体类 > 嵌入参数 章节),它可分为 普通内嵌参数 与 拼接参数,他们可以轻松处理各种复杂的 SQL 检索问题。

普通内嵌参数

普通内嵌参数,是以一个冒号(:)前缀(形如 :name)的形式嵌入到实体类注解的 SQL 片段中的参数。

例如,有这样的一个 SearchBean:

@SearchBean(
    tables = "student", 
    joinCond = "age = :age"
) 
public class Student {

    @DbField("s.name")
    private String name;

    // Getter and Setter ...
}
1
2
3
4
5
6
7
8
9
10
11

则我们可以用如下方式检索年龄为 20 的学生:

Map<String, Object> params = new HashMap<>();
params.put("age", 20);      // 指定内嵌参数 age 的值为 20
// 查询 年龄为 20 的学生
List<Student> students = searcher.searchList(Student.class, params);

// 使用参数构建器的等效写法(since v2.2.0):

Map<String, Object> params = MapUtils.builder()
        .field("age", 20)
        .build();
User jack = searcher.searchFirst(User.class, params);
1
2
3
4
5
6
7
8
9
10
11

TIP

普通内嵌参数 最终会被 Bean Searcher 处理为一种 JDBC 参数,无需担心 SQL 注入问题。

拼接参数

拼接参数(since v2.1),是以一个冒号(:)为前缀一个冒号(:)为后缀(形如 :name:)的形式嵌入到实体类注解的 SQL 片段中的参数。

拼接参数的用武之地非常广:能用 普通内嵌参数 的地方肯定能用 拼接参数,而 普通内嵌参数 搞不定的地方 拼接参数 则可以轻松搞定,它可以做到 动态生成 SQL

参考:示例 > 动态检索 > 分表检索 案例。