Java 如何通用化查询逻辑应对复杂的查询需求?

2022-04-17 15:42:06 +08:00
 jimisun

数据库有一些数据,如下模拟;


        ArrayList<User> objects = Lists.newArrayList();
        objects.add(new User("zhangsan", "123456", 18, 1));
        objects.add(new User("lisi", "123456", 22, 1));
        objects.add(new User("wangwu", "123456", 30, 1));
        objects.add(new User("zhaoliu", "123456", 43, 1));
        objects.add(new User("xiaoli", "xiaoli67889", 16, 0));
        objects.add(new User("xiaona", "nai324389", 22, 0));

问题抛出

针对这些数据的查询而言,通常会在 service 层定义许多查询接口,例如

面对需求的变化多样,总是需要增量添加 controller 方法,service 方法,甚至 dao 方法,如何解决这个问题呢?

面向函数编程是否能满足呢?

//dao
public static List<User> getUserList() {
        ArrayList<User> objects = Lists.newArrayList();
        objects.add(new User("zhangsan", "123456", 18, 1));
        objects.add(new User("lisi", "123456", 22, 1));
        objects.add(new User("wangwu", "123456", 30, 1));
        objects.add(new User("zhaoliu", "123456", 43, 1));
        objects.add(new User("xiaoli", "xiaoli67889", 16, 0));
        objects.add(new User("xiaona", "nai324389", 22, 0));
        return objects;
        }
//service
public static Optional getUserListByPredicate(Predicate<User> predicate) {
        List<User> userList = UserDao.getUserList();
        ArrayList<Object> resultList = Lists.newArrayList();
        for (User user : userList) {
        if (predicate.test(user)) {
        resultList.add(user);
        }
        }
        return Optional.ofNullable(resultList);
        }
        
//controller
public static void main(String[] args) {

        //查询性别为男,年龄 20 以下,并且密码为默认密码 123456 的用户
        Optional<List> result = UserService.getUserListByPredicate((User user) -> {
        return user.getSex() == 1 && user.getAge() < 20 && user.getPassword().equals("123456");
        });


        result.get().stream().forEach(user -> System.out.println(user));
        }

我的想法是,dao 层总是返回全量的数据(此处有问题性能问题),在 service 层对查询条件进行抽象,controller 只需要将查询条件传入即可。

更进一步用 stream 处理

//dao
public static List<User> getUserList() {
ArrayList<User> objects = Lists.newArrayList();
objects.add(new User("zhangsan", "123456", 18, 1));
objects.add(new User("lisi", "123456", 22, 1));
objects.add(new User("wangwu", "123456", 30, 1));
objects.add(new User("zhaoliu", "123456", 43, 1));
objects.add(new User("xiaoli", "xiaoli67889", 16, 0));
objects.add(new User("xiaona", "nai324389", 22, 0));
return objects;
}
//controller 层
    /**
     * 查询性别为男,年龄 20 以下,并且密码为默认密码 123456 的用户
     *
     * @param args
     */
    public static void main(String[] args) {
        List<User> userList = UserDao.getUserList();
        userList.stream().filter(
                user -> user.getSex() == 1 && user.getAge() < 20 && user.getPassword().equals("123456")
        ).forEach(user -> System.out.println(user));
    }

我的想法是,controller 总是获取所有的数据,针对流根据业务进行业务操作。

——————————

以上两种方法是否可行? 问题?

1667 次点击
所在节点    问与答
13 条回复
PerFectTime
2022-04-17 16:06:08 +08:00
我们是维护了一个数据列表的列视图权限,在此基础上通过列视图的数据类型(bit/string/字典)由可配置的高级查询功能可以对每一列的情况进行筛选
eggoxygen
2022-04-17 16:26:25 +08:00
根据 ORM 框架不同有不同解决方案吧。
比如 JPA 的 Specification / QueryDsl 。
定义好需要查询的 Condition / Criteria 。
查询时传入即可。
Leviathann
2022-04-17 16:26:32 +08:00
为什么不根据查询条件动态生成 sql
xiangyuecn
2022-04-17 17:16:50 +08:00
多写一条 if else 就要被抓取坐牢
micean
2022-04-17 17:52:35 +08:00
比如某个男人的 apijson……
lower
2022-04-17 17:57:56 +08:00
直接让前端传 sql 语句吧,他们爱查啥查啥……
EscYezi
2022-04-17 19:08:36 +08:00
看场景都是同一些数据同一些字段数值不同。controller 层只需要一个接口,定义一个含有多个字段的 vo ,本次查询用不到的字段和前端协商一个默认值就 ok
dao 层 mybatis 的 xml 文件中 if 和 choose 根据各种情况拼接查询条件; mybatis-plus 也可以在拼接查询条件时增加 bool 参数指定是否拼接
全部查询出来数据少还好,多起来一次拿几十万数据出来,数据库和 java 服务压力都很大
letitbesqzr
2022-04-17 22:05:26 +08:00
试试用 Aviator 之类的表达式解析工具? 让前端传表达式
rehoni
2022-04-18 08:29:55 +08:00
定义一个通用的查询过滤器 Qo 数组,用作查询条件的拼接。当数组为空时,默认查全部 sql 为 select*;数组中每个对象对应一个条件,如年龄 20 以下、默认密码是 123456 ,拼接出来 sql 就是 select * where age < 20 ,pwd = ‘123456’; Qo 对象的 JSON 很明显包含字段名 age ,条件<,值 20 等,这是最基础的,然后在此 JSON 基础上还可以做一些拓展,如复杂字段建立驼峰关系或者建立映射,条件提供枚举,时间类型提供格式化,整体条件提供前端解决方案如指定为下拉框、时间选择器,再者就是可以利用框架特性来进行条件 Qo 的封装来实现通用效果,如 mybatis-plus 的条件构造器。
whatevers
2022-04-18 10:03:36 +08:00
单表查询用 Mybatis 逆向工程生成 Mapper ,前端传参生成动态 sql
li746224
2022-04-18 10:48:50 +08:00
graphql?
90d0n
2022-04-18 11:17:51 +08:00
1. mybatis, 用 myabtis-plus 的 QueryWrapper, 动态拼接一下查询条件.
https://baomidou.com/pages/10c804

2. jpa, 看文档 4.8.2 那一节, Querydsl Web Support.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html


实现后接口大概是这样: http://your.api/user?name=Alice&page=0&size=20&sort=age,asc
aguesuka
2022-04-18 14:07:12 +08:00
前端到后端用 luence 语法, 后端映射到 sql

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/847485

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX