Mybatis plus 动态分页(单表) 多表可以联系我,我也实现了
你还在为前端传一大堆条件查询写一大堆where条件吗?你还在痛苦苦恼一个条件一个if标签吗?
<select id="fuzzyQuery" resultType="你的实体类Reference" parameterType="你的实体类Reference">
SELECT * FROM sz_staff
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test='staff.userName!=null and staff.userName!=" "'>
AND USER_NAME like CONCAT('%',#{staff.userName},'%')
</if>
<if test='staff.phone!=null and staff.phone!=" "'>
AND PHONE like CONCAT('%',#{staff.phone},'%')
</if>
<if test='staff.belongFirm!=null and staff.belongFirm!=" "'>
AND BELONG_FIRM like CONCAT('%',#{staff.belongFirm},'%')
</if>
<if test='staff.positionId!=null and staff.positionId!=" "'>
AND POSITION_ID=#{staff.positionId}
</if>
<if test='staff.superLeader!=null and staff.superLeader!=" "'>
AND SUPER_LEADER like CONCAT('%',#{staff.superLeader},'%')
</if>
<if test='staff.status!=null and staff.status!=" "'>
AND STATUS=#{staff.status}
</if>
<if test='staff.isSupportPeople!=null and staff.isSupportPeople!=" "'>
AND IS_SUPPORT_PEOPLE=#{staff.isSupportPeople}
</if>
</trim>
</select>
你觉得这种代码恶心吗?
基于这种恶心的Page 代码,我忍无可忍写了一个工具,就是前端根据我们约定的规范动态传入条件值来充当条件。
实际效果:
实际sql
SELECT p_id,name,url,context,insurance,problem,serve,notice,details,status,create_time,update_time FROM web_produce WHERE (1 = '1' AND create_time = '2021-01-27 10:33:57') ORDER BY status DESC LIMIT 0,5
下面一步一步带你写出来。单表和多表皆可以,生产可用。
一:单表分页
1.数据格式
/**
条件格式,必须与前端约定好
*/
public interface ConstantType {
String desc = "desc";
String asc = "asc";
public enum ParamType {
/**
* 条件查询
*/
filter_,
/**
* EQ // 等于
* <p>
* NE // 不等于
* <p>
* LIKE // 模糊查询
* <p>
* NOTLIKE // 不模糊查询
* <p>
* LIKESTART // 左侧模糊查询
* <p>
* LIKEEND // 右侧模糊查询
* <p>
* LT // 小于
* <p>
* GT // 大于
* <p>
* LE // 小于等于
* <p>
* GE // 大于等于
*/
EQ, NE, LIKE,NOTLIKE, LIKESTART, LIKEEND, LT, GT, LE, GE,
/**
* 根据某个字段排序,AES,DESC
*/
orderBy, orderDir,
/**
* 当前页,个数
*/
page, size;
public static ParamType getMsgByType(String type) {
for (ParamType val : ParamType.values()) {
if (val.toString().equals(type)) {
return val;
}
}
return null;
}
}
}
ParamType 就是一种格式约束
比如:
这种就是 filter_ 是一种条件查询, EQ 就是等于的意思,说白了就是 where后面的动态条件 where name = '3333'
filter_LIKEEND_name 就是LIKEEND右模糊 where name like '3333%'
多个filter 后面就是and
暂时没有多个or的形式,因为涉及到or就比较复杂,所以不考虑or的情况。仅仅是and。
so easy !
mybatis plus 分页插件,不用不行啊
/**
* 配置分页插件
*/
@Configuration
@MapperScan("com.yfh.zhw.mapper.*.mapper*")
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
2. 驼峰转换 一个工具类
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 驼峰与下划线转换
*/
public class UnderlineToCamelUtil {
public static final char UNDERLINE = '_';
/**
* 驼峰格式字符串转换为下划线格式字符串
*
* @param param
* @return
*/
public static String camelToUnderline(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
//如果首字母为大写字母就不用转换
char indexChars = param.charAt(0);
if (Character.isUpperCase(indexChars)){
return param;
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (Character.isUpperCase(c)) {
sb.append(UNDERLINE);
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 下划线格式字符串转换为驼峰格式字符串
*
* @param param
* @return
*/
public static String underlineToCamel(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (c == UNDERLINE) {
if (++i < len) {
sb.append(Character.toUpperCase(param.charAt(i)));
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 下划线格式字符串转换为驼峰格式字符串2
*
* @param param
* @return
*/
public static String underlineToCamel2(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
StringBuilder sb = new StringBuilder(param);
Matcher mc = Pattern.compile("_").matcher(param);
int i = 0;
while (mc.find()) {
int position = mc.end() - (i++);
sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
}
return sb.toString();
}
public static void main(String[] args) {
// String aaa = "app_version_fld";
// System.out.println(underlineToCamel(aaa));
// System.out.println(underlineToCamel2(aaa));
String aaa = "tESTID";
System.out.println(camelToUnderline(aaa));
}
}
3.接受条件参数,一般的可以从controller中显示接受参数,但是我不采用这种。
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* SpringMVC相关操作
目的是获取前端传入的参数
*
* @author kong
*/
public class SpringMVCUtil {
/**
* 获取当前会话的 request
*
* @return request
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return servletRequestAttributes.getRequest();
}
/**
* 获取当前会话的 response
*
* @return response
*/
public static HttpServletResponse getResponse() {
// 大善人SpringMVC提供的封装
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return servletRequestAttributes.getResponse();
}
/**
* 根据KEY 获取相应的值 全部从请求头中获取
*
* @param key key名
* @param isFilterflag 是否为filter查询 true是
* @return map key-value 的数值
*/
public static Map<String, Object> getRequestParam(String key, boolean isFilterflag) {
HashMap<String, Object> paramsMap = Maps.newHashMap();
HttpServletRequest request = getRequest();
if (ObjectUtils.isEmpty(request)){
return paramsMap;
}
//是否为filter查询
if (!isFilterflag) {
String parameter = request.getParameter(key);
paramsMap.put(key, parameter);
return paramsMap;
}
//遍历集合数据取得从status开头的数据
Enumeration<String> paraNames = request.getParameterNames();
for (Enumeration<String> e = paraNames; e.hasMoreElements(); ) {
String thisName = e.nextElement();
if (StringUtils.startsWith(thisName, key)) {
paramsMap.put(thisName, request.getParameter(thisName));
}
}
return paramsMap;
}
/**
* 根据KEY 获取相应的值 全部从请求头中获取
*
* @param key key名
* @return String value 的数值
*/
public static String getRequestParam(String key) {
HttpServletRequest request = getRequest();
if (ObjectUtils.isEmpty(request)){
return "";
}
String parameter = request.getParameter(key);
return parameter;
}
}
4.新建一个类实现com.baomidou.mybatisplus.core.metadata.IPage接口, 我需要对里面的page进行一些数据的初始化。QueryWrapper
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yfh.zhw.enums.ConstantType;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Predicate;
public class ZhwPage<T> implements IPage<T> {
private static final long serialVersionUID = 1545996863226928798L;
/**
* 查询数据列表
*/
private List<T> records = Collections.emptyList();
@JsonIgnore
private QueryWrapper<T> queryWrapper;
/**
* 总数
*/
private long total = 0;
/**
* 每页显示条数,默认 10
*/
private long size = 10;
/**
* 当前页
*/
private long current = 1;
/**
* 排序字段信息
*/
@JsonIgnore
private List<OrderItem> orders = new ArrayList<>();
/**
* 自动优化 COUNT SQL
*/
private boolean optimizeCountSql = true;
/**
* 是否进行 count 查询
*/
private boolean isSearchCount = true;
/**
* 分页构造函数
*
* @param current 当前页
* @param size 每页显示条数
*/
public ZhwPage(long current, long size) {
this(current, size, 0);
}
/**
* 分页构造函数
*/
public ZhwPage() {
this(StringUtils.isNotEmpty(SpringMVCUtil.getRequestParam(ConstantType.ParamType.page.toString())) ? Long.valueOf(SpringMVCUtil.getRequestParam(ConstantType.ParamType.page.toString())) : 1,
StringUtils.isNotEmpty(SpringMVCUtil.getRequestParam(ConstantType.ParamType.size.toString())) ? Long.valueOf(SpringMVCUtil.getRequestParam(ConstantType.ParamType.size.toString())) : 10,
0);
HttpServletRequest request = SpringMVCUtil.getRequest();
if (ObjectUtils.isEmpty(request)){
return; //则不需要条件查询
}
Map<String, Object> requestParam = SpringMVCUtil.getRequestParam(ConstantType.ParamType.filter_.toString(), true);
this.queryWrapper = parseWhereSql(requestParam);
}
public ZhwPage(long current, long size, long total) {
this(current, size, total, true);
}
public ZhwPage(long current, long size, boolean isSearchCount) {
this(current, size, 0, isSearchCount);
}
public ZhwPage(long current, long size, long total, boolean isSearchCount) {
if (current > 1) {
this.current = current;
}
this.size = size;
this.total = total;
this.isSearchCount = isSearchCount;
}
public QueryWrapper<T> getQueryWrapper() {
return queryWrapper;
}
public void setQueryWrapper(QueryWrapper<T> queryWrapper) {
this.queryWrapper = queryWrapper;
}
/**
* 是否存在上一页
*
* @return true / false
*/
public boolean hasPrevious() {
return this.current > 1;
}
/**
* 是否存在下一页
*
* @return true / false
*/
public boolean hasNext() {
return this.current < this.getPages();
}
@Override
public List<T> getRecords() {
return this.records;
}
@Override
public ZhwPage<T> setRecords(List<T> records) {
this.records = records;
return this;
}
@Override
public long getTotal() {
return this.total;
}
@Override
public ZhwPage<T> setTotal(long total) {
this.total = total;
return this;
}
@Override
public long getSize() {
return this.size;
}
@Override
public ZhwPage<T> setSize(long size) {
this.size = size;
return this;
}
@Override
public long getCurrent() {
return this.current;
}
@Override
public ZhwPage<T> setCurrent(long current) {
this.current = current;
return this;
}
/**
* 获取当前正序排列的字段集合
* <p>
* 为了兼容,将在不久后废弃
*
* @return 正序排列的字段集合
* @see #getOrders()
* @deprecated 3.2.0
*/
@Override
@Deprecated
public String[] ascs() {
return CollectionUtils.isNotEmpty(orders) ? mapOrderToArray(OrderItem::isAsc) : null;
}
/**
* 查找 order 中正序排序的字段数组
*
* @param filter 过滤器
* @return 返回正序排列的字段数组
*/
private String[] mapOrderToArray(Predicate<OrderItem> filter) {
List<String> columns = new ArrayList<>(orders.size());
orders.forEach(i -> {
if (filter.test(i)) {
columns.add(i.getColumn());
}
});
return columns.toArray(new String[0]);
}
/**
* 移除符合条件的条件
*
* @param filter 条件判断
*/
private void removeOrder(Predicate<OrderItem> filter) {
for (int i = orders.size() - 1; i >= 0; i--) {
if (filter.test(orders.get(i))) {
orders.remove(i);
}
}
}
/**
* 添加新的排序条件,构造条件可以使用工厂:{@link OrderItem#build(String, boolean)}
*
* @param items 条件
* @return 返回分页参数本身
*/
public ZhwPage<T> addOrder(OrderItem... items) {
orders.addAll(Arrays.asList(items));
return this;
}
/**
* 添加新的排序条件,构造条件可以使用工厂:{@link OrderItem#build(String, boolean)}
*
* @param items 条件
* @return 返回分页参数本身
*/
public ZhwPage<T> addOrder(List<OrderItem> items) {
orders.addAll(items);
return this;
}
/**
* 设置需要进行正序排序的字段
* <p>
* Replaced:{@link #addOrder(OrderItem...)}
*
* @param ascs 字段
* @return 返回自身
* @deprecated 3.2.0
*/
@Deprecated
public ZhwPage<T> setAscs(List<String> ascs) {
return CollectionUtils.isNotEmpty(ascs) ? setAsc(ascs.toArray(new String[0])) : this;
}
/**
* 升序
* <p>
* Replaced:{@link #addOrder(OrderItem...)}
*
* @param ascs 多个升序字段
* @deprecated 3.2.0
*/
@Deprecated
public ZhwPage<T> setAsc(String... ascs) {
// 保证原来方法 set 的语意
removeOrder(OrderItem::isAsc);
for (String s : ascs) {
addOrder(OrderItem.asc(s));
}
return this;
}
/**
* 获取需简要倒序排列的字段数组
* <p>
*
* @return 倒序排列的字段数组
* @see #getOrders()
* @deprecated 3.2.0
*/
@Override
@Deprecated
public String[] descs() {
return mapOrderToArray(i -> !i.isAsc());
}
/**
* Replaced:{@link #addOrder(OrderItem...)}
*
* @param descs 需要倒序排列的字段
* @return 自身
* @deprecated 3.2.0
*/
@Deprecated
public ZhwPage<T> setDescs(List<String> descs) {
// 保证原来方法 set 的语意
if (CollectionUtils.isNotEmpty(descs)) {
removeOrder(item -> !item.isAsc());
for (String s : descs) {
addOrder(OrderItem.desc(s));
}
}
return this;
}
/**
* 降序,这方法名不知道是谁起的
* <p>
* Replaced:{@link #addOrder(OrderItem...)}
*
* @param descs 多个降序字段
* @deprecated 3.2.0
*/
@Deprecated
public ZhwPage<T> setDesc(String... descs) {
setDescs(Arrays.asList(descs));
return this;
}
@Override
public List<OrderItem> orders() {
return getOrders();
}
public List<OrderItem> getOrders() {
return orders;
}
public void setOrders(List<OrderItem> orders) {
this.orders = orders;
}
@Override
public boolean optimizeCountSql() {
return optimizeCountSql;
}
@Override
public boolean isSearchCount() {
if (total < 0) {
return false;
}
return isSearchCount;
}
public ZhwPage<T> setSearchCount(boolean isSearchCount) {
this.isSearchCount = isSearchCount;
return this;
}
public ZhwPage<T> setOptimizeCountSql(boolean optimizeCountSql) {
this.optimizeCountSql = optimizeCountSql;
return this;
}
/**
* 组装条件sql 核心代码
* @param requestParam filter_参数集合
* @return
*/
public QueryWrapper<T> parseWhereSql(Map<String, Object> requestParam) {
QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
//因为有where语句所以必须要有 1=1防止空where,导致orderBy失效
queryWrapper.eq("1","1");
//排序方式 true 是ASC ,false是desc
String orderDir = SpringMVCUtil.getRequestParam(ConstantType.ParamType.orderDir.toString());
//排序字段
String orderBy = SpringMVCUtil.getRequestParam(ConstantType.ParamType.orderBy.toString());
if (StringUtils.isNotBlank(orderBy) && StringUtils.isNotBlank(orderDir)){
//驼峰格式字符串转换为下划线格式字符串
orderBy = UnderlineToCamelUtil.camelToUnderline(orderBy);
if (StringUtils.equalsIgnoreCase(orderDir, ConstantType.asc)) {
queryWrapper.orderByAsc(orderBy);
} else {
queryWrapper.orderByDesc(orderBy);
}
}
if (!ObjectUtils.isEmpty(requestParam)) {
Iterator iterator = requestParam.keySet().iterator();
while (iterator.hasNext()) {
//参数名 filter_LIKESTART_列名
String paramName = iterator.next().toString();
if (StringUtils.isBlank(paramName)){
return queryWrapper;
}
//key 列名
String key = paramName.substring(paramName.lastIndexOf("_") + 1);
//type 类型
String type = paramName.substring(7, paramName.lastIndexOf("_"));
if (StringUtils.isBlank(key) || StringUtils.isBlank(type)){
return queryWrapper;
}
//获取ParamType
ConstantType.ParamType paramType = ConstantType.ParamType.getMsgByType(type);
//驼峰格式字符串转换为下划线格式字符串
key = UnderlineToCamelUtil.camelToUnderline(key);
switch (Objects.requireNonNull(paramType)) {
case EQ:
queryWrapper.eq(key, requestParam.get(paramName));
break;
case NE:
queryWrapper.ne(key, requestParam.get(paramName));
break;
case LIKE:
queryWrapper.like(key, requestParam.get(paramName));
break;
case LIKESTART:
queryWrapper.likeLeft(key, requestParam.get(paramName));
break;
case LIKEEND:
queryWrapper.likeRight(key, requestParam.get(paramName));
break;
case NOTLIKE:
queryWrapper.notLike(key, requestParam.get(paramName));
break;
case GT:
queryWrapper.gt(key, requestParam.get(paramName));
break;
case LT:
queryWrapper.lt(key, requestParam.get(paramName));
break;
case LE:
queryWrapper.le(key, requestParam.get(paramName));
break;
case GE:
queryWrapper.ge(key, requestParam.get(paramName));
break;
default:
break;
}
}
}
return queryWrapper;
}
}
5. 可以开始单表操作了
1)controller 实现
@RequestMapping(value = "singlePage", method = RequestMethod.GET)
@ApiOperation(value = "singlePage", httpMethod = "GET", response = ListVo.class,notes = "单表查询")
public WebResponse singlePage() {
ZhwPage<User> userPage = new ZhwPage<User>();
IPage<User> page = userService.singlePage(userPage);
return DataResponse.success(page);
}
2)service 和impl实现
public interface IUserService extends IService<User> {
/**
* 自定义分页 单表查询
* @param userPage
* @return
*/
ZhwPage<User> singlePage(ZhwPage<User> userPage);
}
/**
* <p>
* 服务实现类
* </p>
*
* @author cj
* @since 2021-01-26
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public ZhwPage<User> singlePage(ZhwPage<User> userPage) {
return userMapper.selectPage(userPage,userPage.getQueryWrapper());
}
}
到这就基本可以了
但是还要注意一点,userMapper.xml文件必须要有
3)UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yfh.zhw.mapper.UserMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.yfh.zhw.entity.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="sex" property="sex"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, age, sex
</sql>
</mapper>
4)效果一
因为这个查询出来没有数据,所以mybatis plus 就没有分页了。
4)效果二
这个就算是比较完整的功能就算是实现了。
到此就可以实现效果了,管你前端传什么条件,我自巍然不动,奈我何!!!
转载,请著名原作!请勿抄袭。我花了1天的时间写出来的。