Browse Source

修复MyBatis TypeHandler自动处理异常问题

woody 8 months ago
parent
commit
39779e9390

+ 23 - 19
framework-database/src/main/java/com/chelvc/framework/database/config/TypeHandlerConfigurer.java

@@ -237,25 +237,31 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
     }
 
     /**
-     * 绑定字段类型处理器
+     * 绑定字段类型处理器,成功绑定返回true,否则返回false
      *
      * @param clazz 对象类型
      * @param field 表字段信息
+     * @return true/false
      */
     @SuppressWarnings("unchecked")
-    private void bindTypeHandler(Class<?> clazz, TableFieldInfo field) {
+    private boolean bindTypeHandler(Class<?> clazz, TableFieldInfo field) {
+        // 查找字段类型处理器
         Class<? extends TypeHandler<?>> handler =
                 this.lookupTypeHandlerClass(clazz, field.getField(), field.getTypeHandler());
-        if (handler != null) {
-            ObjectUtils.setValue(field, "typeHandler", handler);
-            String el = ObjectUtils.getValue(field, "el") + ",typeHandler=" + handler.getName();
-            ObjectUtils.setValue(field, "el", el);
+        if (handler == null) {
+            return false;
+        }
 
-            // 注册类型TypeHandler实例
+        // 绑定并注册字段类型处理器
+        ObjectUtils.setValue(field, "typeHandler", handler);
+        String el = ObjectUtils.getValue(field, "el") + ",typeHandler=" + handler.getName();
+        ObjectUtils.setValue(field, "el", el);
+        if (!this.isTypeHandlerRegistered(field.getField().getType())) {
             this.configuration.getTypeHandlerRegistry().register(
                     (Class<Object>) field.getField().getType(), DatabaseContextHolder.initializeTypeHandler(handler)
             );
         }
+        return true;
     }
 
     /**
@@ -506,7 +512,6 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
      * @param field    对象字段
      * @param consumer resultMap元素回调函数
      */
-    @SuppressWarnings("unchecked")
     private void initializeResultMapping(Document document, Class<?> clazz, Field field, Consumer<Element> consumer) {
         // 排除主键字段
         if (field.isAnnotationPresent(TableId.class)) {
@@ -543,11 +548,6 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
             child.setAttribute("typeHandler", handler.getName());
             consumer.accept(child);
         });
-
-        // 注册类型TypeHandler实例
-        this.configuration.getTypeHandlerRegistry().register(
-                (Class<Object>) field.getType(), DatabaseContextHolder.initializeTypeHandler(handler)
-        );
     }
 
     @Override
@@ -566,6 +566,9 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
                 for (XNode child : map.getChildren()) {
                     String property = child.getStringAttribute("property");
                     properties.add(property);
+                    if ("id".equalsIgnoreCase(child.getName())) {
+                        continue;
+                    }
                     Field field = ObjectUtils.findField(clazz, property);
                     if (field == null || field.isAnnotationPresent(TableId.class)) {
                         continue;
@@ -576,11 +579,6 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
                             (Class<? extends TypeHandler<?>>) this.name2class(child.getStringAttribute("typeHandler"));
                     if ((handler = this.lookupTypeHandlerClass(clazz, field, handler)) != null) {
                         ((Element) child.getNode()).setAttribute("typeHandler", handler.getName());
-
-                        // 注册类型TypeHandler实例
-                        this.configuration.getTypeHandlerRegistry().register(
-                                (Class<Object>) field.getType(), DatabaseContextHolder.initializeTypeHandler(handler)
-                        );
                     }
                     if (StringUtils.isEmpty(child.getStringAttribute("typeHandler"))) {
                         continue;
@@ -638,7 +636,13 @@ public class TypeHandlerConfigurer extends MybatisConfigurer {
         // 自动绑定字段类型处理器
         List<TableFieldInfo> fields = table.getFieldList();
         if (ObjectUtils.notEmpty(fields)) {
-            fields.forEach(field -> this.bindTypeHandler(table.getEntityType(), field));
+            boolean bound = false;
+            for (TableFieldInfo field : fields) {
+                bound |= this.bindTypeHandler(table.getEntityType(), field);
+            }
+            if (bound && !table.isAutoInitResultMap()) {
+                ObjectUtils.setValue(table, "autoInitResultMap", true);
+            }
         }
     }
 }

+ 31 - 4
framework-database/src/main/java/com/chelvc/framework/database/interceptor/DynamicInvokeInterceptor.java

@@ -25,6 +25,7 @@ import net.sf.jsqlparser.Model;
 import net.sf.jsqlparser.expression.Alias;
 import net.sf.jsqlparser.expression.BinaryExpression;
 import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.Function;
 import net.sf.jsqlparser.expression.JdbcParameter;
 import net.sf.jsqlparser.expression.NullValue;
 import net.sf.jsqlparser.expression.Parenthesis;
@@ -668,7 +669,9 @@ public class DynamicInvokeInterceptor implements Interceptor {
         if (expression instanceof SelectExpressionItem) {
             expression = ((SelectExpressionItem) expression).getExpression();
         }
-        if (expression instanceof JdbcParameter) {
+        if (expression instanceof Function) {
+            return false;
+        } else if (expression instanceof JdbcParameter) {
             // 如果是占位符参数,则更新关联参数
             int i = ((JdbcParameter) expression).getIndex() - 1;
             String property = bound.getParameterMappings().get(i).getProperty();
@@ -780,12 +783,36 @@ public class DynamicInvokeInterceptor implements Interceptor {
      */
     private boolean initializeDefaultValue(BoundSql bound, Update update, Table table, Pair<?, Expression> operator,
                                            Pair<?, Expression> datetime) {
-        boolean rebuild = false;
         Class<?> model = DatabaseContextHolder.getTableModel(table.getName());
-        if (model != null && Updatable.class.isAssignableFrom(model)) {
-            rebuild = this.initializeDefaultValue(bound, update, table, Expressions.UPDATER_COLUMN, operator);
+        if (model == null) {
+            return false;
+        }
+        boolean rebuild = false;
+        if (Creatable.class.isAssignableFrom(model)) {
+            int index = this.lookupColumnIndex(table, Expressions.CREATOR_COLUMN, update.getColumns());
+            if (index >= 0) {
+                rebuild = this.initializeDefaultValue(bound, update.getExpressions(), index, operator, false);
+            }
+            if ((index = this.lookupColumnIndex(table, Expressions.CREATE_TIME_COLUMN, update.getColumns())) >= 0) {
+                rebuild |= this.initializeDefaultValue(bound, update.getExpressions(), index, datetime, false);
+            }
+        }
+        if (Updatable.class.isAssignableFrom(model)) {
+            rebuild |= this.initializeDefaultValue(bound, update, table, Expressions.UPDATER_COLUMN, operator);
             rebuild |= this.initializeDefaultValue(bound, update, table, Expressions.UPDATE_TIME_COLUMN, datetime);
         }
+        if (Environmental.class.isAssignableFrom(model) && Expressions.env().getLeft() != null) {
+            int index = this.lookupColumnIndex(table, Expressions.ENV_COLUMN, update.getColumns());
+            if (index >= 0) {
+                rebuild |= this.initializeDefaultValue(bound, update.getExpressions(), index, Expressions.env(), false);
+            }
+        }
+        if (Deletable.class.isAssignableFrom(model)) {
+            int index = this.lookupColumnIndex(table, Expressions.DELETED_COLUMN, update.getColumns());
+            if (index >= 0) {
+                rebuild |= this.initializeDefaultValue(bound, update.getExpressions(), index, Expressions.FALSE, false);
+            }
+        }
         return rebuild;
     }
 

+ 7 - 5
framework-wechat/src/main/java/com/chelvc/framework/wechat/DefaultWechatPublicHandler.java

@@ -10,7 +10,6 @@ import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import com.chelvc.framework.base.context.RestContextHolder;
 import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
@@ -63,9 +62,13 @@ public class DefaultWechatPublicHandler implements WechatPublicHandler {
     private static final String SEND_TEMPLATE_MESSAGE_URL =
             "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
 
+    private final String applet;
     private final WechatProperties.Public properties;
 
-    public DefaultWechatPublicHandler(@NonNull WechatProperties.Public properties) {
+    public DefaultWechatPublicHandler(@NonNull WechatProperties.Push push,
+                                      @NonNull WechatProperties.Public properties) {
+        String applet = properties.getPush().getApplet();
+        this.applet = ObjectUtils.ifNull(ObjectUtils.ifNull(applet, push.getApplet()), StringUtils.EMPTY);
         this.properties = properties;
     }
 
@@ -93,7 +96,7 @@ public class DefaultWechatPublicHandler implements WechatPublicHandler {
     @Override
     public WechatWebToken code2token(@NonNull String code) {
         String url = String.format(CODE2TOKEN_URL, this.properties.getAppid(), this.properties.getSecret(), code);
-        return RestContextHolder.get(url, WechatWebToken.class);
+        return WechatContextHolder.get(url, WechatWebToken.class);
     }
 
     @Override
@@ -158,8 +161,7 @@ public class DefaultWechatPublicHandler implements WechatPublicHandler {
         if (debug) {
             log.debug("Wechat public push request: {}, {}, {}, {}", openid, template, redirect, parameters);
         }
-        String applet = (redirect = redirect.trim()).isEmpty() ? StringUtils.EMPTY :
-                ObjectUtils.ifNull(this.properties.getPush().getApplet(), StringUtils.EMPTY);
+        String applet = (redirect = redirect.trim()).isEmpty() ? StringUtils.EMPTY : this.applet;
         Map<String, Object> body = ImmutableMap.of(
                 "touser", openid,
                 "template_id", template,

+ 1 - 1
framework-wechat/src/main/java/com/chelvc/framework/wechat/config/WechatConfigurer.java

@@ -45,7 +45,7 @@ public class WechatConfigurer implements BeanPostProcessor {
         // 注册公众号操作Bean
         if (ObjectUtils.notEmpty(this.properties.getPublics())) {
             this.properties.getPublics().forEach(config -> {
-                WechatPublicHandler handler = new DefaultWechatPublicHandler(config);
+                WechatPublicHandler handler = new DefaultWechatPublicHandler(this.properties.getPush(), config);
                 String name = StringUtils.ifEmpty(config.getName(), config.getAppid());
                 RootBeanDefinition definition = new RootBeanDefinition(WechatPublicHandler.class, () -> handler);
                 this.applicationContext.registerBeanDefinition(name, definition);

+ 5 - 0
framework-wechat/src/main/java/com/chelvc/framework/wechat/config/WechatProperties.java

@@ -18,6 +18,11 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 @ConfigurationProperties("wechat")
 public class WechatProperties {
+    /**
+     * 消息推送配置
+     */
+    private final Push push = new Push();
+
     /**
      * 小程序配置列表
      */