SpringBoot

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

2019-05-19  本文已影响70人  maxzhao_

前言

对于 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 我已知的两种分页多查询条件的查询方式

上一篇下一篇

猜你喜欢

热点阅读