Mybatis-plus通用查詢方法封裝的實(shí)現(xiàn)
定義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; /** * 查詢條數(shù) */ private Integer limit; /** * 需要返回的列(DTO列名) */ private String columnStr; public <T> void setReturnField(SFunction<T, ?>... columns) { this.columnStr = ReturnField.select(columns); } }
DTO調(diào)用方式
工具類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; /** * 通過反序列化轉(zhuǎn)換 lambda 表達(dá)式,該方法只能序列化 lambda 表達(dá)式,不能序列化接口實(shí)現(xiàn)或者正常非 lambda 寫法的對象 * * @param lambda lambda對象 * @return 返回解析后的 SerializedLambda */ public static SerializedLambda resolve(SFunction<?, ?> lambda) { if (!lambda.getClass().isSynthetic()) { throw new RuntimeException("該方法僅能傳入 lambda 表達(dá)式產(chǎn)生的合成類"); } 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); } /** * 獲取實(shí)現(xiàn)者的方法名稱 * * @return 方法名稱 */ public String getImplMethodName() { return implMethodName; } /** * 正?;惷Q,將類名稱中的 / 替換為 . * * @param name 名稱 * @return 正常的類名 */ private String normalizedName(String name) { return name.replace('/', '.'); } /** * @return 獲取實(shí)例化方法的類型 */ 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 的時(shí)候,調(diào)用該方法", 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("非數(shù)據(jù)庫實(shí)體類"); } //返回字段 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) { //設(shè)置屬性可訪問 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()) { //是數(shù)據(jù)表字段,不是數(shù)據(jù)表字段不處理 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()) { //是數(shù)據(jù)表字段,不是數(shù)據(jù)表字段不處理 paramMap.put(tableField.value(), value); } return; } //處理沒有加注解的屬性(兼容完全服務(wù)駝峰規(guī)范的數(shù)據(jù)表) if (!Modifier.isStatic(declaredField.getModifiers())) { paramMap.put(name, value); } } }
到此這篇關(guān)于Mybatis-plus通用查詢方法封裝的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Mybatis-plus通用查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解讀CommandLineRunner或者ApplicationRunner接口
這篇文章主要介紹了解讀CommandLineRunner或者ApplicationRunner接口的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02SpringBoot的@ControllerAdvice處理全局異常詳解
這篇文章主要介紹了SpringBoot的@ControllerAdvice處理全局異常詳解,但有時(shí)卻往往會產(chǎn)生一些bug,這時(shí)候就破壞了返回?cái)?shù)據(jù)的一致性,導(dǎo)致調(diào)用者無法解析,所以我們常常會定義一個(gè)全局的異常攔截器,需要的朋友可以參考下2024-01-01SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn)
本文主要介紹了SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Java8 Lambda表達(dá)式模板方法實(shí)現(xiàn)解析
這篇文章主要介紹了Java8 Lambda表達(dá)式模板方法實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java訂單30分鐘未支付自動取消該怎么實(shí)現(xiàn)
在開發(fā)中往往會遇到一些關(guān)于延時(shí)任務(wù)的需求,例如生成訂單30分鐘未支付,則自動取消,下面這篇文章主要給大家介紹了關(guān)于Java訂單30分鐘未支付自動取消該怎么實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2023-03-03dubbo?filter中有關(guān)bean注入和配置文件讀取方式
這篇文章主要介紹了dubbo?filter中有關(guān)bean注入和配置文件讀取方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05springboot+dubbo實(shí)現(xiàn)時(shí)間輪算法
時(shí)間輪是一種高效利用線程資源進(jìn)行批量化調(diào)度的算法,本文主要介紹了springboot+dubbo實(shí)現(xiàn)時(shí)間輪算法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04