From 3b586cbbfd4332fa490649aecd9f4f248ab45b5f Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 11 Oct 2019 19:31:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=88=E4=B8=80=E6=B3=A2=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/aop/FluxTestController.java | 1 + .../web/api/crud/entity/Entity.java | 14 ++ .../web/api/crud/entity/GenericEntity.java | 2 +- .../web/api}/crud/entity/PagerResult.java | 2 +- .../api/crud/entity/TransactionManagers.java | 7 + hsweb-commons/hsweb-commons-crud/pom.xml | 5 + .../crud/configuration/AutoDDLProcessor.java | 18 +- .../configuration/EasyOrmConfiguration.java | 78 ++++---- .../EasyormRepositoryRegistrar.java | 36 ++-- .../JdbcSqlExecutorConfiguration.java | 33 ++++ .../R2dbcSqlExecutorConfiguration.java | 30 ++++ .../web/crud/entity/LogicalDeleteEntity.java | 19 -- .../web/crud/generator/MD5Generator.java | 5 +- .../generator/SnowFlakeStringIdGenerator.java | 6 +- .../web/crud/service/CrudService.java | 7 +- .../web/crud/service/GenericCrudService.java | 2 +- .../web/crud/service/ReactiveCrudService.java | 4 +- .../web/crud/sql/DefaultR2dbcExecutor.java | 1 + .../web/crud/web/QueryController.java | 9 + .../main/resources/META-INF/spring.factories | 4 +- .../hswebframework/web/crud/CrudTests.java | 5 + .../web/crud/TestApplication.java | 4 +- hsweb-core/pom.xml | 10 ++ .../web/bean/DefaultToStringOperator.java | 11 +- .../web/exception/ValidationException.java | 45 +++++ .../web/validator/ValidatorUtils.java | 38 ++++ .../web/starter/HswebAutoConfiguration.java | 6 +- .../web/system/authorization/api/User.java | 24 --- .../api/entity/ActionEntity.java | 0 .../entity/AuthorizationSettingEntity.java | 0 .../api/entity/DataAccessEntity.java | 0 .../api/entity/DimensionEntity.java | 1 - .../api/entity/DimensionUserEntity.java | 2 +- .../api/entity/OptionalField.java | 0 .../api/entity/ParentPermission.java | 0 .../api/entity/PermissionEntity.java | 0 .../authorization/api/entity/UserEntity.java | 23 ++- .../ClearUserAuthorizationCacheEvent.java | 17 ++ .../api/event/UserCreatedEvent.java | 15 ++ .../api/event/UserModifiedEvent.java | 21 +++ .../api/reactive/ReactiveUserService.java | 27 --- .../api/service/UserService.java | 38 ++++ .../service/reactive/ReactiveUserService.java | 30 ++++ .../pom.xml | 45 +++++ .../service/DefaultReactiveUserService.java | 166 ++++++++++++++++++ .../defaults/service/DefaultUserService.java | 144 +++++++++++++++ .../DefaultReactiveUserServiceTest.java | 60 +++++++ .../reactive/ReactiveTestApplication.java | 27 +++ .../service/sync/DefaultUserServiceTest.java | 46 +++++ .../service/sync/TestApplication.java | 21 +++ .../src/test/resources/application.yml | 11 ++ 51 files changed, 948 insertions(+), 172 deletions(-) rename hsweb-commons/{hsweb-commons-crud/src/main/java/org/hswebframework/web => hsweb-commons-api/src/main/java/org/hswebframework/web/api}/crud/entity/PagerResult.java (97%) create mode 100644 hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TransactionManagers.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/JdbcSqlExecutorConfiguration.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/R2dbcSqlExecutorConfiguration.java delete mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/LogicalDeleteEntity.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/QueryController.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java delete mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/User.java rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/ActionEntity.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java (92%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java (96%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/OptionalField.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/ParentPermission.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java (100%) rename hsweb-system/hsweb-system-authorization/{hsweb-system-authorization-default => hsweb-system-authorization-api}/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java (56%) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/ClearUserAuthorizationCacheEvent.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserCreatedEvent.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserModifiedEvent.java delete mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/reactive/ReactiveUserService.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/UserService.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultUserService.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveUserServiceTest.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/DefaultUserServiceTest.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/TestApplication.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/resources/application.yml diff --git a/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/FluxTestController.java b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/FluxTestController.java index 2934bd34a..26b619ae6 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/FluxTestController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/FluxTestController.java @@ -13,6 +13,7 @@ public class FluxTestController { @GetMapping public Mono getUser() { + return Authentication .currentReactive() .switchIfEmpty(Mono.error(UnAuthorizedException::new)); diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/Entity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/Entity.java index c254583b0..573203d38 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/Entity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/Entity.java @@ -19,6 +19,9 @@ package org.hswebframework.web.api.crud.entity; +import org.hswebframework.web.bean.FastBeanCopier; +import org.hswebframework.web.validator.ValidatorUtils; + import java.io.Serializable; /** @@ -29,5 +32,16 @@ import java.io.Serializable; */ public interface Entity extends Serializable { + default void tryValidate(Class... groups) { + ValidatorUtils.tryValidate(this, groups); + } + default T copyTo(Class target, String... ignoreProperties) { + return FastBeanCopier.copy(this, target, ignoreProperties); + } + + @SuppressWarnings("all") + default T copyFrom(Object target, String... ignoreProperties) { + return (T) FastBeanCopier.copy(target, this, ignoreProperties); + } } diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericEntity.java index 1b11c26f3..3755523e7 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericEntity.java @@ -34,7 +34,7 @@ import javax.persistence.Id; @Setter public class GenericEntity implements Entity { - @Column(length = 32) + @Column(length = 32,updatable = false) @Id private PK id; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/PagerResult.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java similarity index 97% rename from hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/PagerResult.java rename to hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java index 636aa68cf..57582cb7f 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/PagerResult.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java @@ -16,7 +16,7 @@ * */ -package org.hswebframework.web.crud.entity; +package org.hswebframework.web.api.crud.entity; import lombok.Getter; diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TransactionManagers.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TransactionManagers.java new file mode 100644 index 000000000..f4d608945 --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TransactionManagers.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.api.crud.entity; + +public interface TransactionManagers { + + String r2dbcTransactionManager = "connectionFactoryTransactionManager";// System.getProperty(""); + +} diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index ca1ae786d..750dfcb86 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -84,6 +84,11 @@ test + + org.springframework + spring-aspects + + org.hswebframework.web hsweb-commons-api 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 0836d65e4..7539beb7a 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 @@ -6,19 +6,20 @@ import lombok.extern.slf4j.Slf4j; import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; import org.hswebframework.web.api.crud.entity.EntityFactory; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.ReactiveTransactionManager; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; @Getter @Setter @Slf4j -public class AutoDDLProcessor { +public class AutoDDLProcessor implements InitializingBean { private Set entities = new HashSet<>(); @@ -36,7 +37,9 @@ public class AutoDDLProcessor { private boolean reactive; - public void init() { + + @Override + public void afterPropertiesSet() { if(entityFactory instanceof MapperEntityFactory){ MapperEntityFactory factory= ((MapperEntityFactory) entityFactory); @@ -44,7 +47,6 @@ public class AutoDDLProcessor { factory.addMapping(entity.getEntityType(),MapperEntityFactory.defaultMapper(entity.getRealType())); } } - if (properties.isAutoDdl()) { List entities = this.entities.stream().map(EntityInfo::getRealType).collect(Collectors.toList()); if(reactive){ @@ -64,7 +66,7 @@ public class AutoDDLProcessor { .commit() .sync(); } catch (Exception e) { - log.error(e.getMessage(), e); + log.warn(e.getMessage(), e); } } } 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 e39410be8..72f7f99bc 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 @@ -1,12 +1,10 @@ package org.hswebframework.web.crud.configuration; -import io.r2dbc.spi.ConnectionFactory; import lombok.SneakyThrows; import org.hswebframework.ezorm.core.meta.Feature; import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; -import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; import org.hswebframework.ezorm.rdb.mapping.EntityManager; import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; @@ -15,25 +13,23 @@ import org.hswebframework.ezorm.rdb.mapping.parser.EntityTableMetadataParser; import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata; import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator; +import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.hswebframework.web.crud.annotation.EnableEasyormRepository; +import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; import org.hswebframework.web.crud.generator.MD5Generator; import org.hswebframework.web.crud.generator.SnowFlakeStringIdGenerator; -import org.hswebframework.web.crud.sql.DefaultJdbcExecutor; -import org.hswebframework.web.crud.annotation.EnableEasyormRepository; -import org.hswebframework.web.api.crud.entity.EntityFactory; -import org.hswebframework.web.crud.sql.DefaultJdbcReactiveExecutor; -import org.hswebframework.web.crud.sql.DefaultR2dbcExecutor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; -import javax.sql.DataSource; import java.util.List; +import java.util.Optional; @Configuration @EnableConfigurationProperties(EasyormProperties.class) @@ -43,37 +39,10 @@ public class EasyOrmConfiguration { @Autowired private EasyormProperties properties; - @Configuration - @ConditionalOnBean(DataSource.class) - public static class JdbcSqlExecutorConfiguration { - @Bean - @ConditionalOnMissingBean - public SyncSqlExecutor syncSqlExecutor() { - return new DefaultJdbcExecutor(); - } - - @Bean - @ConditionalOnMissingBean - public ReactiveSqlExecutor reactiveSqlExecutor() { - return new DefaultJdbcReactiveExecutor(); - } - - } - - @Configuration - @ConditionalOnClass(ConnectionFactory.class) - public static class R2dbcSqlExecutorConfiguration { - @Bean - @ConditionalOnMissingBean - public ReactiveSqlExecutor reactiveSqlExecutor() { - return new DefaultR2dbcExecutor(); - } - - @Bean - @ConditionalOnMissingBean - public SyncSqlExecutor syncSqlExecutor(ReactiveSqlExecutor reactiveSqlExecutor) { - return ReactiveSyncSqlExecutor.of(reactiveSqlExecutor); - } + @Bean + @ConditionalOnMissingBean + public EntityFactory entityFactory(){ + return new MapperEntityFactory(); } @Bean @@ -121,17 +90,36 @@ public class EasyOrmConfiguration { @Bean @ConditionalOnMissingBean - public RDBDatabaseMetadata databaseMetadata(){ - return properties.createDatabaseMetadata(); + @SuppressWarnings("all") + public RDBDatabaseMetadata databaseMetadata(Optional syncSqlExecutor, + Optional reactiveSqlExecutor) { + RDBDatabaseMetadata metadata = properties.createDatabaseMetadata(); + syncSqlExecutor.ifPresent(metadata::addFeature); + reactiveSqlExecutor.ifPresent(metadata::addFeature); + + return metadata; } @Bean @ConditionalOnMissingBean - public DatabaseOperator databaseOperator(RDBDatabaseMetadata metadata, List features) { - features.forEach(metadata::addFeature); + public DatabaseOperator databaseOperator(RDBDatabaseMetadata metadata) { + return DefaultDatabaseOperator.of(metadata); } + @Bean + public BeanPostProcessor autoRegisterFeature(RDBDatabaseMetadata metadata) { + return new BeanPostProcessor() { + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof Feature) { + metadata.addFeature(((Feature) bean)); + } + return bean; + } + }; + } + @Bean public MD5Generator md5Generator(){ return new MD5Generator(); 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 1fafff9d5..d80bf0911 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 @@ -44,6 +44,13 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar Map attr = importingClassMetadata.getAnnotationAttributes(EnableEasyormRepository.class.getName()); if (attr == null) { return; + } + boolean reactivePrecent = false; + try { + Class.forName("io.r2dbc.spi.ConnectionFactory"); + reactivePrecent = true; + } catch (Exception e) { + } String[] arr = (String[]) attr.get("value"); String path = Arrays.stream(arr) @@ -94,19 +101,19 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar idType = implementFor.idType(); } - EntityInfo entityInfo = new EntityInfo(genericType, entityType, idType, reactive == null || reactive.enable()); + EntityInfo entityInfo = new EntityInfo(genericType, entityType, idType, reactivePrecent && (reactive == null || reactive.enable())); if (!entityInfos.contains(entityInfo) || implementFor != null) { entityInfos.add(entityInfo); } } - boolean reactive=false; + boolean reactive = false; for (EntityInfo entityInfo : entityInfos) { Class entityType = entityInfo.getEntityType(); Class idType = entityInfo.getIdType(); Class realType = entityInfo.getRealType(); if (entityInfo.isReactive()) { - reactive=true; + reactive = true; log.debug("register ReactiveRepository<{},{}>", entityType.getName(), idType.getSimpleName()); ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultReactiveRepository.class, entityType, idType); @@ -117,18 +124,18 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); definition.getPropertyValues().add("entityType", realType); registry.registerBeanDefinition(realType.getSimpleName().concat("ReactiveRepository"), definition); - } else { - log.debug("register SyncRepository<{},{}>", entityType.getName(), idType.getSimpleName()); - - ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultSyncRepository.class, entityType, idType); - - RootBeanDefinition definition = new RootBeanDefinition(); - definition.setTargetType(repositoryType); - definition.setBeanClass(SyncRepositoryFactoryBean.class); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - definition.getPropertyValues().add("entityType", realType); - registry.registerBeanDefinition(realType.getSimpleName().concat("SyncRepository"), definition); } + + log.debug("register SyncRepository<{},{}>", entityType.getName(), idType.getSimpleName()); + + ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultSyncRepository.class, entityType, idType); + + RootBeanDefinition definition = new RootBeanDefinition(); + definition.setTargetType(repositoryType); + definition.setBeanClass(SyncRepositoryFactoryBean.class); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + definition.getPropertyValues().add("entityType", realType); + registry.registerBeanDefinition(realType.getSimpleName().concat("SyncRepository"), definition); } RootBeanDefinition definition = new RootBeanDefinition(); @@ -137,7 +144,6 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); definition.getPropertyValues().add("entities", entityInfos); definition.getPropertyValues().add("reactive", reactive); - definition.setInitMethodName("init"); registry.registerBeanDefinition(AutoDDLProcessor.class.getName(), definition); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/JdbcSqlExecutorConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/JdbcSqlExecutorConfiguration.java new file mode 100644 index 000000000..92f9ecf17 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/JdbcSqlExecutorConfiguration.java @@ -0,0 +1,33 @@ +package org.hswebframework.web.crud.configuration; + +import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.web.crud.sql.DefaultJdbcExecutor; +import org.hswebframework.web.crud.sql.DefaultJdbcReactiveExecutor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +@AutoConfigureAfter(DataSourceAutoConfiguration.class) +@ConditionalOnBean(DataSource.class) +public class JdbcSqlExecutorConfiguration { + @Bean + @ConditionalOnMissingBean + public SyncSqlExecutor syncSqlExecutor() { + return new DefaultJdbcExecutor(); + } + + @Bean + @ConditionalOnMissingBean + public ReactiveSqlExecutor reactiveSqlExecutor() { + return new DefaultJdbcReactiveExecutor(); + } + +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/R2dbcSqlExecutorConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/R2dbcSqlExecutorConfiguration.java new file mode 100644 index 000000000..db7f8ded0 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/R2dbcSqlExecutorConfiguration.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.crud.configuration; + +import io.r2dbc.spi.ConnectionFactory; +import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; +import org.hswebframework.web.crud.sql.DefaultR2dbcExecutor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryAutoConfiguration") +@ConditionalOnBean(ConnectionFactory.class) +public class R2dbcSqlExecutorConfiguration { + @Bean + @ConditionalOnMissingBean + public ReactiveSqlExecutor reactiveSqlExecutor() { + return new DefaultR2dbcExecutor(); + } + + @Bean + @ConditionalOnMissingBean + public SyncSqlExecutor syncSqlExecutor(ReactiveSqlExecutor reactiveSqlExecutor) { + return ReactiveSyncSqlExecutor.of(reactiveSqlExecutor); + } +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/LogicalDeleteEntity.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/LogicalDeleteEntity.java deleted file mode 100644 index 75a6a5164..000000000 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/LogicalDeleteEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.hswebframework.web.crud.entity; - -/** - * 逻辑删除 - * - * @author zhouhao - * @since 3.0.6 - */ -public interface LogicalDeleteEntity { - - Boolean getDeleted(); - - void setDeleted(boolean deleted); - - Long getDeleteTime(); - - void setDeleteTime(Long deleteTime); - -} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/MD5Generator.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/MD5Generator.java index 1024e49a0..db836d162 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/MD5Generator.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/MD5Generator.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.generator; -import org.hswebframework.ezorm.core.DefaultValue; import org.hswebframework.ezorm.core.DefaultValueGenerator; import org.hswebframework.ezorm.core.RuntimeDefaultValue; import org.hswebframework.web.id.IDGenerator; @@ -12,8 +11,8 @@ public class MD5Generator implements DefaultValueGenerator { } @Override - public DefaultValue generate() { - return (RuntimeDefaultValue) IDGenerator.MD5::generate; + public RuntimeDefaultValue generate() { + return IDGenerator.MD5::generate; } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/SnowFlakeStringIdGenerator.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/SnowFlakeStringIdGenerator.java index 26db55191..6b0b2a995 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/SnowFlakeStringIdGenerator.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/SnowFlakeStringIdGenerator.java @@ -1,10 +1,8 @@ package org.hswebframework.web.crud.generator; -import org.hswebframework.ezorm.core.DefaultValue; import org.hswebframework.ezorm.core.DefaultValueGenerator; import org.hswebframework.ezorm.core.RuntimeDefaultValue; import org.hswebframework.web.id.IDGenerator; -import org.springframework.stereotype.Component; public class SnowFlakeStringIdGenerator implements DefaultValueGenerator { @Override @@ -13,8 +11,8 @@ public class SnowFlakeStringIdGenerator implements DefaultValueGenerator { } @Override - public DefaultValue generate() { - return (RuntimeDefaultValue) IDGenerator.SNOW_FLAKE_STRING::generate; + public RuntimeDefaultValue generate() { + return IDGenerator.SNOW_FLAKE_STRING::generate; } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/CrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/CrudService.java index 7a8264e8d..89ee96083 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/CrudService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/CrudService.java @@ -1,15 +1,17 @@ package org.hswebframework.web.crud.service; +import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.core.param.QueryParam; import org.hswebframework.ezorm.rdb.mapping.SyncDelete; import org.hswebframework.ezorm.rdb.mapping.SyncQuery; import org.hswebframework.ezorm.rdb.mapping.SyncRepository; import org.hswebframework.ezorm.rdb.mapping.SyncUpdate; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; -import org.hswebframework.web.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.PagerResult; import org.springframework.transaction.annotation.Transactional; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -36,6 +38,9 @@ public interface CrudService { @Transactional(readOnly = true) default List findById(Collection id) { + if (CollectionUtils.isEmpty(id)) { + return Collections.emptyList(); + } return getRepository() .findById(id); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericCrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericCrudService.java index 00acf84eb..5b519de3a 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericCrudService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericCrudService.java @@ -3,7 +3,7 @@ package org.hswebframework.web.crud.service; import org.hswebframework.ezorm.rdb.mapping.SyncRepository; import org.springframework.beans.factory.annotation.Autowired; -public class GenericCrudService implements CrudService { +public abstract class GenericCrudService implements CrudService { @Autowired private SyncRepository repository; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java index 466047dcd..1abb650be 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java @@ -6,9 +6,9 @@ import org.hswebframework.ezorm.rdb.mapping.ReactiveQuery; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; -import org.hswebframework.web.crud.entity.PagerResult; -import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.api.crud.entity.PagerResult; import org.reactivestreams.Publisher; +import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java index b169f5887..995a2af15 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java @@ -10,6 +10,7 @@ import org.hswebframework.web.datasource.R2dbcDataSource; import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils; +import org.springframework.transaction.NoTransactionException; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/QueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/QueryController.java new file mode 100644 index 000000000..4e66951cf --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/QueryController.java @@ -0,0 +1,9 @@ +package org.hswebframework.web.crud.web; + +import org.hswebframework.web.crud.service.CrudService; + +public interface QueryController { + + CrudService getService(); + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/META-INF/spring.factories b/hsweb-commons/hsweb-commons-crud/src/main/resources/META-INF/spring.factories index eb0efa4e6..36e4ec0d2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/resources/META-INF/spring.factories +++ b/hsweb-commons/hsweb-commons-crud/src/main/resources/META-INF/spring.factories @@ -1,3 +1,5 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.hswebframework.web.crud.configuration.EasyOrmConfiguration \ No newline at end of file +org.hswebframework.web.crud.configuration.EasyOrmConfiguration,\ +org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ +org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration \ No newline at end of file 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 c80f6b2b9..7ae8d079e 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 @@ -18,9 +18,14 @@ public class CrudTests { @Autowired private TestEntityService service; + @Autowired + private TestEntityService service2; + @Test public void test(){ + TestEntity entity = TestEntity.of("test",100); + Mono.just(entity) .as(service::insert) .as(StepVerifier::create) 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 a2289da27..1b2c011f3 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 @@ -3,10 +3,12 @@ package org.hswebframework.web.crud; import org.hswebframework.web.api.crud.entity.EntityFactory; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; -@SpringBootApplication +@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @Configuration public class TestApplication { diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index b5f4c2488..4a0b08c6c 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -74,6 +74,16 @@ ${hsweb.expands.version} true + + org.springframework + spring-aspects + + + + org.glassfish + javax.el + 3.0.0 + \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/DefaultToStringOperator.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/DefaultToStringOperator.java index 54d010bc5..adf25dd03 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/DefaultToStringOperator.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/DefaultToStringOperator.java @@ -36,7 +36,8 @@ public class DefaultToStringOperator implements ToStringOperator { private Map> converts; - private Function coverStringConvert = (o) -> coverString(String.valueOf(o), 50); + private Function coverStringConvert = (o) -> coverString(String.valueOf(o), 80); + private Function> simpleConvertBuilder = type -> { if (Date.class.isAssignableFrom(type)) { @@ -46,7 +47,7 @@ public class DefaultToStringOperator implements ToStringOperator { } }; - Predicate simpleTypePredicate = ((Predicate) String.class::isAssignableFrom) + private Predicate simpleTypePredicate = ((Predicate) String.class::isAssignableFrom) .or(Class::isEnum) .or(Class::isPrimitive) .or(Date.class::isAssignableFrom) @@ -115,7 +116,7 @@ public class DefaultToStringOperator implements ToStringOperator { try { Field field = ReflectionUtils.findField(targetType, descriptor.getName()); if (null == field) { - log.warn("无法获取字段{},该字段将不会被打码!", descriptor.getName()); + log.debug("无法获取字段{},该字段将不会被打码!", descriptor.getName()); } propertyIgnore = field.getAnnotation(ToString.Ignore.class); features = AnnotationUtils.getAnnotation(field, ToString.Features.class); @@ -128,7 +129,7 @@ public class DefaultToStringOperator implements ToStringOperator { propertyFeature = ToString.Feature.createFeatures(features.value()); } } catch (Exception e) { - log.warn("无法获取字段{},该字段将不会被打码!", descriptor.getName()); + log.debug("无法获取字段{},该字段将不会被打码!", descriptor.getName()); } //是否设置了打码 boolean cover = (propertyIgnore == null && defaultCover) || (propertyIgnore != null && propertyIgnore.cover()); @@ -232,7 +233,7 @@ public class DefaultToStringOperator implements ToStringOperator { } class ConvertConfig { - long features; + long features; Set ignoreProperty; } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java new file mode 100644 index 000000000..d49037fcf --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -0,0 +1,45 @@ +package org.hswebframework.web.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.ConstraintViolation; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@Getter +@Setter +public class ValidationException extends BusinessException { + + private List details; + + public ValidationException(String message) { + super(message); + } + + public ValidationException(String message, List details) { + super(message); + this.details = details; + } + + public ValidationException(String message, Set violations) { + super(message); + if (null != violations && !violations.isEmpty()) { + details = new ArrayList<>(); + for (ConstraintViolation violation : violations) { + details.add(new Detail(violation.getPropertyPath().toString(), violation.getMessage())); + } + } + } + + @Getter + @Setter + @AllArgsConstructor + public static class Detail { + String property; + + String message; + } +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java new file mode 100644 index 000000000..13b9a16a0 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -0,0 +1,38 @@ +package org.hswebframework.web.validator; + +import org.hswebframework.web.exception.ValidationException; + +import javax.el.ExpressionFactory; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import java.util.Set; + +public final class ValidatorUtils { + + private ValidatorUtils() { + } + + static volatile Validator validator; + + public static Validator getValidator() { + if (validator == null) { + synchronized (ValidatorUtils.class) { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + return validator = factory.getValidator(); + } + } + return validator; + } + + public static T tryValidate(T bean, Class... group) { + Set> violations = getValidator().validate(bean, group); + if (!violations.isEmpty()) { + throw new ValidationException(violations.iterator().next().getMessage(), violations); + } + + return bean; + } + +} diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/HswebAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/HswebAutoConfiguration.java index a4c35f51d..23690164f 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/HswebAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/HswebAutoConfiguration.java @@ -10,9 +10,5 @@ import org.springframework.context.annotation.Configuration; public class HswebAutoConfiguration { - @Bean - @ConditionalOnMissingBean - public EntityFactory entityFactory(){ - return new MapperEntityFactory(); - } + } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/User.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/User.java deleted file mode 100644 index 59b05352a..000000000 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/User.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.hswebframework.web.system.authorization.api; - - - -import lombok.Getter; -import lombok.Setter; - -import java.io.Serializable; - - -@Getter -@Setter -public class User implements Serializable { - - private String id; - - private String username; - - private String type; - - private Byte status; - - -} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/ActionEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/ActionEntity.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/ActionEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/ActionEntity.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java similarity index 92% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java index 9ae7f4768..faf5b505a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java @@ -17,7 +17,6 @@ import java.util.Map; @Getter @Setter @Table(name = "s_dimension",indexes = { - @Index(name = "idx_dims_ass_id",columnList = "association_relation,association_id"), @Index(name = "idx_dims_path",columnList = "path") }) public class DimensionEntity extends GenericTreeSortSupportEntity { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java similarity index 96% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java index 88c43fdab..0000def5f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java @@ -48,7 +48,7 @@ public class DimensionUserEntity extends GenericEntity { private String relationName; @Column(name = "features") - @ColumnType(jdbcType = JDBCType.NUMERIC) + @ColumnType(jdbcType = JDBCType.NUMERIC, javaType = Long.class) @EnumCodec(toMask = true) private DimensionUserFeature[] features; diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/OptionalField.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/OptionalField.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/OptionalField.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/OptionalField.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/ParentPermission.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/ParentPermission.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/ParentPermission.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/ParentPermission.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java similarity index 56% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java index fcf84cab9..bbdbf9026 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java @@ -1,39 +1,43 @@ package org.hswebframework.web.system.authorization.api.entity; -import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; import org.hswebframework.web.api.crud.entity.GenericEntity; import org.hswebframework.web.api.crud.entity.RecordCreationEntity; import org.hswebframework.web.bean.ToString; +import org.hswebframework.web.validator.CreateGroup; import javax.persistence.Column; +import javax.persistence.GeneratedValue; import javax.persistence.Index; import javax.persistence.Table; import javax.validation.constraints.NotBlank; @Getter @Setter -@Table(name = "s_user", indexes = -@Index(name = "user_username_idx", columnList = "username", unique = true) +@Table(name = "s_user", + indexes = @Index(name = "user_username_idx", columnList = "username", unique = true) ) -public class UserEntity extends GenericEntity implements RecordCreationEntity { +public class UserEntity extends GenericEntity implements RecordCreationEntity { @Column(length = 128, nullable = false) - @NotBlank(message = "姓名不能为空") + @NotBlank(message = "姓名不能为空", groups = CreateGroup.class) private String name; @Column(length = 128, nullable = false, updatable = false) + @NotBlank(message = "用户名不能为空", groups = CreateGroup.class) private String username; @Column(nullable = false) @ToString.Ignore(cover = false) - @JsonIgnore + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @NotBlank(message = "密码不能为空", groups = CreateGroup.class) private String password; @Column(nullable = false) @ToString.Ignore(cover = false) - @JsonIgnore + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String salt; @Column @@ -48,4 +52,9 @@ public class UserEntity extends GenericEntity implements RecordCreation @Column(name = "create_time", updatable = false) private Long createTime; + @Override + @GeneratedValue(generator = "md5") + public String getId() { + return super.getId(); + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/ClearUserAuthorizationCacheEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/ClearUserAuthorizationCacheEvent.java new file mode 100644 index 000000000..d366b080f --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/ClearUserAuthorizationCacheEvent.java @@ -0,0 +1,17 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author zhouhao + * @see org.springframework.context.event.EventListener + * @since 3.0.0-RC + */ +@AllArgsConstructor +@Getter +public class ClearUserAuthorizationCacheEvent { + private String userId; + + private boolean all; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserCreatedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserCreatedEvent.java new file mode 100644 index 000000000..1dbcef9e0 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserCreatedEvent.java @@ -0,0 +1,15 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; + +/** + * @author zhouhao + * @since 3.0.4 + */ +@Getter +@AllArgsConstructor +public class UserCreatedEvent { + UserEntity userEntity; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserModifiedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserModifiedEvent.java new file mode 100644 index 000000000..06e43fd89 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserModifiedEvent.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; + +/** + * 用户密码发生修改时事件 + * + * @author zhouhao + * @see org.springframework.context.event.EventListener + * @see org.springframework.context.ApplicationEventPublisher + * @since 3.0 + */ +@AllArgsConstructor +@Getter +public class UserModifiedEvent { + private UserEntity userEntity; + + private boolean passwordModified; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/reactive/ReactiveUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/reactive/ReactiveUserService.java deleted file mode 100644 index 713659157..000000000 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/reactive/ReactiveUserService.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.hswebframework.web.system.authorization.api.reactive; - -import org.hswebframework.ezorm.core.param.QueryParam; -import org.hswebframework.web.system.authorization.api.User; -import org.hswebframework.web.system.authorization.api.request.SaveUserRequest; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - - -public interface ReactiveUserService { - - Flux save(Publisher userEntity); - - Mono getByUsername(String username); - - Mono getByUsernameAndPassword(String username, String plainPassword); - - Mono changeState(Publisher userId, byte state); - - Mono updatePassword(String userId, String oldPassword, String newPassword); - - Flux findUser(QueryParam queryParam); - - Mono countUser(QueryParam queryParam); - -} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/UserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/UserService.java new file mode 100644 index 000000000..a27837800 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/UserService.java @@ -0,0 +1,38 @@ +package org.hswebframework.web.system.authorization.api.service; + +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + + +public interface UserService { + + boolean saveUser(UserEntity userEntity); + + Optional findByUsername(@NotEmpty String username); + + Optional findByUsernameAndPassword(@NotEmpty String username, @NotEmpty String plainPassword); + + Optional findById(String id); + + List findById(Collection ids); + + boolean changeState(String userId, byte state); + + void changePassword(String userId, String oldPassword, String newPassword); + + List findUser(QueryParam queryParam); + + long countUser(QueryParam queryParam); + + PagerResult findUserPager(QueryParam param); +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java new file mode 100644 index 000000000..253d97b9b --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.system.authorization.api.service.reactive; + +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + + +public interface ReactiveUserService { + + Mono newUserInstance(); + + Mono saveUser(Mono userEntity); + + Mono findByUsername(String username); + + Mono findById(String id); + + Mono findByUsernameAndPassword(String username, String plainPassword); + + Mono changeState(Publisher userId, byte state); + + Mono changePassword(String userId, String oldPassword, String newPassword); + + Flux findUser(QueryParam queryParam); + + Mono countUser(QueryParam queryParam); + +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/pom.xml index 9da9cda8b..b2f8bd069 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/pom.xml @@ -12,6 +12,7 @@ hsweb-system-authorization-default + org.hswebframework.web hsweb-system-authorization-api @@ -23,6 +24,50 @@ hsweb-commons-crud ${project.version} + + + commons-codec + commons-codec + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-jdbc + test + + + + com.h2database + h2 + test + + + + org.springframework.boot.experimental + spring-boot-starter-data-r2dbc + test + + + + + com.zaxxer + HikariCP + 3.4.1 + test + + + + io.r2dbc + r2dbc-h2 + test + + \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java new file mode 100644 index 000000000..ccc7c1ae6 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java @@ -0,0 +1,166 @@ +package org.hswebframework.web.system.authorization.defaults.service; + +import org.apache.commons.codec.digest.DigestUtils; +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.web.api.crud.entity.TransactionManagers; +import org.hswebframework.web.crud.service.GenericReactiveCrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.system.authorization.api.PasswordEncoder; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.api.event.UserCreatedEvent; +import org.hswebframework.web.system.authorization.api.event.UserModifiedEvent; +import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; +import org.hswebframework.web.validator.CreateGroup; +import org.reactivestreams.Publisher; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.validation.ValidationException; + + +public class DefaultReactiveUserService extends GenericReactiveCrudService implements ReactiveUserService { + + @Autowired + private ReactiveRepository repository; + + @Autowired(required = false) + private PasswordEncoder passwordEncoder = (password, salt) -> DigestUtils.md5Hex(String.format("hsweb.%s.framework.%s", password, salt)); + + @Autowired + private ApplicationEventPublisher eventPublisher; + + @Override + public Mono newUserInstance() { + return getRepository().newInstance(); + } + + @Override + @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.r2dbcTransactionManager) + public Mono saveUser(Mono request) { + return request + .flatMap(userEntity -> { + if (StringUtils.isEmpty(userEntity.getId())) { + return doAdd(userEntity); + } + return findById(userEntity.getId()) + .flatMap(ignore -> doUpdate(userEntity)) + .switchIfEmpty(doAdd(userEntity)); + }).thenReturn(true); + } + + protected Mono doAdd(UserEntity userEntity) { + + return Mono.defer(() -> { + userEntity.setSalt(IDGenerator.RANDOM.generate()); + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); + return Mono.just(userEntity) + .doOnNext(e -> e.tryValidate(CreateGroup.class)) + .filterWhen(e -> createQuery() + .where(userEntity::getUsername) + .count().map(i -> i == 0)) + .switchIfEmpty(Mono.error(() -> new ValidationException("用户名已存在"))) + .as(getRepository()::insert) + .thenReturn(userEntity) + .doOnSuccess(e -> eventPublisher.publishEvent(new UserCreatedEvent(e))); + }); + + } + + + protected Mono doUpdate(UserEntity userEntity) { + return Mono.defer(() -> { + boolean passwordChanged = StringUtils.hasText(userEntity.getPassword()); + if (passwordChanged) { + userEntity.setSalt(IDGenerator.RANDOM.generate()); + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); + } + return getRepository() + .createUpdate() + .set(userEntity) + .where(userEntity::getId) + .execute() + .doOnSuccess(__ -> eventPublisher.publishEvent(new UserModifiedEvent(userEntity, passwordChanged))) + .thenReturn(userEntity); + }); + + } + + + @Override + @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + public Mono findById(String id) { + return getRepository().findById(Mono.just(id)); + } + + @Override + @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + public Mono findByUsername(String username) { + return Mono.justOrEmpty(username) + .flatMap(_name -> repository.createQuery() + .where(UserEntity::getUsername, _name) + .fetchOne()); + } + + @Override + @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + public Mono findByUsernameAndPassword(String username, String plainPassword) { + return Mono.justOrEmpty(username) + .flatMap(_name -> repository + .createQuery() + .where(UserEntity::getUsername, _name) + .fetchOne()) + .filter(user -> passwordEncoder.encode(plainPassword, user.getSalt()) + .equals(user.getPassword())); + } + + @Override + @Transactional(rollbackFor = Exception.class, transactionManager = "connectionFactoryTransactionManager") + public Mono changeState(Publisher userId, byte state) { + return Flux.from(userId) + .collectList() + .flatMap(list -> repository + .createUpdate() + .set(UserEntity::getStatus, state) + .where() + .in(UserEntity::getId, list) + .execute()); + } + + @Override + @Transactional(rollbackFor = Exception.class, transactionManager = "connectionFactoryTransactionManager") + public Mono changePassword(String userId, String oldPassword, String newPassword) { + return findById(userId) + .switchIfEmpty(Mono.error(NotFoundException::new)) + .filter(user -> passwordEncoder.encode(oldPassword, user.getSalt()).equals(user.getPassword())) + .switchIfEmpty(Mono.error(() -> new ValidationException("密码错误"))) + .flatMap(user -> repository.createUpdate() + .set(UserEntity::getPassword, passwordEncoder.encode(newPassword, user.getSalt())) + .where(user::getId) + .execute()) + .map(i -> i > 0); + } + + @Override + @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + public Flux findUser(QueryParam queryParam) { + return repository + .createQuery() + .setParam(queryParam) + .fetch(); + } + + @Override + @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + public Mono countUser(QueryParam queryParam) { + return repository + .createQuery() + .setParam(queryParam) + .count(); + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultUserService.java new file mode 100644 index 000000000..0f24ade90 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultUserService.java @@ -0,0 +1,144 @@ +package org.hswebframework.web.system.authorization.defaults.service; + +import org.apache.commons.codec.digest.DigestUtils; +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.crud.service.GenericCrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.system.authorization.api.PasswordEncoder; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.api.event.UserCreatedEvent; +import org.hswebframework.web.system.authorization.api.event.UserModifiedEvent; +import org.hswebframework.web.system.authorization.api.service.UserService; +import org.hswebframework.web.validator.CreateGroup; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Mono; + +import javax.validation.ValidationException; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +@Transactional(rollbackFor = Exception.class) +public class DefaultUserService extends GenericCrudService implements UserService { + + @Autowired(required = false) + private PasswordEncoder passwordEncoder = (password, salt) -> DigestUtils.md5Hex(String.format("hsweb.%s.framework.%s", password, salt)); + + @Autowired + private ApplicationEventPublisher eventPublisher; + + @Override + public boolean saveUser(UserEntity userEntity) { + if (StringUtils.isEmpty(userEntity.getId())) { + return doAdd(userEntity); + } + UserEntity old = findById(userEntity.getId()).orElse(null); + if (old == null) { + return doAdd(userEntity); + } + + return doUpdate(userEntity); + } + + protected boolean doAdd(UserEntity userEntity) { + userEntity.tryValidate(CreateGroup.class); + userEntity.setStatus((byte)1); + + userEntity.setSalt(IDGenerator.RANDOM.generate()); + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); + if (createQuery() + .where(userEntity::getUsername) + .count() > 0) { + throw new ValidationException("用户名已存在"); + } + getRepository().insert(userEntity); + eventPublisher.publishEvent(new UserCreatedEvent(userEntity)); + return true; + } + + + protected boolean doUpdate(UserEntity userEntity) { + boolean passwordChanged = StringUtils.hasText(userEntity.getPassword()); + if (passwordChanged) { + userEntity.setSalt(IDGenerator.RANDOM.generate()); + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); + } + getRepository() + .createUpdate() + .set(userEntity) + .where(userEntity::getId) + .execute(); + + eventPublisher.publishEvent(new UserModifiedEvent(userEntity, passwordChanged)); + return true; + } + + @Override + @Transactional(readOnly = true) + public List findById(Collection id) { + return super.findById(id); + } + + @Override + @Transactional(readOnly = true) + public Optional findById(String id) { + return super.findById(id); + } + + @Override + @Transactional(readOnly = true) + public Optional findByUsername(String username) { + return createQuery() + .where(UserEntity::getUsername, username) + .fetchOne(); + } + + @Override + @Transactional(readOnly = true) + public Optional findByUsernameAndPassword(String username, String plainPassword) { + return findByUsername(username) + .filter(user -> passwordEncoder.encode(plainPassword, user.getSalt()).equals(user.getPassword())); + } + + @Override + public boolean changeState(String userId, byte state) { + return createUpdate() + .where(UserEntity::getId, userId) + .set(UserEntity::getStatus, state) + .execute() > 0; + } + + @Override + public void changePassword(String userId, String oldPassword, String newPassword) { + Mono.justOrEmpty(findById(userId)) + .switchIfEmpty(Mono.error(NotFoundException::new)) + .filter(user -> passwordEncoder.encode(oldPassword, user.getSalt()).equals(user.getPassword())) + .switchIfEmpty(Mono.error(() -> new ValidationException("密码错误"))) + .map(user -> createUpdate() + .set(UserEntity::getPassword, passwordEncoder.encode(newPassword, user.getSalt())) + .where(user::getId).execute()) + .block(); + } + + @Override + @Transactional(readOnly = true) + public List findUser(QueryParam queryParam) { + return createQuery().setParam(queryParam).fetch(); + } + + @Override + @Transactional(readOnly = true) + public long countUser(QueryParam queryParam) { + return createQuery().setParam(queryParam).count(); + } + + @Override + public PagerResult findUserPager(QueryParam param) { + return queryPager(param); + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveUserServiceTest.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveUserServiceTest.java new file mode 100644 index 000000000..8aba9e02e --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveUserServiceTest.java @@ -0,0 +1,60 @@ +package org.hswebframework.web.system.authorization.defaults.service.reactive; + +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ReactiveTestApplication.class) +public class DefaultReactiveUserServiceTest { + + @Autowired + private ReactiveUserService userService; + + @Test + public void testCrud() { + UserEntity userEntity = userService.newUserInstance().blockOptional().orElseThrow(NullPointerException::new); + userEntity.setName("test"); + userEntity.setUsername("admin"); + userEntity.setPassword("admin"); + + userService.saveUser(Mono.just(userEntity)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + Assert.assertNotNull(userEntity.getId()); + + userEntity.setUsername("admin2"); + userEntity.setPassword("admin2"); + userService.saveUser(Mono.just(userEntity)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + userService.changeState(Mono.just(userEntity.getId()), (byte) 1) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); + + userService.changePassword(userEntity.getId(), "admin2", "admin") + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + userService.findByUsernameAndPassword("admin", "admin") + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + + + } + +} \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java new file mode 100644 index 000000000..1672e1bb3 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java @@ -0,0 +1,27 @@ +package org.hswebframework.web.system.authorization.defaults.service.reactive; + +import org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration; +import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.reactive.ReactiveTransactionAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@SpringBootApplication(exclude = { + //TransactionAutoConfiguration.class, + JdbcSqlExecutorConfiguration.class +}) +@ImportAutoConfiguration(ReactiveTransactionAutoConfiguration.class) +public class ReactiveTestApplication { + + + @Bean + public DefaultReactiveUserService defaultReactiveUserService(){ + + return new DefaultReactiveUserService(); + } + +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/DefaultUserServiceTest.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/DefaultUserServiceTest.java new file mode 100644 index 000000000..76979f8f2 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/DefaultUserServiceTest.java @@ -0,0 +1,46 @@ +package org.hswebframework.web.system.authorization.defaults.service.sync; + +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.api.service.UserService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class) +public class DefaultUserServiceTest { + + @Autowired + private UserService userService; + + @Test + public void testCrud() { + UserEntity userEntity = new UserEntity(); + userEntity.setName("test"); + userEntity.setUsername("admin"); + userEntity.setPassword("admin"); + + Assert.assertTrue(userService.saveUser(userEntity)); + + Assert.assertNotNull(userEntity.getId()); + + userEntity.setUsername("admin2"); + userEntity.setPassword("admin2"); + userService.saveUser(userEntity); + + userService.changeState(userEntity.getId(), (byte) 1); + + userService.changePassword(userEntity.getId(),"admin2","admin"); + + UserEntity entity = userService.findByUsernameAndPassword("admin", "admin").orElseThrow(NullPointerException::new); + + Assert.assertEquals(entity.getName(), userEntity.getName()); + + Assert.assertEquals(entity.getStatus().byteValue(), (byte) 1); + + } + +} \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/TestApplication.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/TestApplication.java new file mode 100644 index 000000000..4ccc2b136 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/sync/TestApplication.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.system.authorization.defaults.service.sync; + +import org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration; +import org.hswebframework.web.system.authorization.defaults.service.DefaultUserService; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication(exclude = { + R2dbcSqlExecutorConfiguration.class +}) +public class TestApplication { + + + @Bean + public DefaultUserService defaultUserService(){ + + return new DefaultUserService(); + } + +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/resources/application.yml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/resources/application.yml new file mode 100644 index 000000000..ef4f76c2d --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/resources/application.yml @@ -0,0 +1,11 @@ +logging: + level: + org.hswebframework: debug + org.springframework.transaction: debug + org.springframework.data.r2dbc.connectionfactory: debug +#spring: +# r2dbc: + +easyorm: + default-schema: PUBLIC + dialect: h2 \ No newline at end of file