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层的使用

先给看下代码吧。

@RestControllerpublic class CommonQueryController {@Resourceprivate 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一起,每天不一样!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

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

MySQL的基础操作

前言 对MySQL的一些基础操作做一下学习性的总结&#xff0c;基本上是照着视频写的。 MySQL的安装 MySQL的下载 MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ 配置环境变量 下载之后直接解压&#xff0c…

c++ 虚函数类对象模型

一、复杂的菱形继承及菱形虚拟继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承。 多继承&#xff1a;一个子类有两个或以上直接父类时称这个继承关系为多继承。 菱形继承&#xff1a;菱形继承是多继承的一种特殊情况。 菱形继承的问题&#xff1a;从…

2023年京东儿童智能手表行业数据分析(京东销售数据分析)

儿童消费市场向来火爆&#xff0c;儿童智能手表作为能够实现定位导航&#xff0c;信息通讯&#xff0c;SOS求救&#xff0c;远程监听&#xff0c;智能防丢等多功能的智能可穿戴设备&#xff0c;能够通过较为精准的定位功能和安全防护能力保障儿童的安全&#xff0c;因而广受消费…

C#详解-Contains、StartsWith、EndsWith、Indexof、lastdexof

目录 简介: 过程: 举例1.1 举例1.2 ​ 总结: 简介: 在C#中Contains、StarsWith和EndWith、IndexOf都是字符串函数。 1.Contains函数用于判断一个字符串是否包含指定的子字符串&#xff0c;返回一个布尔值&#xff08;True或False&#xff09;。 2.StartsWith函数用于判断一…

数据结构-二叉树

在学习二叉树之前.必须先要掌握一些树的重要概念: 结点的度:一个结点含有的子树个数称为该结点的度.树的度:一棵树中,所有节点度的最大值称为树的度.叶子结点:度为0的结点称为叶子节点.(也叫终端结点)双亲结点:若一个结点含有子结点,则这个结点称为其子结点的双亲结点(也叫父节…

USB隔离器电路分析,SA8338矽塔sytatek电机驱动,源特科技VPS8701,开关电源,电源 大师

一、 USB隔离器电路分析 进行usb隔离可以使用USB隔离模块 ADUM3160 ADUM4160 注意&#xff1a;B0505S 最大带载0.16A&#xff0c;副边需要带载能力需要改变方案 比如移动硬盘至少需要0.5A 用充电宝、18650、设计5V1A输出电源 二、 1A隔离电压方案

redis乐观锁+启用事务解决超卖

乐观锁用于监视库存&#xff08;watch&#xff09;&#xff0c;然后接下来就启用事务。 启用事务&#xff0c;将减库存、下单这两个步骤&#xff0c;放到一个事务当中即可解决秒杀问题、防止超卖。 但是&#xff01;&#xff01;&#xff01;乐观锁&#xff0c;会带来" …

Leetcode67 二进制求和

给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 代码 class Solution {public String addBinary(String a, String b) {StringBuilder res new StringBuilder();int carry 0;int i a.length() - 1, j b.length() - 1;while(i > 0 || j &…

keepalived+lvs+nginx高并发集群

keepalivedlvsnginx高并发集群 简介&#xff1a; keepalivedlvsnginx高并发集群&#xff0c;是通过LVS将请求流量均匀分发给nginx集群&#xff0c;而当单机nginx出现状态异常或宕机时&#xff0c;keepalived会主动切换并将不健康nginx下线&#xff0c;维持集群稳定高可用 1.L…

Linux系统之安装OneNav个人书签管理器

Linux系统之安装OneNav个人书签管理器 一、OneNav介绍1.OneNav简介2.OneNav特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查本地yum仓库状态 四、安装httpd服务4.1 安装httpd4.2 启动httpd服务4…

低代码开发ERP:精打细算,聚焦核心投入

企业数字化转型已经成为现代商业环境中的一项关键任务。如今&#xff0c;企业面临着日益激烈的竞争和不断变化的市场需求。在这样的背景下&#xff0c;数字化转型不仅是企业生存的必然选择&#xff0c;也是取得竞争优势和实现可持续发展的关键因素。 在数字化转型的过程中&…

神经网络入门

前言 本文主要介绍最基础的神经网络&#xff0c;包括其结构&#xff0c;学习方法&#xff0c; C \texttt{C} C 的实现代码。 Python \texttt{Python} Python 的代码可以搜索互联网得到。 前排提示&#xff1a;本人涉及一丁点数学知识。 神经网络的结构 神经网络包括多个层…

[Linux]进程概念

[Linux]进程概念 文章目录 [Linux]进程概念进程的定义进程和程序的关系Linux下查看进程Linux下通过系统调用获取进程标示符Linux下通过系统调用创建进程-fork函数使用 进程的定义 进程是程序的一个执行实例&#xff0c;是担当分配系统资源&#xff08;CPU时间&#xff0c;内存…

二、数学建模之整数规划篇

1.定义 2.例题 3.使用软件及解题 一、定义 1.整数规划&#xff08;Integer Programming&#xff0c;简称IP&#xff09;&#xff1a;是一种数学优化问题&#xff0c;它是线性规划&#xff08;Linear Programming&#xff0c;简称LP&#xff09;的一个扩展形式。在线性规划中&…

构造不包含字母和数字的webshell

文章目录 利用不含字母与数字进行绕过知识介绍题目方法一&#xff1a;异或操作绕过方法二&#xff1a;取反进行绕过 过滤不是很严格的情况进阶绕过利用php7特性直接绕过 利用不含字母与数字进行绕过 知识介绍 <?phpecho "A"^"";?>从运行结果为! …

深度学习|CNN卷积神经网络

CNN卷积神经网络 解决的问题人类的视觉原理原理卷积层——提取特征池化层——数据降维全连接层——输出结果 应用图像处理自然语言处理 解决的问题 在CNN没有出现前&#xff0c;图像对人工智能来说非常难处理。 主要原因&#xff1a; 图像要处理的数据量太大了。图像由像素组…

使用IDEA把Java程序打包成jar

点击左上角File,选择Project Structure 左侧选中Artifacts,点击右侧的号 选择JAR->From modules with dependencies 选择你要运行的main方法所在的类,选好了点击OK Artifacts添加完成后点击右下角OK 在工具栏中找到Build,选择Build Artifacts 刚才创建好的Artifacts,选择Bui…

【附安装包】Midas Civil2019安装教程

软件下载 软件&#xff1a;Midas Civil版本&#xff1a;2019语言&#xff1a;简体中文大小&#xff1a;868.36M安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.5GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.…

Java设计模式-抽象工厂模式

简介 设计模式是软件设计中的一种常见方法&#xff0c;通过定义一系列通用的解决方案&#xff0c;来解决常见的软件设计问题。其中&#xff0c;抽象工厂模式是一种非常常见的设计模式&#xff0c;它可以帮助我们创建一组相关的对象&#xff0c;而不需要指定具体的实现方式。 …