Bean Searcher v4.3.0 重大更新!

往期阅读:

Bean Searcher 是什么?

Bean Searcher 是一款专注高级查询的只读 ORM 开源项目,官网 bs.zhxu.cn/

本次更新内容

1、新增用于在后端嵌套构造复杂条件的 and(..)or(..) 方法:

例如,后端想查询满足 {[(name = 'Jack' 且 忽略大小写) 并且 (gender = 'Male')] 或者 [name = 'Alice' 并且 gender = 'Female']} 并且 (age >= 20) 条件的所有 User 数据,则可以:

  • v4.3.0 新增的 后端构造检索条件 的写法:
java 复制代码
// 构造检索参数
var params = MapUtils.builder()
        .or(o -> o
            .and(a -> a
                .field(User::getName, "Jack").ic()
                .field(User::getGender, "Male")
            )
            .and(a -> a
                .field(User::getName, "Alice")
                .field(User::getGender, "Female")
            )
        )
        .field(User::getAge, "20").op(GreateEqual.class)
        .build();
// 执行查询
List<User> users = beanSearcher.searchAll(User.class, params);

使用 and(..)or(..) 方法后,无需在手动调用 groupExpr(..) 设置逻辑表达式,因为它会自动生成了。

  • v4.3.0 之前的 后端构造检索条件 的写法:
java 复制代码
// 构造检索参数
var params = MapUtils.builder()
        .group("A")             // A 组开始
        .field(User::getName, "Jack").ic()
        .field(User::getGender, "Male")
        .group("B")             // B 组开始
        .field(User::getName, "Alice")
        .field(User::getGender, "Female")
        .group("C")             // C 组开始
        .field(User::getAge, "20").op(GreateEqual.class)
        .groupExpr("(A|B)&C")   // 组间逻辑关系(组表达式)
        .build();
// 执行查询
List<User> users = beanSearcher.searchAll(User.class, params);
  • 当然,同样的检索条件,后端可以只写一行代码,由前端传参控制:

前端只需传参:

txt 复制代码
A.name=Jack      // A 组条件
A.name-ic=true
A.gender=Male
B.name=Alice     // B 组条件
B.gender=Female
C.age=20         // C 组条件
C.age-op=ge
gexpr=(A|B)&C    // 组间的逻辑关系

然后,在后端一行代码实现查询:

java 复制代码
@GetMapping("/users")
public SearchResult<User> users(HttpServletRequest request) {
    // 接收前端参数,执行查询(无需担心非法参数,框架会自动过滤)
    return beanSearcher.search(User.class, MapUtils.flat(request.getParameterMap())); 
}

参考:bs.zhxu.cn/guide/param...

2、前端传参的 关系表达式 与 后端参数构建器构建的逻辑关系支持合并:

例如,前端传参:

txt 复制代码
A.name=Jack      // A 组条件
B.name=Alice     // B 组条件
gexpr=A|B        // 组间的逻辑关系

然后,后端也构建了逻辑关系:

java 复制代码
@GetMapping("/users")
public SearchResult<User> users(HttpServletRequest request) {
    // 接收前端参数
    var params = MapUtils.flatBuilder(request.getParameterMap())
            // 附加一些条件
            .or(o -> o
                .field(User::getGender, "Female")
                .field(User::getAge, "20").op(LessThan.class)
            )
            .build();
    // 执行查询
    return beanSearcher.search(User.class, params); 
}

则实际生成的条件为:(name = 'Jack' 或者 name = 'Alice') 并且 (gender = 'Female' 或者 age < 20)

参考:bs.zhxu.cn/guide/param...

3、拼接参数,支持直接使用 集合参数值

例如在 SearchBean 中定义了一个 ages 拼接参数:

java 复制代码
@SearchBean(where = "age in (:ages:)")
public class User {
    // ...
}

然后在检索时,可以为其直接添加集合参数值:

java 复制代码
var params = MapUtils.builder()
        .put("ages", Arrays.asList(20,30,40))   // 直接使用 List 参数值,也可以使用 Set
        .build();
List<User> users = searcher.searchList(User.class, params);

也可以使用数组作为参数值:

java 复制代码
var params = MapUtils.builder()
        .put("ages", new int[] {20,30,40})     // 可以使用原生数组
        .put("ages", new Integer[] {20,30,40}) // 也可以使用对象数组
        .build();
List<User> users = searcher.searchList(User.class, params);

v4.3.0 之前,只能使用字符串:

java 复制代码
var params = MapUtils.builder()
        .put("ages", "20,30,40")               // v4.3.0 之前的用法,只能传字符串
        .build();
List<User> users = searcher.searchList(User.class, params);

参考:bs.zhxu.cn/guide/param...

4、支持前端同名参数传多个值的用法

例如,前端这样请求用户查询接口:

  • 新支持的方式:GET /users ? age=20 & age=30 & age-op=bt

则其与下面的方式等效:

  • 原始传参方式:GET /users ? age-0=20 & age-1=30 & age-op=bt

bt 是什么?请参考:bs.zhxu.cn/guide/param...

5、支持后缀运算符的简化传参形式

例如,前端原本的两个参数 age=20 & age-op=ge,现在可以简化成一个:age-ge=20

即使进行了逻辑分组,也可以被简化,例如:

txt 复制代码
A.age=30
A.age-op=gt

可以简化为

txt 复制代码
A.age-gt=30

参考:bs.zhxu.cn/guide/advan...

6、支持让前端以 JSON 数组的方式传递多个参数值

例如,原来的传参形式(age between 20 and 30):

txt 复制代码
age-0=20
age-1=30
age-op=bt

现在可以简化为:

txt 复制代码
age=[20,30]
age-op=bt

当然还可以进一步简化:

txt 复制代码
age-bt=[20,30]

参考:bs.zhxu.cn/guide/advan...

7、新增 AlwaysTrue(恒真:at)与 AlwaysFalse(恒假:af)运算符

  • AlwaysTrue(恒真:at)始终生成条件 1
  • AlwaysFalse(恒真:af)始终生成条件 0

例如,前端传参 name=Jack & age = 30 两个参数进行用户查询,后端接口里想忽略前端的 age 字段,则可以:

java 复制代码
@GetMapping("/users")
public SearchResult<User> users(HttpServletRequest request) {
    var params = MapUtils.flatBuilder(request.getParameterMap())
            field(User::getAge).op(AlwaysTrue.class) // 使用 恒真 运算符
            .build();
    return beanSearcher.search(User.class, params); 
}

则,最终生成的 SQL 条件为 ... where name = 'Jack' and 1,起到吧 age 参数忽略的目的。当然,我们还可以使用 条件约束,直接声明 age 字段不能参与 where 条件,来到达通用的效果:

java 复制代码
public class User {
    @DbField(conditional = false)
    private int age;
    // ...
}

只不过使用这种方式,age 字段就再也不能动态作为条件了。所以,这两种方式分别适用于不同的场景。

8、升级了 Oracle 方言的分页语法

升级了 OracleDialect, 采用了 offset ? rows fetch next ? rows only 分页语法,该语法在 Oracle 12c(2013年6月发布)及以上版本支持。

所以如果你使用的是 12c 以前的 Oracle 版本,在使用 Bean Searcher v4.3+ 时,则需要将老版本的 OracleDialect(点击查看方言代码) 拷贝到自己的项目中,作为自定义方言使用。

参考:bs.zhxu.cn/guide/advan...

9、升级 BeanMetaSearchSql、等类,优化或增加了一些 API

  • BeanMeta 新增了 getSqlSnippets() 方法,用户可以在 过滤器拦截器 中 使用该方法获取该实体类上所有已解析的 SQL 片段;
  • SearchSql 新增了 getSearchParam() 方法,用户可以在 拦截器 中使用该方法获取到解析后的检索参数;
  • 优化参数构建器的 field(FieldFn, Collection)field(String, Collection) 方法,使其第二个参数兼容传入 null 的用法,例如下面的代码将不再报错:
java 复制代码
// List 参数,但是值为 null,最终该参数条件会被忽略
List<Long> idList = null;

var params = MapUtils.builder()
        .field(User::getId, idList).op(InList.class)
        .build();
List<User> users = beanSearcher.search(User.class, params); 

10、新增 5 个配置项

yml 复制代码
bean-searcher:
    params:
        group:
            # 指定组表达式是否可合并,默认 true
            mergeable: true
        filter:
            # 是否启用 SizeLimitParamFilter,默认 true
            use-size-limit: true
            # 是否启用 ArrayValueParamFilter,默认 true
            use-array-value: true
            # 是否启用 SuffixOpParamFilter,默认 true
            use-suffix-op: true
            # 是否启用 JsonArrayParamFilter,默认 true
            use-json-array: true

参考:bs.zhxu.cn/guide/info/...

最后:点个 STAR 吧

往期阅读:

相关推荐
IT_陈寒13 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro13 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax14 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH14 小时前
Koa和Express的区别
后端
MariaH14 小时前
Koa框架的使用
后端
luckdewei15 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某16 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy16 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom17 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github
唐青枫20 小时前
Java JDBC 实战指南:从 Connection 到事务和连接池
java