BeanSearcher入门

374 阅读7分钟

这篇文章不是严格的教程,是我学习的手记吧,发出来大家共同学习。

概述

今天给大家介绍一个java数据库查询的开源项目,叫BeanSearcher(Apache2.0,国产开源项目)。 我们使用java操作数据库很多时候使用的是mybatis、Hibernate、jpa等等,都是具有完整的CRUD功能的,而BeanSearcher专做查询功能,对多表查询支持的非常好。优点灵活小巧,即可以像使用sql语句查询一样的方便,又保留了ORM的面向对象编程特点。在使用时不必再纠结mybatis的各种映射,do和vo的转换,能够极大的提高我们的开发效率,又不增加维护难度。 官网网址:bs.zhxu.cn

特点&优点

  1. 集成简单,注解开发,学习难度低,可以很快上手使用
  2. 支持参数过滤、字段转换器、Select指定字段、SQL拦截
  3. 可以快速方便的进行多表查询
  4. 简化了DO/VO的转换
  5. 扩展性强
  6. 支持多数据源

在BeanSearcher有MapSearcher和BeanSearcher两个检索器,是我们用来进行查询的最重要的工具,其中MapSearcher查询出的结果都是以Map对象呈现,BeanSearcher的结果以Bean或者叫VO的对象呈现,根据实际开发的需求,我们可以选择不同的检索器。

学习目标

  1. 单表查询
  2. 如果使用查询参数
    1. Map硬编码
    2. MapUtils使用
  1. 多表查询
    1. 2表联合查询
    2. 2个以上的表联合查询
  1. 子查询
  2. 分组查询

基本功能

项目Demo地址

gitee.com/radium/bean…

视频地址

www.bilibili.com/video/BV1Ae…

项目集成

首先看一下如何集成BeanSearcher,我们这里已经准备了一个springboot+mybatis的项目,我们将beanSearcher集成上来。

SpringBoot项目只需要添加bean-searcher-boot-starter一个依赖就可以了。

<!-- Bean Searcher 核心依赖,任何框架都可使用该依赖 -->
<dependency>
  <groupId>com.ejlchina</groupId>
  <artifactId>bean-searcher</artifactId>
  <version>3.8.0</version>
</dependency>
<!-- SpringBoot / Grails 的项目直接使用以下依赖,更为方便(只添加这一个依赖即可) -->
<dependency>
  <groupId>com.ejlchina</groupId>
  <artifactId>bean-searcher-boot-starter</artifactId>
  <version>3.8.0</version>
</dependency>

基本配置

如果我们之前使用的mybatis,那么我们的Bean对象命名可能就是UserDO、UserDAO之类的字样,这个时候我们简单的做一些配置,让BeanSearcher忽略这个Bean上多余的字母,让他和我们的数据库表做好映射。

bean-searcher:
  sql:
    default-mapping:
      redundant-suffixes: DO

查询

我们可以直接使用之前mybatis中的DO来进行查询,不需要新建DO。

无参查询

beanSearcher.searchList(UserDO.class,null);

可以使用searchFirst来查询一个数据,如果查询出多个结果是不会抛异常的。

beanSearcher.searchFirst(UserDO.class,null);

查询参数的使用

通过构造一个Map进行查询参数

public List<UserDO> userList( String name, Integer age){
        Map<String,Object> params = new HashMap<>();
        params.put("name",name);
        params.put("age",age);
        params.put("age-op","gt");
        return beanSearcher.searchList(UserDO.class,params);
    }
//

这里有一个age-op是来设置查询age是的运算符,(这里的op,可以通过参数进行设置),默认每个参数都会有一个eq的运算符,我们在这里设置了age字段的运算符是>

使用MapUtils简化查询参数

很明显这么查询也会很慢,这里我们就可以来看看BeanSearcher给我们提供的MapUtils了,使用这个工具可以更方便的进行查询参数的拼装工作。

@RequestMapping(value = "users2")
    public List<UserDO> userList2( String name, Integer age){
        return beanSearcher.searchList(UserDO.class,
                MapUtils.builder()
                        .field(UserDO::getName,name).op(Equal.class)
                        .field(UserDO::getAge,age).op(GreaterThan.class)
                        .build()
        );
    }

MapUtils.flat一行代码实现查询参数

虽然代码很多,但是好消息是我们变成了一行,而且我们不用再去拼接字段名了,一切看起来都挺顺利。那如果这个时候产品经理说了用户名称需要进行模糊查询怎么办,又要改界面,加参数。不不不~~MapUtils还有办法。

@RequestMapping(value = "users3")
    public List<UserDO> userList3(HttpServletRequest request){
        return beanSearcher.searchList(UserDO.class,
                MapUtils.flat(request.getParameterMap())
        );
    }

通过flat方法将一个 value 为数组的 Map 对象,拉平为 value 为单值的 Map 对象,我们这里直接将界面上的参数map传过去,然后对我们界面的入参调整一下,完成了,以后再加什么参数都无所谓啦,只需要调整前端入参就可以了。

age=32&name=mi&age-op=gt&name-op=ct

分页查询

不需要额外的配置天生支持分页查询,只需要我们传递page和size做为查询参数就可以了。分页数据的返回需要我们自己处理一下,简单的写了一下,具体的封装工作根据各位项目的实际情况处理吧。

public Page<StatisticVO> statisticPage(HttpServletRequest request){
    Map<String,Object> where = MapUtils.flat(request.getParameterMap());
    SearchResult<StatisticVO> search = beanSearcher.search(StatisticVO.class,
            where);

    Page<StatisticVO> page = new Page<>();
    page.setTotal(search.getTotalCount().longValue());
    page.setRecords(search.getDataList());
    page.setCurrent(Long.valueOf(where.get("page").toString()));
    return page;
}

多表查询

先来看看数据库结构

两个表

班级统计
学校班级
@SearchBean(
        tables = "school s , class c",
        where = "s.id = c.school_id",
        autoMapTo = "c"
)
@Data
public class StatisticVO {
    @DbField("s.name")
    String name;
    String grade;
    String num;
}
@RequestMapping(value ="statistic")
public List<StatisticVO> statistic(HttpServletRequest request){
    return beanSearcher.searchList(StatisticVO.class, MapUtils.flat(request.getParameterMap()));
}

多个表

班级统计
学校班级学生
@SearchBean(
        tables = "school s " +
                "left join class c on c.school_id = s.id " +
                "left join student st on st.class_id = c.id",
        autoMapTo = "c"
)
@Data
public class Statistic1VO {
    @DbField("s.name")
    String name;
    String grade;
    String num;
    @DbField("st.name")
    String studentName;
}
@RequestMapping(value ="statistic1")
    public List<Statistic1VO> statistic1(HttpServletRequest request){
        return beanSearcher.searchList(Statistic1VO.class, MapUtils.flat(request.getParameterMap()));
    }

子查询

班级统计
学校班级学生总成绩
@SearchBean(
        tables = "school s " +
                "left join class c on c.school_id = s.id " +
                "left join student st on st.class_id = c.id",
        autoMapTo = "c"
)
@Data
public class Statistic1VO {
    @DbField("s.name")
    String name;
    String grade;
    String num;
    @DbField("st.name")
    String studentName;
}
@RequestMapping(value ="statistic2")
    public List<Statistic2VO> statistic2(HttpServletRequest request){
        return beanSearcher.searchList(Statistic2VO.class, MapUtils.flat(request.getParameterMap()));
    }

分组查询

统计一下每个班级的成绩,要求根据批次和科目统计

班级统计
学校班级总成绩
@SearchBean(
        tables = "performance p " +
                "left join student stu on stu.id = p.student_id " +
                "left join class c on c.id = stu.class_id " +
                "left join school sc on sc.id = c.school_id",
        autoMapTo = "c",
        groupBy = "sc.name,c.grade,c.num"
)
@Data
public class Statistic3VO {
    @DbField("sc.name")
    String name;
    @DbField("concat(c.grade,'年',c.num,'班')")
    String gradeClass;
    @DbField("sum(p.score)")
    Double sumScore;
}
public List<Statistic3VO> statistic3(HttpServletRequest request){
        return beanSearcher.searchList(Statistic3VO.class, MapUtils.flat(request.getParameterMap()));
    }

\

需要了解的参数配置

排序约束配置

配置键名含义可选值默认值
bean-searcher.sql.default-mapping.sort-type默认排序约束ALLOW_PARAM、ONLY_ENTITYALLOW_PARAM

表名注解缺省配置

配置键名含义可选值默认值
bean-searcher.sql.default-mapping.table-prefix表名前缀字符串null
bean-searcher.sql.default-mapping.underline-case表名和字段名是否驼峰转小写下划线(since v3.7.0)布尔值true
bean-searcher.sql.default-mapping.upper-case表名和字段名是否大写布尔值false
bean-searcher.sql.default-mapping.redundant-suffixes类名的冗余后缀(可配多个)(since v3.3.0)冗余后缀null

默认继承方式配置

配置键名含义可选值默认值
bean-searcher.sql.default-mapping.inherit-type默认继承类型ALL、TABLE、FIELD、NONEALL

全局属性忽略配置

配置键名含义可选值默认值
bean-searcher.sql.default-mapping.ignore-fields需要全局忽略的属性名(可指定多个)字符串数组null

分页参数配置

配置键名含义可选值默认值
bean-searcher.params.pagination.type分页类型page、offsetpage
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每页大小参数名字符串size
bean-searcher.params.pagination.offset偏移参数名(在 type = offset 时有效)字符串offset
bean-searcher.params.pagination.start起始页码 或 起始偏移量自然数0

排序参数配置

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

字段参数配置

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

逻辑分组参数配置

配置键名含义可选值默认值
bean-searcher.params.group.enable是否开启逻辑分组功能布尔true
bean-searcher.params.group.expr-name逻辑表达式参数名字符串gexpr
bean-searcher.params.group.expr-cache-size表达式解析缓存(个数)整型50
bean-searcher.params.group.separator组名分隔符字符串.

指定Select字段配置

配置键名含义可选值默认值
bean-searcher.params.only-selectonlySelect 参数名字符串onlySelect
bean-searcher.params.select-excludeselectExclude 参数名字符串selectExclude

SQL方言配置

配置键名含义可选值默认值
bean-searcher.sql.dialectSQL 方言MySQL、Oracle、PostgreSQL、SqlServerMySQL

慢SQL日志与监听

配置键名含义类型默认值
bean-searcher.sql.slow-sql-threshol慢 SQL 阈值(单位:毫秒)int500

\

字段运算符

运算符缩写SQL 片段是否忽略空值含义
Equaleqx = ?等于(是缺省默认的运算符)
NotEqualnex != ?不等于
GreaterThangtx > ?大于
GreaterEqualgex >= ?大于等于
LessThanltx < ?小于
LessEquallex <= ?小于等于
Betweenbtx between ?1 and ?2 /x >= ?1 / x <= ?2在...之间(范围查询)
NotBetweennbx not between ?1 and ?2 / x < ?1 / x > ?2不在...之间(范围查询)(since v3.3
Containctx like '%?%'包含(模糊查询)(since v3.2
StartWithswx like '?%'以...开头(模糊查询)
EndWithewx like '%?'以...结尾(模糊查询)
OrLikeolx like ?1 or x like ?2 or ...模糊或匹配(可有多个参数值)(since v3.7
NotLikenkx not like ?反模糊匹配(since v3.8
InListil/ mvx in (?, ?, ...)多值查询(InList / il自 v3.3 新增,之前是MultiValue/ mv)
NotInnix not in (?, ?, ...)多值查询(since v3.3
IsNullnlx is null为空(since v3.3
NotNullnnx is not null不为空(since v3.3
Emptyeyx is null or x = ''为空(仅适用于 字符串 类型的字段)
NotEmptynyx is not null and x != ''不为空(仅适用于 字符串 类型的字段)