mybatis-plus QueryWrapper自定义查询条件

mybatis-plus框架功能很强大,把很多功能都集成了,比如自动生成代码结构,mybatis

crud封装,分页,动态数据源等等,附上官网链接https://mp.baomidou.com/,github上有代码例子,国内小伙伴推荐码云https://gitee.com/baomidou/mybatis-plus。

但是,其中还是有些小坑,文档也没有涉及的很全面,碰到问题,百度或者发issue,能力强的还是直接看源码好,一切答案都在源码中

版本推荐用3.1.0,3.1.1及以上版本有bug,访问mapper接口的时候,会把数据库date类型转换为localDateTime,报错java.sql.SQLFeatureNotSupportedException

解决方案可以参考 https://blog.csdn.net/lkh1992/article/details/90024829

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>

mybatis-plus里有个类QueryWrapper,封装sql对象,包括where条件,order by排序,select哪些字段等等。该类的具体用法,网上教程很多。

这里有个需求,通过前端提交查询条件,后台动态拼接成where的sql语句,用于查询。常规做法是前端提交一堆查询参数,controller层用一个对象接收,然后在mybatis的xml里对该对象里的各种属性做判断.

<select id="test">
select * from test
<where>
<if test=" name != null and name != '' ">
and name=#{name}
</if>
...
</where>
</select>

这有个问题是具体字段连接类型就有很多,like,=,>,<等等。当然要实现功能有很多种方式,mybatis-plus的QueryWrapper很强大,可以通过对象的方式进行查询操作,但是不同的页面都自己管自己,效率低下,会存在大量重复代码。所以我就想自己封装一套,从前端的查询条件传固定格式的参数,到后台进行转换,自动拼接成对应的where sql语句,再传到mybatis xml里进行动态查询。这样所有页面就可以统一,便于操作。下面进入正题:

前端

前端用的技术是html+jquery,jquery操作dom做各种操作。html就仅仅是样式展现,不涉及任何的逻辑代码,没有使用vue之类的mvvm框架,也没有使用thymeleaf之类的模板引擎,其实这些都会在html嵌入污染代码,导致美工修改页面样式的时候一脸蒙蔽。html就是纯的html+css,通过jquery来完成剩余的工作。

index.html

<form id="myform">
<input name="name"/>
<input name="age"/>
<input name="startdate"/>
<input name="enddate"/>
</form>

jquery发起post请求,拼接的参数如下:

var searchParam = [
{column: "COLUMN_NAME",type: "like", value: "tim"},
{column: "COLUMN_AGE",type: "eq", value: "22"},
{column: "COLUMN_DATE",type: "ge", value: "2019-08-16 00:00:00"},
{column: "COLUMN_DATE",type: "le", value: "2019-08-16 23:59:59"}
];

其中column值 为数据表的字段名;type值为sql字段拼接的方式,规则可自己定制;value就是字段值了;目标拼接成的sql语句如下:

COLUMN_NAME like '%tim%' and COLUMN_AGE=22 and COLUMN_DATE>='2019-08-16 00:00:00' and COLUMN_DATE<='2019-08-16 23:59:59'

jquery发起post请求:

$.ajax({
url: "list",
type: "post",
data: {pageNum:1,pageSize:20,condition:JSON.stringify(searchParam),...(根据需要自己加请求参数)}
success: function(result){...}
});

说明:请求参数condition为什么要传json字符串后续有介绍。

后端

controller接收前端发过来的参数,碰到一个问题,在有多个请求参数的情况下,如何接收 集合对象 请求参数?使用了很多方法都不行,后续有空再研究下,目前使用的方法简单粗暴,就上传json字符串,后端转换成对象。

Controller:

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@RequestMapping(value = "/list", method = RequestMethod.POST)
public Object getTestList(@RequestParam(name = "pageNum", required = false, defaultValue = "1") int pageNum,
@RequestParam(name = "pageSize", required = false, defaultValue = "15") int pageSize,
@RequestParam(name = "condition",required = false) String conditionJson) {
QueryWrapper queryWrapper = SearchUtil.parseWhereSql(conditionJson);
queryWrapper.orderByDesc("CREATE_DATE");
return service.getPageTestList(queryWrapper,pageNum,pageSize);
}

SearchUtil:

public static QueryWrapper parseWhereSql(String conditionJson){
QueryWrapper queryWrapper = new QueryWrapper();
if(StrUtil.isNotEmpty(conditionJson)){
List<ConditionVo> conditionList = JSON.parseArray(conditionJson,ConditionVo.class);
if(CollUtil.isNotEmpty(conditionList)){
for(ConditionVo conditionVo : conditionList){
switch (conditionVo.getType()){
case "eq": queryWrapper.eq(conditionVo.getColumn(),conditionVo.getValue());break;
case "ne": queryWrapper.ne(conditionVo.getColumn(),conditionVo.getValue());break;
case "like": queryWrapper.like(conditionVo.getColumn(),conditionVo.getValue());break;
case "leftlike": queryWrapper.likeLeft(conditionVo.getColumn(),conditionVo.getValue());break;
case "rightlike": queryWrapper.likeRight(conditionVo.getColumn(),conditionVo.getValue());break;
case "notlike": queryWrapper.notLike(conditionVo.getColumn(),conditionVo.getValue());break;
case "gt": queryWrapper.gt(conditionVo.getColumn(),conditionVo.getValue());break;
case "lt": queryWrapper.lt(conditionVo.getColumn(),conditionVo.getValue());break;
case "ge": queryWrapper.ge(conditionVo.getColumn(),conditionVo.getValue());break;
case "le": queryWrapper.le(conditionVo.getColumn(),conditionVo.getValue());break;
}
}
}
}
return queryWrapper;
}

该类是重点,根据type不同的值进行组合,queryWrapper包含了很多拼接方法,可以看文档。这里只写了一些常用的拼接方法。

ConditionVo:

@Data
public class ConditionVo implements Serializable {
private static final long serialVersionUID = -5099378457111419832L;
/**
* 数据库字段名
*/
private String column;
/**
* 字段值
*/
private String value;
/**
* 连接类型,如llike,equals,gt,ge,lt,le
*/
private String type;
}

拿到queryWrapper对象就是重点了,之后就是sql操作了。

Service:

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@Override
public IPage<ListVo> getPageEntityList(QueryWrapper queryWrapper, int pageNum, int pageSize) {
Page<ListVo> page = new Page<>(pageNum,pageSize);
IPage<ListVo> list = page(page,queryWrapper);
return list;
}
@Override
public IPage<ListVo> getPageTestList(QueryWrapper queryWrapper, int pageNum, int pageSize) {
Page<ListVo> page = new Page<>(pageNum,pageSize);
IPage<ListVo> list = mapper.getPageTestList(page,queryWrapper);
return list;
}

上面的第一个方法getPageEntityList使用的是mybatis-plus自带的page(page,queryWrapper)方法,具体使用方法可以查看官方文档。使用该方法就不需要自己写sql语句了。本篇文章重点是下面那个方法getPageTestList

mybatis-plus自带了强大的翻页功能,只需往mapper方法里传入一个Page类,该类实现了IPage接口。

这里有个坑,通过看源码发现,mapper方法的参数有顺序要求:page对象一定要放在第一个参数,否则翻页查询会报错。源码在com.baomidou.mybatisplus.core.override.MybatisMapperMethod中public Object execute(SqlSession sqlSession, Object[] args)方法的case SELECT判断里,因反编译后的行数可能不同,所以贴上具体是哪个方法,我这边反编译后在68行。

ListVo是自己的业务对象。

Mapper:

import com.baomidou.mybatisplus.core.toolkit.Constants;
IPage<ListVo> getPageTestList(Page<ListVo> page,@Param(Constants.WRAPPER) Wrapper query);

大家可以进Constans这个接口看下源码都有哪些值,后续xml要用到。

XML:

<select id="getPageTestList" resultType="xx.xx.xx.ListVo">
select * from test
<if test="ew.emptyOfWhere == false">
${ew.customSqlSegment}
</if>
</select>

这里先强调一点,${ew.customSqlSegment}是用美元符号$,而不是#。

这里的ew是啥?其实就是mapper方法里的@Param(Constants.WRAPPER) Wrapper query对象,Constants.WRAPPER的值就是ew。

首先判断ew.emptyOfWhere是否存在where条件,有的话再拼接上去。ew里还有个属性nonEmptyOfWhere,看单词应该跟emptyOfWhere的值相反,但是在xml中使用却提示不存在,不知道为什么,又是一个地雷?

ew.customSqlSegment又是啥,该值是WHERE + sql语句,还有个ew.sqlSegment是不包括WHERE字符串。大家可以在service层输出queryWrapper里面的相关方法:

log.info(queryWrapper.isEmptyOfWhere()+"");
log.info(queryWrapper.getCustomSqlSegment());
log.info(queryWrapper.getSqlSegment());
log.info(queryWrapper.getParamNameValuePairs().toString());

输出如下:

getCustomSqlSegment()

WHERE COLUMN_NAME LIKE

{ew.paramNameValuePairs.MPGENVAL1}

getSqlSegment()

LIKE #{ew.paramNameValuePairs.MPGENVAL1}

getParamNameValuePairs()

{MPGENVAL1=%tim%}

看到这,mybatis框架用的熟练的小伙伴们应该就懂了吧,这样就可以避免sql注入的问题。

这里又有 一个小坑,就是order by排序。传入了page参数,mybatis-plus底层就会帮你翻页查询,会查询总数量。通过输出的sql日志可以发现,其实框架是在你的sql基础上外面再套一层select count(1) from。这里会有个问题,本人用的数据库是sqlserver,如果在count查询语句里用了order by就会出错,解决方法是调用queryWrapper对象中的排序方法,如:queryWrapper.orderByDesc("CREATE_DATE"),xml中就不要用order by。所以我在controller层用了这个方法,这样mybatis-plus底层会合理地进行查询。

总结

通过上面这种封装方式,就不需要在xml里面做一大堆的where条件if判断来拼接sql。

mybatis-plus框架功能很强大,且还在维护中,有空可以仔细阅读下文档、官方例子,能力强的可以直接看源码,一切答案都在源码中。

mybatis-plus QueryWrapper自定义查询条件的更多相关文章

  1. JEECG中datagrid方法自定义查询条件

    自定义加添加查询条件的用法: CriteriaQuery cq = new CriteriaQuery(EquipmentEntity.class, dataGrid); //查询条件组装器 org. ...

  2. MyBatis Generator Example.Criteria 查询条件复制

    背景: 我们在开发中使用MyBatis Generator生成的 XxxExample查询时,咋添加 or 查询时候,可能两个 Example.Criteria 对象的条件存在交集,即多个查询条件是相 ...

  3. 通过视图实现自定义查询<持续完善中。。。>

    目前实现: ----普通查询路径 /viewShow/viewShow/list.htm ----Echarts查询路劲 /viewShow/viewShow/echarts.htm 1.自定义查询条 ...

  4. jeecg 扩展封装查询条件 时间段查询

    使用jeecg框架开发的小伙伴们知道,添加查询条件,通常是我们加一个配置(query="true")就可以将该字段设置为查询条件.简单方便.但是这样的配置查询条件仅适用于输入框输入 ...

  5. 【mybatis】mybatis自定义动态字段查询,mybatis实现动态字段查询,如果某个条件为null,则不查询某个字段,否则就查询某个字段

    mybatis实现动态字段查询,如果某个条件为null,则不查询某个字段,否则就查询某个字段 先看一下 怎么实现动态的自定义字段查询: 例如: 而field 就是数据表中的某一个字段 String f ...

  6. 【mysql】 mybatis实现 主从表 left join 1:n 一对多 分页查询 主表从表都有查询条件 【mybatis】count 统计+JSON查询

    mybatis实现 主从表 left join  1:n 一对多 分页查询   主表从表都有查询条件+count 需求: ======================================= ...

  7. Azure 基础:自定义 Table storage 查询条件

    本文是在 <Azure 基础:Table storage> 一文的基础上介绍如何自定义 Azure Table storage 的查询过滤条件.如果您还不太清楚 Azure Table s ...

  8. Mybatis中动态SQL多条件查询

    Mybatis中动态SQL多条件查询 mybatis中用于实现动态SQL的元素有: if:用if实现条件的选择,用于定义where的字句的条件. choose(when otherwise)相当于Ja ...

  9. MyBatis 传入List集合作为条件查询数据

    使用的是SSM框架,数据库是MySQL,做查询的时候传入List集合,使用SQL语句的in方式查询数据 主要有两点问题:我的List集合是利用的另外一个语句查询出来的,传入参数是int类型,返回值是i ...

随机推荐

  1. youtube使用youtube-dl下载挂代理的方法

    youtube-dl.exe --no-check-certificate --proxy=127.0.0.1:1080 --external-downloader=aria2c --external ...

  2. 牛客练习赛56 E 小雀和他的王国

    题目链接:https://ac.nowcoder.com/acm/contest/3566/E 思路:tarjan缩点,桥重建图,dfs跑树的直径. #include <iostream> ...

  3. 纪中21日c组T2 2117. 【2016-12-30普及组模拟】台风

    2117. 台风 (File IO): input:storm.in output:storm.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制 Goto Proble ...

  4. 第二章.学习halcon的准备工作

    *图片读取 read_image (Test1, 'C:/Users/Administrator/Desktop/new/Test1.jpg') *文件夹读取 list_files ('C:/User ...

  5. MVC开发模式以及Smarty模板引擎的使用

    Linux 全局安装 composer 将目录切换到/usr/local/bin/目录 cd /usr/local/bin/ 在 bin 目录中下载 composer curl -sS https:/ ...

  6. tensorflow模型的保存与加载

    模型的保存与加载一般有三种模式:save/load weights(最干净.最轻量级的方式,只保存网络参数,不保存网络状态),save/load entire model(最简单粗暴的方式,把网络所有 ...

  7. gulp常用插件之rev-del使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 rev-del这是一款从模块(如gulp-rev)生成的修订清单中删除旧的.未使用的指纹文件. 更多使用文档请点击访问rev-del工具官网. 安 ...

  8. Supermarket POJ - 1456 贪心+并查集

    #include<iostream> #include<algorithm> using namespace std; const int N=1e5; struct edge ...

  9. Python GUI编程(TKinter)(简易计算器)

    搞课设搞得心累,现在看到人脸这两个字就烦躁,无聊搞搞tkinter,实现一个计算器的功能,能够简单的加减乘除. 简单的页面如下: 简单的代码如下: # encoding:utf-8 import tk ...

  10. 0级搭建类009-Fedora 30 安装(F30) 公开

    项目文档引子系列是根据项目原型,制作的测试实验文档,目的是为了提升项目过程中的实际动手能力,打造精品文档AskScuti. 项目文档引子系列目前不对外发布,仅作为博客记录.如学员在实际工作过程中需提前 ...