diff --git a/ruoyi-admin/src/test/java/org/dromara/test/MyBatisPlusTest.java b/ruoyi-admin/src/test/java/org/dromara/test/MyBatisPlusTest.java new file mode 100644 index 000000000..2b63a25c6 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/MyBatisPlusTest.java @@ -0,0 +1,54 @@ +package org.dromara.test; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import jakarta.annotation.Resource; +import org.dromara.common.mybatis.wrapper.AutoQueryWrapper; +import org.dromara.demo.domain.TestDemo; +import org.dromara.demo.mapper.TestDemoMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 单元测试案例 + * + * @author Lion Li + */ +@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件 +@DisplayName("条件构造器测试") +public class MyBatisPlusTest { + + @Resource + TestDemoMapper testDemoMapper; + + /** + * 没有TableName注解的类或@TableField(exist = false)的注解不能使用LambdaQueryWrapper + */ + @Test + public void test01() { + try { + testDemoMapper.selectOne(new LambdaQueryWrapper() + .like(TestDemo::getNickName, "狮子") + ); + } catch (Exception e) { + System.out.println("can not find lambda cache for this property [nickName] of entity [org.dromara.demo" + + ".domain.TestDemo]"); + } + } + + + @Test + public void test02() { + AutoQueryWrapper wrapper = new AutoQueryWrapper() + .like(TestDemo::getNickName, "狮子") + .eq(TestDemo::getValue, "")// 自动判空 + .singleResult();// 保证结果只有一个 + + // 如果子查询条件需要参数,可以这样设置,不需要再额外传递一个param + wrapper.setParam(TestDemo::getUserName, "admin"); + + System.out.println(testDemoMapper.queryOne(wrapper)); + + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/wrapper/AutoQueryWrapper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/wrapper/AutoQueryWrapper.java new file mode 100644 index 000000000..352f8cf5c --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/wrapper/AutoQueryWrapper.java @@ -0,0 +1,230 @@ +package org.dromara.common.mybatis.wrapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.LambdaUtils; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * @author qixia + */ +public class AutoQueryWrapper extends QueryWrapper { + + private final Map entity = new HashMap<>(); + + public Object getParam(String key) { + return entity.get(key); + } + + public Object getParam(SFunction key) { + return entity.get(getFieldName(key)); + } + + public void setParam(String key, Object value) { + entity.put(key, value); + } + + public void setParam(SFunction key, Object value) { + entity.put(getFieldName(key), value); + } + + public Boolean isNotEmpty(String key) { + return entity.get(key) != null && entity.get(key) != ""; + } + + public AutoQueryWrapper eq(boolean condition, SFunction column, Object val) { + super.eq(condition, toUnderline(column), val); + return this; + } + + public AutoQueryWrapper eq(SFunction column, Object val) { + super.eq(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper ne(boolean condition, SFunction column, Object val) { + super.ne(condition, toUnderline(column), val); + return this; + } + + public AutoQueryWrapper ne(SFunction column, Object val) { + super.ne(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper gt(SFunction column, Object val) { + super.gt(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper ge(SFunction column, Object val) { + super.ge(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper lt(SFunction column, Object val) { + super.lt(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper le(SFunction column, Object val) { + super.le(isNotEmpty(val), toUnderline(column), val); + return this; + } + + public AutoQueryWrapper like(Boolean condition, SFunction column, Object val) { + if (val instanceof String) { + super.like(condition, toUnderline(column), escapeStr((String) val)); + } else { + super.like(condition, toUnderline(column), val); + } + return this; + } + + public AutoQueryWrapper like(SFunction column, Object val) { + if (val instanceof String) { + super.like(toUnderline(column), escapeStr((String) val)); + } else { + super.like(toUnderline(column), val); + } + return this; + } + + public AutoQueryWrapper between(SFunction column, Object val1, Object val2) { + super.between(isNotEmpty(val1) && isNotEmpty(val1), toUnderline(column), val1, val2); + return this; + } + + public AutoQueryWrapper in(SFunction column, Collection coll) { + super.in(isNotEmpty(coll), toUnderline(column), coll); + return this; + } + + public AutoQueryWrapper inSql(SFunction column, String sql) { + super.inSql(toUnderline(column), sql); + return this; + } + + public AutoQueryWrapper isNotNull(SFunction column) { + super.isNotNull(toUnderline(column)); + return this; + } + + public AutoQueryWrapper isNull(SFunction column) { + super.isNull(toUnderline(column)); + return this; + } + + public AutoQueryWrapper singleResult() { + super.last("limit 1"); + return this; + } + + public AutoQueryWrapper orderByAsc(SFunction column) { + super.orderByAsc(toUnderline(column)); + return this; + } + + public AutoQueryWrapper orderByDesc(SFunction column) { + super.orderByDesc(toUnderline(column)); + return this; + } + + /** + * 获取字段名 + * + * @param column + * @return + */ + private String getFieldName(SFunction column) { + String result = LambdaUtils.extract(column).getImplMethodName().replaceAll("get", ""); + return Character.toLowerCase(result.charAt(0)) + result.substring(1); + } + + /** + * 方法名转下划线命名 + * + * @param str + * @return + */ + private String toUnderline(String str) { + if (str == null || str.isEmpty()) { + return str; + } + StringBuilder result = new StringBuilder(); + for (char c : str.toCharArray()) { + if (Character.isUpperCase(c)) { + result.append('_'); + } + result.append(Character.toLowerCase(c)); + } + return result.toString().replace("get_", ""); + } + + /** + * 方法名转下划线命名 + * + * @param column + * @return + */ + private String toUnderline(SFunction column) { + return toUnderline((LambdaUtils.extract(column).getImplMethodName())); + } + + /** + * 特殊字符转义 + * + * @param str + * @return + */ + private static String escapeStr(String str) { + if (str != null && !str.isEmpty()) { + str = str.replaceAll("\\\\", "\\\\\\\\"); + str = str.replaceAll("_", "\\\\_"); + str = str.replaceAll("%", "\\\\%"); + } + return str; + } + + /** + * 判断是否不为空 + * + * @param obj + * @return + */ + private static boolean isNotEmpty(Object obj) { + return !isEmpty(obj); + } + + /** + * 判断是否为空 + * + * @param obj + * @return + */ + private static boolean isEmpty(Object obj) { + if (null == obj) { + return true; + } + + if (obj instanceof CharSequence) { + return ((CharSequence) obj).length() == 0; + } else if (obj instanceof Map) { + return ((Map) obj).isEmpty(); + } else if (obj instanceof Iterable) { + return !((Iterable) obj).iterator().hasNext(); + } else if (obj instanceof Iterator) { + return !((Iterator) obj).hasNext(); + } else if (obj.getClass().isArray()) { + return 0 == Array.getLength(obj); + } + + return false; + } + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java index d3af0c963..d625e1f7b 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java @@ -65,4 +65,16 @@ public class TestDemo extends TenantEntity { @TableLogic private Long delFlag; + /** + * 用户名 + */ + @TableField(exist = false) + private String userName; + + /** + * 昵称 + */ + @TableField(exist = false) + private String nickName; + } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java index 19b2d52df..f2fbc3240 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java @@ -61,4 +61,5 @@ public interface TestDemoMapper extends BaseMapperPlus { }) int updateById(@Param(Constants.ENTITY) TestDemo entity); + TestDemo queryOne(@Param(Constants.WRAPPER) Wrapper ew); } diff --git a/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml index dbf89a31e..0a2da011d 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml +++ b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml @@ -8,4 +8,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT * FROM test_demo ${ew.customSqlSegment} + +