spring boot分装通用的查询+分页接口

背景

在用spring boot+mybatis plus实现增删改查的时候,总是免不了各种模糊查询和分页的查询。每个数据表设计一个模糊分页,这样代码就造成了冗余,且对自身的技能提升没有帮助。那么有没有办法实现一个通用的增删改查的方法呢?今天的shigen闲不住,参照gitee大神蜗牛的项目,实现了通用的查询+分页的封装。

在此之前,希望你对于mybatis plus的基本API有一定的了解。

那么我先列举一下我之前写的代码,实现的模糊查询和分页吧。

Page<SlowLogData> page = new Page<>(queryVo.getPageNum(), queryVo.getPageSize());
        if (StrUtil.isAllNotBlank(sortColumn, isAsc)) {
            OrderItem orderItem = new OrderItem(sortColumn, Boolean.parseBoolean(isAsc));
            page.addOrder(orderItem);
        }

        LambdaQueryWrapper<SlowLogData> queryWrapper = new LambdaQueryWrapper<SlowLogData>()
            .like(keywordIsNotEmpty, SlowLogData::getInstanceId, keyword)
            .or()
            .like(keywordIsNotEmpty, SlowLogData::getInstanceName, keyword)
            .or()
            .like(keywordIsNotEmpty, SlowLogData::getDatabase, keyword)
            .or()
            .like(keywordIsNotEmpty, SlowLogData::getSqlText, keyword)
            .or()
            .like(keywordIsNotEmpty, SlowLogData::getUserName, keyword)
            .gt(startTime != null, SlowLogData::getTimestamp, startTime)
            .lt(endTime != null, SlowLogData::getTimestamp, endTime);

        return getBaseMapper().selectPage(page, queryWrapper);

怎么样,我只能先肯定的说这个肯定比mybatis更好一些,至少我的Java字段名变了,我这边就可以在编译的时候报错,提示去修改。那么,shigen是个喜欢把代码写优雅的人,这样的代码是活不久的。

改造

先分析一下我需要的效果或者说是功能:

  • 根据某些字段的值精确匹配
  • 根据某些字段的值进行模糊匹配
  • 根据某些字段排序,可以升序降序
  • 还要进行数据的分页展示

所以,如果停留在第一阶段:代码能实现,那我以上的代码就可以实现。但是有更高的要求和代码的复用性上,我推荐我一下的实现。

查询条件封装

我写了一个工具类AggregateQueriesUtil,实现动态查询条件的封装。

public class AggregateQueriesUtil {

    /**
     * 聚合查询对象拼接
     *
     * @param queries   查询对象
     * @param aggregate 聚合查询对象
     * @return {@link QueryWrapper}<{@link Q}>
     */
    public static <Q, T, R> QueryWrapper<Q> splicingAggregateQueries(QueryWrapper<Q> queries, AggregateQueries<T, R> aggregate) {
        if (aggregate.hasEqualsQueries()) {
            equalsQueries(queries, aggregate.getEqualsQueries());
        }
        if (aggregate.hasFuzzyQueries()) {
            fuzzyQueries(queries, aggregate.getFuzzyQueries());
        }
        if (aggregate.hasSortField()) {
            aggregate.setSortType(aggregate.hasSortType() ? aggregate.getSortType() : 0);
            applySort(queries, aggregate.getSortField(), aggregate.getSortType());
        }
        return queries;
    }

    /**
     * equals查询对象拼接
     *
     * @param queries 查询对象
     * @param obj     聚合查询属性对象
     */
    public static <Q> void equalsQueries(QueryWrapper<Q> queries, Object obj) {
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            String underlineCase = StrUtil.toUnderlineCase(field.getName());
            try {
                if (field.get(obj) != null) {
                    queries.eq(underlineCase, field.get(obj));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 模糊查询对象拼接
     *
     * @param queries 查询对象
     * @param obj     模糊查询属性对象
     */
    public static <Q> void fuzzyQueries(QueryWrapper<Q> queries, Object obj) {
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            String underlineCase = StrUtil.toUnderlineCase(field.getName());
            try {
                if (field.get(obj) != null) {
                    queries.like(underlineCase, field.get(obj));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 排序
     *
     * @param wrapper   查询对象
     * @param sortField 排序字段
     * @param sortType  排序类型
     */
    private static <Q> void applySort(QueryWrapper<Q> wrapper, String sortField, int sortType) {
        String field = StrUtil.toUnderlineCase(sortField);
        if (sortType == 1) {
            wrapper.orderByDesc(field);
        } else {
            wrapper.orderByAsc(field);
        }
    }
}

第一个方法就是核心的方法:实现聚合查询对象的拼接,分别处理equals查询、like查询和排序。也可以看到这里用到了反射,实现对象属性名的获取,然后通过属性名获得传进来的对象的值。

那这里涉及到AggregateQueries,它到底是什么呢?这个就是我们查询条件的聚合类。

查询条件聚合类

查询条件聚合类

文章篇幅限制,这里仅做一个截图展示。

这里边其实是对查询条件的聚合。T表示的是等于查询条件的对象,它的属性是对应的实体属性的子集即可;R表示的是模糊查询条件对象(R是一个Bean,可以根据对象的属性作为模糊查询的条件),和T差不多。剩下的三个属性分别是排序字段、排序方式,和最后的分页。

那么,shigen写了这么多了,我该怎么调用呢?

controller层的使用

先给看下代码吧。

@RestController

public class CommonQueryController {

    @Resource
    private UserMapper userMapper;

    @PostMapping(value = "index/query")
    public Result<List<User>> get(@RequestBody AggregateQueries<UserQueries, UserFuzzyQueries> aggregate) {
        PaginationDTO pagination = aggregate.getPagination();
        QueryWrapper<User> wrapper = AggregateQueriesUtil.splicingAggregateQueries(new QueryWrapper<>(), aggregate);
        Page<User> page = new Page<>(pagination.getPageNum(), pagination.getPageSize());
        Page<User> userPage = userMapper.selectPage(page, wrapper);
        List<User> records = userPage.getRecords();
        return Result.ok(records);
    }


}

这是spring boot接口的写法,可以看到关键点就在于调用我的工具类AggregateQueriesUtil.splicingAggregateQueries(new QueryWrapper<>(), aggregate);拼装成一个动态的QueryWrapper,之后就是page的获得,最后用mapper进行分页查询。

我的AggregateQueries的范型类也很简单:

@Data
public class UserQueries {

    private Integer isDeleted;

}

只要保证自己定义的queries的属性集合是对应的实体类集合的子集即可。

验证

忙活了这么久,来验证一下吧。我的实体类的属性我先列举出来:

实体类属性

现在调用我的接口查询,我的参数是:

{
  "equalsQueries": {
    "isDeleted": 0
  },
  "pagination": {
    "pageNum": 0,
    "pageSize": 1
  },
  "fuzzyQueries": {
    "phone": "132",
    "introduction": "知道"
  },
  "sortField": "id",
  "sortType": 1
}

用原生的sql写出来就是:

select * from user where is_deleted=0 and phone like concat('%', '132', '%') and introduction like concat('%',"知道", "%") order by id desc limit 0,1;

查出来的结果正好是一条,我的分页容量也是1,这是正常的。那我的接口调用呢?

sql查询的结果

数据是没问题的,查验一下sql确定一下:

==>  Preparing: SELECT id,username,password,introduction,is_deleted,create_time,update_time FROM user WHERE (is_deleted = ? AND phone LIKE ? AND introduction like ?) ORDER BY id DESC LIMIT ?
==> Parameters: 0(Integer), %132%(String), %知道%(String), 1(Long)

可以看到,这也是没问题的了。好的,shigen大功告成!一个简易版的模糊查询+分页的通用工具封装实现了。

总结

以上使用了Java的反射和mybatis plusqueryWrapper实现了动态的模糊查询+分页,很好的减少了查询的代码冗余量,可以用在实际的项目中,减少代码的重复率,提升开发效率。代码我放在了shigen的gitee上。上边也有很多shigen别的学习笔记,欢迎大家的学习和参考。

但是,我也必须得承认美中不足的地方!

  1. 反射的效率如何保证

其实反射有它的优势,但是也会影响程序的效率,我的代码也并没有做实际的效率测试。

Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            String underlineCase = StrUtil.toUnderlineCase(field.getName());
            try {
                if (field.get(obj) != null) {
                    queries.eq(underlineCase, field.get(obj));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
}
  1. 异常的处理

我该如何保证不管是等于查询和模糊查询的对象属性和我对应的实体类属性是包含的关系呢,我觉得可以做进一步的改进。

  1. 多种排序条件的组合

如:我需要根据id升序,再根据introduction降序,我该咋办!我觉得可以列一个TODO了。

以上就是我本篇的全部内容了,如果觉得很不错的话,也希望伙伴们点赞、评论、在看和关注哈,这样就不活错过很多的干货了。

shigen一起,每天不一样!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/83739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

课程项目设计--项目设计--宿舍管理系统--vue+springboot完成项目--项目从零开始

写在前面&#xff1a; 本文是从项目设计到完成开始写的&#xff0c;本来这个项目基础功能是做完了的&#xff0c;但是之前时间紧张想从头做起了。之前一周写前端后端累死了. 设计是关键&#xff0c;这一篇主讲设计。可能后面会有修改&#xff0c;本人实力有限,学习的也是别人的…

搞定二叉树

树的名词与概念 子树&#xff1a;树是一个有限集合&#xff0c;子树则是该集合的子集。就像套娃一样&#xff0c;一棵树下面还包含着其子树。比如&#xff0c;树T1 的子树为 树T2、T3、T4&#xff0c;树T2的子树为 T5、T6 。 上图中还有许多子树没有标记出来 。 结点(Node)&am…

Stable Diffusion:使用自己的数据集微调训练LoRA模型

Stable Diffusion&#xff1a;使用自己的数据集微调训练LoRA模型 前言前提条件相关介绍微调训练LoRA模型下载kohya_ss项目安装kohya_ss项目运行kohya_ss项目准备数据集生成关键词模型参数设置预训练模型设置文件夹设置训练参数设置 开始训练LoRA模型TensorBoard查看训练情况 测…

基于Googlenet深度学习网络的信号调制类型识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 深度学习与卷积神经网络 4.2 数据预处理 4.3 GoogLeNet结构 4.4 分类器 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ............…

聚焦电力行业CentOS迁移,麒麟信安受邀参加第六届电力信息通信新技术大会暨数字化发展论坛并发表主题演讲

为加快推进“双碳”目标下的新型能源体系和新型电力系统建设&#xff0c;深化新一代数字技术与电力业务的融合发展&#xff0c;促进电力行业关键技术自主创新、安全可控&#xff0c;助力电力企业数字化转型升级和高质量发展&#xff0c;2023年8月9-11日&#xff0c;第六届电力信…

攻防世界-warmup

原题解题思路 只有一张图片&#xff0c;就查看源代码&#xff0c;有一个source.php。 查看source.php&#xff0c;白名单中还有一个hint.php。 hint.php告诉我们flag的位置ffffllllaaaagggg 但是直接跳转是没用的&#xff0c;构造payload。 http://61.147.171.105:55725/sourc…

Dockerfile制作Web应用系统nginx镜像

目录 1.所需实现的具体内容 2.编写Dockerfile Dockerfile文件内容&#xff1a; 默认网页内容&#xff1a; 3.构建镜像 4.现在我们运行一个容器&#xff0c;查看我们的网页是否可访问 5.现在再将我们的镜像打包并上传到镜像仓库 1.所需实现的具体内容 基于centos基础镜像…

8.部署项目

项目地址&#xff1a;RuoYi-Cloud-Plus: 项目正式入驻 dromara 开源社区 迁移地址: https://gitee.com/dromara/RuoYi-Cloud-Plus 1.获取源码 需要有gitee账户 先把源码fork到自己的仓库中 需要多等待一段时间 勾选对应的环境 构建项目 2.sql导入 将sql导入到与sql文件名…

【uniapp】中 微信小程序实现echarts图表组件的封装

插件地址&#xff1a;echarts-for-uniapp - DCloud 插件市场 图例&#xff1a; 一、uniapp 安装 npm i uniapp-echarts --save 二、文件夹操作 将 node_modules 下的 uniapp-echarts 文件夹复制到 components 文件夹下 当前不操作此步骤的话&#xff0c;运行 -> 运行到小…

批量爬虫采集完成任务

批量爬虫采集是现代数据获取的重要手段&#xff0c;然而如何高效完成这项任务却是让许多程序员头疼的问题。本文将分享一些实际操作价值高的方法&#xff0c;帮助你提高批量爬虫采集的效率和专业度。 目标明确&#xff0c;任务合理划分&#xff1a; 在开始批量爬虫采集前&…

怎么查看小程序中的会员信息

商家通过查看会员信息&#xff0c;可以更好地了解用户&#xff0c;并为他们提供更个性化的服务和推荐。接下来&#xff0c;就将介绍如何查看会员信息。 商家在管理员后台->会员管理处&#xff0c;可以查看到会员列表。支持搜索会员的卡号、手机号和等级。还支持批量删除会员…

Rancher-RKE-install 部署k8s集群

一、为什么用Rancher-RKE-install 1.CNCF认证的k8s安装程序。 2.有中文文档。 二、安装步骤 1.下载Rancher-Rke的二进制包-下面是项目的地址 GitHub - rancher/rke: Rancher Kubernetes Engine (RKE), an extremely simple, lightning fast Kubernetes distrib…

代码随想录打卡—day21—【二叉树】— 8.21

1 530. 二叉搜索树的最小绝对差 530. 二叉搜索树的最小绝对差 想法&#xff1a;先直接中序遍历&#xff08;升序的序列&#xff09;过程中相邻两个数的差值取min&#xff0c;自己写一次AC代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* …

关于视频监控平台EasyCVR视频汇聚平台建设“明厨亮灶”具体实施方案以及应用

一、方案背景 近几年来&#xff0c;餐饮行业的食品安全、食品卫生等新闻频频发生&#xff0c;比如某火锅店、某网红奶茶&#xff0c;食材以次充好、后厨卫生被爆堪忧&#xff0c;种种问题引起大众关注和热议。这些负面新闻不仅让餐饮门店的品牌口碑暴跌&#xff0c;附带的连锁…

爬虫工具的选择与使用:阐述Python爬虫优劣势

作为专业爬虫ip方案解决服务商&#xff0c;我们每天都面对着大量的数据采集任务需求。在众多的爬虫工具中&#xff0c;Python爬虫凭借其灵活性和功能强大而备受青睐。本文将为大家分享Python爬虫在市场上的优势与劣势&#xff0c;帮助你在爬虫业务中脱颖而出。 一、优势篇 灵活…

32.Netty源码之服务端如何处理客户端新建连接

highlight: arduino-light 服务端如何处理客户端新建连接 Netty 服务端完全启动后&#xff0c;就可以对外工作了。接下来 Netty 服务端是如何处理客户端新建连接的呢&#xff1f; 主要分为四步&#xff1a; md Boss NioEventLoop 线程轮询客户端新连接 OP_ACCEPT 事件&#xff…

分享图片 | 快速浏览网页资源,批量保存、一键分享图片

前言 小伙伴学习吉他&#xff0c;有时需要在互联网搜索曲谱资源&#xff0c;而多数曲谱均为图片&#xff0c;并且为多页&#xff0c;在电脑上显示练习很不方便&#xff0c;需要停下来点击鼠标进行翻页&#xff0c;影响练习的连贯性。 为了解决上述问题&#xff0c;通常把图片…

【数据分析入门】Jupyter Notebook

目录 一、保存/加载二、适用多种编程语言三、编写代码与文本3.1 编辑单元格3.2 插入单元格3.3 运行单元格3.4 查看单元格 四、Widgets五、帮助 Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 …

宇宙原理:黑洞基础。

宇宙原理&#xff1a;黑洞基础TOC 黑洞的数理基础&#xff1a;一个由满数组成的数盘&#xff0c;经过自然演进&#xff0c;将会逐步稀疏化、最终会向纯数方案发展&#xff1b;纯数方案虽然只有{2}、无数&#xff08;虚拟&#xff09;、{0,1,2,3}&#xff08;虚拟&#xff09;、…

jenkins同一jar包部署到多台服务器

文章目录 安装插件配置ssh服务构建完成后执行 没有部署过可以跟这个下面的步骤先部署一遍&#xff0c;我这篇主要讲jenkins同一jar包部署到多台服务器 【Jenkins】部署Springboot项目https://blog.csdn.net/qq_39017153/article/details/131901613 安装插件 Publish Over SSH 这…