mirror of
https://gitee.com/best_handsome/mybatis-plus-join
synced 2025-07-11 00:02:22 +08:00
This commit is contained in:
parent
095e4cf20a
commit
8f1ef267c4
@ -3,6 +3,7 @@ package com.github.yulichang.base;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.yulichang.interfaces.MPJBaseJoin;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -11,8 +12,33 @@ import java.util.Map;
|
||||
* @author yulichang
|
||||
* @see ServiceImpl
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MPJBaseServiceImpl<M extends MPJBaseMapper<T>, T> extends ServiceImpl<M, T> implements MPJBaseService<T> {
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
protected Class<T> currentMapperClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
protected Class<T> currentModelClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <DTO> DTO selectJoinOne(Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinOne(clazz, wrapper);
|
||||
|
@ -2,10 +2,20 @@ package com.github.yulichang.injector;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.mapper.Mapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
|
||||
import com.github.yulichang.method.*;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* SQL 注入器
|
||||
@ -15,6 +25,7 @@ import java.util.List;
|
||||
*/
|
||||
@ConditionalOnMissingBean(DefaultSqlInjector.class)
|
||||
public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
private static final Log logger = LogFactory.getLog(MPJSqlInjector.class);
|
||||
|
||||
@Override
|
||||
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
|
||||
@ -27,4 +38,31 @@ public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
list.add(new SelectJoinMapsPage());
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
|
||||
Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);
|
||||
if (modelClass != null) {
|
||||
String className = mapperClass.toString();
|
||||
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
|
||||
if (!mapperRegistryCache.contains(className)) {
|
||||
List<AbstractMethod> methodList = this.getMethodList(mapperClass);
|
||||
if (CollectionUtils.isNotEmpty(methodList)) {
|
||||
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
|
||||
// 循环注入自定义方法
|
||||
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
|
||||
} else {
|
||||
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
|
||||
}
|
||||
mapperRegistryCache.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
196
src/main/java/com/github/yulichang/toolkit/ReflectionKit.java
Normal file
196
src/main/java/com/github/yulichang/toolkit/ReflectionKit.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2021, baomidou (jobob@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.github.yulichang.toolkit;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.*;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
/**
|
||||
* 反射工具类,提供反射相关的快捷操作
|
||||
*
|
||||
* @author Caratacus
|
||||
* @author hcl
|
||||
* @since 2016-09-22
|
||||
*/
|
||||
public final class ReflectionKit {
|
||||
private static final Log logger = LogFactory.getLog(ReflectionKit.class);
|
||||
/**
|
||||
* class field cache
|
||||
*/
|
||||
private static final Map<Class<?>, List<Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP = new IdentityHashMap<>(8);
|
||||
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_TO_WRAPPER_MAP = new IdentityHashMap<>(8);
|
||||
|
||||
static {
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);
|
||||
PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
|
||||
for (Map.Entry<Class<?>, Class<?>> entry : PRIMITIVE_WRAPPER_TYPE_MAP.entrySet()) {
|
||||
PRIMITIVE_TYPE_TO_WRAPPER_MAP.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段值
|
||||
*
|
||||
* @param entity 实体
|
||||
* @param fieldName 字段名称
|
||||
* @return 属性值
|
||||
*/
|
||||
public static Object getFieldValue(Object entity, String fieldName) {
|
||||
Class<?> cls = entity.getClass();
|
||||
Map<String, Field> fieldMaps = getFieldMap(cls);
|
||||
try {
|
||||
Field field = fieldMaps.get(fieldName);
|
||||
Assert.notNull(field, "Error: NoSuchField in %s for %s. Cause:", cls.getSimpleName(), fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(entity);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw ExceptionUtils.mpe("Error: Cannot read field in %s. Cause:", e, cls.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 反射对象获取泛型
|
||||
* </p>
|
||||
*
|
||||
* @param clazz 对象
|
||||
* @param genericIfc 所属泛型父类
|
||||
* @param index 泛型所在位置
|
||||
* @return Class
|
||||
*/
|
||||
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final Class<?> genericIfc, final int index) {
|
||||
Class<?>[] typeArguments = GenericTypeResolver.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
|
||||
return null == typeArguments ? null : typeArguments[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取该类的所有属性列表
|
||||
* </p>
|
||||
*
|
||||
* @param clazz 反射类
|
||||
*/
|
||||
public static Map<String, Field> getFieldMap(Class<?> clazz) {
|
||||
List<Field> fieldList = getFieldList(clazz);
|
||||
return CollectionUtils.isNotEmpty(fieldList) ? fieldList.stream().collect(Collectors.toMap(Field::getName, field -> field)) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取该类的所有属性列表
|
||||
* </p>
|
||||
*
|
||||
* @param clazz 反射类
|
||||
*/
|
||||
public static List<Field> getFieldList(Class<?> clazz) {
|
||||
if (Objects.isNull(clazz)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return CollectionUtils.computeIfAbsent(CLASS_FIELD_CACHE, clazz, k -> {
|
||||
Field[] fields = k.getDeclaredFields();
|
||||
List<Field> superFields = new ArrayList<>();
|
||||
Class<?> currentClass = k.getSuperclass();
|
||||
while (currentClass != null) {
|
||||
Field[] declaredFields = currentClass.getDeclaredFields();
|
||||
Collections.addAll(superFields, declaredFields);
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
/* 排除重载属性 */
|
||||
Map<String, Field> fieldMap = excludeOverrideSuperField(fields, superFields);
|
||||
/*
|
||||
* 重写父类属性过滤后处理忽略部分,支持过滤父类属性功能
|
||||
* 场景:中间表不需要记录创建时间,忽略父类 createTime 公共属性
|
||||
* 中间表实体重写父类属性 ` private transient Date createTime; `
|
||||
*/
|
||||
return fieldMap.values().stream()
|
||||
/* 过滤静态属性 */
|
||||
.filter(f -> !Modifier.isStatic(f.getModifiers()))
|
||||
/* 过滤 transient关键字修饰的属性 */
|
||||
.filter(f -> !Modifier.isTransient(f.getModifiers()))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 排序重置父类属性
|
||||
* </p>
|
||||
*
|
||||
* @param fields 子类属性
|
||||
* @param superFieldList 父类属性
|
||||
*/
|
||||
public static Map<String, Field> excludeOverrideSuperField(Field[] fields, List<Field> superFieldList) {
|
||||
// 子类属性
|
||||
Map<String, Field> fieldMap = Stream.of(fields).collect(toMap(Field::getName, identity(),
|
||||
(u, v) -> {
|
||||
throw new IllegalStateException(String.format("Duplicate key %s", u));
|
||||
},
|
||||
LinkedHashMap::new));
|
||||
superFieldList.stream().filter(field -> !fieldMap.containsKey(field.getName()))
|
||||
.forEach(f -> fieldMap.put(f.getName(), f));
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为基本类型或基本包装类型
|
||||
*
|
||||
* @param clazz class
|
||||
* @return 是否基本类型或基本包装类型
|
||||
*/
|
||||
public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
return (clazz.isPrimitive() || PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz));
|
||||
}
|
||||
|
||||
public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
|
||||
return (clazz.isPrimitive() && clazz != void.class ? PRIMITIVE_TYPE_TO_WRAPPER_MAP.get(clazz) : clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置可访问对象的可访问权限为 true
|
||||
*
|
||||
* @param object 可访问的对象
|
||||
* @param <T> 类型
|
||||
* @return 返回设置后的对象
|
||||
*/
|
||||
public static <T extends AccessibleObject> T setAccessible(T object) {
|
||||
return AccessController.doPrivileged(new SetAccessibleAction<>(object));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user