Mybatis-plus通用查询方法封装的实现
作者:微云村
本文主要介绍了Mybatis-plus通用查询方法封装的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
定义DTO
package com.lbdj.user.service.dto; import com.lbdj.toolkit.utils.ReturnField; import com.lbdj.toolkit.utils.SFunction; import lombok.Data; /** * 用户DTO * * @author 作者 * @since 2023-06-27 */ @Data public class LbdjUserDTO { /** * 主键 */ private Long id; private String userNo; /** * 昵称 */ private String nickName; /** * 密码 */ private String password; /** * 查询条数 */ private Integer limit; /** * 需要返回的列(DTO列名) */ private String columnStr; public <T> void setReturnField(SFunction<T, ?>... columns) { this.columnStr = ReturnField.select(columns); } }
DTO调用方式
工具类1(适用在没有mybatis-plus包的情况下)
package com.lbdj.toolkit.utils; import java.io.Serializable; import java.util.function.Function; @FunctionalInterface public interface SFunction<T, R> extends Function<T, R>, Serializable { }
package com.lbdj.toolkit.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.Serializable; @SuppressWarnings("unused") public class SerializedLambda implements Serializable { private static final long serialVersionUID = 8025925345765570181L; private Class<?> capturingClass; private String functionalInterfaceClass; private String functionalInterfaceMethodName; private String functionalInterfaceMethodSignature; private String implClass; private String implMethodName; private String implMethodSignature; private int implMethodKind; private String instantiatedMethodType; private Object[] capturedArgs; /** * 通过反序列化转换 lambda 表达式,该方法只能序列化 lambda 表达式,不能序列化接口实现或者正常非 lambda 写法的对象 * * @param lambda lambda对象 * @return 返回解析后的 SerializedLambda */ public static SerializedLambda resolve(SFunction<?, ?> lambda) { if (!lambda.getClass().isSynthetic()) { throw new RuntimeException("该方法仅能传入 lambda 表达式产生的合成类"); } try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(serialize(lambda))) { @Override protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException { Class<?> clazz; try { clazz = toClassConfident(objectStreamClass.getName()); } catch (Exception ex) { clazz = super.resolveClass(objectStreamClass); } return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz; } }) { return (SerializedLambda) objIn.readObject(); } catch (ClassNotFoundException | IOException e) { throw new RuntimeException("This is impossible to happen",e); } } /** * 获取接口 class * * @return 返回 class 名称 */ public String getFunctionalInterfaceClassName() { return normalizedName(functionalInterfaceClass); } /** * 获取 class 的名称 * * @return 类名 */ public String getImplClassName() { return normalizedName(implClass); } /** * 获取实现者的方法名称 * * @return 方法名称 */ public String getImplMethodName() { return implMethodName; } /** * 正常化类名称,将类名称中的 / 替换为 . * * @param name 名称 * @return 正常的类名 */ private String normalizedName(String name) { return name.replace('/', '.'); } /** * @return 获取实例化方法的类型 */ public Class<?> getInstantiatedType() { String instantiatedTypeName = normalizedName(instantiatedMethodType.substring(2, instantiatedMethodType.indexOf(';'))); return toClassConfident(instantiatedTypeName); } /** * @return 字符串形式 */ @Override public String toString() { String interfaceName = getFunctionalInterfaceClassName(); String implName = getImplClassName(); return String.format("%s -> %s::%s", interfaceName.substring(interfaceName.lastIndexOf('.') + 1), implName.substring(implName.lastIndexOf('.') + 1), implMethodName); } public static Class<?> toClassConfident(String name) { try { return classForName(name); } catch (ClassNotFoundException e) { try { return Class.forName(name); } catch (ClassNotFoundException ex) { throw new RuntimeException("找不到指定的class!请仅在明确确定会有 class 的时候,调用该方法", e); } } } private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper(); public static Class<?> classForName(String className) throws ClassNotFoundException { return classLoaderWrapper.classForName(className); } public static byte[] serialize(Object object) { if (object == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(object); oos.flush(); } catch (IOException ex) { throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex); } return baos.toByteArray(); } }
package com.lbdj.toolkit.utils; public class ClassLoaderWrapper { ClassLoader defaultClassLoader; ClassLoader systemClassLoader; ClassLoaderWrapper() { try { systemClassLoader = ClassLoader.getSystemClassLoader(); } catch (SecurityException ignored) { // AccessControlException on Google App Engine } } public Class<?> classForName(String name) throws ClassNotFoundException { return classForName(name, getClassLoaders(null)); } Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException { for (ClassLoader cl : classLoader) { if (null != cl) { try { return Class.forName(name, true, cl); } catch (ClassNotFoundException e) { // we'll ignore this until all classloaders fail to locate the class } } } throw new ClassNotFoundException("Cannot find class: " + name); } ClassLoader[] getClassLoaders(ClassLoader classLoader) { return new ClassLoader[]{ classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader(), systemClassLoader}; } }
package com.lbdj.toolkit.utils; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; /** * 通过lambda获取字段名 */ public class ReturnField { /** * SerializedLambda 反序列化缓存 */ private static final Map<String, WeakReference<SerializedLambda>> FUNC_CACHE = new ConcurrentHashMap<>(); @SafeVarargs public final static <T> String select(SFunction<T, ?>... columns) { if(columns == null || columns.length == 0){ return null; } HashSet<String> returnField = new HashSet<>(8); Arrays.stream(columns).forEach(col -> { String fieldName = parseFunction(col); returnField.add(fieldName); }); StringBuffer colStrBuffer = new StringBuffer(); returnField.forEach(m -> { colStrBuffer.append(m).append(","); }); if (colStrBuffer.toString().endsWith(",")) { colStrBuffer.replace(colStrBuffer.toString().length() - 1, colStrBuffer.toString().length(), ""); } String colStr = colStrBuffer.toString(); return colStr; } public static <T> String parseFunction(SFunction<T, ?> function) { SerializedLambda serializedLambda = resolve(function); String fieldName = methodToProperty(serializedLambda.getImplMethodName()); return fieldName; } public static String methodToProperty(String name) { if (name.startsWith("is")) { name = name.substring(2); } else { if (!name.startsWith("get") && !name.startsWith("set")) { throw new RuntimeException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get' or 'set'."); } name = name.substring(3); } if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) { name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); } return name; } public static <T> SerializedLambda resolve(SFunction<T, ?> func) { Class<?> clazz = func.getClass(); String name = clazz.getName(); return Optional.ofNullable(FUNC_CACHE.get(name)) .map(WeakReference::get) .orElseGet(() -> { SerializedLambda lambda = SerializedLambda.resolve(func); FUNC_CACHE.put(name, new WeakReference<>(lambda)); return lambda; }); } }
工具类2(适用在有mybatis-plus包的情况下)
Mapper通用查询方法
@Override public List<LbdjUserDTO> selectBase(LbdjUserDTO request) { LbdjUser user = BeanConvertUtils.convert(request, LbdjUser::new, null); QueryWrapper<LbdjUser> queryWrapper = new QueryWrapper<>(); //封装返回字段&查询条件 InitCommonQueryUtils.initQuery(user, request.getColumnStr(), queryWrapper); queryWrapper.last(" limit " + request.getLimit()); List<LbdjUser> result = list(queryWrapper); if (CollectionUtils.isEmpty(result)) { return Arrays.asList(); } return BeanConvertUtils.convertList(result, LbdjUserDTO::new); }
package com.lbdj.user.service.common.utils; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.lbdj.user.service.common.advice.exception.RRException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; import java.util.List; public class InitCommonQueryUtils { public static <T> void initQuery(T entity, String columnStr, QueryWrapper<T> queryWrapper) { Class<T> type = (Class<T>) entity.getClass(); TableName annotation = type.getAnnotation(TableName.class); if (annotation == null) { throw new RRException("非数据库实体类"); } //返回字段 StringBuilder columns = new StringBuilder(); //查询条件 HashMap<String, Object> paramMap = new HashMap<>(); Field[] declaredFields = type.getDeclaredFields(); List<String> columnArr = null; if (null != columnStr && !"".equals(columnStr)) { columnArr = Arrays.asList(columnStr.split(",")); } /** * 有兼容历史问题,表中字段半驼峰、非驼峰问题 */ for (Field declaredField : declaredFields) { //设置属性可访问 declaredField.setAccessible(true); //属性名 String name = declaredField.getName(); //获取主键 TableId tableId = declaredField.getAnnotation(TableId.class); //获取非主键的 TableField tableField = declaredField.getAnnotation(TableField.class); //拼接返回字段 appendReturnField(name, columnArr, columns, tableId, tableField); //拼接查询条件 appendCondition(entity, paramMap, declaredField, name, tableId, tableField); } //返回字段 if (columns.length() > 0) { queryWrapper.select(columns.toString()); } //查询条件 if (paramMap.size() > 0) { queryWrapper.allEq(paramMap, false); } } private static void appendReturnField(String name, List<String> columnArr, StringBuilder columns, TableId tableId, TableField tableField) { if (null == columnArr) { return; } if (!columnArr.contains(name)) { return; } if (tableId != null) { if (columns.length() > 0) { columns.append(","); } columns.append(tableId.value()); return; } if (tableField != null) { if (columns.length() > 0) { columns.append(","); } if (tableField.exist()) { //是数据表字段,不是数据表字段不处理 columns.append(tableField.value()); } } } private static <T> void appendCondition(T entity, HashMap<String, Object> paramMap, Field declaredField, String name, TableId tableId, TableField tableField) { // 获取属性的值 Object value = null; try { value = declaredField.get(entity); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (null == value) { return; } if (tableId != null) { paramMap.put(tableId.value(), value); return; } if (tableField != null) { if (tableField.exist()) { //是数据表字段,不是数据表字段不处理 paramMap.put(tableField.value(), value); } return; } //处理没有加注解的属性(兼容完全服务驼峰规范的数据表) if (!Modifier.isStatic(declaredField.getModifiers())) { paramMap.put(name, value); } } }
到此这篇关于Mybatis-plus通用查询方法封装的实现的文章就介绍到这了,更多相关Mybatis-plus通用查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!