Spring Boot Jpa 我已知的两种分页多查询条件的查询方式

前言

对于 SpringBoot 自带的 Spring JPA 方式的分页多条件查询, 目前我只掌握了两种,一种貌似还不支持条件的嵌套,下面就开始说明。

表结构得表现一下吧

SQL太长了,放到最后。

JPA 的 repo 操作类

/**
 * JpaSpecificationExecutor 这是为了实现第二种查询方式
 * @author maxzhao
 * @date 2019-05-06
 */
@Repository(value = "appTableRepository")
public interface AppTableRepository extends JpaRepository<AppTable, String>, JpaSpecificationExecutor<AppTable> {

}

测试代码

备注:把application.*的文件拷贝到 test目录的 resources下。

/**
 * 测试
 * @author maxzhao
 * @date 2019-06-06
 */
@RunWith(SpringRunner.class)
// BasicApplication 是启动类
@SpringBootTest(classes = BasicApplication.class)
public class AppColumnServiceTest {
    // 如果没有日志可以删掉
    private final static Logger logger = LoggerFactory.getLogger(AppTablesRepositoryTest.class);
    @Resource(name = "appTableRepository")
    private AppTableRepository appTableRepository;

    @Before
    public void startInit() {
        logger.info("---------------- {} -------------------", "AppColumnServiceTest");
    }

    @After
    public void endDestory() {    }

    @Test
    public void listTableTest() {
        //Sort.Direction是个枚举有ASC(升序)和DESC(降序)
        Sort.Direction sort = Sort.Direction.ASC;
        //PageRequest继承于AbstractPageRequest并且实现了Pageable
        //获取PageRequest对象 index:页码 从0开始  size每页容量 sort排序方式 "tab_name"->properties 以谁为准排序
        // 这里的tabName是实体的属性,不是数据库字段的名称
        Pageable pageable = PageRequest.of(0, 5, sort, "tabName");
        
        //region 查询条件设置方式一:
        //要匹配的实例对象
        AppTable appTable = new AppTable();
        appTable.setTabName("app_");
        //定义匹配规则 匹配"vendorId"这个属性 exact 精准匹配
        // 这里的tabName是实体的属性,不是数据库字段的名称
        ExampleMatcher exampleMatcher = ExampleMatcher
                .matching()
                .withMatcher("tabName", ExampleMatcher.GenericPropertyMatchers.contains());
        Example<AppTable> example = Example.of(appTable, exampleMatcher);
        //下面加断点,查询结果集
        Page<AppTable> page = appTableRepository.findAll(example, pageable);
        //获取总页数
        page.getTotalPages();
        //获取总元素个数
        page.getTotalElements();
        //获取该分页的列表
        page.getContent();
        page.getSize();
        //endregion
        
        //查询条件设置方式二:
        Specification<AppTable> specification = (Specification<AppTable>) (root, query, criteriaBuilder) -> {
            // 这里的tabName是实体的属性,不是数据库字段的名称
            Path<String> name = root.get("tabName");
            //Path<String> alias = root.get("alias");
            //查询条件1
            Predicate p1 = criteriaBuilder.like(name, "%" + "app_" + "%");
            //查询条件2
        //Predicate p2 = criteriaBuilder.lt(alias param.getAge());
            //查询条件1和2的关系
        //Predicate p = criteriaBuilder.and(p1, p2);
            return p1;
        };
        //下面加断点,查询结果集
        Page<AppTable> page2 = appTableRepository.findAll(specification,pageable);
        //endregion
    } 
}

代码中需要加断点的地方数据是一样的,如果不一样,设置了排序规则就没有如果。

上面注释也写的很清楚了,这两种查询方式第一种应该是没有嵌套查询的(我没有翻到源码,网上也搜不到案例),第二种也不麻烦,就多继承一个接口,可以实现嵌套查询。

查询方式二的第二种查询方式(单表多条件)

(网上找的案例,不记得地址了,我也只是 cp了这部分代码,上面的测试一下,这个就懂了 )

// Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb
List<Predicate> predicates = new ArrayList<>();
if (user.getUserId() != null && !user.getUserId().equals("")) {
    predicates.add(cb.like(root.get("userId").as(String.class), "%" + user.getUserId() + "%"));
}
if (user.getUserName() != null && !user.getUserName().equals("")) {
    predicates.add(cb.like(root.get("userName").as(String.class), "%" + user.getUserName() + "%"));
}
if (user.getGender() != null && !user.getGender().equals("")) {
    predicates.add(cb.like(root.get("gender").as(String.class), "%" + user.getGender() + "%"));
}
if (user.getAge() != null && !user.getAge().equals("")) {
    predicates.add(cb.like(root.get("age").as(String.class), "%" + user.getAge() + "%"));
}
Predicate[] pre = new Predicate[predicates.size()];
criteriaQuery.where(predicates.toArray(pre));
return cb.and(predicates.toArray(pre));

查询方式二的第二种查询方式(多表、多条件)

备注:记得设置 @ManyToOne或者 @OneToMany之类的外键关联哦

// (Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb)
List<Predicate> list = new ArrayList<>();
                //根据userId 查询user
if (StringUtils.isNotBlank(params.getUserId())) {
    list.add(cb.equal(root.get("userId").as(String.class), params.getUserId()));
}
                //根据userName 模糊查询user
if (StringUtils.isNotBlank(params.getUserName())) {
    list.add(cb.like(root.get("userName").as(String.class), "%" + params.getUserName() + "%"));
}
                //根据gender 查询user
if (StringUtils.isNotBlank(params.getGender())) {
    list.add(cb.equal(root.get("gender").as(String.class), params.getGender()));
}
                //根据age>? 查询user
if (StringUtils.isNotBlank(params.getAge())) {
    list.add(cb.gt(root.get("age").as(Integer.class), Integer.valueOf(params.getAge())));
}
                //根据gradeName 查询user
if (StringUtils.isNotBlank(params.getGradeName())) {
    Join<Grade, User> join = root.join("grade", JoinType.LEFT);
    list.add(cb.equal(join.get("gradeName"), params.getGradeName()));
}
                //根据schoolName 查询user
if (StringUtils.isNotBlank(params.getSchoolName())) {
    Join<School, User> join = root.join("grade", JoinType.LEFT);
    list.add(cb.equal(join.get("school").get("schoolName"), params.getSchoolName()));
}
Predicate[] pre = new Predicate[list.size()];
criteriaQuery.where(list.toArray(pre));
return cb.and(list.toArray(pre));

不推荐上面这种用法,这么用让微服务颜面何存?

附录:

数据库SQL:

-- MySql
create table app_table
(
    tab_name     varchar(255) not null comment '表名主键'
        primary key,
    alias        varchar(255) null comment '别名',
    can_del_data int          null comment '是否可以清除数据0否1是',
    id_cols      varchar(255) null comment '主键列名',
    remark       varchar(255) null comment '备注',
    tab_type     int          null comment '物理表类型(app 1应用级;cf_ 2配置级;bn 3 业务级;tmp 4临时;5其它数据表)'
)comment '应用表信息' charset = utf8;
-- 数据
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_area', '地区编码表', 0, 'id', '地区编码表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_column', '应用表字段信息', 0, 'id', '应用表字段信息', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_dept', '部门管理', 0, 'id', '部门管理', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_dict', '应用字典表', 0, 'id', '应用字典表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_dict_value', '应用字典属性表', 0, 'id', '应用字典属性表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_log', '系统日志', 0, 'id', '系统日志', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_menu', '菜单表', 0, 'id', '菜单表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_role', '角色表', 0, 'id', '角色表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_role_group', '角色组表', 0, 'id', '角色组表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_role_group_link', '角色与角色组表', 0, 'id', '角色与角色组表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_role_menu', '角色菜单表', 0, 'id', '角色菜单表', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_table', '应用表信息', 0, 'tab_name', '应用表信息', 1);
INSERT INTO app_table (tab_name, alias, can_del_data, id_cols, remark, tab_type) VALUES ('app_user', '用户表', 0, 'id', '用户表', 1);

create table app_column
(
    id             varchar(255)  not null comment '主键'
        primary key,
    alias          varchar(255)  null comment '别名',
    app_dict_id    bigint        null comment '绑定字典主键',
    char_length    int           null comment '内容长度',
    col_default    varchar(255)  null comment '默认值',
    col_name       varchar(255)  null comment '字段名',
    col_type       varchar(255)  null comment '字段类型(用于与使用控件相关)',
    col_type_alias varchar(255)  null comment '字段类型描述',
    is_null        int default 1 null comment '是否允许空(1 是 0 否)',
    remark         varchar(255)  null comment '备注',
    scale          int           null comment '精度',
    tab_name       varchar(255)  null comment '表名',
    time_format    varchar(255)  null comment '时间格式'
)comment '应用表字段信息' charset = utf8;


specificationin语句

Path<String> path = root.get("tabName");
CriteriaBuilder.In<String> in = criteriaBuilder.in(path);
in.value("app_table");
in.value("app_column");
criteriaBuilder.and(in);
return criteriaBuilder.and(p1, in);

本文地址:Spring Boot Jpa 我已知的两种分页多查询条件的查询方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容