mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-06-20 14:56:06 +08:00
优化动态表单
This commit is contained in:
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
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<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) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
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;};");
|
||||
|
||||
|
||||
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};");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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所需的配置-->
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user