Commit cf451604 authored by 薛涛 Toby Xue's avatar 薛涛 Toby Xue 🆒

#1971

parent f80bd7c1
Pipeline #4313 canceled with stages
package logwire.web.bo;
import logwire.core.resource.JavaBeanContainer;
import logwire.core.resource.JavaBeanContainerBuilder;
import logwire.core.resource.Util;
import logwire.web.bo.loader.BoRelationBeanDefinitionLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class BoRelationBeanContainerBuilder implements JavaBeanContainerBuilder {
public static final String CONTAINER_NAME = "BO_RELATION_CONTAINER";
@Override
public JavaBeanContainer build(ApplicationContext applicationContext) {
return new JavaBeanContainer(Util.getExactBean(applicationContext, BoRelationBeanDefinitionLoader.class));
}
@Override
public String getContainerName() {
return CONTAINER_NAME;
}
}
package logwire.web.bo; package logwire.web.bo;
import logwire.core.exceptions.ApplicationException;
import logwire.web.bo.proxy.Proxy;
import logwire.web.service.query.QueryService; import logwire.web.service.query.QueryService;
import logwire.web.tenant.TenantProjectService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Map;
@Component @Component
public class BoService { public class BoService {
@Autowired @Autowired
QueryService queryService; QueryService queryService;
@Autowired
TenantProjectService tenantProjectService;
public Object createBizObject(Class clazz) {
Map<String, BoRelationDefinition> boRelationDefinitions = (Map<String, BoRelationDefinition>) tenantProjectService.getCurrentProject().getBeansByContainerName(BoRelationBeanContainerBuilder.CONTAINER_NAME);
BoRelationDefinition boRelationDefinition = boRelationDefinitions.get(clazz.getName());
if (boRelationDefinition != null) {
try {
return Proxy.createObjectOperationProvider(boRelationDefinition, boRelationDefinitions);
} catch (IllegalAccessException | InstantiationException e) {
throw ApplicationException.wrap(e);
}
}
return null;
}
} }
...@@ -2,19 +2,13 @@ package logwire.web.bo.field.parse; ...@@ -2,19 +2,13 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.BigIntegerField; import logwire.core.meta.model.fields.BigIntegerField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class BigIntegerFieldParser extends FieldParser<BigIntegerField> { public class BigIntegerFieldParser extends FieldParser<BigIntegerField> {
@Override @Override
protected BigIntegerField newField(Field field, Annotation[] annotations) { protected BigIntegerField newField(String name, Field field) {
return new BigIntegerField(field.getName()); return new BigIntegerField(name);
}
@Override
protected void setField(BigIntegerField newField, Annotation[] annotations) {
} }
private BigIntegerFieldParser() { private BigIntegerFieldParser() {
......
package logwire.web.bo.field.parse; package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.StringField; import logwire.core.meta.model.fields.MultipleChoiceField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class BizArrayFieldParser extends FieldParser<StringField> { public class BizArrayFieldParser extends FieldParser<MultipleChoiceField> {
@Override @Override
protected StringField newField(Field field, Annotation[] annotations) { protected MultipleChoiceField newField(String name, Field field) {
return new StringField(field.getName(), 100); return new MultipleChoiceField(name, 100);
} }
private BizArrayFieldParser() { private BizArrayFieldParser() {
......
...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse; ...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.BooleanField; import logwire.core.meta.model.fields.BooleanField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class BooleanFieldParser extends FieldParser<BooleanField> { public class BooleanFieldParser extends FieldParser<BooleanField> {
@Override @Override
protected BooleanField newField(Field field, Annotation[] annotations) { protected BooleanField newField(String name, Field field) {
return new BooleanField(field.getName()); return new BooleanField(name);
} }
private BooleanFieldParser() { private BooleanFieldParser() {
......
package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.ChoiceField;
import java.lang.reflect.Field;
public class ChoiceFieldParser extends FieldParser<ChoiceField> {
@Override
protected ChoiceField newField(String name, Field field) {
return new ChoiceField(name, 50);
}
private ChoiceFieldParser() {
}
public static ChoiceFieldParser getInstance() {
return ChoiceFieldParser.SingletonHolder.instance;
}
private static class SingletonHolder {
private static ChoiceFieldParser instance = new ChoiceFieldParser();
}
}
...@@ -2,14 +2,13 @@ package logwire.web.bo.field.parse; ...@@ -2,14 +2,13 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.DateTimeField; import logwire.core.meta.model.fields.DateTimeField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class DateTimeFieldParser extends FieldParser<DateTimeField> { public class DateTimeFieldParser extends FieldParser<DateTimeField> {
@Override @Override
protected DateTimeField newField(Field field, Annotation[] annotations) { protected DateTimeField newField(String name, Field field) {
return new DateTimeField(field.getName()); return new DateTimeField(name);
} }
private DateTimeFieldParser() { private DateTimeFieldParser() {
......
...@@ -2,14 +2,13 @@ package logwire.web.bo.field.parse; ...@@ -2,14 +2,13 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.DecimalField; import logwire.core.meta.model.fields.DecimalField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class DecimalFieldParser extends FieldParser<DecimalField> { public class DecimalFieldParser extends FieldParser<DecimalField> {
@Override @Override
protected DecimalField newField(Field field, Annotation[] annotations) { protected DecimalField newField(String name, Field field) {
return new DecimalField(field.getName(), 18, 6); return new DecimalField(name, 18, 6);
} }
private DecimalFieldParser() { private DecimalFieldParser() {
......
package logwire.web.bo.field.parse; package logwire.web.bo.field.parse;
import java.lang.annotation.Annotation; import logwire.core.bo.annotation.Array;
import logwire.core.bo.annotation.Column;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public abstract class FieldParser<T extends logwire.core.meta.model.fields.Field> { public abstract class FieldParser<T extends logwire.core.meta.model.fields.Field> {
protected abstract T newField(Field field, Annotation[] annotations); protected abstract T newField(String name, Field field);
public T parse(Field field, Annotation[] annotations) { public T parse(String name, Field field) {
T newField = newField(field, annotations); T newField = newField(name, field);
setField(newField, annotations); setField(newField, field);
return newField; return newField;
} }
protected void setField(T newField, Annotation[] annotations) { protected void setField(T newField, Field field) {
if (field.getAnnotation(Column.class) != null) {
int length = field.getAnnotation(Column.class).length();
if (length != 0) {
newField.setLength(length);
}
} else if (field.getAnnotation(Array.class) != null) {
int length = field.getAnnotation(Array.class).length();
if (length != 0) {
newField.setLength(length);
}
}
} }
......
package logwire.web.bo.field.parse; package logwire.web.bo.field.parse;
import logwire.core.bo.annotation.Choice;
import logwire.core.bo.annotation.ForeignKey;
import logwire.core.bo.field.BizArray; import logwire.core.bo.field.BizArray;
import logwire.core.bo.field.BizOne;
import logwire.core.exceptions.ApplicationException;
import java.lang.annotation.Annotation; import java.lang.reflect.Type;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
public abstract class FieldParserUtil { public abstract class FieldParserUtil {
...@@ -17,14 +21,30 @@ public abstract class FieldParserUtil { ...@@ -17,14 +21,30 @@ public abstract class FieldParserUtil {
* @param annotations * @param annotations
* @return * @return
*/ */
public static FieldParser getParser(java.lang.reflect.Field field, Annotation[] annotations) { public static FieldParser getParser(java.lang.reflect.Field field) {
return getParserByFieldType(field); if (field.getAnnotation(Choice.class) != null) {
if (field.getType().equals(String.class)) {
return ChoiceFieldParser.getInstance();
} else if (field.getType().equals(BizArray.class)) {
return BizArrayFieldParser.getInstance();
} else {
throw new ApplicationException("@Choice 只能用与 String/BizArray 类型");
}
} else if (field.getAnnotation(ForeignKey.class) != null) {
//弱关联
if (field.getType().equals(BizOne.class)) {
return ForeignKeyFieldParser.getInstance();
} else {
throw new ApplicationException("@ForeignKey 只能用与 BizOne 类型");
}
}
return getParserByFieldType(field.getType());
} }
private static FieldParser getParserByFieldType(java.lang.reflect.Field field) { public static FieldParser getParserByFieldType(Type clazz) {
// 此时一定是存在 Field 类型的 annotation // 此时一定是存在 Field 类型的 annotation
// 根据字段类型来推断 Parser // 根据字段类型来推断 Parser
Class clazz = field.getType();
if (clazz.equals(String.class)) { if (clazz.equals(String.class)) {
return StringFieldParser.getInstance(); return StringFieldParser.getInstance();
} else if (clazz.equals(Integer.class) || clazz.equals(int.class)) { } else if (clazz.equals(Integer.class) || clazz.equals(int.class)) {
...@@ -41,7 +61,9 @@ public abstract class FieldParserUtil { ...@@ -41,7 +61,9 @@ public abstract class FieldParserUtil {
return DecimalFieldParser.getInstance(); return DecimalFieldParser.getInstance();
} else if (clazz.equals(BizArray.class)) { } else if (clazz.equals(BizArray.class)) {
return BizArrayFieldParser.getInstance(); return BizArrayFieldParser.getInstance();
} else if (clazz.equals(BizOne.class)) {
return ForeignKeyFieldParser.getInstance();
} }
return null; throw new ApplicationException("该字段类型无法识别");
} }
} }
package logwire.web.bo.field.parse;
import logwire.core.bo.annotation.ForeignKey;
import logwire.core.bo.field.BizOne;
import logwire.core.exceptions.ApplicationException;
import logwire.core.meta.model.fields.ForeignKeyField;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ForeignKeyFieldParser extends FieldParser<ForeignKeyField> {
@Override
protected ForeignKeyField newField(String name, Field field) {
/**
*
* BizOne类型表示外键字段,
* TODO 若使用了@ForeignKey 弱关联
*
* */
if (field.getType().equals(BizOne.class)) {
if (field.getAnnotation(ForeignKey.class) != null) {
return new ForeignKeyField(name, field.getAnnotation(ForeignKey.class).referBoName());
} else {
Type genericType = field.getGenericType();
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];
return new ForeignKeyField(name, actualTypeArgument.getTypeName());
}
} else {
throw new ApplicationException("非BizOne类型不能作为外键");
}
}
private ForeignKeyFieldParser() {
}
public static ForeignKeyFieldParser getInstance() {
return ForeignKeyFieldParser.SingletonHolder.instance;
}
private static class SingletonHolder {
private static ForeignKeyFieldParser instance = new ForeignKeyFieldParser();
}
}
...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse; ...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.IntegerField; import logwire.core.meta.model.fields.IntegerField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class IntegerFieldParser extends FieldParser<IntegerField> { public class IntegerFieldParser extends FieldParser<IntegerField> {
@Override @Override
protected IntegerField newField(Field field, Annotation[] annotations) { protected IntegerField newField(String name, Field field) {
return new IntegerField(field.getName()); return new IntegerField(name);
} }
private IntegerFieldParser() { private IntegerFieldParser() {
......
...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse; ...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.SmallIntegerField; import logwire.core.meta.model.fields.SmallIntegerField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class SmallIntegerFieldParser extends FieldParser<SmallIntegerField> { public class SmallIntegerFieldParser extends FieldParser<SmallIntegerField> {
@Override @Override
protected SmallIntegerField newField(Field field, Annotation[] annotations) { protected SmallIntegerField newField(String name, Field field) {
return new SmallIntegerField(field.getName()); return new SmallIntegerField(name);
} }
private SmallIntegerFieldParser() { private SmallIntegerFieldParser() {
......
...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse; ...@@ -2,13 +2,12 @@ package logwire.web.bo.field.parse;
import logwire.core.meta.model.fields.StringField; import logwire.core.meta.model.fields.StringField;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class StringFieldParser extends FieldParser<StringField> { public class StringFieldParser extends FieldParser<StringField> {
@Override @Override
protected StringField newField(Field field, Annotation[] annotations) { protected StringField newField(String name, Field field) {
return new StringField(field.getName(), 50); return new StringField(name, 50);
} }
private StringFieldParser() { private StringFieldParser() {
......
package logwire.web.bo.handler; package logwire.web.bo.handler;
import logwire.core.bo.handler.TypeOperationHandler; import logwire.core.bo.handler.TypeOperationHandler;
import logwire.web.bo.BoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CreateOperationHandler implements TypeOperationHandler { public class CreateOperationHandler implements TypeOperationHandler {
@Autowired
BoService boService;
@Override @Override
public Object execute(Class aClass, Object... args) { public Object execute(Class clazz, Object... args) {
return null; return boService.createBizObject(clazz);
} }
@Override @Override
......
package logwire.web.bo.loader; package logwire.web.bo.loader;
import logwire.core.bo.annotation.BizModel; import logwire.core.bo.annotation.*;
import logwire.core.bo.annotation.Column; import logwire.core.bo.field.BizArray;
import logwire.core.bo.field.BizMany;
import logwire.core.bo.field.BizText;
import logwire.core.bo.object.BizObject; import logwire.core.bo.object.BizObject;
import logwire.core.exceptions.ApplicationException; import logwire.core.exceptions.ApplicationException;
import logwire.core.meta.model.Model; import logwire.core.meta.model.Model;
import logwire.core.meta.model.fields.*;
import logwire.core.meta.query.IQuery; import logwire.core.meta.query.IQuery;
import logwire.core.resource.BeanLoader; import logwire.core.resource.BeanLoader;
import logwire.core.resource.loader.JavaModelBeanLoader; import logwire.core.resource.loader.JavaModelBeanLoader;
...@@ -17,10 +20,11 @@ import org.springframework.beans.factory.config.BeanDefinition; ...@@ -17,10 +20,11 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -31,9 +35,9 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme ...@@ -31,9 +35,9 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme
/** /**
* load BoModel 的逻辑: * load BoModel 的逻辑:
* 1、先遍历出所有BizObject的子类 * 1、先遍历出所有 BizObject 的子类 得到集合
* 2、将直接继承BizObject的类初始化 * 2、筛选出当中使用 @BizModel 的类,构建 Model,字段包含父类的字段
* 3、剩余的类中,判断是否独立的model(包含BizModel注解),若是,生成Model;若不是,字段添加至父类的Model * 3、将集合中的剩余类的字段添加到父类对应的Model
* *
* @param project 当前租户 * @param project 当前租户
* @param input 待加载的资源 * @param input 待加载的资源
...@@ -43,21 +47,23 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme ...@@ -43,21 +47,23 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme
@Override @Override
public void load(TenantProject project, TenantProject input, Consumer<IQuery> consumer) throws Exception { public void load(TenantProject project, TenantProject input, Consumer<IQuery> consumer) throws Exception {
TenantClassLoader classLoader = project.getTenantBeanContext().getTenantClassLoader(); TenantClassLoader classLoader = project.getTenantBeanContext().getTenantClassLoader();
//先扫描到所有的 BizObject (BizObject的所有子类)
ClassPathScanningCandidateComponentProvider provider = loaderUtil.getScanningBeanProvider(); ClassPathScanningCandidateComponentProvider provider = loaderUtil.getScanningBeanProvider();
provider.setResourceLoader(new DefaultResourceLoader(classLoader)); provider.setResourceLoader(new DefaultResourceLoader(classLoader));
provider.addIncludeFilter(loaderUtil.getAbstractTypeFilter(BizObject.class)); provider.addIncludeFilter(loaderUtil.getAbstractTypeFilter(BizObject.class));
Set<BeanDefinition> beans = provider.findCandidateComponents("logwire.web.bo"); Map<Boolean, List<BeanDefinition>> isBizModel = provider.findCandidateComponents("logwire.web")
.stream()
List<BeanDefinition> bizModelList = beans.stream().filter(beanDefinition -> { .collect(Collectors.groupingBy(beanDefinition -> {
try { try {
Class<?> clazz = classLoader.loadClass(beanDefinition.getBeanClassName()); Class<?> clazz = classLoader.loadClass(beanDefinition.getBeanClassName());
BizModel bizModelAnnotation = clazz.getAnnotation(BizModel.class); BizModel bizModelAnnotation = clazz.getAnnotation(BizModel.class);
return bizModelAnnotation != null; return bizModelAnnotation != null;
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new ApplicationException(""); throw new ApplicationException("");
} }
}).collect(Collectors.toList()); }));
List<BeanDefinition> bizModelList = isBizModel.get(true);
for (BeanDefinition beanDefinition : bizModelList) { for (BeanDefinition beanDefinition : bizModelList) {
Class<?> clazz = classLoader.loadClass(beanDefinition.getBeanClassName()); Class<?> clazz = classLoader.loadClass(beanDefinition.getBeanClassName());
//独立model //独立model
...@@ -67,12 +73,7 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme ...@@ -67,12 +73,7 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme
model.setIncludeAuditFields(true); model.setIncludeAuditFields(true);
model.setIncludeVersionField(true); model.setIncludeVersionField(true);
model.setIncludeDomainField(true); model.setIncludeDomainField(true);
initField(clazz, model); initField(clazz, model, consumer);
/*
//todo
this.initIndex(clazz, model);
this.initSign(model);*/
consumer.accept(model); consumer.accept(model);
} }
...@@ -80,23 +81,105 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme ...@@ -80,23 +81,105 @@ public class BoModelBeanLoader extends BeanLoader<IQuery, TenantProject> impleme
} }
private void initField(Class<?> clazz, Model model) { private void initField(Class<?> clazz, Model model, Consumer consumer) {
//获取所有带有Column注解的字段
Field[] fields = clazz.getDeclaredFields(); Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) { for (Field f : fields) {
Column column = f.getAnnotation(Column.class); if (f.getAnnotation(Column.class) != null) {
if (column != null) { //带有Column注解的字段
Annotation[] annotations = f.getDeclaredAnnotations(); FieldParser parser = FieldParserUtil.getParser(f);
FieldParser parser = FieldParserUtil.getParser(f, annotations); logwire.core.meta.model.fields.Field field = parser.parse(f.getName(), f);
if (parser == null) {
continue;
}
logwire.core.meta.model.fields.Field field = parser.parse(f, annotations);
model.addField(field); model.addField(field);
} else if (f.getAnnotation(Text.class) != null) {
// 带有Text注解的字段 大文本属性会创建一张子表(Model),子表名为:BO表名_属性名,一个BO有多个大字段时,使用同一张表
if (f.getType() != BizText.class) {
throw new ApplicationException("@Text 字段类型必须为BizText");
}
newTextModel(model, f, consumer);
} else if (f.getAnnotation(Array.class) != null) {
// 带有Text注解的字段 大文本属性会创建一张子表(Model),子表名为:BO表名_属性名,一个BO有多个大字段时,使用同一张表
if (f.getType() != BizArray.class) {
throw new ApplicationException("@Array 字段类型必须为BizArray");
}
newArrayModel(model, f, consumer);
} else if (f.getAnnotation(Many.class) != null) {
// 带有Text注解的字段 大文本属性会创建一张子表(Model),子表名为:BO表名_属性名,一个BO有多个大字段时,使用同一张表
if (f.getType() != BizMany.class) {
throw new ApplicationException("@Many 字段类型必须为BizMany");
}
newManyModel(model, f, consumer);
} }
} }
} }
/**
* 数组字段值存到一个列中,用逗号分隔 字段:
* owner_id/所属对象ID (BigInt)
* value/值 (varchar/numeric/boolean/bigint/integer/timestamp)
* idx/顺序 Integer
*
* @param f
* @param consumer
*/
private void newArrayModel(Model model, Field f, Consumer consumer) {
Array array = f.getAnnotation(Array.class);
Model arrayModel = new Model();
arrayModel.setName(model.getName() + "_" + f.getName());
arrayModel.setVerboseName(array.label());
ForeignKeyField ownerId = new ForeignKeyField("owner_id", model.getName());
ownerId.setPrimaryKey(true);
arrayModel.addField(ownerId);
arrayModel.addField(new IntegerField("idx"));
Type actualTypeArguments = ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
FieldParser parser = FieldParserUtil.getParserByFieldType(actualTypeArguments);
logwire.core.meta.model.fields.Field valueField = parser.parse("value", f);
model.addField(valueField);
consumer.accept(model);
}
/**
* 大文本 字段:
* owner_id/所属对象ID (BigInt)
* field_name/字段名 varchar(50)
* value/值 (varchar/numeric/boolean/bigint/integer/timestamp)
*
* @param model
* @param f
* @param consumer
*/
private void newTextModel(Model model, Field f, Consumer consumer) {
Text text = f.getAnnotation(Text.class);
Model textModel = new Model();
textModel.setName(model.getName() + "_text");
textModel.setVerboseName(text.label());
ForeignKeyField ownerId = new ForeignKeyField("owner_id", model.getName());
ownerId.setPrimaryKey(true);
textModel.addField(ownerId);
textModel.addField(new StringField("field_name", 50));
textModel.addField(new TextField("value"));
consumer.accept(model);
}
/**
* 多对多关联属性 字段:
* id
* master_id 主表ID
* slave_id 从表ID
*
* @param model
* @param f
* @param consumer
*/
private void newManyModel(Model model, Field f, Consumer consumer) {
Many many = f.getAnnotation(Many.class);
Model manyModel = new Model();
manyModel.setName(model.getName() + "_" + f.getName());
manyModel.setVerboseName(many.label());
manyModel.addField(new AutoField());
manyModel.addField(new ForeignKeyField("master_id", model.getName()));
manyModel.addField(new ForeignKeyField("slave_id", many.referBoName()));
consumer.accept(model);
}
@Override @Override
public boolean accept(TenantProject input) { public boolean accept(TenantProject input) {
return true; return true;
......
...@@ -2,6 +2,7 @@ package logwire.web.bo.loader; ...@@ -2,6 +2,7 @@ package logwire.web.bo.loader;
import logwire.core.bo.eventhandler.OperationEventHandler; import logwire.core.bo.eventhandler.OperationEventHandler;
import logwire.core.bo.handler.OperationHandler; import logwire.core.bo.handler.OperationHandler;
import logwire.core.bo.handler.TypeOperationHandler;
import logwire.core.bo.object.BizObject; import logwire.core.bo.object.BizObject;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
...@@ -26,10 +27,18 @@ public class LoaderUtil { ...@@ -26,10 +27,18 @@ public class LoaderUtil {
} }
public boolean isAssignableFrom(Class<?> beanClass) {
return BizObject.class.isAssignableFrom(beanClass);
}
public boolean isBizObject(Class<?> beanClass) { public boolean isBizObject(Class<?> beanClass) {
return BizObject.class.isAssignableFrom(beanClass); return BizObject.class.isAssignableFrom(beanClass);
} }
public boolean isTypeOperationHandler(Class<?> beanClass) {
return TypeOperationHandler.class.isAssignableFrom(beanClass);
}
public boolean isOperationHandler(Class<?> beanClass) { public boolean isOperationHandler(Class<?> beanClass) {
return OperationHandler.class.isAssignableFrom(beanClass); return OperationHandler.class.isAssignableFrom(beanClass);
} }
...@@ -57,6 +66,12 @@ public class LoaderUtil { ...@@ -57,6 +66,12 @@ public class LoaderUtil {
super(useDefaultFilters); super(useDefaultFilters);
} }
/**
*
* //TODO 注释
* @param beanDefinition
* @return
*/
@Override @Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata(); AnnotationMetadata metadata = beanDefinition.getMetadata();
......
package logwire.web.bo.provider;
import logwire.core.bo.annotation.ObjectOperationProvider;
import logwire.core.bo.annotation.Operation;
import logwire.core.bo.object.BizObject;
//所有BO Object 默认Operation定义
@ObjectOperationProvider(type = BizObject.class)
public interface DefaultObjectOperationProvider {
@Operation()
void save();
@Operation()
void delete();
@Operation()
void update(String... fields);
// 更多操作定义
}
\ No newline at end of file
...@@ -15,7 +15,7 @@ public interface DefaultTypeOperationProvider { ...@@ -15,7 +15,7 @@ public interface DefaultTypeOperationProvider {
<X> X create(); <X> X create();
@Operation() @Operation()
<X> X create(Map defaultValues); <X> X createWithDefault(Map defaultValues);
@Operation() @Operation()
<X> X create(String query); <X> X create(String query);
...@@ -42,7 +42,7 @@ public interface DefaultTypeOperationProvider { ...@@ -42,7 +42,7 @@ public interface DefaultTypeOperationProvider {
<X extends BizObject> BizList<X> createList(Map fields); <X extends BizObject> BizList<X> createList(Map fields);
@Operation() @Operation()
<X extends BizObject> BizList<X> findAll(Map fields); <X extends BizObject, T extends BizList<X>> T findAll(Map fields);
@Operation() @Operation()
<X extends BizObject> BizList<X> findAll(String query); <X extends BizObject> BizList<X> findAll(String query);
......
package logwire.web.bo.proxy;
import logwire.core.bo.handler.Handler;
import logwire.core.bo.object.BizObject;
import logwire.web.bo.BoRelationDefinition;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.SuperMethod;
import net.bytebuddy.implementation.bind.annotation.This;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class ObjectOperationInterceptor {
private static final Logger logger = LoggerFactory.getLogger(TypeOperationInterceptor.class);
private BoRelationDefinition boRelationDefinition;
public ObjectOperationInterceptor(BoRelationDefinition boRelationDefinition) {
this.boRelationDefinition = boRelationDefinition;
}
public Object interceptor(@This Object proxy, @Origin Method method,
@SuperMethod Method superMethod,
@AllArguments Object[] args) throws Exception {
if (superMethod != null) {
return superMethod.invoke(boRelationDefinition.getBoClass().getSuperclass().getField("service"), args);
}
return doHandler(method, args);
}
/**
* 根据methodName执行对应的handler
*/
private Object doHandler(Method method, Object[] args) {
Class<? extends BizObject> bizClazz = boRelationDefinition.getBoClass();
String operationName = method.getName();
logger.debug("Execute operation {} start", new Object[]{operationName});
getHandler(operationName, boRelationDefinition.getTypeOperationEventHandlers(),
typeOperationEventHandler -> !typeOperationEventHandler.isAfter())
.doBefore(bizClazz, args);
Object result = getHandler(operationName, boRelationDefinition.getTypeOperationHandlers(),
typeOperationHandler -> typeOperationHandler.accept(bizClazz, args))
.execute(bizClazz, args);
getHandler(operationName, boRelationDefinition.getTypeOperationEventHandlers(),
typeOperationEventHandler -> typeOperationEventHandler.isAfter())
.doAfter(bizClazz, result, args);
return result;
}
private <T extends Handler> T getHandler(String operation, List<T> handlers, Function<T, Boolean> function) {
return handlers.stream()
.filter(handler -> operation.equals(handler.getOperation()) && function.apply(handler))
.max(Comparator.comparing(T::getOrder)).get();
}
}
package logwire.web.bo.proxy; package logwire.web.bo.proxy;
import com.google.common.collect.Lists;
import logwire.core.bo.handler.ObjectOperationHandler;
import logwire.core.bo.object.BizObject; import logwire.core.bo.object.BizObject;
import logwire.web.bo.BoRelationDefinition; import logwire.web.bo.BoRelationDefinition;
import logwire.web.bo.provider.DefaultTypeOperationProvider; import logwire.web.bo.provider.DefaultTypeOperationProvider;
...@@ -7,9 +9,11 @@ import net.bytebuddy.ByteBuddy; ...@@ -7,9 +9,11 @@ import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.matcher.ElementMatchers;
import java.util.List;
import java.util.Map;
public class Proxy { public class Proxy {
/** /**
*
* 初始化 BO的 service : TypeOperationProvider * 初始化 BO的 service : TypeOperationProvider
* *
* @param boRelationDefinition * @param boRelationDefinition
...@@ -19,21 +23,41 @@ public class Proxy { ...@@ -19,21 +23,41 @@ public class Proxy {
* @throws NoSuchFieldException * @throws NoSuchFieldException
*/ */
public static Object createTypeOperationProvider(BoRelationDefinition boRelationDefinition) throws IllegalAccessException, InstantiationException, NoSuchFieldException { public static Object createTypeOperationProvider(BoRelationDefinition boRelationDefinition) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<? extends BizObject> beanClass = boRelationDefinition.getBoClass(); Class<? extends BizObject> boClass = boRelationDefinition.getBoClass();
// 动态生成service // 动态生成service
// 若直接继承了BizObject,则动态代理继承DefaultTypeOperationProvider,否则继承父类中的service对应的TypeOperationProvider // 若直接继承了BizObject,则动态代理继承DefaultTypeOperationProvider,
// 否则继承父类中的service对应的TypeOperationProvider
Class superClass = DefaultTypeOperationProvider.class; Class superClass = DefaultTypeOperationProvider.class;
if (beanClass.getSuperclass() != BizObject.class) { if (boClass.getSuperclass() != BizObject.class) {
// parent TypeOperationProvider // parent TypeOperationProvider
superClass = beanClass.getSuperclass().getField("serivce").getClass(); superClass = boClass.getSuperclass().getField("service").getClass();
} }
return new ByteBuddy().subclass(superClass) return new ByteBuddy().subclass(superClass)
.implement(boRelationDefinition.getTypeOperationProviders()) .implement(boRelationDefinition.getTypeOperationProviders())
.method(ElementMatchers.any()) .method(ElementMatchers.any())
.intercept(MethodDelegation.to(new TypeOperationInterceptor(boRelationDefinition))) .intercept(MethodDelegation.to(new TypeOperationInterceptor(boRelationDefinition)))
.make() .make()
.load(beanClass.getClassLoader()) .load(boClass.getClassLoader())
.getLoaded().newInstance();
}
public static Object createObjectOperationProvider(BoRelationDefinition boRelationDefinition, Map<String, BoRelationDefinition> boRelationDefinitions) throws IllegalAccessException, InstantiationException {
Class<? extends BizObject> boClass = boRelationDefinition.getBoClass();
Class boSuperClass = boClass.getSuperclass();
List<ObjectOperationHandler> interfaces = Lists.newArrayList(boRelationDefinition.getObjectOperationHandlers());
while (boSuperClass != BizObject.class) {
interfaces.addAll(boRelationDefinitions.get(boSuperClass.getName()).getObjectOperationHandlers());
boSuperClass = boSuperClass.getSuperclass();
}
return new ByteBuddy().subclass(boClass.getSuperclass())
.implement(boRelationDefinition.getObjectOperationProviders())
.method(ElementMatchers.any())
.intercept(MethodDelegation.to(new ObjectOperationInterceptor(boRelationDefinition)))
.make()
.load(boClass.getClassLoader())
.getLoaded().newInstance(); .getLoaded().newInstance();
} }
} }
...@@ -32,7 +32,7 @@ public class TypeOperationInterceptor { ...@@ -32,7 +32,7 @@ public class TypeOperationInterceptor {
@SuperMethod Method superMethod, @SuperMethod Method superMethod,
@AllArguments Object[] args) throws Exception { @AllArguments Object[] args) throws Exception {
if (superMethod != null) { if (superMethod != null) {
return superMethod.invoke(proxy, args); return superMethod.invoke(boRelationDefinition.getBoClass().getSuperclass().getField("service"), args);
} }
return doHandler(method, args); return doHandler(method, args);
} }
...@@ -62,7 +62,7 @@ public class TypeOperationInterceptor { ...@@ -62,7 +62,7 @@ public class TypeOperationInterceptor {
private <T extends Handler> T getHandler(String operation, List<T> handlers, Function<T, Boolean> function) { private <T extends Handler> T getHandler(String operation, List<T> handlers, Function<T, Boolean> function) {
return handlers.stream() return handlers.stream()
.filter(handler -> operation.equals(handler.getOperation()) && function.apply(handler)) .filter(handler -> operation.equals(handler.getOperation()) && function.apply(handler))
.max(Comparator.comparing(T::getOrder)).get(); .min(Comparator.comparing(T::getOrder)).get();
} }
} }
......
...@@ -159,10 +159,10 @@ public class Session { ...@@ -159,10 +159,10 @@ public class Session {
for (int i = 0; i < this.bizObjects.size(); i++) { for (int i = 0; i < this.bizObjects.size(); i++) {
BizObject t = this.bizObjects.get(i); BizObject t = this.bizObjects.get(i);
if (QueryTransactionCode.TX_INSERT.equals(t.getTxCode())) { if (QueryTransactionCode.TX_INSERT.equals(t.getTxCode())) {
List<BizObject> list = insertBizObjects.get(t.getModelName()); List<BizObject> list = insertBizObjects.get(t.getBoName());
if (list == null) { if (list == null) {
list = Lists.newArrayList(); list = Lists.newArrayList();
insertBizObjects.put(t.getModelName(), list); insertBizObjects.put(t.getBoName(), list);
} }
list.add(t); list.add(t);
} else { } else {
...@@ -197,14 +197,14 @@ public class Session { ...@@ -197,14 +197,14 @@ public class Session {
} }
otherBizObjects.clear(); otherBizObjects.clear();
} }
logwire.web.biz.session.SessionHolder.clear(); SessionHolder.clear();
} }
private void persistedHeader(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) { private void persistedHeader(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) {
//明细表有增删改时,头表一定要修改(如果不是新增的头表)而不管主表的数据是否有变化 //明细表有增删改时,头表一定要修改(如果不是新增的头表)而不管主表的数据是否有变化
Map<String, Set<BizObject>> headers = itemHeaderRelations.get(t.getModelName()); Map<String, Set<BizObject>> headers = itemHeaderRelations.get(t.getBoName());
if (headers != null && !headers.isEmpty()) { if (headers != null && !headers.isEmpty()) {
Set<BizObject> set = headers.get(t.getPkValue()); Set<BizObject> set = headers.get(t.getId());
if (set == null || set.isEmpty()) { if (set == null || set.isEmpty()) {
return; return;
} }
...@@ -222,12 +222,10 @@ public class Session { ...@@ -222,12 +222,10 @@ public class Session {
private void persistedInsert(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) { private void persistedInsert(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) {
BizObjectAgent agent = getOperableAgent(t); BizObjectAgent agent = getOperableAgent(t);
TenantUser currentUser = SecurityUtil.currentUser(); TenantUser currentUser = SecurityUtil.currentUser();
if (BizObjectStatus.NEW_SAVE.equals(t.getBizObjectStatus())) { if (BizObjectStatus.NEW_SAVE.equals(t.getTxCode())) {
agent.setInternal(QueryTransactionCode.TX_FIELD_NAME, QueryTransactionCode.TX_INSERT); agent.setInternal(QueryTransactionCode.TX_FIELD_NAME, QueryTransactionCode.TX_INSERT);
// persistedBefore(t, itemHeaderRelations, queryService); TODO 新增明细表前先新增主表 // persistedBefore(t, itemHeaderRelations, queryService); TODO 新增明细表前先新增主表
actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_INSERT_BEFORE.name(), currentUser.getDomain(), t); queryService.insert(t.getBoName(), t.toMap());
queryService.insert(t.getModelName(), t.toMap());
actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_INSERT_AFTER.name(), currentUser.getDomain(), t);
persistedRecorder.accept(t); persistedRecorder.accept(t);
persistedHeader(t, queryService, persistedRecorder); persistedHeader(t, queryService, persistedRecorder);
} }
...@@ -351,15 +349,15 @@ public class Session { ...@@ -351,15 +349,15 @@ public class Session {
* @param fieldName * @param fieldName
*/ */
public void cache(BizObject t, String fieldName) { public void cache(BizObject t, String fieldName) {
Object pkValue = t.getPkValue(); Object pkValue = t.getId();
if (pkValue == null) { if (pkValue == null) {
return; return;
} }
//拿到存放某个 model 的主键缓存值的 map //拿到存放某个 model 的主键缓存值的 map
Map<String, Map<String, Set<Object>>> modelMap = pkCache.get(t.getModelName()); Map<String, Map<String, Set<Object>>> modelMap = pkCache.get(t.getBoName());
if (modelMap == null) { if (modelMap == null) {
modelMap = Maps.newHashMap(); modelMap = Maps.newHashMap();
pkCache.put(t.getModelName(), modelMap); pkCache.put(t.getBoName(), modelMap);
} }
//拿到存放通过某个 model 的 某个字段查询得到的主键后缓存值的 map //拿到存放通过某个 model 的 某个字段查询得到的主键后缓存值的 map
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment