From 75c7af8b12fc4357c81ea6e2913153bf7e0a2ec0 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 2 Jul 2018 18:05:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8A=A8=E6=80=81=E8=A1=A8?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/form/DynamicFormColumnEntity.java | 7 + .../form/SimpleDynamicFormColumnEntity.java | 30 ++-- .../service/form/OptionalConvertBuilder.java | 3 + .../form/simple/SimpleDynamicFormService.java | 24 ++- .../dict/DefaultOptionalConvertBuilder.java | 13 ++ ...tionaryOptionalConvertBuilderStrategy.java | 14 +- .../dict/OptionalConvertBuilderStrategy.java | 5 +- .../validator/DynamicBeanValidator.java | 30 +--- .../DynamicBeanValidatorFactory.java | 147 ++++++++++++++++-- .../validator/JSR303AnnotationInfo.java | 14 ++ .../JSR303AnnotationParserStrategy.java | 14 ++ .../validator/jsr303/AbstractStrategy.java | 109 +++++++++++++ .../validator/jsr303/EmailStrategy.java | 28 ++++ .../validator/jsr303/LengthStrategy.java | 27 ++++ .../validator/jsr303/NotBlankStrategy.java | 21 +++ .../validator/jsr303/NotNullStrategy.java | 20 +++ .../validator/jsr303/RangeStrategy.java | 26 ++++ .../mappers/form/DynamicFormColumnMapper.xml | 1 + .../src/main/resources/hsweb-starter.js | 2 +- .../simple/SimpleDynamicFormServiceTest.java | 5 +- 20 files changed, 477 insertions(+), 63 deletions(-) create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationInfo.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationParserStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/AbstractStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/EmailStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/LengthStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotBlankStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotNullStrategy.java create mode 100644 hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/RangeStrategy.java diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/DynamicFormColumnEntity.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/DynamicFormColumnEntity.java index 89d1cdb4b..8c0cd74ec 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/DynamicFormColumnEntity.java +++ b/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 { Long getSortIndex(); void setSortIndex(Long sortIndex); + + List getValidator(); + + void setValidator(List validator); + } \ No newline at end of file diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/SimpleDynamicFormColumnEntity.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/SimpleDynamicFormColumnEntity.java index bbf6f7e34..c085f4e52 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/entity/form/SimpleDynamicFormColumnEntity.java +++ b/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 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 validator; } \ No newline at end of file diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/service/form/OptionalConvertBuilder.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/service/form/OptionalConvertBuilder.java index 63e83f567..3c0a79126 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-api/src/main/java/org/hswebframework/web/service/form/OptionalConvertBuilder.java +++ b/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); } diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormService.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormService.java index 9d36b72d9..fcff300a1 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormService.java +++ b/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 initializeCustomers; + @Autowired + private ValidatorFactory validatorFactory; + + @Autowired(required = false) + private ObjectWrapperFactory objectWrapperFactory; + @Override protected IDGenerator getIDGenerator() { return IDGenerator.MD5; @@ -355,6 +364,8 @@ public class SimpleDynamicFormService extends GenericEntityService { RDBColumnMetaData columnMeta = new RDBColumnMetaData(); columnMeta.setName(column.getColumnName()); @@ -444,6 +456,9 @@ public class SimpleDynamicFormService extends GenericEntityService() : 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(() -> (List) Arrays.asList(javaType.getEnumConstants())); } switch (jdbcType) { case BLOB: diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DefaultOptionalConvertBuilder.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DefaultOptionalConvertBuilder.java index eefb8d38c..653db2460 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DefaultOptionalConvertBuilder.java +++ b/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); + } } diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DictionaryOptionalConvertBuilderStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DictionaryOptionalConvertBuilderStrategy.java index ceb3e0696..ac4bd4580 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/DictionaryOptionalConvertBuilderStrategy.java +++ b/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> 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> converter = + new EnumDictValueConverter<>(() -> dictDefineRepository.getDefine(dictId).getItems()); + + return converter; + } } diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/OptionalConvertBuilderStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/OptionalConvertBuilderStrategy.java index ceabe3321..295f4659e 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/dict/OptionalConvertBuilderStrategy.java +++ b/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); } diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidator.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidator.java index d9e253b09..c81f65855 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidator.java +++ b/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 beanSupplier; - public static void main(String[] args) { - MapBean bean = Proxy.create(MapBean.class) - .addField("private String name;", NotBlank.class, Maps.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 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 { diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidatorFactory.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidatorFactory.java index b93fd4113..62342233d 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/DynamicBeanValidatorFactory.java +++ b/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 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(); + } + + 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}"); } + builder.append("\nreturn null;\n}"); return builder.toString(); } + + protected List createValidatorAnnotation(Set 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) { - StringBuilder builder = new StringBuilder(); - Proxy 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;};"); - - + 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 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 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};"); } - proxy.addMethod(createSetPropertyCode(tableMetaData)); - return null; + keySet.append("}));\n}"); + + proxy.addMethod(keySet.toString()); + proxy.addMethod(createSetPropertyCode(tableMetaData)); + proxy.addMethod(createGetPropertyCode(tableMetaData)); + + //尝试一下能否创建实例 + MapBean mapBean = proxy.newInstance(); + Assert.notNull(mapBean, "创建验证器失败!"); + return new DynamicBeanValidator(proxy::newInstance); } } diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationInfo.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationInfo.java new file mode 100644 index 000000000..042ed8104 --- /dev/null +++ b/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 annotation; + + private Map properties; +} \ No newline at end of file diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationParserStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/JSR303AnnotationParserStrategy.java new file mode 100644 index 000000000..8044d68d4 --- /dev/null +++ b/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 configMap); +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/AbstractStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/AbstractStrategy.java new file mode 100644 index 000000000..02506e14a --- /dev/null +++ b/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 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 getAnnotationType(); + + @Getter + @Setter + public static class PropertyMapping { + private String name; + private Class type; + + public static PropertyMapping of(String name, Class type) { + PropertyMapping mapping = new PropertyMapping<>(); + + mapping.name = name; + mapping.type = type; + + return mapping; + } + + public static PropertyMapping of(String name, Class type, Function converter) { + PropertyMapping mapping = new PropertyMapping<>(); + mapping.name = name; + mapping.type = type; + mapping.converter = converter; + return mapping; + } + + private Function 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 configMap) { + JSR303AnnotationInfo info = new JSR303AnnotationInfo(); + info.setAnnotation(getAnnotationType()); + + Map properties = new HashMap<>(); + + propertyMappings.forEach(mapping -> { + Object value = mapping.getConverter().apply(configMap.get(mapping.getName())); + if (null != value) { + properties.put(mapping.getName(), value); + } + }); + + List 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; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/EmailStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/EmailStrategy.java new file mode 100644 index 000000000..3ebebb14e --- /dev/null +++ b/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 getAnnotationType() { + return Email.class; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/LengthStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/LengthStrategy.java new file mode 100644 index 000000000..7a9cf1a3b --- /dev/null +++ b/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 getAnnotationType() { + return Length.class; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotBlankStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotBlankStrategy.java new file mode 100644 index 000000000..f3404a759 --- /dev/null +++ b/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 getAnnotationType() { + return NotBlank.class; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotNullStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/NotNullStrategy.java new file mode 100644 index 000000000..a5b9e71c1 --- /dev/null +++ b/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 getAnnotationType() { + return NotNull.class; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/RangeStrategy.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/java/org/hswebframework/web/service/form/simple/validator/jsr303/RangeStrategy.java new file mode 100644 index 000000000..87d2ff4f2 --- /dev/null +++ b/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 getAnnotationType() { + return Range.class; + } +} diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/form/DynamicFormColumnMapper.xml b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/form/DynamicFormColumnMapper.xml index 20869dadf..fa7d7c7d4 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/form/DynamicFormColumnMapper.xml +++ b/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 @@ + diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/main/resources/hsweb-starter.js b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/main/resources/hsweb-starter.js index 4909ba0bf..ccf9fa7de 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/main/resources/hsweb-starter.js +++ b/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") diff --git a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/test/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormServiceTest.java b/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/test/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormServiceTest.java index 3022ee229..dd3db5634 100644 --- a/hsweb-system/hsweb-system-dynamic-form/hsweb-system-dynamic-form-starter/src/test/java/org/hswebframework/web/service/form/simple/SimpleDynamicFormServiceTest.java +++ b/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() { { - put("name", "张三"); +// put("name", "张三"); put("age", 10); } });