Browse Source

优化动态表单

zhouhao 6 years ago
parent
commit
75c7af8b12
20 changed files with 476 additions and 62 deletions
  1. 7 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/DynamicFormColumnEntity.java
  2. 17 13
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/SimpleDynamicFormColumnEntity.java
  3. 3 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/service/form/OptionalConvertBuilder.java
  4. 21 3
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormService.java
  5. 13 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DefaultOptionalConvertBuilder.java
  6. 12 2
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DictionaryOptionalConvertBuilderStrategy.java
  7. 4 1
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/OptionalConvertBuilderStrategy.java
  8. 4 26
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidator.java
  9. 131 14
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidatorFactory.java
  10. 14 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationInfo.java
  11. 14 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationParserStrategy.java
  12. 109 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/AbstractStrategy.java
  13. 28 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/EmailStrategy.java
  14. 27 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/LengthStrategy.java
  15. 21 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotBlankStrategy.java
  16. 20 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotNullStrategy.java
  17. 26 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/RangeStrategy.java
  18. 1 0
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/form/DynamicFormColumnMapper.xml
  19. 1 1
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/main/resources/hsweb-starter.js
  20. 3 2
      hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/test/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormServiceTest.java

+ 7 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/DynamicFormColumnEntity.java

@@ -4,6 +4,8 @@ import org.hibernate.validator.constraints.NotBlank;
 import org.hswebframework.web.commons.entity.GenericEntity;
 import org.hswebframework.web.validator.group.CreateGroup;
 
+import java.util.List;
+
 /**
  * 动态表单 实体
  *
@@ -195,4 +197,9 @@ public interface DynamicFormColumnEntity extends GenericEntity<String> {
     Long getSortIndex();
 
     void setSortIndex(Long sortIndex);
+
+    List<String> getValidator();
+
+    void setValidator(List<String> validator);
+
 }

+ 17 - 13
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/SimpleDynamicFormColumnEntity.java

@@ -4,6 +4,8 @@ import lombok.Getter;
 import lombok.Setter;
 import org.hswebframework.web.commons.entity.SimpleGenericEntity;
 
+import java.util.List;
+
 /**
  * 动态表单
  *
@@ -13,29 +15,31 @@ import org.hswebframework.web.commons.entity.SimpleGenericEntity;
 @Setter
 public class SimpleDynamicFormColumnEntity extends SimpleGenericEntity<String> implements DynamicFormColumnEntity {
     //表单ID
-    private String  formId;
+    private String       formId;
     //字段名称
-    private String  name;
+    private String       name;
     //数据库列
-    private String  columnName;
+    private String       columnName;
     //备注
-    private String  describe;
+    private String       describe;
     //别名
-    private String  alias;
+    private String       alias;
     //java类型
-    private String  javaType;
+    private String       javaType;
     //jdbc类型
-    private String  jdbcType;
+    private String       jdbcType;
     //数据类型
-    private String  dataType;
+    private String       dataType;
     //长度
-    private Integer length;
+    private Integer      length;
     //精度
-    private Integer precision;
+    private Integer      precision;
     //小数点位数
-    private Integer scale;
+    private Integer      scale;
     //数据字典配置
-    private String  dictConfig;
+    private String       dictConfig;
     //序号
-    private Long    sortIndex;
+    private Long         sortIndex;
+    //验证器配置
+    private List<String> validator;
 }

+ 3 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/service/form/OptionalConvertBuilder.java

@@ -1,6 +1,7 @@
 package org.hswebframework.web.service.form;
 
 import org.hswebframework.ezorm.core.OptionConverter;
+import org.hswebframework.ezorm.core.ValueConverter;
 import org.hswebframework.web.entity.form.DictConfig;
 import org.hswebframework.web.entity.form.DynamicFormColumnEntity;
 
@@ -10,4 +11,6 @@ import org.hswebframework.web.entity.form.DynamicFormColumnEntity;
  */
 public interface OptionalConvertBuilder {
     OptionConverter build(DictConfig dictConfig);
+
+    ValueConverter buildValueConverter(DictConfig dictConfig);
 }

+ 21 - 3
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormService.java

@@ -4,7 +4,9 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.hswebframework.ezorm.core.ObjectWrapperFactory;
 import org.hswebframework.ezorm.core.Trigger;
+import org.hswebframework.ezorm.core.ValidatorFactory;
 import org.hswebframework.ezorm.core.ValueConverter;
 import org.hswebframework.ezorm.rdb.RDBDatabase;
 import org.hswebframework.ezorm.rdb.meta.Correlation;
@@ -33,6 +35,7 @@ import org.hswebframework.web.service.form.OptionalConvertBuilder;
 import org.hswebframework.web.service.form.initialize.ColumnInitializeContext;
 import org.hswebframework.web.service.form.initialize.DynamicFormInitializeCustomer;
 import org.hswebframework.web.service.form.initialize.TableInitializeContext;
+import org.hswebframework.web.service.form.simple.dict.EnumDictValueConverter;
 import org.hswebframework.web.validator.group.CreateGroup;
 import org.hswebframework.web.validator.group.UpdateGroup;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -78,6 +81,12 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
     @Autowired(required = false)
     private List<DynamicFormInitializeCustomer> initializeCustomers;
 
+    @Autowired
+    private ValidatorFactory validatorFactory;
+
+    @Autowired(required = false)
+    private ObjectWrapperFactory objectWrapperFactory;
+
     @Override
     protected IDGenerator<String> getIDGenerator() {
         return IDGenerator.MD5;
@@ -355,6 +364,8 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
                 ? databaseRepository.getDefaultDatabase()
                 : databaseRepository.getDatabase(form.getDataSourceId());
         RDBTableMetaData metaData = buildTable(database, form, columns);
+        metaData.setValidator(validatorFactory.createValidator(metaData));
+
         try {
             if (!database.getMeta().getParser().tableExists(metaData.getName())) {
                 database.createTable(metaData);
@@ -433,6 +444,7 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
         metaData.setAlias(form.getAlias());
         metaData.setCorrelations(buildCorrelations(form.getCorrelations()));
         buildTrigger(form.getTriggers()).forEach(metaData::on);
+
         columns.forEach(column -> {
             RDBColumnMetaData columnMeta = new RDBColumnMetaData();
             columnMeta.setName(column.getColumnName());
@@ -444,6 +456,9 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
             columnMeta.setJdbcType(JDBCType.valueOf(column.getJdbcType()));
             columnMeta.setJavaType(getJavaType(column.getJavaType()));
             columnMeta.setProperties(column.getProperties() == null ? new HashMap<>() : column.getProperties());
+            if (!CollectionUtils.isEmpty(column.getValidator())) {
+                columnMeta.setValidator(new HashSet<>(column.getValidator()));
+            }
             if (StringUtils.isEmpty(column.getDataType())) {
                 Dialect dialect = database.getMeta().getDialect();
                 columnMeta.setDataType(dialect.buildDataType(columnMeta));
@@ -462,6 +477,9 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
             customColumnSetting(database, form, metaData, column, columnMeta);
             metaData.addColumn(columnMeta);
         });
+        if (objectWrapperFactory != null) {
+            metaData.setObjectWrapper(objectWrapperFactory.createObjectWrapper(metaData));
+        }
         customTableSetting(database, form, metaData);
         //没有主键并且没有id字段
         if (metaData.getColumns().stream().noneMatch(RDBColumnMetaData::isPrimaryKey) && metaData.findColumn("id") == null) {
@@ -470,6 +488,7 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
             primaryKey.setDataType(dialect.buildDataType(primaryKey));
             metaData.addColumn(primaryKey);
         }
+
         return metaData;
     }
 
@@ -551,9 +570,8 @@ public class SimpleDynamicFormService extends GenericEntityService<DynamicFormEn
                 .values()
                 .contains(javaType) || javaType != Map.class || javaType != List.class;
 
-
-        if (EnumDict.class.isAssignableFrom(javaType)) {
-            // TODO: 18-4-25
+        if (javaType.isEnum() && EnumDict.class.isAssignableFrom(javaType)) {
+            return new EnumDictValueConverter<EnumDict>(() -> (List) Arrays.asList(javaType.getEnumConstants()));
         }
         switch (jdbcType) {
             case BLOB:

+ 13 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DefaultOptionalConvertBuilder.java

@@ -1,6 +1,7 @@
 package org.hswebframework.web.service.form.simple.dict;
 
 import org.hswebframework.ezorm.core.OptionConverter;
+import org.hswebframework.ezorm.core.ValueConverter;
 import org.hswebframework.web.entity.form.DictConfig;
 import org.hswebframework.web.service.form.OptionalConvertBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,4 +32,16 @@ public class DefaultOptionalConvertBuilder implements OptionalConvertBuilder {
                 .map(strategy -> strategy.build(dictConfig))
                 .orElse(null);
     }
+
+    @Override
+    public ValueConverter buildValueConverter(DictConfig dictConfig) {
+        if(CollectionUtils.isEmpty(strategies)){
+            return null;
+        }
+        return strategies.stream()
+                .filter(strategy -> strategy.support(dictConfig.getType()))
+                .findFirst()
+                .map(strategy -> strategy.buildValueConverter(dictConfig))
+                .orElse(null);
+    }
 }

+ 12 - 2
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DictionaryOptionalConvertBuilderStrategy.java

@@ -3,6 +3,7 @@ package org.hswebframework.web.service.form.simple.dict;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import org.hswebframework.ezorm.core.OptionConverter;
+import org.hswebframework.ezorm.core.ValueConverter;
 import org.hswebframework.web.dict.DictDefineRepository;
 import org.hswebframework.web.dict.EnumDict;
 import org.hswebframework.web.entity.form.DictConfig;
@@ -35,9 +36,7 @@ public class DictionaryOptionalConvertBuilderStrategy implements OptionalConvert
         String dictId = conf.getString("dictId");
         String fieldName = conf.getString("fieldName");
         String sppliter = conf.getString("sppliter");
-
         String writeObject = conf.getString("writeObject");
-
         EnumDictOptionConverter<EnumDict<Object>> converter = new EnumDictOptionConverter<>(() -> dictDefineRepository.getDefine(dictId).getItems(), fieldName);
 
         converter.setWriteObject(!"false".equalsIgnoreCase(writeObject));
@@ -48,4 +47,15 @@ public class DictionaryOptionalConvertBuilderStrategy implements OptionalConvert
 
         return converter;
     }
+
+    @Override
+    public ValueConverter buildValueConverter(DictConfig dictConfig) {
+        JSONObject conf = JSON.parseObject(dictConfig.getConfig());
+        String dictId = conf.getString("dictId");
+
+        EnumDictValueConverter<EnumDict<Object>> converter =
+                new EnumDictValueConverter<>(() -> dictDefineRepository.getDefine(dictId).getItems());
+
+        return converter;
+    }
 }

+ 4 - 1
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/OptionalConvertBuilderStrategy.java

@@ -1,6 +1,7 @@
 package org.hswebframework.web.service.form.simple.dict;
 
 import org.hswebframework.ezorm.core.OptionConverter;
+import org.hswebframework.ezorm.core.ValueConverter;
 import org.hswebframework.web.entity.form.DictConfig;
 
 /**
@@ -15,10 +16,12 @@ public interface OptionalConvertBuilderStrategy {
     boolean support(String type);
 
     /**
-     * 根据配置创建转换器
+     * 根据配置创建选项转换器
      *
      * @param dictConfig 配置内容
      * @return 转换器对象
      */
     OptionConverter build(DictConfig dictConfig);
+
+    ValueConverter buildValueConverter(DictConfig dictConfig);
 }

+ 4 - 26
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidator.java

@@ -1,47 +1,25 @@
 package org.hswebframework.web.service.form.simple.validator;
 
-import org.hibernate.validator.constraints.NotBlank;
 import org.hswebframework.ezorm.core.Validator;
-import org.hswebframework.web.Maps;
 import org.hswebframework.web.bean.FastBeanCopier;
 import org.hswebframework.web.commons.bean.ValidateBean;
-import org.hswebframework.web.proxy.Proxy;
 import org.hswebframework.web.validator.group.CreateGroup;
 import org.hswebframework.web.validator.group.UpdateGroup;
 
-import javax.validation.GroupSequence;
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.function.Supplier;
 
 public class DynamicBeanValidator implements Validator {
 
     protected Supplier<ValidateBean> beanSupplier;
 
-    public static void main(String[] args) {
-        MapBean bean = Proxy.create(MapBean.class)
-                .addField("private String name;", NotBlank.class, Maps.<String, Object>buildMap()
-                        .put("message", "测试")
-                        .put("groups", new Class[]{CreateGroup.class})
-                        .get())
-                .addMethod("public String getName(){return this.name;}")
-                .addMethod("public java.util.Set keySet(){return new java.util.HashSet(java.util.Arrays.asList(new String[]{\"name\"}));}")
-                .addMethod("public void setName(String name){  this.name=name;}")
-                .addMethod("public void setProperty(String name,Object value){  this.name=(String)value;}")
-                .addMethod("public Object getProperty(String name){ return this.name;}")
-                .newInstance();
-
-
-        bean.setProperty("name", "test");
-
-        System.out.println((MapBean) bean.tryValidate(CreateGroup.class));
-
+    public DynamicBeanValidator(Supplier<ValidateBean> beanSupplier) {
+        this.beanSupplier = beanSupplier;
     }
 
     @Override
-    public boolean validate(Object o, Operation operation) {
+    public boolean validate(Object source, Operation operation) {
         ValidateBean validateBean = beanSupplier.get();
-        FastBeanCopier.copy(o, validateBean);
+        FastBeanCopier.copy(source, validateBean);
         if (operation == Operation.INSERT) {
             validateBean.tryValidate(CreateGroup.class);
         } else {

+ 131 - 14
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidatorFactory.java

@@ -1,25 +1,52 @@
 package org.hswebframework.web.service.form.simple.validator;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import javassist.CtField;
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.annotation.Annotation;
+import javassist.bytecode.annotation.MemberValue;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import org.hswebframework.ezorm.core.Validator;
 import org.hswebframework.ezorm.core.ValidatorFactory;
 import org.hswebframework.ezorm.core.meta.ColumnMetaData;
 import org.hswebframework.ezorm.core.meta.TableMetaData;
 import org.hswebframework.utils.StringUtils;
-import org.hswebframework.web.bean.FastBeanCopier;
 import org.hswebframework.web.proxy.Proxy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.hswebframework.web.proxy.Proxy.createMemberValue;
 
 /**
  * @author zhouhao
  * @since 3.0.0-RC
  */
+@Component
+@Slf4j
 public class DynamicBeanValidatorFactory implements ValidatorFactory {
 
+    @Autowired
+    private List<JSR303AnnotationParserStrategy> strategies;
+
     private String createSetPropertyCode(TableMetaData tableMetaData) {
         StringBuilder builder = new StringBuilder();
-        builder.append("public void setProperty(String property,Object value){");
+        builder.append("public void setProperty(String property,Object value){\n");
+        int index = 0;
         for (ColumnMetaData column : tableMetaData.getColumns()) {
             String propertyName = column.getAlias();
             Class type = column.getJavaType();
+            if (index++ > 0) {
+                builder.append("\nelse ");
+            }
             builder.append("if(property.intern()==\"")
                     .append(propertyName)
                     .append("\"||property.intern()==\"")
@@ -29,38 +56,128 @@ public class DynamicBeanValidatorFactory implements ValidatorFactory {
                     .append("((").append(type.getName()).append(")")
                     .append("org.hswebframework.web.bean.FastBeanCopier.DEFAULT_CONVERT.convert(value,")
                     .append(type.getName())
-                    .append(",null))")
+                    .append(".class,null));")
                     .append("\n}");
-
         }
+        builder.append("}");
         return builder.toString();
     }
 
-    @Override
-    public Validator createValidator(TableMetaData tableMetaData) {
+    private String createGetPropertyCode(TableMetaData tableMetaData) {
         StringBuilder builder = new StringBuilder();
+        int index = 0;
+        builder.append("public Object getProperty(String property){\n");
+        for (ColumnMetaData column : tableMetaData.getColumns()) {
+            String propertyName = column.getAlias();
+            if (index++ > 0) {
+                builder.append("\nelse ");
+            }
+            builder.append("if(property.intern()==\"")
+                    .append(propertyName)
+                    .append("\"||property.intern()==\"")
+                    .append(column.getName())
+                    .append("\"){\n")
+                    .append("return this.get")
+                    .append(StringUtils.toUpperCaseFirstOne(propertyName))
+                    .append("();")
+                    .append("\n}");
 
-        Proxy<MapBean> proxy = Proxy.create(MapBean.class);
-        proxy.addField("private java.util.Map proxy;")
-                .addMethod("public java.util.Map getProxy(){return this.proxy;};")
-                .addMethod("public org.hswebframework.web.service.form.simple.validator.MapBean setProxy(java.util.Map proxy){ this.proxy=proxy; return this;};");
+        }
+        builder.append("\nreturn null;\n}");
+        return builder.toString();
+    }
 
 
+    protected List<JSR303AnnotationInfo> createValidatorAnnotation(Set<String> config) {
+        if (CollectionUtils.isEmpty(config)) {
+            return Collections.emptyList();
+        }
+
+        return config.stream()
+                .map(this::createValidatorAnnotation)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    protected JSR303AnnotationInfo createValidatorAnnotation(String config) {
+        //JSON
+        if (config.startsWith("{")) {
+            JSONObject jsonConfig = JSON.parseObject(config);
+            String type = jsonConfig.getString("type");
+            return strategies.stream().filter(strategy -> strategy.support(type))
+                    .findFirst()
+                    .map(strategy -> strategy.parse(jsonConfig))
+                    .orElse(null);
+        }
+
+        return null;
+    }
+
+    @Override
+    public Validator createValidator(TableMetaData tableMetaData) {
+        Proxy<MapBean> proxy = Proxy.create(MapBean.class);
+        StringBuilder keySet = new StringBuilder("public java.util.Set keySet(){\n return new java.util.HashSet(java.util.Arrays.asList(new String[]{");
+        int index = 0;
         for (ColumnMetaData column : tableMetaData.getColumns()) {
             String propertyName = column.getAlias();
             Class type = column.getJavaType();
             String typeName = type.getName();
 
-            proxy.addField("private " + type.getName() + " " + propertyName + ";");
-            proxy.addField("public void set " + StringUtils.toUpperCaseFirstOne(propertyName) + "(" + typeName + " " + propertyName + "){\n" +
+            if (index++ > 0) {
+                keySet.append(",");
+            }
+
+            keySet.append("\"")
+                    .append(propertyName)
+                    .append("\"");
+
+            proxy.custom(ctClass -> {
+                try {
+                    CtField ctField = CtField.make("private " + type.getName() + " " + propertyName + ";", ctClass);
+                    List<JSR303AnnotationInfo> jsr303 = createValidatorAnnotation(column.getValidator());
+                    //添加注解
+                    if (!CollectionUtils.isEmpty(jsr303)) {
+                        ConstPool constPool = ctClass.getClassFile().getConstPool();
+                        AnnotationsAttribute attributeInfo = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
+                        for (JSR303AnnotationInfo jsr303AnnotationInfo : jsr303) {
+                            Class<? extends java.lang.annotation.Annotation> jsr303Ann = jsr303AnnotationInfo.getAnnotation();
+                            Annotation ann = new javassist.bytecode.annotation.Annotation(jsr303Ann.getName(), constPool);
+                            if (!CollectionUtils.isEmpty(jsr303AnnotationInfo.getProperties())) {
+                                jsr303AnnotationInfo.getProperties().forEach((key, value) -> {
+                                    MemberValue memberValue = createMemberValue(value, constPool);
+                                    if (memberValue != null) {
+                                        ann.addMemberValue(key, memberValue);
+                                    }
+                                });
+                            }
+                            attributeInfo.addAnnotation(ann);
+                        }
+                        ctField.getFieldInfo().addAttribute(attributeInfo);
+                    }
+                    ctClass.addField(ctField);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            });
+
+            proxy.addMethod("public void set" + StringUtils.toUpperCaseFirstOne(propertyName) + "(" + typeName + " " + propertyName + "){\n" +
                     "this." + propertyName + "=" + propertyName + ";\n" +
                     "\n};");
-            proxy.addField("public " + typeName + " get " + StringUtils.toUpperCaseFirstOne(propertyName) + "(){\n" +
+
+            proxy.addMethod("public " + typeName + " get" + StringUtils.toUpperCaseFirstOne(propertyName) + "(){\n" +
                     "return this." + propertyName + ";\n" +
                     "\n};");
         }
+
+        keySet.append("}));\n}");
+
+        proxy.addMethod(keySet.toString());
         proxy.addMethod(createSetPropertyCode(tableMetaData));
+        proxy.addMethod(createGetPropertyCode(tableMetaData));
 
-        return null;
+        //尝试一下能否创建实例
+        MapBean mapBean = proxy.newInstance();
+        Assert.notNull(mapBean, "创建验证器失败!");
+        return new DynamicBeanValidator(proxy::newInstance);
     }
 }

+ 14 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationInfo.java

@@ -0,0 +1,14 @@
+package org.hswebframework.web.service.form.simple.validator;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+@Setter
+@Getter
+public class JSR303AnnotationInfo {
+    private Class<? extends java.lang.annotation.Annotation> annotation;
+
+    private Map<String, Object> properties;
+}

+ 14 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationParserStrategy.java

@@ -0,0 +1,14 @@
+package org.hswebframework.web.service.form.simple.validator;
+
+import java.util.Map;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+public interface JSR303AnnotationParserStrategy {
+
+    boolean support(String type);
+
+    JSR303AnnotationInfo parse(Map<String, Object> configMap);
+}

+ 109 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/AbstractStrategy.java

@@ -0,0 +1,109 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.web.bean.FastBeanCopier;
+import org.hswebframework.web.service.form.simple.validator.JSR303AnnotationInfo;
+import org.hswebframework.web.service.form.simple.validator.JSR303AnnotationParserStrategy;
+import org.hswebframework.web.validator.group.CreateGroup;
+import org.hswebframework.web.validator.group.UpdateGroup;
+import org.springframework.util.CollectionUtils;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Slf4j
+public abstract class AbstractStrategy implements JSR303AnnotationParserStrategy {
+
+    private List<PropertyMapping> propertyMappings = new ArrayList<>();
+
+    public AbstractStrategy() {
+        propertyMappings.add(PropertyMapping.of("message", String.class));
+    }
+
+    public void addPropertyMapping(PropertyMapping mapping) {
+        propertyMappings.add(mapping);
+    }
+
+    protected String getTypeString() {
+        return getAnnotationType().getSimpleName();
+    }
+
+    protected abstract Class<? extends Annotation> getAnnotationType();
+
+    @Getter
+    @Setter
+    public static class PropertyMapping<T> {
+        private String   name;
+        private Class<T> type;
+
+        public static <T> PropertyMapping<T> of(String name, Class<T> type) {
+            PropertyMapping mapping = new PropertyMapping<>();
+
+            mapping.name = name;
+            mapping.type = type;
+
+            return mapping;
+        }
+
+        public static <T> PropertyMapping<T> of(String name, Class<T> type, Function<Object, T> converter) {
+            PropertyMapping mapping = new PropertyMapping<>();
+            mapping.name = name;
+            mapping.type = type;
+            mapping.converter = converter;
+            return mapping;
+        }
+
+        private Function<Object, T> converter = source -> FastBeanCopier.DEFAULT_CONVERT.convert(source, type, null);
+    }
+
+    @Override
+    public boolean support(String type) {
+        return type != null && (getTypeString().equalsIgnoreCase(type));
+    }
+
+    @Override
+    public JSR303AnnotationInfo parse(Map<String, Object> configMap) {
+        JSR303AnnotationInfo info = new JSR303AnnotationInfo();
+        info.setAnnotation(getAnnotationType());
+
+        Map<String, Object> properties = new HashMap<>();
+
+        propertyMappings.forEach(mapping -> {
+            Object value = mapping.getConverter().apply(configMap.get(mapping.getName()));
+            if (null != value) {
+                properties.put(mapping.getName(), value);
+            }
+        });
+
+        List<Object> groups = new JSONObject(configMap).getJSONArray("groups");
+        if (!CollectionUtils.isEmpty(groups)) {
+            properties.put("groups", groups.stream().map(obj -> {
+                if ("create".equals(obj)) {
+                    return CreateGroup.class;
+                } else if ("update".equals(obj)) {
+                    return UpdateGroup.class;
+                } else {
+                    try {
+                        return Class.forName(String.valueOf(obj));
+                    } catch (ClassNotFoundException e) {
+                        return CreateGroup.class;
+                    }
+                }
+            }).toArray());
+        }
+        info.setProperties(properties);
+        return info;
+    }
+}

+ 28 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/EmailStrategy.java

@@ -0,0 +1,28 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.Length;
+import org.springframework.stereotype.Component;
+
+import javax.validation.constraints.Pattern;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Component
+@Slf4j
+public class EmailStrategy extends AbstractStrategy {
+
+    public EmailStrategy() {
+        addPropertyMapping(PropertyMapping.of("regexp", String.class));
+    }
+
+    @Override
+    protected Class<Email> getAnnotationType() {
+        return Email.class;
+    }
+}

+ 27 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/LengthStrategy.java

@@ -0,0 +1,27 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.validator.constraints.Length;
+import org.springframework.stereotype.Component;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Component
+@Slf4j
+public class LengthStrategy extends AbstractStrategy {
+
+    public LengthStrategy() {
+        addPropertyMapping(PropertyMapping.of("min", int.class));
+
+        addPropertyMapping(PropertyMapping.of("max", int.class));
+    }
+
+    @Override
+    protected Class<Length> getAnnotationType() {
+        return Length.class;
+    }
+}

+ 21 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotBlankStrategy.java

@@ -0,0 +1,21 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.validator.constraints.NotBlank;
+import org.springframework.stereotype.Component;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Component
+@Slf4j
+public class NotBlankStrategy extends AbstractStrategy {
+
+    @Override
+    protected Class<NotBlank> getAnnotationType() {
+        return NotBlank.class;
+    }
+}

+ 20 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotNullStrategy.java

@@ -0,0 +1,20 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Component
+@Slf4j
+public class NotNullStrategy extends AbstractStrategy {
+
+    @Override
+    protected Class<NotNull> getAnnotationType() {
+        return NotNull.class;
+    }
+}

+ 26 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/RangeStrategy.java

@@ -0,0 +1,26 @@
+package org.hswebframework.web.service.form.simple.validator.jsr303;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Component
+@Slf4j
+public class RangeStrategy extends AbstractStrategy {
+
+    public RangeStrategy() {
+        addPropertyMapping(PropertyMapping.of("min", int.class));
+
+        addPropertyMapping(PropertyMapping.of("max", int.class));
+    }
+
+    @Override
+    protected Class<Range> getAnnotationType() {
+        return Range.class;
+    }
+}

+ 1 - 0
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/form/DynamicFormColumnMapper.xml

@@ -19,6 +19,7 @@
         <result property="dictConfig" column="dict_config" javaType="String" jdbcType="CLOB"/>
         <result property="sortIndex" column="sort_index" javaType="Long" jdbcType="DECIMAL"/>
         <result property="properties" column="properties" javaType="java.util.Map" jdbcType="CLOB"/>
+        <result property="validator" column="validator" javaType="java.util.List" jdbcType="CLOB"/>
     </resultMap>
 
     <!--用于动态生成sql所需的配置-->

+ 1 - 1
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/main/resources/hsweb-starter.js

@@ -54,7 +54,7 @@ function install(context) {
         .addColumn().name("properties").alias("properties").comment("其他配置").jdbcType(java.sql.JDBCType.CLOB).commit()
         .addColumn().name("dict_config").alias("dictConfig").comment("字典配置").jdbcType(java.sql.JDBCType.CLOB).commit()
         .addColumn().name("sort_index").alias("sortIndex").comment("排序序号").jdbcType(java.sql.JDBCType.DECIMAL).length(32, 0).commit()
-
+        .addColumn().name("validator").alias("validator").comment("验证器配置").jdbcType(java.sql.JDBCType.CLOB).commit()
         .comment("动态表单列").commit();
 
     database.createOrAlter("s_dyn_form_log")

+ 3 - 2
hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/test/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormServiceTest.java

@@ -15,6 +15,7 @@ import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.sql.Array;
 import java.sql.JDBCType;
 import java.sql.SQLException;
 import java.util.Arrays;
@@ -65,7 +66,7 @@ public class SimpleDynamicFormServiceTest extends SimpleWebApplicationTests {
         column_name.setJavaType("string");
         column_name.setJdbcType(JDBCType.VARCHAR.getName());
         column_name.setLength(32);
-
+        column_name.setValidator(Arrays.asList("{\"type\":\"NotBlank\",\"groups\":[\"create\"],\"message\":\"姓名不能为空\"}"));
         DynamicFormColumnEntity column_age = entityFactory.newInstance(DynamicFormColumnEntity.class);
         column_age.setName("年龄");
         column_age.setColumnName("age");
@@ -87,7 +88,7 @@ public class SimpleDynamicFormServiceTest extends SimpleWebApplicationTests {
 
         dynamicFormOperationService.insert(form.getId(), new HashMap<String, Object>() {
             {
-                put("name", "张三");
+//                put("name", "张三");
                 put("age", 10);
             }
         });