diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java index ce99ab329..7f420a448 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java @@ -49,13 +49,11 @@ public class AutoDDLProcessor implements InitializingBean { @Override @SneakyThrows public void afterPropertiesSet() { - if (entityFactory instanceof MapperEntityFactory) { - MapperEntityFactory factory = ((MapperEntityFactory) entityFactory); - for (EntityInfo entity : entities) { - factory.addMapping(entity.getEntityType(), MapperEntityFactory.defaultMapper(entity.getRealType())); - } - } - List entities = this.entities.stream().map(EntityInfo::getRealType).collect(Collectors.toList()); + + List> entities = this.entities + .stream() + .map(e -> entityFactory.getInstanceType(e.getRealType(), true)) + .collect(Collectors.toList()); if (properties.isAutoDdl()) { //加载全部表信息 if (reactive) { @@ -63,7 +61,7 @@ public class AutoDDLProcessor implements InitializingBean { .doOnNext(type -> log.trace("auto ddl for {}", type)) .map(type -> { RDBTableMetadata metadata = resolver.resolve(type); - EntityDDLEvent event = new EntityDDLEvent(this,type,metadata); + EntityDDLEvent event = new EntityDDLEvent<>(this, type, metadata); eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); return metadata; }) @@ -83,7 +81,7 @@ public class AutoDDLProcessor implements InitializingBean { log.trace("auto ddl for {}", type); try { RDBTableMetadata metadata = resolver.resolve(type); - EntityDDLEvent event = new EntityDDLEvent(this,type,metadata); + EntityDDLEvent event = new EntityDDLEvent<>(this, type, metadata); eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); operator.ddl() .createOrAlter(metadata) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DetectEntityColumnMapping.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DetectEntityColumnMapping.java new file mode 100644 index 000000000..dbe2cf036 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DetectEntityColumnMapping.java @@ -0,0 +1,56 @@ +package org.hswebframework.web.crud.configuration; + +import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; +import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; +import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; + +import java.util.Map; +import java.util.Optional; + +class DetectEntityColumnMapping implements EntityColumnMapping { + private final String id; + private final Class type; + private final EntityColumnMapping mapping; + + public DetectEntityColumnMapping(Class type, + EntityColumnMapping mapping) { + this.id = MappingFeatureType.columnPropertyMapping.createFeatureId(type); + this.type = type; + this.mapping = mapping; + } + + @Override + public Class getEntityType() { + return type; + } + + @Override + public Optional getColumnByProperty(String property) { + return mapping.getColumnByProperty(property); + } + + @Override + public Optional getPropertyByColumnName(String columnName) { + return mapping.getPropertyByColumnName(columnName); + } + + @Override + public Optional getColumnByName(String columnName) { + return mapping.getColumnByName(columnName); + } + + @Override + public Map getColumnPropertyMapping() { + return mapping.getColumnPropertyMapping(); + } + + @Override + public String getId() { + return id; + } + + @Override + public String getName() { + return getId(); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java index 15714adf8..bedc725fd 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java @@ -6,6 +6,7 @@ import org.hswebframework.ezorm.core.meta.Feature; import org.hswebframework.ezorm.rdb.events.EventListener; import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.mapping.DefaultEntityColumnMapping; import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; import org.hswebframework.ezorm.rdb.mapping.EntityManager; import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; @@ -186,16 +187,25 @@ public class EasyormConfiguration { @Bean @ConditionalOnMissingBean public EntityTableMetadataParser jpaEntityTableMetadataParser(RDBDatabaseMetadata metadata, + EntityFactory factory, ObjectProvider customizers) { JpaEntityTableMetadataParser parser = new JpaEntityTableMetadataParser() { @Override public Optional parseTableMetadata(Class entityType) { - Optional tableOpt = super.parseTableMetadata(entityType); + Class realType = factory.getInstanceType(entityType, true); + Optional tableOpt = super.parseTableMetadata(realType); tableOpt.ifPresent(table -> { + if (realType != entityType) { + table.addFeature(new DetectEntityColumnMapping( + entityType, + table.findFeatureNow( + MappingFeatureType.columnPropertyMapping.createFeatureId(realType) + ))); + } for (TableMetadataCustomizer customizer : customizers) { - customizer.customTable(entityType, table); + customizer.customTable(realType, table); } }); return tableOpt; @@ -203,7 +213,8 @@ public class EasyormConfiguration { @Override protected JpaEntityTableMetadataParserProcessor createProcessor(RDBTableMetadata table, Class type) { - return new JpaEntityTableMetadataParserProcessor(table, type) { + Class realType = factory.getInstanceType(type, true); + return new JpaEntityTableMetadataParserProcessor(table, realType) { @Override protected void customColumn(PropertyDescriptor descriptor, Field field, @@ -211,7 +222,7 @@ public class EasyormConfiguration { Set annotations) { super.customColumn(descriptor, field, column, annotations); for (TableMetadataCustomizer customizer : customizers) { - customizer.customColumn(type, descriptor, field, annotations, column); + customizer.customColumn(realType, descriptor, field, annotations, column); } } }; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormRepositoryRegistrar.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormRepositoryRegistrar.java index 2beddadfc..bd6575bb7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormRepositoryRegistrar.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormRepositoryRegistrar.java @@ -46,8 +46,10 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar private String getResourceClassName(Resource resource) { try { - return metadataReaderFactory.getMetadataReader(resource) - .getClassMetadata().getClassName(); + return metadataReaderFactory + .getMetadataReader(resource) + .getClassMetadata() + .getClassName(); } catch (IOException e) { return null; } @@ -98,46 +100,31 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar for (String className : scanEntities(arr)) { Class entityType = org.springframework.util.ClassUtils.forName(className, null); if (Arrays.stream(anno) - .noneMatch(ann -> AnnotationUtils.findAnnotation(entityType, ann) != null)) { + .noneMatch(ann -> AnnotationUtils.getAnnotation(entityType, ann) != null)) { continue; } - ImplementFor implementFor = AnnotationUtils.findAnnotation(entityType, ImplementFor.class); Reactive reactive = AnnotationUtils.findAnnotation(entityType, Reactive.class); - Class genericType = Optional - .ofNullable(implementFor) - .map(ImplementFor::value) - .orElseGet(() -> { - return Stream - .of(entityType.getInterfaces()) - .filter(e -> GenericEntity.class.isAssignableFrom(e)) - .findFirst() - .orElse(entityType); - }); Class idType = null; - if (implementFor == null || implementFor.idType() == Void.class) { - try { - if (GenericEntity.class.isAssignableFrom(entityType)) { - idType = ClassUtils.getGenericType(entityType); - } - if (idType == null) { - Method getId = org.springframework.util.ClassUtils.getMethod(entityType, "getId"); - idType = getId.getReturnType(); - } - } catch (Exception e) { - idType = String.class; + try { + if (GenericEntity.class.isAssignableFrom(entityType)) { + idType = ClassUtils.getGenericType(entityType); } - } else { - idType = implementFor.idType(); + if (idType == null) { + Method getId = org.springframework.util.ClassUtils.getMethod(entityType, "getId"); + idType = getId.getReturnType(); + } + } catch (Exception e) { + idType = String.class; } - EntityInfo entityInfo = new EntityInfo(genericType, + EntityInfo entityInfo = new EntityInfo(entityType, entityType, idType, reactiveEnabled, nonReactiveEnabled); - if (!entityInfos.contains(entityInfo) || implementFor != null) { + if (!entityInfos.contains(entityInfo)) { entityInfos.add(entityInfo); } @@ -187,15 +174,6 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar registry.registerBeanDefinition(AutoDDLProcessor.class.getName() + "_" + count.incrementAndGet(), definition); } -// try { -// BeanDefinition definition = registry.getBeanDefinition(AutoDDLProcessor.class.getName()); -// Set infos = (Set) definition.getPropertyValues().get("entities"); -// infos.addAll(entityInfos); -// } catch (NoSuchBeanDefinitionException e) { -// -// } - - } static AtomicInteger count = new AtomicInteger(); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EntityInfo.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EntityInfo.java index 179dd4c3f..c9ca892f6 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EntityInfo.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EntityInfo.java @@ -10,11 +10,11 @@ import lombok.Setter; @EqualsAndHashCode(of = "entityType") @AllArgsConstructor public class EntityInfo { - private Class entityType; + private Class entityType; - private Class realType; + private Class realType; - private Class idType; + private Class idType; private boolean reactive; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java index 1d2667584..c61c6f805 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java @@ -73,6 +73,11 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { return this; } + public MapperEntityFactory addMappingIfAbsent(Class target, Mapper mapper) { + realTypeMapper.putIfAbsent(target, mapper); + return this; + } + public MapperEntityFactory addCopier(PropertyCopier copier) { Class source = (Class) ClassUtils.getGenericType(copier.getClass(), 0); Class target = (Class) ClassUtils.getGenericType(copier.getClass(), 1); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java index b8dfee3a2..983e57bf4 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java @@ -8,13 +8,14 @@ import org.hswebframework.ezorm.core.DefaultValue; import org.hswebframework.ezorm.core.DefaultValueGenerator; import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; import org.hswebframework.web.id.IDGenerator; +import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @Slf4j -public class DefaultIdGenerator implements DefaultValueGenerator { +public class DefaultIdGenerator implements DefaultValueGenerator { @Getter @Setter @@ -32,14 +33,10 @@ public class DefaultIdGenerator implements DefaultValueGeneratorMono.justOrEmpty(metadata.findFeature(DefaultValueGenerator.createId(id)))) - .doOnNext(gen-> log.debug("use default id generator : {} for column : {}", gen.getSortId(), metadata.getFullName())) - .map(gen->gen.generate(metadata)) - .switchIfEmpty(Mono.error(()->new UnsupportedOperationException("不支持的生成器:" + defaultId))) - .toFuture() - .get(); + String genId = mappings.getOrDefault(metadata.getOwner().getName(), defaultId); + DefaultValueGenerator generator = metadata.findFeatureNow(DefaultValueGenerator.createId(genId)); + log.debug("use default id generator : {} for column : {}", generator.getSortId(), metadata.getFullName()); + return generator.generate(metadata); } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/CrudTests.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/CrudTests.java index becf82e82..e172ea4ab 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/CrudTests.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/CrudTests.java @@ -1,5 +1,6 @@ package org.hswebframework.web.crud; +import org.hswebframework.web.crud.entity.CustomTestEntity; import org.hswebframework.web.crud.entity.TestEntity; import org.hswebframework.web.crud.service.TestEntityService; import org.junit.Assert; @@ -13,22 +14,31 @@ import reactor.test.StepVerifier; @SpringBootTest @RunWith(SpringJUnit4ClassRunner.class) -public class CrudTests { +public class CrudTests { @Autowired private TestEntityService service; @Test - public void test(){ - - TestEntity entity = TestEntity.of("test",100); + public void test() { + CustomTestEntity entity = new CustomTestEntity(); + entity.setExt("xxx"); + entity.setAge(1); + entity.setName("test"); + Mono.just(entity) - .as(service::insert) - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .cast(TestEntity.class) + .as(service::insert) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); Assert.assertNotNull(entity.getId()); + + service.findById(entity.getId()) + .as(StepVerifier::create) + .expectNextMatches(e -> e instanceof CustomTestEntity) + .verifyComplete(); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/TestApplication.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/TestApplication.java index 1b2c011f3..ebe8f483b 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/TestApplication.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/TestApplication.java @@ -1,7 +1,9 @@ package org.hswebframework.web.crud; import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.hswebframework.web.crud.entity.factory.EntityMappingCustomizer; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -13,7 +15,9 @@ import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; public class TestApplication { @Bean - public EntityFactory entityFactory(){ - return new MapperEntityFactory(); + public EntityFactory entityFactory(ObjectProvider customizers) { + MapperEntityFactory factory = new MapperEntityFactory(); + customizers.forEach(customizer -> customizer.custom(factory)); + return factory; } } diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/CustomTestEntity.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/CustomTestEntity.java new file mode 100644 index 000000000..a66d07edb --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/CustomTestEntity.java @@ -0,0 +1,26 @@ +package org.hswebframework.web.crud.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.bean.ToString; +import org.hswebframework.web.crud.generator.Generators; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Table; + +@Getter +@Setter +@AllArgsConstructor(staticName = "of") +@NoArgsConstructor +public class CustomTestEntity extends TestEntity { + + + @Column + @ToString.Ignore + private String ext; + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestEntity.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestEntity.java index 7ab89919d..f34e50de0 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestEntity.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestEntity.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; import org.hswebframework.web.crud.generator.Generators; import javax.persistence.Column; @@ -16,6 +17,7 @@ import javax.persistence.Table; @Table(name = "s_test") @AllArgsConstructor(staticName = "of") @NoArgsConstructor +@EnableEntityEvent public class TestEntity extends GenericEntity { @Column(length = 32) diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/CustomTestCustom.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/CustomTestCustom.java new file mode 100644 index 000000000..0f60ec701 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/CustomTestCustom.java @@ -0,0 +1,15 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.web.crud.entity.CustomTestEntity; +import org.hswebframework.web.crud.entity.TestEntity; +import org.hswebframework.web.crud.entity.factory.EntityMappingCustomizer; +import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; +import org.springframework.stereotype.Component; + +@Component +public class CustomTestCustom implements EntityMappingCustomizer { + @Override + public void custom(MapperEntityFactory factory) { + factory.addMapping(TestEntity.class, new MapperEntityFactory.Mapper<>(CustomTestEntity.class,CustomTestEntity::new)); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestEntityService.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestEntityService.java index 236a8d8a4..e813fa099 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestEntityService.java @@ -1,10 +1,19 @@ package org.hswebframework.web.crud.service; import org.hswebframework.web.crud.entity.TestEntity; +import org.hswebframework.web.crud.events.EntityCreatedEvent; import org.hswebframework.web.id.IDGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; @Service public class TestEntityService extends GenericReactiveCrudService { + + @EventListener + public void handleEvent(EntityCreatedEvent event){ + + System.out.println(event.getEntity()); + } }