diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/interceptor/MPJInterceptor.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/interceptor/MPJInterceptor.java index 35ac7e6..a8f4e87 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/interceptor/MPJInterceptor.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/interceptor/MPJInterceptor.java @@ -57,35 +57,34 @@ public class MPJInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { + Object ew = null; Object[] args = invocation.getArgs(); if (args[0] instanceof MappedStatement) { MappedStatement ms = (MappedStatement) args[0]; if (args[1] instanceof Map) { Map map = (Map) args[1]; - Object ew = map.getOrDefault(Constants.WRAPPER, null); + ew = map.getOrDefault(Constants.WRAPPER, null); if (Objects.nonNull(ew) && ew instanceof MPJBaseJoin) { - if (CollectionUtils.isNotEmpty(map)) { - Class rt = null; - if (map.containsKey(Constant.CLAZZ) && map.get(Constant.CLAZZ) != null) { - rt = (Class) map.get(Constant.CLAZZ); - } else { - if (CollectionUtils.isNotEmpty(ms.getResultMaps())) { - Class entity = MPJTableMapperHelper.getEntity(getMapper(ms.getId(), ms.getResource())); - Class type = ms.getResultMaps().get(0).getType(); - if (Objects.nonNull(entity) && Objects.nonNull(type) - && !MPJReflectionKit.isPrimitiveOrWrapper(type) && (entity == type)) { - rt = type; - } + Class rt = null; + if (map.containsKey(Constant.CLAZZ) && map.get(Constant.CLAZZ) != null) { + rt = (Class) map.get(Constant.CLAZZ); + } else { + if (CollectionUtils.isNotEmpty(ms.getResultMaps())) { + Class entity = MPJTableMapperHelper.getEntity(getMapper(ms.getId(), ms.getResource())); + Class type = ms.getResultMaps().get(0).getType(); + if (Objects.nonNull(entity) && Objects.nonNull(type) + && !MPJReflectionKit.isPrimitiveOrWrapper(type) && (entity == type)) { + rt = type; } } - if (Objects.nonNull(rt)) { - args[0] = getMappedStatement(ms, rt, ew, map); - } + } + if (Objects.nonNull(rt)) { + args[0] = getMappedStatement(ms, rt, ew, map); } } } } - return invocation.proceed(); + return fill(ew, invocation.proceed()); } @@ -362,6 +361,24 @@ public class MPJInterceptor implements Interceptor { } } + private Object fill(Object ew, Object proceed) { + if (Objects.isNull(ew) || !(ew instanceof SelectWrapper) || MPJReflectionKit.isPrimitiveOrWrapper(proceed.getClass())) { + return proceed; + } + if (proceed instanceof List) { + List list = (List) proceed; + if (!list.isEmpty()) { + Object o = list.stream().filter(Objects::nonNull).findFirst().orElse(null); + if (o == null || MPJReflectionKit.isPrimitiveOrWrapper(o.getClass())) { + return proceed; + } + } + } + SelectWrapper selectWrapper = (SelectWrapper) ew; + selectWrapper.doFill(proceed); + return proceed; + } + private Class getMapper(String id, String resource) { Class clazz = MS_MAPPER_CACHE.computeIfAbsent(id, key -> { try { diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/FillUtils.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/FillUtils.java new file mode 100644 index 0000000..80811f2 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/FillUtils.java @@ -0,0 +1,162 @@ +package com.github.yulichang.toolkit; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.github.yulichang.toolkit.support.FieldCache; +import com.github.yulichang.toolkit.support.LambdaMeta; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.github.yulichang.wrapper.interfaces.MConsumer; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 填充 + * + * @auther yulichang + * @since 1.5.1 + */ +@SuppressWarnings({"unchecked", "unused"}) +public final class FillUtils { + + public static void fill(Object data, SFunction field, SFunction tagField) { + fill(data, field, tagField, (MConsumer>) null); + } + + public static void fill(Object data, SFunction field, SFunction tagField, MConsumer> consumer) { + LambdaMeta meta = LambdaUtils.getMeta(tagField); + FieldCache fieldCache = MPJReflectionKit.getFieldMap(meta.getInstantiatedClass()).get(meta.getName()); + fill(data, field, getTagClass(fieldCache.getField()), tagField, consumer); + } + + public static void fill(Object data, SFunction field, Class oneClass, SFunction tagField) { + fill(data, field, oneClass, tagField, null); + } + + public static void fill(Object data, SFunction field, Class oneClass, SFunction tagField, MConsumer> consumer) { + TableInfo tableInfo = TableHelper.getAssert(oneClass); + Assert.notNull(tableInfo.getKeyProperty(), "not found key property by class %s", oneClass.getName()); + fill(data, field, new SF(oneClass, tableInfo.getKeyProperty()), tagField, consumer); + } + + public static void fill(Object data, SFunction field, SFunction oneField, SFunction tagField) { + fill(data, field, oneField, tagField, null); + } + + public static void fill(Object data, SFunction field, SFunction oneField, SFunction tagField, MConsumer> consumer) { + doFill(data, field, oneField, tagField, consumer); + } + + private static void doFill(Object data, SFunction field, SFunction oneField, SFunction tagField, MConsumer> consumer) { + if (data == null || field == null || oneField == null || tagField == null) { + return; + } + if (data instanceof IPage) { + doFill(((IPage) data).getRecords(), field, oneField, tagField, consumer); + return; + } + if (data instanceof Collection) { + Collection collection = (Collection) data; + if (collection.isEmpty() || collection.stream().allMatch(Objects::isNull)) { + return; + } + } + + LambdaMeta sourceMeta = LambdaUtils.getMeta(field); + FieldCache sourceCache = MPJReflectionKit.getFieldMap(sourceMeta.getInstantiatedClass()).get(sourceMeta.getName()); + + LambdaMeta tagMeta = LambdaUtils.getMeta(tagField); + FieldCache tagCache = MPJReflectionKit.getFieldMap(tagMeta.getInstantiatedClass()).get(tagMeta.getName()); + + FieldCache oneCache; + if (oneField instanceof SF) { + SF sf = (SF) oneField; + oneCache = MPJReflectionKit.getFieldMap(sf.getClazz()).get(sf.getName()); + } else { + LambdaMeta oneMeta = LambdaUtils.getMeta(oneField); + oneCache = MPJReflectionKit.getFieldMap(oneMeta.getInstantiatedClass()).get(oneMeta.getName()); + } + + Class wrapperClass = (oneField instanceof SF) ? ((SF) oneField).clazz : LambdaUtils.getEntityClass(oneField); + MPJLambdaWrapper wrapper = new MPJLambdaWrapper((Class) wrapperClass) { + + @Override + public MPJLambdaWrapper in(SFunction column, Collection coll) { + if (column instanceof SF) { + SF sf = (SF) column; + TableInfo tableInfo = TableHelper.getAssert(sf.getClazz()); + return super.in(alias + StringPool.DOT + tableInfo.getKeyColumn(), coll); + } + return super.in(column, coll); + } + + @Override + public MPJLambdaWrapper eq(SFunction column, Object val) { + if (column instanceof SF) { + SF sf = (SF) column; + TableInfo tableInfo = TableHelper.getAssert(sf.getClazz()); + return super.eq(alias + StringPool.DOT + tableInfo.getKeyColumn(), val); + } + return super.eq(column, val); + } + }; + + boolean many = Collection.class.isAssignableFrom(tagCache.getType()); + + if (data instanceof Collection) { + List collection = ((Collection) data).stream().filter(Objects::nonNull).collect(Collectors.toList()); + Set sourceSet = collection.stream().map(sourceCache::getFieldValue).collect(Collectors.toSet()); + if (!sourceSet.isEmpty()) { + wrapper.in(oneField, sourceSet); + if (consumer != null) { + consumer.accept(wrapper); + } + List list = wrapper.list(); + Map map; + if (many) + map = list.stream().collect(Collectors.groupingBy(oneCache::getFieldValue)); + else + map = list.stream().collect(Collectors.toMap(oneCache::getFieldValue, i -> i)); + //匹配 + collection.forEach(item -> tagCache.setFieldValue(item, map.get(sourceCache.getFieldValue(item)))); + } + } else { + Object sourceVal = sourceCache.getFieldValue(data); + wrapper.eq(oneField, sourceVal); + if (consumer != null) { + consumer.accept(wrapper); + } + Object x = many ? wrapper.list(tagCache.getType()) : wrapper.one(tagCache.getType()); + if (x != null) { + tagCache.setFieldValue(data, x); + } + } + } + + private static Class getTagClass(Field field) { + if (Collection.class.isAssignableFrom(field.getType())) { + return (Class) MPJReflectionKit.getGenericType(field); + } else { + return (Class) field.getType(); + } + } + + @Getter + @AllArgsConstructor + private static class SF implements SFunction { + private Class clazz; + private String name; + + + @Override + public Object apply(Object o) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LambdaUtils.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LambdaUtils.java index 4b2cffd..ce99ecd 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LambdaUtils.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LambdaUtils.java @@ -28,6 +28,10 @@ public final class LambdaUtils { return (Class) extract(fn).getInstantiatedClass(); } + public static LambdaMeta getMeta(SFunction fn) { + return extract(fn); + } + /** * 该缓存可能会在任意不定的时间被清除 * @@ -35,7 +39,7 @@ public final class LambdaUtils { * @param 类型,被调用的 Function 对象的目标类型 * @return 返回解析后的结果 */ - public static LambdaMeta extract(SFunction func) { + private static LambdaMeta extract(SFunction func) { // 1. IDEA 调试模式下 lambda 表达式是一个代理 if (func instanceof Proxy) { return new IdeaProxyLambdaMeta((Proxy) func); diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/FieldCache.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/FieldCache.java index 53d05d0..ee86453 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/FieldCache.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/FieldCache.java @@ -1,5 +1,6 @@ package com.github.yulichang.toolkit.support; +import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; import lombok.Data; import java.lang.reflect.Field; @@ -16,4 +17,30 @@ public class FieldCache { public Field field; public Class type; + + public boolean isAccessible = false; + + public Object getFieldValue(Object object) { + try { + if (!isAccessible) { + isAccessible = true; + field.setAccessible(true); + } + return field.get(object); + } catch (IllegalAccessException e) { + throw ExceptionUtils.mpe(e); + } + } + + public void setFieldValue(Object source, Object value) { + try { + if (!isAccessible) { + isAccessible = true; + field.setAccessible(true); + } + field.set(source, value); + } catch (IllegalAccessException e) { + throw ExceptionUtils.mpe(e); + } + } } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/LambdaMeta.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/LambdaMeta.java index 80295f7..10f5b2b 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/LambdaMeta.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/support/LambdaMeta.java @@ -15,6 +15,8 @@ */ package com.github.yulichang.toolkit.support; +import org.apache.ibatis.reflection.property.PropertyNamer; + /** * Lambda 信息 *

@@ -22,6 +24,10 @@ package com.github.yulichang.toolkit.support; */ public interface LambdaMeta { + default String getName() { + return PropertyNamer.methodToProperty(getImplMethodName()); + } + /** * 获取 lambda 表达式实现方法的名称 * diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/JoinAbstractLambdaWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/JoinAbstractLambdaWrapper.java index 685b78d..eea063f 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/JoinAbstractLambdaWrapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/JoinAbstractLambdaWrapper.java @@ -253,7 +253,6 @@ public abstract class JoinAbstractLambdaWrapper String columnsToString(Integer index, PrefixEnum prefixEnum, String alias, SFunction... columns) { diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java index 61edee0..23696e3 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; * @author yulichang */ @SuppressWarnings({"unused", "DuplicatedCode"}) -public class MPJLambdaWrapper extends JoinAbstractLambdaWrapper> implements +public class MPJLambdaWrapper extends JoinAbstractLambdaWrapper> implements Fill>, Query>, QueryLabel>, Chain, SelectWrapper> { /** @@ -65,6 +65,8 @@ public class MPJLambdaWrapper extends JoinAbstractLambdaWrapper> wrapperMap; + private List> fill; + /** * 推荐使用 带 class 的构造方法 */ @@ -282,6 +284,21 @@ public class MPJLambdaWrapper extends JoinAbstractLambdaWrapper addFill(MConsumer consumer) { + if (this.fill == null) { + this.fill = new ArrayList<>(); + } + this.fill.add(consumer); + return typedThis; + } + + @Override + public void doFill(Object obj) { + if (this.fill != null) { + this.fill.forEach(c -> c.accept(obj)); + } + } /** * union @@ -397,5 +414,6 @@ public class MPJLambdaWrapper extends JoinAbstractLambdaWrapper { + + Children addFill(MConsumer consumer); + + default Children fill(SFunction field, SFunction tagField) { + return addFill(c -> FillUtils.fill(c, field, tagField)); + } + + default Children fill(SFunction field, SFunction tagField, MConsumer> consumer) { + return addFill(c -> FillUtils.fill(c, field, tagField, (MConsumer>) ((Object) consumer))); + } + + default Children fill(SFunction field, Class oneClass, SFunction tagField) { + return addFill(c -> FillUtils.fill(c, field, oneClass, tagField)); + } + + default Children fill(SFunction field, Class oneClass, SFunction tagField, MConsumer> consumer) { + return addFill(c -> FillUtils.fill(c, field, oneClass, tagField, (MConsumer>) ((Object) consumer))); + } + + default Children fill(SFunction field, SFunction oneField, SFunction tagField) { + return addFill(c -> FillUtils.fill(c, field, oneField, tagField)); + } + + default Children fill(SFunction field, SFunction oneField, SFunction tagField, MConsumer> consumer) { + return addFill(c -> FillUtils.fill(c, field, oneField, tagField, (MConsumer>) ((Object) consumer))); + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MBiPredicate.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MBiPredicate.java index 8f6c228..5e0ad08 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MBiPredicate.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MBiPredicate.java @@ -7,7 +7,7 @@ import java.util.function.BiPredicate; * on function * * @author yulichang - * @since 1.4.14 + * @since 1.5.0 */ @FunctionalInterface public interface MBiPredicate extends BiPredicate, Serializable { diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MConsumer.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MConsumer.java new file mode 100644 index 0000000..bc71d92 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MConsumer.java @@ -0,0 +1,13 @@ +package com.github.yulichang.wrapper.interfaces; + +import java.io.Serializable; +import java.util.function.Consumer; + +/** + * Serializable Consumer + * + * @auther yulichang + * @since 1.5.1 + */ +public interface MConsumer extends Consumer, Serializable { +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MPredicate.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MPredicate.java index 2dd7c19..407baea 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MPredicate.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/MPredicate.java @@ -7,7 +7,7 @@ import java.util.function.Predicate; * on function * * @author yulichang - * @since 1.4.14 + * @since 1.5.0 */ @FunctionalInterface public interface MPredicate extends Predicate, Serializable { diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/SelectWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/SelectWrapper.java index e5ab461..ee2ecf5 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/SelectWrapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/SelectWrapper.java @@ -33,4 +33,7 @@ public interface SelectWrapper { PageInfo getPageInfo(); boolean isPageByMain(); + + default void doFill(Object obj) { + } } diff --git a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/UserDO.java b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/UserDO.java index a95e819..cfdba99 100644 --- a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/UserDO.java +++ b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/UserDO.java @@ -69,6 +69,9 @@ public class UserDO extends ID implements Serializable { @TableField(exist = false) private List addressList; + @TableField(exist = false) + private AddressDO address1; + @TableField(exist = false) private List addressList2; } diff --git a/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/unit/FillTest.java b/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/unit/FillTest.java new file mode 100644 index 0000000..dfdfa98 --- /dev/null +++ b/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/unit/FillTest.java @@ -0,0 +1,54 @@ +package com.github.yulichang.test.join.unit; + +import com.github.yulichang.test.join.entity.UserDO; +import com.github.yulichang.test.util.Reset; +import com.github.yulichang.toolkit.JoinWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +@SuppressWarnings("OptionalGetWithoutIsPresent") +@SpringBootTest +public class FillTest { + + + @BeforeEach + void setUp() { + Reset.reset(); + } + + + @Test + void fill() { + MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class).selectAll(UserDO.class); + + wrapper.fill(UserDO::getAddressId, UserDO::getAddressList); + + List list = wrapper.clone().list(); + list.forEach(System.out::println); + + assert !list.stream().findFirst().get().getAddressList().isEmpty(); + } + + @Test + void fill1() { + MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class).selectAll(UserDO.class) + .eq(UserDO::getId, 1); + + + wrapper.fill(UserDO::getAddressId, UserDO::getAddress1, w -> { + System.out.println(1); +// w.last("limit 1"); + }); + + UserDO list = wrapper.clone().one(); + System.out.println(list); + + assert list.getAddress1() != null; + } + + +}