Ver código fonte

优化Excel文件读取逻辑;优化更新信息自动设值逻辑;

woody 11 meses atrás
pai
commit
b69066af63
22 arquivos alterados com 758 adições e 278 exclusões
  1. 6 0
      framework-common/src/main/java/com/chelvc/framework/common/util/DateUtils.java
  2. 12 2
      framework-common/src/main/java/com/chelvc/framework/common/util/ExcelUtils.java
  3. 53 5
      framework-common/src/main/java/com/chelvc/framework/common/util/ObjectUtils.java
  4. 76 99
      framework-database/src/main/java/com/chelvc/framework/database/context/DatabaseContextHolder.java
  5. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueBooleansTypeHandler.java
  6. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueDoublesTypeHandler.java
  7. 14 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueFilesTypeHandler.java
  8. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueFloatsTypeHandler.java
  9. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueIntegersTypeHandler.java
  10. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueLongsTypeHandler.java
  11. 14 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueModificationsTypeHandler.java
  12. 14 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniquePeriodsTypeHandler.java
  13. 14 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueRegionsTypeHandler.java
  14. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueShortsTypeHandler.java
  15. 12 0
      framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueStringsTypeHandler.java
  16. 2 25
      framework-database/src/main/java/com/chelvc/framework/database/interceptor/DeletedExcludeInterceptor.java
  17. 63 0
      framework-database/src/main/java/com/chelvc/framework/database/interceptor/Expressions.java
  18. 74 50
      framework-database/src/main/java/com/chelvc/framework/database/interceptor/JsonHandlerConfigureInterceptor.java
  19. 330 50
      framework-database/src/main/java/com/chelvc/framework/database/interceptor/PropertyUpdateInterceptor.java
  20. 0 45
      framework-database/src/main/java/com/chelvc/framework/database/support/EnhanceService.java
  21. 1 1
      framework-redis/src/main/java/com/chelvc/framework/redis/config/RedisConfigurer.java
  22. 1 1
      framework-rocketmq/src/main/java/com/chelvc/framework/rocketmq/config/RocketMQConfigurer.java

+ 6 - 0
framework-common/src/main/java/com/chelvc/framework/common/util/DateUtils.java

@@ -34,6 +34,12 @@ public final class DateUtils {
     public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER =
             DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
+    /**
+     * 默认日期时间毫秒格式化处理器
+     */
+    public static final DateTimeFormatter DEFAULT_DATETIME_MILLIS_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
+
     /**
      * 年份数字格式化处理器
      */

+ 12 - 2
framework-common/src/main/java/com/chelvc/framework/common/util/ExcelUtils.java

@@ -163,7 +163,7 @@ public final class ExcelUtils {
         if (value instanceof Date) {
             return DateUtils.format((Date) value);
         } else if (value instanceof Number) {
-            return BigDecimal.valueOf(((Number) value).doubleValue()).toString();
+            return BigDecimal.valueOf(((Number) value).doubleValue()).toPlainString();
         }
         return ObjectUtils.ifNull(value, Object::toString);
     }
@@ -475,10 +475,12 @@ public final class ExcelUtils {
          * 单元格列下标列表(从小到大排序)
          */
         private final TreeSet<Integer> columns = new TreeSet<>();
+
         /**
          * 单元格列下标/单元格映射表
          */
         private final Map<Integer, Cell> cells = new HashMap<>();
+
         /**
          * 行下标(从0开始)
          */
@@ -864,34 +866,42 @@ public final class ExcelUtils {
          * 开始行下标
          */
         private final int index;
+
         /**
          * 值是否为日期
          */
         protected boolean datable;
+
         /**
          * 数据是否关联
          */
         protected boolean related;
+
         /**
          * 文件包
          */
         protected OPCPackage pkg;
+
         /**
          * 共享字符串表
          */
         protected SharedStringsTable shared;
+
         /**
          * 当前行
          */
         private Row row;
+
         /**
          * 迭代数量
          */
         private int count;
+
         /**
          * 当前列下标
          */
         private int column;
+
         /**
          * 当前单元格值
          */
@@ -958,7 +968,7 @@ public final class ExcelUtils {
                 cell.setCellValue(Integer.parseInt(value) > 0);
             } else if (cell.getCellType() == CellType.NUMERIC) {
                 double number = Double.parseDouble(value);
-                if (this.datable) {
+                if (this.datable && !MobileUtils.isMobile(value)) {
                     cell.setCellValue(DateUtil.getJavaDate(number));
                 } else {
                     cell.setCellValue(number);

+ 53 - 5
framework-common/src/main/java/com/chelvc/framework/common/util/ObjectUtils.java

@@ -1047,12 +1047,43 @@ public final class ObjectUtils {
      */
     public static java.lang.reflect.Type lookupSuperclassParameterized(@NonNull Class<?> clazz,
                                                                        @NonNull Class<?> superclass) {
-        java.lang.reflect.Type supered = lookupGenericSuperclass(clazz, superclass);
-        if (supered instanceof ParameterizedType) {
-            java.lang.reflect.Type[] arguments = ((ParameterizedType) supered).getActualTypeArguments();
-            return isEmpty(arguments) ? Object.class : arguments[0];
+        return lookupSuperclassParameterized(clazz, superclass, null);
+    }
+
+    /**
+     * 查找对象父类/接口泛型
+     *
+     * @param clazz       对象类型
+     * @param superclass  父类/接口类型
+     * @param defaultType 默认类型
+     * @return 泛型类型
+     */
+    public static java.lang.reflect.Type lookupSuperclassParameterized(@NonNull Class<?> clazz,
+                                                                       @NonNull Class<?> superclass,
+                                                                       java.lang.reflect.Type defaultType) {
+        java.lang.reflect.Type[] types = lookupSuperclassParameterizes(clazz, superclass);
+        java.lang.reflect.Type type = isEmpty(types) ? null : types[0];
+        return ObjectUtils.ifNull(type, defaultType);
+    }
+
+    /**
+     * 查找对象父类/接口泛型
+     *
+     * @param clazz      对象类型
+     * @param superclass 父类/接口类型
+     * @return 泛型类型数组
+     */
+    public static java.lang.reflect.Type[] lookupSuperclassParameterizes(@NonNull Class<?> clazz,
+                                                                         @NonNull Class<?> superclass) {
+        for (java.lang.reflect.Type type : getGenericSuperclasses(clazz)) {
+            if (Objects.equals(type2class(type), superclass)) {
+                if (type instanceof ParameterizedType) {
+                    return ((ParameterizedType) type).getActualTypeArguments();
+                }
+                return new java.lang.reflect.Type[0];
+            }
         }
-        return Object.class;
+        return new java.lang.reflect.Type[0];
     }
 
     /**
@@ -1340,6 +1371,23 @@ public final class ObjectUtils {
         return Stream.of(object);
     }
 
+    /**
+     * 将对象转换为集合
+     *
+     * @param object 对象实例
+     * @return 对象集合
+     */
+    public static Collection<?> collection(Object object) {
+        if (object instanceof Stream) {
+            return ((Stream<?>) object).collect(Collectors.toList());
+        } else if (object instanceof Object[]) {
+            return Arrays.asList((Object[]) object);
+        } else if (object instanceof Collection) {
+            return (Collection<?>) object;
+        }
+        return Collections.singletonList(object);
+    }
+
     /**
      * 获取字符串长度
      *

+ 76 - 99
framework-database/src/main/java/com/chelvc/framework/database/context/DatabaseContextHolder.java

@@ -28,7 +28,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -109,18 +108,6 @@ public final class DatabaseContextHolder {
      */
     private static SqlSessionTemplate SESSION_TEMPLATE;
 
-    /**
-     * 数据加密密码处理器
-     */
-    private static final ThreadLocal<Cipher> ENCRYPT_CIPHER =
-            ThreadLocal.withInitial(() -> getCipher(Cipher.ENCRYPT_MODE));
-
-    /**
-     * 数据解密密码处理器
-     */
-    private static final ThreadLocal<Cipher> DECRYPT_CIPHER =
-            ThreadLocal.withInitial(() -> getCipher(Cipher.DECRYPT_MODE));
-
     private DatabaseContextHolder() {
     }
 
@@ -258,10 +245,7 @@ public final class DatabaseContextHolder {
      * @param name 表名称
      * @return 表信息
      */
-    public static TableInfo getTable(String name) {
-        if (StringUtils.isEmpty(name)) {
-            return null;
-        }
+    public static TableInfo getTable(@NonNull String name) {
         TableInfo table = TableInfoHelper.getTableInfo(name);
         if (table == null) {
             if (name.charAt(0) == '`' && name.charAt(name.length() - 1) == '`') {
@@ -279,7 +263,7 @@ public final class DatabaseContextHolder {
      * @param type 数据模型类型
      * @return 数据表信息
      */
-    public static TableInfo getTable(Class<?> type) {
+    public static TableInfo getTable(@NonNull Class<?> type) {
         return getTable(type, true);
     }
 
@@ -432,16 +416,6 @@ public final class DatabaseContextHolder {
         });
     }
 
-    /**
-     * 是否开启数据加解密功能
-     *
-     * @return true/false
-     */
-    public static boolean isCodecEnabled() {
-        DatabaseProperties.Codec codec = getProperties().getCodec();
-        return StringUtils.notEmpty(codec.getSecret()) && StringUtils.notEmpty(codec.getIv());
-    }
-
     /**
      * 判断对象是否是需要加解密的
      *
@@ -459,45 +433,12 @@ public final class DatabaseContextHolder {
      * @return 密码处理器
      */
     public static Cipher getCipher(int mode) {
-        if (!isCodecEnabled()) {
-            return null;
-        }
         DatabaseProperties.Codec codec = getProperties().getCodec();
+        AssertUtils.nonempty(codec.getSecret(), () -> "Codec secret is missing");
+        AssertUtils.nonempty(codec.getIv(), () -> "Codec iv is missing");
         return AESUtils.getCipher(mode, codec.getSecret(), codec.getIv());
     }
 
-    /**
-     * 获取数据编密码处理器
-     *
-     * @param consumer 密码处理器接收函数
-     */
-    public static void encoder(@NonNull Consumer<Cipher> consumer) {
-        Cipher cipher = ENCRYPT_CIPHER.get();
-        try {
-            if (Objects.nonNull(cipher)) {
-                consumer.accept(cipher);
-            }
-        } finally {
-            ENCRYPT_CIPHER.remove();
-        }
-    }
-
-    /**
-     * 获取数据解码密码处理器
-     *
-     * @param consumer 密码处理器接收函数
-     */
-    public static void decoder(@NonNull Consumer<Cipher> consumer) {
-        Cipher cipher = DECRYPT_CIPHER.get();
-        try {
-            if (Objects.nonNull(cipher)) {
-                consumer.accept(cipher);
-            }
-        } finally {
-            DECRYPT_CIPHER.remove();
-        }
-    }
-
     /**
      * 编码数据
      *
@@ -505,11 +446,7 @@ public final class DatabaseContextHolder {
      * @return 数据密文
      */
     public static String encode(String plaintext) {
-        if (plaintext == null) {
-            return null;
-        }
-        Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
-        return cipher == null ? plaintext : AESUtils.encode(cipher, plaintext);
+        return plaintext == null ? null : AESUtils.encode(getCipher(Cipher.ENCRYPT_MODE), plaintext);
     }
 
     /**
@@ -518,25 +455,47 @@ public final class DatabaseContextHolder {
      * @param entity 数据实体
      */
     public static void encode(@NonNull Object entity) {
-        if (isCodecEnabled() && isConfidential(entity.getClass())) {
-            encoder(cipher -> encode(cipher, entity));
+        List<Field> fields = getConfidentialFields(entity.getClass());
+        if (ObjectUtils.notEmpty(fields)) {
+            Cipher cipher = null;
+            for (Field field : fields) {
+                String plaintext = (String) ObjectUtils.getValue(entity, field);
+                if (plaintext != null) {
+                    if (cipher == null) {
+                        cipher = getCipher(Cipher.ENCRYPT_MODE);
+                    }
+                    String ciphertext = AESUtils.encode(cipher, plaintext);
+                    ObjectUtils.setValue(entity, field, ciphertext);
+                }
+            }
         }
     }
 
     /**
-     * 编码敏感数据属性
+     * 批量编码敏感数据属性
      *
-     * @param cipher 密码处理器
-     * @param entity 数据实体
+     * @param entities 数据实体集合
      */
-    public static void encode(@NonNull Cipher cipher, @NonNull Object entity) {
-        List<Field> fields = getConfidentialFields(entity.getClass());
-        if (ObjectUtils.notEmpty(fields)) {
-            fields.forEach(field -> {
-                String plaintext = (String) ObjectUtils.getValue(entity, field);
-                String ciphertext = AESUtils.encode(cipher, plaintext);
-                ObjectUtils.setValue(entity, field, ciphertext);
-            });
+    public static void encode(@NonNull Collection<?> entities) {
+        if (ObjectUtils.isEmpty(entities)) {
+            return;
+        }
+
+        Cipher cipher = null;
+        for (Object entity : entities) {
+            List<Field> fields = getConfidentialFields(entity.getClass());
+            if (ObjectUtils.notEmpty(fields)) {
+                for (Field field : fields) {
+                    String plaintext = (String) ObjectUtils.getValue(entity, field);
+                    if (plaintext != null) {
+                        if (cipher == null) {
+                            cipher = getCipher(Cipher.ENCRYPT_MODE);
+                        }
+                        String ciphertext = AESUtils.encode(cipher, plaintext);
+                        ObjectUtils.setValue(entity, field, ciphertext);
+                    }
+                }
+            }
         }
     }
 
@@ -547,11 +506,7 @@ public final class DatabaseContextHolder {
      * @return 数据明文
      */
     public static String decode(String ciphertext) {
-        if (ciphertext == null) {
-            return null;
-        }
-        Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
-        return cipher == null ? ciphertext : AESUtils.decode(cipher, ciphertext);
+        return ciphertext == null ? null : AESUtils.decode(getCipher(Cipher.DECRYPT_MODE), ciphertext);
     }
 
     /**
@@ -560,25 +515,47 @@ public final class DatabaseContextHolder {
      * @param entity 数据实体
      */
     public static void decode(@NonNull Object entity) {
-        if (isCodecEnabled() && isConfidential(entity.getClass())) {
-            decoder(cipher -> decode(cipher, entity));
+        List<Field> fields = getConfidentialFields(entity.getClass());
+        if (ObjectUtils.notEmpty(fields)) {
+            Cipher cipher = null;
+            for (Field field : fields) {
+                String ciphertext = (String) ObjectUtils.getValue(entity, field);
+                if (ciphertext != null) {
+                    if (cipher == null) {
+                        cipher = getCipher(Cipher.DECRYPT_MODE);
+                    }
+                    String plaintext = AESUtils.decode(cipher, ciphertext);
+                    ObjectUtils.setValue(entity, field, plaintext);
+                }
+            }
         }
     }
 
     /**
-     * 解码敏感数据属性
+     * 批量解码敏感数据属性
      *
-     * @param cipher 密码处理器
-     * @param entity 数据实体
+     * @param entities 数据实体集合
      */
-    public static void decode(@NonNull Cipher cipher, @NonNull Object entity) {
-        List<Field> fields = getConfidentialFields(entity.getClass());
-        if (ObjectUtils.notEmpty(fields)) {
-            fields.forEach(field -> {
-                String ciphertext = (String) ObjectUtils.getValue(entity, field);
-                String plaintext = AESUtils.decode(cipher, ciphertext);
-                ObjectUtils.setValue(entity, field, plaintext);
-            });
+    public static void decode(@NonNull Collection<?> entities) {
+        if (ObjectUtils.isEmpty(entities)) {
+            return;
+        }
+
+        Cipher cipher = null;
+        for (Object entity : entities) {
+            List<Field> fields = getConfidentialFields(entity.getClass());
+            if (ObjectUtils.notEmpty(fields)) {
+                for (Field field : fields) {
+                    String ciphertext = (String) ObjectUtils.getValue(entity, field);
+                    if (ciphertext != null) {
+                        if (cipher == null) {
+                            cipher = getCipher(Cipher.DECRYPT_MODE);
+                        }
+                        String plaintext = AESUtils.decode(cipher, ciphertext);
+                        ObjectUtils.setValue(entity, field, plaintext);
+                    }
+                }
+            }
         }
     }
 

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueBooleansTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的真假值列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueBooleansTypeHandler extends JsonTypeHandler.Default<Set<Boolean>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueDoublesTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的双精度浮点数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueDoublesTypeHandler extends JsonTypeHandler.Default<Set<Double>> {
+}

+ 14 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueFilesTypeHandler.java

@@ -0,0 +1,14 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+import com.chelvc.framework.common.model.File;
+
+/**
+ * 唯一的文件信息列表字段类型处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueFilesTypeHandler extends JsonTypeHandler.Default<Set<File>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueFloatsTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的单精度浮点数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueFloatsTypeHandler extends JsonTypeHandler.Default<Set<Float>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueIntegersTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的整数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueIntegersTypeHandler extends JsonTypeHandler.Default<Set<Integer>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueLongsTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的长整数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueLongsTypeHandler extends JsonTypeHandler.Default<Set<Long>> {
+}

+ 14 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueModificationsTypeHandler.java

@@ -0,0 +1,14 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+import com.chelvc.framework.common.model.Modification;
+
+/**
+ * 唯一的对象更新信息列表字段类型处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueModificationsTypeHandler extends JsonTypeHandler.Default<Set<Modification>> {
+}

+ 14 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniquePeriodsTypeHandler.java

@@ -0,0 +1,14 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+import com.chelvc.framework.common.model.Period;
+
+/**
+ * 唯一的时间周期列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniquePeriodsTypeHandler extends JsonTypeHandler.Default<Set<Period>> {
+}

+ 14 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueRegionsTypeHandler.java

@@ -0,0 +1,14 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+import com.chelvc.framework.common.model.Region;
+
+/**
+ * 唯一的地区字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueRegionsTypeHandler extends JsonTypeHandler.Default<Set<Region>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueShortsTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的短整数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueShortsTypeHandler extends JsonTypeHandler.Default<Set<Short>> {
+}

+ 12 - 0
framework-database/src/main/java/com/chelvc/framework/database/handler/UniqueStringsTypeHandler.java

@@ -0,0 +1,12 @@
+package com.chelvc.framework.database.handler;
+
+import java.util.Set;
+
+/**
+ * 唯一的长整数列表字段处理实现
+ *
+ * @author Woody
+ * @date 2024/4/3
+ */
+public class UniqueStringsTypeHandler extends JsonTypeHandler.Default<Set<String>> {
+}

+ 2 - 25
framework-database/src/main/java/com/chelvc/framework/database/interceptor/DeletedExcludeInterceptor.java

@@ -1,13 +1,10 @@
 package com.chelvc.framework.database.interceptor;
 
-import java.math.BigInteger;
-
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
 import com.chelvc.framework.database.context.DatabaseContextHolder;
 import com.chelvc.framework.database.entity.Deletable;
 import net.sf.jsqlparser.expression.Expression;
-import net.sf.jsqlparser.expression.LongValue;
 
 /**
  * 借助租户隔离功能实现删除数据排除拦截,数据查询自动过滤已删除数据
@@ -16,34 +13,14 @@ import net.sf.jsqlparser.expression.LongValue;
  * @date 2024/1/30
  */
 public class DeletedExcludeInterceptor implements TenantLineHandler {
-    /**
-     * 删除标记字段名称
-     */
-    public static final String COLUMN = "deleted";
-
-    /**
-     * 未删除值对象
-     */
-    private static final LongValue VALUE = new LongValue(0) {
-        @Override
-        public long getValue() {
-            return 0;
-        }
-
-        @Override
-        public BigInteger getBigIntegerValue() {
-            return BigInteger.ZERO;
-        }
-    };
-
     @Override
     public Expression getTenantId() {
-        return VALUE;
+        return Expressions.ZERO_VALUE;
     }
 
     @Override
     public String getTenantIdColumn() {
-        return COLUMN;
+        return Expressions.DELETED_COLUMN.getColumnName();
     }
 
     @Override

+ 63 - 0
framework-database/src/main/java/com/chelvc/framework/database/interceptor/Expressions.java

@@ -0,0 +1,63 @@
+package com.chelvc.framework.database.interceptor;
+
+import java.math.BigInteger;
+
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.NullValue;
+import net.sf.jsqlparser.schema.Column;
+
+/**
+ * SQL表达式工具类
+ *
+ * @author Woody
+ * @date 2024/5/16
+ */
+final class Expressions {
+    private Expressions() {
+    }
+
+    /**
+     * 空值
+     */
+    public static final NullValue NULL_VALUE = new NullValue();
+
+    /**
+     * 零值
+     */
+    public static final LongValue ZERO_VALUE = new LongValue(0) {
+        @Override
+        public long getValue() {
+            return 0;
+        }
+
+        @Override
+        public BigInteger getBigIntegerValue() {
+            return BigInteger.ZERO;
+        }
+    };
+
+    /**
+     * 创建人字段
+     */
+    public static final Column CREATOR_COLUMN = new Column("creator");
+
+    /**
+     * 创建时间字段
+     */
+    public static final Column CREATE_TIME_COLUMN = new Column("create_time");
+
+    /**
+     * 更新人字段
+     */
+    public static final Column UPDATER_COLUMN = new Column("updater");
+
+    /**
+     * 更新时间字段
+     */
+    public static final Column UPDATE_TIME_COLUMN = new Column("update_time");
+
+    /**
+     * 逻辑删除字段
+     */
+    public static final Column DELETED_COLUMN = new Column("deleted");
+}

+ 74 - 50
framework-database/src/main/java/com/chelvc/framework/database/interceptor/JsonHandlerConfigureInterceptor.java

@@ -6,7 +6,7 @@ import java.lang.reflect.Type;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.Set;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -38,6 +38,17 @@ import com.chelvc.framework.database.handler.SetTypeHandler;
 import com.chelvc.framework.database.handler.SetsTypeHandler;
 import com.chelvc.framework.database.handler.ShortsTypeHandler;
 import com.chelvc.framework.database.handler.StringsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueBooleansTypeHandler;
+import com.chelvc.framework.database.handler.UniqueDoublesTypeHandler;
+import com.chelvc.framework.database.handler.UniqueFilesTypeHandler;
+import com.chelvc.framework.database.handler.UniqueFloatsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueIntegersTypeHandler;
+import com.chelvc.framework.database.handler.UniqueLongsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueModificationsTypeHandler;
+import com.chelvc.framework.database.handler.UniquePeriodsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueRegionsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueShortsTypeHandler;
+import com.chelvc.framework.database.handler.UniqueStringsTypeHandler;
 import com.google.common.collect.Maps;
 import javassist.ClassPool;
 import javassist.CtClass;
@@ -57,16 +68,6 @@ import org.w3c.dom.Element;
  */
 @Slf4j
 public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor {
-    /**
-     * JSON类型处理器计数器
-     */
-    private final AtomicLong counter = new AtomicLong(0);
-
-    /**
-     * JSON类型/处理器映射表
-     */
-    private final Map<Type, Class<?>> handlers = Maps.newConcurrentMap();
-
     /**
      * 内置的别名/对象类型映射表
      */
@@ -109,48 +110,72 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
             return SetTypeHandler.class;
         } else if (ObjectUtils.isOnlyList(type)) {
             return ListTypeHandler.class;
-        } else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == List.class) {
+        } else if (type instanceof ParameterizedType) {
+            Type raw = ((ParameterizedType) type).getRawType();
             Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
-            if (arg == int.class || arg == Integer.class) {
-                return IntegersTypeHandler.class;
-            } else if (arg == short.class || arg == Short.class) {
-                return ShortsTypeHandler.class;
-            } else if (arg == long.class || arg == Long.class) {
-                return LongsTypeHandler.class;
-            } else if (arg == float.class || arg == Float.class) {
-                return FloatsTypeHandler.class;
-            } else if (arg == double.class || arg == Double.class) {
-                return DoublesTypeHandler.class;
-            } else if (arg == boolean.class || arg == Boolean.class) {
-                return BooleansTypeHandler.class;
-            } else if (arg == String.class) {
-                return StringsTypeHandler.class;
-            } else if (arg == File.class) {
-                return FilesTypeHandler.class;
-            } else if (arg == Period.class) {
-                return PeriodsTypeHandler.class;
-            } else if (arg == Region.class) {
-                return RegionsTypeHandler.class;
-            } else if (arg == Modification.class) {
-                return ModificationsTypeHandler.class;
-            } else if (ObjectUtils.isOnlyMap(arg)) {
-                return MapsTypeHandler.class;
-            } else if (ObjectUtils.isOnlySet(arg)) {
-                return SetsTypeHandler.class;
-            } else if (ObjectUtils.isOnlyList(arg)) {
-                return ListsTypeHandler.class;
+            if (raw == Set.class) {
+                if (arg == int.class || arg == Integer.class) {
+                    return UniqueIntegersTypeHandler.class;
+                } else if (arg == short.class || arg == Short.class) {
+                    return UniqueShortsTypeHandler.class;
+                } else if (arg == long.class || arg == Long.class) {
+                    return UniqueLongsTypeHandler.class;
+                } else if (arg == float.class || arg == Float.class) {
+                    return UniqueFloatsTypeHandler.class;
+                } else if (arg == double.class || arg == Double.class) {
+                    return UniqueDoublesTypeHandler.class;
+                } else if (arg == boolean.class || arg == Boolean.class) {
+                    return UniqueBooleansTypeHandler.class;
+                } else if (arg == String.class) {
+                    return UniqueStringsTypeHandler.class;
+                } else if (arg == File.class) {
+                    return UniqueFilesTypeHandler.class;
+                } else if (arg == Period.class) {
+                    return UniquePeriodsTypeHandler.class;
+                } else if (arg == Region.class) {
+                    return UniqueRegionsTypeHandler.class;
+                } else if (arg == Modification.class) {
+                    return UniqueModificationsTypeHandler.class;
+                }
+            } else if (raw == List.class) {
+                if (arg == int.class || arg == Integer.class) {
+                    return IntegersTypeHandler.class;
+                } else if (arg == short.class || arg == Short.class) {
+                    return ShortsTypeHandler.class;
+                } else if (arg == long.class || arg == Long.class) {
+                    return LongsTypeHandler.class;
+                } else if (arg == float.class || arg == Float.class) {
+                    return FloatsTypeHandler.class;
+                } else if (arg == double.class || arg == Double.class) {
+                    return DoublesTypeHandler.class;
+                } else if (arg == boolean.class || arg == Boolean.class) {
+                    return BooleansTypeHandler.class;
+                } else if (arg == String.class) {
+                    return StringsTypeHandler.class;
+                } else if (arg == File.class) {
+                    return FilesTypeHandler.class;
+                } else if (arg == Period.class) {
+                    return PeriodsTypeHandler.class;
+                } else if (arg == Region.class) {
+                    return RegionsTypeHandler.class;
+                } else if (arg == Modification.class) {
+                    return ModificationsTypeHandler.class;
+                } else if (ObjectUtils.isOnlyMap(arg)) {
+                    return MapsTypeHandler.class;
+                } else if (ObjectUtils.isOnlySet(arg)) {
+                    return SetsTypeHandler.class;
+                } else if (ObjectUtils.isOnlyList(arg)) {
+                    return ListsTypeHandler.class;
+                }
             }
         }
-        return this.handlers.computeIfAbsent(type, t -> {
-            try {
-                return this.initializeJsonHandlerClass(field);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        });
+        try {
+            return this.initializeJsonHandlerClass(field);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
 
-
     /**
      * 初始化JSON类型处理器对象
      *
@@ -161,8 +186,7 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
     private Class<?> initializeJsonHandlerClass(Field field) throws Exception {
         ClassPool pool = ClassPool.getDefault();
         CtClass handler = pool.makeClass(String.format(
-                "%s.JsonTypeHandler_%d",
-                field.getDeclaringClass().getPackage().getName(), this.counter.incrementAndGet()
+                "%s.JsonTypeHandler_%s", field.getDeclaringClass().getPackage().getName(), StringUtils.uuid()
         ));
         handler.setSuperclass(pool.get(JsonTypeHandler.Simple.class.getName()));
         CtConstructor constructor = new CtConstructor(new CtClass[]{}, handler);

+ 330 - 50
framework-database/src/main/java/com/chelvc/framework/database/interceptor/PropertyUpdateInterceptor.java

@@ -1,5 +1,7 @@
 package com.chelvc.framework.database.interceptor;
 
+import java.sql.Connection;
+import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -9,9 +11,13 @@ import java.util.Objects;
 import java.util.stream.Collectors;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.common.exception.ParameterInvalidException;
+import com.chelvc.framework.common.util.DateUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
+import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.database.context.DatabaseContextHolder;
 import com.chelvc.framework.database.context.UniqueContext;
 import com.chelvc.framework.database.entity.Creatable;
@@ -19,9 +25,25 @@ import com.chelvc.framework.database.entity.Deletable;
 import com.chelvc.framework.database.entity.Entity;
 import com.chelvc.framework.database.entity.Updatable;
 import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.expression.Alias;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.StringValue;
+import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
+import net.sf.jsqlparser.expression.operators.relational.ItemsList;
+import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.schema.Column;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.Statements;
+import net.sf.jsqlparser.statement.insert.Insert;
+import net.sf.jsqlparser.statement.update.Update;
 import org.apache.ibatis.binding.MapperMethod;
 import org.apache.ibatis.cache.CacheKey;
 import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.SqlCommandType;
@@ -30,6 +52,7 @@ import org.apache.ibatis.plugin.Intercepts;
 import org.apache.ibatis.plugin.Invocation;
 import org.apache.ibatis.plugin.Plugin;
 import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.RowBounds;
 import org.springframework.stereotype.Component;
@@ -44,6 +67,7 @@ import org.springframework.stereotype.Component;
 @Component
 @Intercepts({
         @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
+        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
         @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
                 RowBounds.class, ResultHandler.class}),
         @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
@@ -51,66 +75,258 @@ import org.springframework.stereotype.Component;
 })
 public class PropertyUpdateInterceptor implements Interceptor {
     /**
-     * 初始化实体默认属性值
+     * 构建操作人字段值表达式
      *
-     * @param entity 数据实体
+     * @return 表达式实例
      */
-    private void initializeDefaultValue(Entity<?> entity) {
-        Date now = new Date();
+    private Expression operator() {
         Long operator = SessionContextHolder.getId();
-        if (entity instanceof Creatable) {
-            Creatable<?> creatable = (Creatable<?>) entity;
-            if (creatable.getCreator() == null) {
-                creatable.setCreator(operator);
+        return operator == null ? Expressions.NULL_VALUE : new LongValue(operator);
+    }
+
+    /**
+     * 构建操作时间字段值表达式
+     *
+     * @return 表达式实例
+     */
+    private Expression datetime() {
+        return new StringValue(DateUtils.DEFAULT_DATETIME_MILLIS_FORMATTER.format(LocalDateTime.now()));
+    }
+
+    /**
+     * 判断是否包含指定列
+     *
+     * @param columns 列对象实例列表
+     * @param column  列对象实例
+     * @return true/false
+     */
+    private boolean isContains(List<Column> columns, Column column) {
+        if (ObjectUtils.notEmpty(columns)) {
+            for (Column c : columns) {
+                if (Objects.equals(c.getColumnName(), column.getColumnName())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断是否包含指定列
+     *
+     * @param table   表对象实例
+     * @param columns 列对象实例列表
+     * @param column  列对象实例
+     * @return true/false
+     */
+    private boolean isContains(Table table, List<Column> columns, Column column) {
+        if (ObjectUtils.notEmpty(columns)) {
+            for (Column c : columns) {
+                String alias = ObjectUtils.ifNull(table.getAlias(), Alias::getName, table::getName);
+                if (Objects.equals(alias, ObjectUtils.ifNull(c.getTable(), Table::getName))
+                        && Objects.equals(c.getColumnName(), column.getColumnName())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 初始化创建信息默认值
+     *
+     * @param creatable 创建信息
+     */
+    private void initializeCreatableValue(Creatable<?> creatable) {
+        creatable.setCreator(SessionContextHolder.getId());
+        creatable.setCreateTime(new Date());
+    }
+
+    /**
+     * 初始化创建信息
+     *
+     * @param type   对象类型
+     * @param insert 数据插入对象实例
+     * @return true/false
+     */
+    private boolean initializeCreatableValue(Class<?> type, Insert insert) {
+        if (!Creatable.class.isAssignableFrom(type)) {
+            return false;
+        }
+
+        // 设置创建人字段值
+        boolean containCreator = this.isContains(insert.getColumns(), Expressions.CREATOR_COLUMN);
+        if (!containCreator) {
+            insert.addColumns(Expressions.CREATOR_COLUMN);
+            Expression operator = this.operator();
+            ItemsList items = insert.getItemsList();
+            if (items instanceof MultiExpressionList) {
+                ((MultiExpressionList) items).getExpressionLists().forEach(el -> el.getExpressions().add(operator));
+            } else {
+                ((ExpressionList) items).getExpressions().add(operator);
+            }
+        }
+
+        // 设置创建时间字段值
+        boolean containCreateTime = this.isContains(insert.getColumns(), Expressions.CREATE_TIME_COLUMN);
+        if (!containCreateTime) {
+            insert.addColumns(Expressions.CREATE_TIME_COLUMN);
+            Expression datetime = this.datetime();
+            ItemsList items = insert.getItemsList();
+            if (items instanceof MultiExpressionList) {
+                ((MultiExpressionList) items).getExpressionLists().forEach(el -> el.getExpressions().add(datetime));
+            } else {
+                ((ExpressionList) items).getExpressions().add(datetime);
+            }
+        }
+        return !(containCreator && containCreateTime);
+    }
+
+    /**
+     * 初始化修改信息默认值
+     *
+     * @param updatable 修改信息
+     */
+    private void initializeUpdatableValue(Updatable<?> updatable) {
+        updatable.setUpdater(SessionContextHolder.getId());
+        updatable.setUpdateTime(new Date());
+    }
+
+    /**
+     * 初始化修改信息
+     *
+     * @param type   对象类型
+     * @param insert 数据插入对象实例
+     * @return true/false
+     */
+    private boolean initializeUpdatableValue(Class<?> type, Insert insert) {
+        if (!Updatable.class.isAssignableFrom(type)) {
+            return false;
+        }
+
+        // 设置更新人字段值
+        boolean containUpdater = this.isContains(insert.getColumns(), Expressions.UPDATER_COLUMN);
+        if (!containUpdater) {
+            insert.addColumns(Expressions.UPDATER_COLUMN);
+            Expression operator = this.operator();
+            ItemsList items = insert.getItemsList();
+            if (items instanceof MultiExpressionList) {
+                ((MultiExpressionList) items).getExpressionLists().forEach(el -> el.getExpressions().add(operator));
+            } else {
+                ((ExpressionList) items).getExpressions().add(operator);
             }
-            if (creatable.getCreateTime() == null) {
-                creatable.setCreateTime(now);
+        }
+
+        // 设置更新时间字段值
+        boolean containUpdateTime = this.isContains(insert.getColumns(), Expressions.UPDATE_TIME_COLUMN);
+        if (!containUpdateTime) {
+            insert.addColumns(Expressions.UPDATE_TIME_COLUMN);
+            Expression datetime = this.datetime();
+            ItemsList items = insert.getItemsList();
+            if (items instanceof MultiExpressionList) {
+                ((MultiExpressionList) items).getExpressionLists().forEach(el -> el.getExpressions().add(datetime));
+            } else {
+                ((ExpressionList) items).getExpressions().add(datetime);
             }
         }
-        if (entity instanceof Updatable) {
-            Updatable<?> updatable = (Updatable<?>) entity;
-            updatable.setUpdater(operator);
-            updatable.setUpdateTime(now);
+        return !(containUpdater && containUpdateTime);
+    }
+
+    /**
+     * 初始化修改信息
+     *
+     * @param type   对象类型
+     * @param update 数据修改对象实例
+     * @return true/false
+     */
+    private boolean initializeUpdatableValue(Class<?> type, Update update) {
+        if (!Updatable.class.isAssignableFrom(type)) {
+            return false;
+        }
+
+        // 设置更新人字段值
+        Table table = update.getTable();
+        boolean containUpdater = this.isContains(table, update.getColumns(), Expressions.UPDATER_COLUMN);
+        if (!containUpdater) {
+            if (StringUtils.isEmpty(table.getAlias())) {
+                update.addColumns(Expressions.UPDATER_COLUMN);
+            } else {
+                update.addColumns(new Column(table, Expressions.UPDATER_COLUMN.getColumnName()));
+            }
+            update.addExpressions(this.operator());
         }
-        if (entity instanceof Deletable) {
-            Deletable<?> deletable = (Deletable<?>) entity;
-            if (deletable.getDeleted() == null) {
-                deletable.setDeleted(false);
+
+        // 设置更新时间字段值
+        boolean containUpdateTime = this.isContains(table, update.getColumns(), Expressions.UPDATE_TIME_COLUMN);
+        if (!containUpdateTime) {
+            if (StringUtils.isEmpty(table.getAlias())) {
+                update.addColumns(Expressions.UPDATE_TIME_COLUMN);
+            } else {
+                update.addColumns(new Column(table, Expressions.UPDATE_TIME_COLUMN.getColumnName()));
             }
+            update.addExpressions(this.datetime());
+        }
+        return !(containUpdater && containUpdateTime);
+    }
+
+    /**
+     * 初始化删除信息默认值
+     *
+     * @param deletable 删除信息
+     */
+    private void initializeDeletableValue(Deletable<?> deletable) {
+        deletable.setDeleted(false);
+    }
+
+    /**
+     * 初始化删除信息
+     *
+     * @param type   对象类型
+     * @param insert 数据插入对象实例
+     * @return true/false
+     */
+    private boolean initializeDeletableValue(Class<?> type, Insert insert) {
+        if (Deletable.class.isAssignableFrom(type)
+                && !this.isContains(insert.getColumns(), Expressions.UPDATER_COLUMN)) {
+            insert.addColumns(Expressions.DELETED_COLUMN);
+            insert.addSetExpressionList(Expressions.ZERO_VALUE);
+            return true;
         }
+        return false;
     }
 
     /**
-     * 数据查询
+     * 数据查询拦截
      *
      * @param invocation 方法调用信息
      * @return 查询结果
      * @throws Throwable 操作异常
      */
     private Object select(Invocation invocation) throws Throwable {
-        // 加密数据解码
+        // 铭感数据解密
         Object result = invocation.proceed();
-        if (ObjectUtils.notBlank(result) && DatabaseContextHolder.isCodecEnabled()) {
-            try {
-                DatabaseContextHolder.decoder(cipher -> ObjectUtils.stream(result).forEach(
-                        entity -> DatabaseContextHolder.decode(cipher, entity)
-                ));
-            } catch (Exception e) {
-                log.warn("Confidential value decode failed: {}", e.getMessage());
+        try {
+            if (result instanceof Collection) {
+                DatabaseContextHolder.decode((Collection<?>) result);
+            } else if (result != null) {
+                DatabaseContextHolder.decode(result);
             }
+        } catch (Exception e) {
+            log.warn("Confidential value decode failed: {}", e.getMessage());
         }
         return result;
     }
 
     /**
-     * 数据更新
+     * 数据更新拦截
      *
      * @param invocation 方法调用信息
+     * @param operation  更新操作类型
      * @return 更新结果
      * @throws Throwable 操作异常
      */
-    private Object modify(Invocation invocation) throws Throwable {
-        // 获取更新目标对象实例
+    private Object modify(Invocation invocation, SqlCommandType operation) throws Throwable {
+        // 获取更新参数
         Object object = invocation.getArgs()[1];
         if (object instanceof MapperMethod.ParamMap) {
             // 如果是批量更新则为ParamMap
@@ -124,15 +340,65 @@ public class PropertyUpdateInterceptor implements Interceptor {
             }
         }
 
-        // 数据更新
+        // 实体数据更新
         if (object instanceof Collection) {
-            ((Collection<?>) object).forEach(entity -> {
+            for (Object entity : (Collection<?>) object) {
                 if (entity instanceof Entity) {
-                    this.modify((Entity<?>) entity);
+                    this.modify((Entity<?>) entity, operation);
                 }
-            });
+            }
         } else if (object instanceof Entity) {
-            this.modify((Entity<?>) object);
+            this.modify((Entity<?>) object, operation);
+        }
+        return invocation.proceed();
+    }
+
+    /**
+     * SQL预处理拦截
+     *
+     * @param invocation 方法调用信息
+     * @return 执行结果
+     * @throws Throwable 操作异常
+     */
+    private Object prepare(Invocation invocation) throws Throwable {
+        Statements statements;
+        BoundSql bound = ((StatementHandler) invocation.getTarget()).getBoundSql();
+        try {
+            statements = CCJSqlParserUtil.parseStatements(bound.getSql());
+        } catch (JSQLParserException e) {
+            throw new RuntimeException(e);
+        }
+
+        // 构建带默认值SQL语句
+        StringBuilder sql = null;
+        for (Statement statement : statements.getStatements()) {
+            boolean changed = false;
+            if (statement instanceof Insert) {
+                Insert insert = (Insert) statement;
+                TableInfo table = DatabaseContextHolder.getTable(insert.getTable().getName());
+                Class<?> type = ObjectUtils.ifNull(table, TableInfo::getEntityType);
+                changed = type != null && (this.initializeCreatableValue(type, insert)
+                        || this.initializeUpdatableValue(type, insert) || this.initializeDeletableValue(type, insert));
+            } else if (statement instanceof Update) {
+                Update update = (Update) statement;
+                TableInfo table = DatabaseContextHolder.getTable(update.getTable().getName());
+                Class<?> type = ObjectUtils.ifNull(table, TableInfo::getEntityType);
+                changed = type != null && this.initializeUpdatableValue(type, update);
+            }
+            if (changed) {
+                if (sql == null) {
+                    sql = new StringBuilder();
+                }
+                if (sql.length() > 0) {
+                    sql.append(StringPool.SEMICOLON);
+                }
+                sql.append(statement.toString());
+            }
+        }
+
+        // 重置SQL语句
+        if (sql != null) {
+            SystemMetaObject.forObject(bound).setValue("sql", sql.toString());
         }
         return invocation.proceed();
     }
@@ -140,17 +406,30 @@ public class PropertyUpdateInterceptor implements Interceptor {
     /**
      * 实体信息更新
      *
-     * @param entity 实体对象实例
-     * @param <T>    实体类型
+     * @param entity    实体对象实例
+     * @param operation 更新操作类型
+     * @param <T>       实体类型
      */
     @SuppressWarnings("unchecked")
-    private <T extends Entity<?>> void modify(T entity) {
-        // 初始化实体默认属性值
-        this.initializeDefaultValue(entity);
+    private <T extends Entity<?>> void modify(T entity, SqlCommandType operation) {
+        // 初始化字段默认值
+        if (operation == SqlCommandType.INSERT) {
+            if (entity instanceof Creatable) {
+                this.initializeCreatableValue((Creatable<?>) entity);
+            }
+            if (entity instanceof Updatable) {
+                this.initializeUpdatableValue((Updatable<?>) entity);
+            }
+            if (entity instanceof Deletable) {
+                this.initializeDeletableValue((Deletable<?>) entity);
+            }
+        } else if (operation == SqlCommandType.UPDATE && entity instanceof Updatable) {
+            this.initializeUpdatableValue((Updatable<?>) entity);
+        }
 
         // 设置加密属性值
         Class<T> clazz = (Class<T>) entity.getClass();
-        boolean encoding = DatabaseContextHolder.isCodecEnabled() && DatabaseContextHolder.isConfidential(clazz);
+        boolean encoding = DatabaseContextHolder.isConfidential(clazz);
         T original = encoding ? ObjectUtils.copying(entity, clazz) : entity;
         if (encoding) {
             DatabaseContextHolder.encode(entity);
@@ -193,20 +472,21 @@ public class PropertyUpdateInterceptor implements Interceptor {
 
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
-        if (!(invocation.getTarget() instanceof Executor)) {
-            return invocation.proceed();
-        }
-        SqlCommandType operation = ((MappedStatement) invocation.getArgs()[0]).getSqlCommandType();
-        if (operation == SqlCommandType.SELECT) {
-            return this.select(invocation);
-        } else if (operation == SqlCommandType.INSERT || operation == SqlCommandType.UPDATE) {
-            return this.modify(invocation);
+        if (invocation.getTarget() instanceof Executor) {
+            SqlCommandType operation = ((MappedStatement) invocation.getArgs()[0]).getSqlCommandType();
+            if (operation == SqlCommandType.SELECT) {
+                return this.select(invocation);
+            } else if (operation == SqlCommandType.INSERT || operation == SqlCommandType.UPDATE) {
+                return this.modify(invocation, operation);
+            }
+        } else if (invocation.getTarget() instanceof StatementHandler) {
+            return this.prepare(invocation);
         }
         return invocation.proceed();
     }
 
     @Override
     public Object plugin(Object target) {
-        return target instanceof Executor ? Plugin.wrap(target, this) : target;
+        return target instanceof Executor || target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
     }
 }

+ 0 - 45
framework-database/src/main/java/com/chelvc/framework/database/support/EnhanceService.java

@@ -4,18 +4,11 @@ import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
 
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
-import com.baomidou.mybatisplus.core.conditions.update.Update;
 import com.baomidou.mybatisplus.extension.conditions.query.ChainQuery;
-import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
-import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
-import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.common.model.Pagination;
 import com.chelvc.framework.common.model.Paging;
 import com.chelvc.framework.database.context.DatabaseContextHolder;
-import com.chelvc.framework.database.entity.Updatable;
 import lombok.NonNull;
 
 /**
@@ -26,44 +19,6 @@ import lombok.NonNull;
  * @date 2024/3/10
  */
 public interface EnhanceService<T> extends IService<T>, EventService<T> {
-    @Override
-    default UpdateChainWrapper<T> update() {
-        Class<?> clazz = this.getEntityClass();
-        return new UpdateChainWrapper<T>(this.getBaseMapper()) {
-            @Override
-            public boolean update(T entity) {
-                if (Updatable.class.isAssignableFrom(clazz)) {
-                    this.setSql("updater = " + SessionContextHolder.getId()).setSql("update_time = now()");
-                }
-                return super.update(entity);
-            }
-        };
-    }
-
-    @Override
-    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
-        Class<?> clazz = this.getEntityClass();
-        return new LambdaUpdateChainWrapper<T>(this.getBaseMapper()) {
-            @Override
-            public boolean update(T entity) {
-                if (Updatable.class.isAssignableFrom(clazz)) {
-                    this.setSql("updater = " + SessionContextHolder.getId()).setSql("update_time = now()");
-                }
-                return super.update(entity);
-            }
-        };
-    }
-
-    @Override
-    default boolean update(T entity, Wrapper<T> wrapper) {
-        if (wrapper instanceof Update && Updatable.class.isAssignableFrom(this.getEntityClass())) {
-            Update<?, ?> update = (Update<?, ?>) wrapper;
-            update.setSql("updater = " + SessionContextHolder.getId());
-            update.setSql("update_time = now()");
-        }
-        return SqlHelper.retBool(this.getBaseMapper().update(entity, wrapper));
-    }
-
     /**
      * 创建或忽略实体
      *

+ 1 - 1
framework-redis/src/main/java/com/chelvc/framework/redis/config/RedisConfigurer.java

@@ -79,7 +79,7 @@ public class RedisConfigurer extends CachingConfigurerSupport implements Applica
                 clazz.getAnnotation(RedisMQConsumer.class),
                 () -> "@RedisMQConsumer annotation is missing: " + clazz.getName()
         );
-        Type type = ObjectUtils.lookupSuperclassParameterized(clazz, RedisMQListener.class);
+        Type type = ObjectUtils.lookupSuperclassParameterized(clazz, RedisMQListener.class, Object.class);
         RedisMQListenerContainer<T> container = ApplicationContextHolder.register(
                 this.counter.incrementAndGet(), RedisMQListenerContainer.class, DefaultRedisMQListenerContainer::new
         );

+ 1 - 1
framework-rocketmq/src/main/java/com/chelvc/framework/rocketmq/config/RocketMQConfigurer.java

@@ -70,7 +70,7 @@ public class RocketMQConfigurer implements ApplicationRunner {
                 clazz.getAnnotation(RocketMQConsumer.class),
                 () -> "@RocketMQConsumer annotation is missing: " + clazz.getName()
         );
-        Type type = ObjectUtils.lookupSuperclassParameterized(clazz, RocketMQListener.class);
+        Type type = ObjectUtils.lookupSuperclassParameterized(clazz, RocketMQListener.class, Object.class);
         RocketMQListenerContainer<T> container = ApplicationContextHolder.register(
                 this.counter.incrementAndGet(), RocketMQListenerContainer.class, () -> {
                     boolean multiple = Math.max(annotation.batch(), 1) > 1;