From a4a42616a4020f0bfec00d9dfba0d2d4371c74c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=91=A8?= Date: Thu, 28 Jan 2021 09:50:57 +0800 Subject: [PATCH 001/542] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d95dc960f..dff65c944 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ # 文档 -TODO +直接看代码: https://github.com/zhou-hao/hsweb4-examples # 实践 -[JetLinks开源物联网平台](https://github.com/jetlinks) \ No newline at end of file +[JetLinks开源物联网平台](https://github.com/jetlinks) From c7da31cbf6678922e4f740a54a06bf7dc3d28fa4 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Jan 2021 10:57:26 +0800 Subject: [PATCH 002/542] 4.0.10-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index ce219986a..81acffd8e 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 58a2c8b2d..b7618225a 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index 13ab3780c..fedc0eba4 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index 28163f83b..b5f2236d6 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 219aaad23..03a295967 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 48f9dc8d9..51e708817 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 56e8a605c..d8214549d 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 49d833290..467552031 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 82a564239..7428b1c97 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index df336b0b2..f4a86905e 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 49cc9b93c..5a570c348 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 5ce0db2ac..5148627d7 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 16e191a4e..d9689d365 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 672ebff17..471ee8b6d 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 6e2f73c0b..1f82b474f 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 0a13dc7f3..dec654fd9 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 2541d0db8..57e3ea011 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index b378bed47..3eb8613e6 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index ed7485bb3..466241364 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 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 ef1d002bb..ba3528840 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 14f7eeb70..8eb3898bd 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 258f0a38f..4578f02c6 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 8cd4dfd2f..04b435cc5 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 1769fd4b6..d9000a375 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index 37070cfcc..dde251c8f 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 2f0c6853c..3173b1f85 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.9 + 4.0.10-SNAPSHOT hsweb-starter hsweb-core From 3c9bf6eb0fc1f8751efce08ad5b6d502456d8139 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Jan 2021 11:00:40 +0800 Subject: [PATCH 003/542] =?UTF-8?q?=E4=BD=BF=E7=94=A8ConcurrentHashMap?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/bean/FastBeanCopier.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index b9deebbed..7f69ccf9c 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -17,6 +17,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -29,7 +30,7 @@ */ @Slf4j public final class FastBeanCopier { - private static final Map CACHE = new HashMap<>(); + private static final Map CACHE = new ConcurrentHashMap<>(); private static final PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils(); @@ -96,7 +97,7 @@ public static T copy(S source, Class target, String... ignore) { } public static T copy(S source, T target, Converter converter, String... ignore) { - return copy(source, target, converter, (ignore == null || ignore.length == 0) ? new java.util.HashSet<>() : new HashSet<>(Arrays.asList(ignore))); + return copy(source, target, converter, (ignore == null || ignore.length == 0) ? Collections.emptySet() : new HashSet<>(Arrays.asList(ignore))); } public static T copy(S source, T target, Set ignore) { From 435eec1ed412f96d6e2ab411b2d9c60748a0d98d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 25 Feb 2021 10:35:13 +0800 Subject: [PATCH 004/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=A4=9A=E4=B8=AApackage=E6=97=B6=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=94=9F=E6=95=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EasyormRepositoryRegistrar.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) 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 d99a4d75e..1f4922154 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 @@ -38,6 +38,14 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar private final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + @SneakyThrows + private Stream doGetResources(String packageStr) { + String path = ResourcePatternResolver + .CLASSPATH_ALL_URL_PREFIX + .concat(packageStr.replace(".", "/")).concat("/**/*.class"); + return Arrays.stream(resourcePatternResolver.getResources(path)); + } + @Override @SneakyThrows @SuppressWarnings("all") @@ -47,33 +55,36 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B if (attr == null) { return; } - boolean reactivePrecent = org.springframework.util.ClassUtils.isPresent("io.r2dbc.spi.ConnectionFactory", this.getClass().getClassLoader()); + boolean reactivePrecent = org.springframework.util.ClassUtils.isPresent("io.r2dbc.spi.ConnectionFactory", this + .getClass() + .getClassLoader()); String[] arr = (String[]) attr.get("value"); - String path = Arrays.stream(arr) - .map(str -> ResourcePatternResolver - .CLASSPATH_ALL_URL_PREFIX - .concat(str.replace(".", "/")).concat("/**/*.class")) - .collect(Collectors.joining()); + Set resources = Arrays + .stream(arr) + .flatMap(this::doGetResources) + .collect(Collectors.toSet()); Class[] anno = (Class[]) attr.get("annotation"); Set entityInfos = new HashSet<>(); - for (Resource resource : resourcePatternResolver.getResources(path)) { + for (Resource resource : resources) { MetadataReader reader = metadataReaderFactory.getMetadataReader(resource); String className = reader.getClassMetadata().getClassName(); - Class entityType = org.springframework.util.ClassUtils.forName(className,null); + Class entityType = org.springframework.util.ClassUtils.forName(className, null); if (Arrays.stream(anno) - .noneMatch(ann -> AnnotationUtils.findAnnotation(entityType, ann) != null)) { + .noneMatch(ann -> AnnotationUtils.findAnnotation(entityType, ann) != null)) { continue; } ImplementFor implementFor = AnnotationUtils.findAnnotation(entityType, ImplementFor.class); Reactive reactive = AnnotationUtils.findAnnotation(entityType, Reactive.class); - Class genericType = Optional.ofNullable(implementFor) + Class genericType = Optional + .ofNullable(implementFor) .map(ImplementFor::value) .orElseGet(() -> { - return Stream.of(entityType.getInterfaces()) + return Stream + .of(entityType.getInterfaces()) .filter(e -> GenericEntity.class.isAssignableFrom(e)) .findFirst() .orElse(entityType); @@ -97,7 +108,8 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B idType = implementFor.idType(); } - EntityInfo entityInfo = new EntityInfo(genericType, entityType, idType, reactivePrecent && (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); } From 16166ee476062ede9de15856b634841935f9d960 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 11 Mar 2021 12:50:21 +0800 Subject: [PATCH 005/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E7=9B=B8=E5=85=B3=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/web/CommonErrorControllerAdvice.java | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 6499d305d..673442ebf 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -1,5 +1,7 @@ package org.hswebframework.web.crud.web; +import io.r2dbc.spi.R2dbcDataIntegrityViolationException; +import io.r2dbc.spi.R2dbcNonTransientException; import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.exception.AuthenticationException; @@ -42,7 +44,7 @@ public class CommonErrorControllerAdvice { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(BusinessException e) { return Mono.just(ResponseMessage.error(e.getCode(), e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @@ -72,7 +74,8 @@ public Mono> handleException(NotFoundException e) { @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ValidationException e) { - return Mono.just(ResponseMessage.>error(400, "illegal_argument", e.getMessage()).result(e.getDetails())); + return Mono.just(ResponseMessage.>error(400, "illegal_argument", e.getMessage()) + .result(e.getDetails())); } @ExceptionHandler @@ -84,7 +87,8 @@ public Mono>> handleException(C @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(BindException e) { - return handleException(new ValidationException(e.getMessage(), e.getBindingResult().getAllErrors() + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) @@ -95,7 +99,8 @@ public Mono>> handleException(B @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(WebExchangeBindException e) { - return handleException(new ValidationException(e.getMessage(), e.getBindingResult().getAllErrors() + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) @@ -107,7 +112,8 @@ public Mono>> handleException(W @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(MethodArgumentNotValidException e) { - return handleException(new ValidationException(e.getMessage(), e.getBindingResult().getAllErrors() + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) @@ -125,7 +131,7 @@ public Mono> handleException(javax.validation.ValidationExcep @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) public Mono> handleException(TimeoutException e) { return Mono.just(ResponseMessage.error(504, "timeout", e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @@ -134,7 +140,7 @@ public Mono> handleException(TimeoutException e) { @Order public Mono> handleException(RuntimeException e) { return Mono.just(ResponseMessage.error(e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @@ -143,14 +149,14 @@ public Mono> handleException(RuntimeException e) { public Mono> handleException(NullPointerException e) { return Mono.just(ResponseMessage.error(e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(IllegalArgumentException e) { return Mono.just(ResponseMessage.error(400, "illegal_argument", e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @@ -163,29 +169,40 @@ public Mono> handleException(AuthenticationException e) @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) public Mono> handleException(MediaTypeNotSupportedStatusException e) { return Mono.just(ResponseMessage - .error(415, "unsupported_media_type", "不支持的请求类型") - .result(e.getSupportedMediaTypes())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .error(415, "unsupported_media_type", "不支持的请求类型") + .result(e.getSupportedMediaTypes())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(NotAcceptableStatusException e) { return Mono.just(ResponseMessage - .error(406, "not_acceptable_media_type", "不支持的响应类型") - .result(e.getSupportedMediaTypes())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .error(406, "not_acceptable_media_type", "不支持的响应类型") + .result(e.getSupportedMediaTypes())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(MethodNotAllowedException e) { return Mono.just(ResponseMessage - .error(405, "method_not_allowed", "不支持的请求方法:" + e.getHttpMethod()) - .result(e.getSupportedMethods())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .error(405, "method_not_allowed", "不支持的请求方法:" + e.getHttpMethod()) + .result(e.getSupportedMethods())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Mono> handleException(R2dbcDataIntegrityViolationException exception) { + if (exception.getMessage().contains("Duplicate")) { + return Mono.just(ResponseMessage.error("存在重复的数据")); + } + log.warn(exception.getMessage(), exception); + return Mono.just(ResponseMessage.error("数据错误")); + } + + @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ServerWebInputException e) { From 25409b8489df1dabb5bfcb8fd27b922f063b2cb9 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 23 Mar 2021 17:54:48 +0800 Subject: [PATCH 006/542] =?UTF-8?q?=E5=AD=90=E8=8A=82=E7=82=B9ID=E4=B8=8D?= =?UTF-8?q?=E8=83=BD=E4=B8=8E=E7=88=B6=E8=8A=82=E7=82=B9ID=E7=9B=B8?= =?UTF-8?q?=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/crud/entity/TreeSupportEntity.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index d369cbd80..2cadbd2a3 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -20,6 +20,7 @@ import org.hswebframework.utils.RandomUtil; +import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.id.IDGenerator; import org.springframework.util.CollectionUtils; @@ -49,6 +50,13 @@ public interface TreeSupportEntity extends Entity { > List getChildren(); + @Override + default void tryValidate(Class... groups) { + if (getId() != null && Objects.equals(getId(), getParentId())) { + throw new ValidationException("parentId", "子节点ID不能与父节点ID相同"); + } + } + /** * 根据path获取父节点的path * @@ -180,7 +188,8 @@ static , PK> void expandTree2List(T root, List, PK> List list2tree(Collection dataList, BiConsumer> childConsumer) { - return list2tree(dataList, childConsumer, (Function, Predicate>) predicate -> node -> node == null || predicate.getNode(node.getParentId()) == null); + return list2tree(dataList, childConsumer, (Function, Predicate>) predicate -> node -> node == null || predicate + .getNode(node.getParentId()) == null); } static , PK> List list2tree(Collection dataList, @@ -211,9 +220,9 @@ static , PK> List list2tree(final Collection< Map cache = new HashMap<>(); // parentId,children Map> treeCache = streamSupplier.get() - .peek(node -> cache.put(node.getId(), node)) - .filter(e -> e.getParentId() != null) - .collect(Collectors.groupingBy(TreeSupportEntity::getParentId)); + .peek(node -> cache.put(node.getId(), node)) + .filter(e -> e.getParentId() != null) + .collect(Collectors.groupingBy(TreeSupportEntity::getParentId)); Predicate rootNodePredicate = predicateFunction.apply(new TreeHelper() { @Override @@ -228,11 +237,11 @@ public N getNode(PK id) { }); return streamSupplier.get() - //设置每个节点的子节点 - .peek(node -> childConsumer.accept(node, treeCache.get(node.getId()))) - //获取根节点 - .filter(rootNodePredicate) - .collect(Collectors.toList()); + //设置每个节点的子节点 + .peek(node -> childConsumer.accept(node, treeCache.get(node.getId()))) + //获取根节点 + .filter(rootNodePredicate) + .collect(Collectors.toList()); } /** From 93e76c4289f26f55f720abe95476cec765462a8e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 24 Mar 2021 16:48:33 +0800 Subject: [PATCH 007/542] =?UTF-8?q?=E7=BB=B4=E5=BA=A6=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=9D=9E=E7=A9=BA=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/system/authorization/api/entity/DimensionEntity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index be53968f5..8c17f52d4 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -7,10 +7,12 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity; +import org.hswebframework.web.validator.CreateGroup; import javax.persistence.Column; import javax.persistence.Index; import javax.persistence.Table; +import javax.validation.constraints.NotBlank; import java.sql.JDBCType; import java.util.List; import java.util.Map; @@ -30,6 +32,7 @@ public class DimensionEntity extends GenericTreeSortSupportEntity { @Comment("维度名称") @Column(length = 32) @Schema(description = "维度名称") + @NotBlank(message = "名称不能为空",groups = CreateGroup.class) private String name; @Comment("描述") From cafc138d3ddafda1e0ca7338b7e8e3976699e3d4 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 25 Mar 2021 10:20:46 +0800 Subject: [PATCH 008/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=A0=91=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E6=97=A0=E6=B3=95=E9=AA=8C=E8=AF=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/api/crud/entity/TreeSupportEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index 2cadbd2a3..6e8d5fa0f 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -52,6 +52,7 @@ public interface TreeSupportEntity extends Entity { @Override default void tryValidate(Class... groups) { + Entity.super.tryValidate(groups); if (getId() != null && Objects.equals(getId(), getParentId())) { throw new ValidationException("parentId", "子节点ID不能与父节点ID相同"); } From 8b8d4d28b347e2d1813621e635bfcb142e9d7052 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 25 Mar 2021 11:43:20 +0800 Subject: [PATCH 009/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A0=91=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E7=9A=84=E5=BE=AA=E7=8E=AF=E5=BC=95=E7=94=A8=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveTreeSortEntityService.java | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index dfa6caeae..e49225f1b 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -32,16 +32,16 @@ default Mono> queryResultToTree(QueryParamEntity paramEntity) { return query(paramEntity) .collectList() .map(list -> TreeSupportEntity.list2tree(list, - this::setChildren, - this::createRootNodePredicate)); + this::setChildren, + this::createRootNodePredicate)); } default Mono> queryIncludeChildrenTree(QueryParamEntity paramEntity) { return queryIncludeChildren(paramEntity) .collectList() .map(list -> TreeSupportEntity.list2tree(list, - this::setChildren, - this::createRootNodePredicate)); + this::setChildren, + this::createRootNodePredicate)); } default Flux queryIncludeChildren(Collection idList) { @@ -68,11 +68,11 @@ default Mono insert(Publisher entityPublisher) { @Override default Mono insertBatch(Publisher> entityPublisher) { return this.getRepository() - .insertBatch(Flux.from(entityPublisher) - .flatMap(Flux::fromIterable) - .flatMap(this::applyTreeProperty) - .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) - .collectList()); + .insertBatch(Flux.from(entityPublisher) + .flatMap(Flux::fromIterable) + .flatMap(this::applyTreeProperty) + .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) + .collectList()); } default Mono applyTreeProperty(E ele) { @@ -80,25 +80,39 @@ default Mono applyTreeProperty(E ele) { StringUtils.isEmpty(ele.getParentId())) { return Mono.just(ele); } - return findById(ele.getParentId()) - .doOnNext(parent -> ele.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4))) - .thenReturn(ele); + + return this.checkCyclicDependency(ele.getId(), ele) + .then(this.findById(ele.getParentId()) + .doOnNext(parent -> ele.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4)))) + .thenReturn(ele); + } + + //校验是否有循环依赖,修改父节点为自己的子节点? + default Mono checkCyclicDependency(K id, E ele) { + return this + .queryIncludeChildren(Collections.singletonList(id)) + .doOnNext(e -> { + if (Objects.equals(ele.getParentId(), e.getId())) { + throw new IllegalArgumentException("不能修改父节点为自己或者自己的子节点"); + } + }) + .then(Mono.just(ele)); } @Override default Mono save(Publisher entityPublisher) { return this.getRepository() - .save(Flux.from(entityPublisher) - .flatMap(this::applyTreeProperty) - //把树结构平铺 - .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) - ); + .save(Flux.from(entityPublisher) + .flatMap(this::applyTreeProperty) + //把树结构平铺 + .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) + ); } @Override default Mono updateById(K id, Mono entityPublisher) { - return save(entityPublisher - .doOnNext(e -> e.setId(id))) + return this + .save(entityPublisher.doOnNext(e -> e.setId(id))) .map(SaveResult::getTotal); } From 690dbd788c3bc706f39ddf20b9fb00ac4cd2ed21 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 25 Mar 2021 11:53:19 +0800 Subject: [PATCH 010/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ID=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/entity/DimensionEntity.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 8c17f52d4..0056a12ed 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -10,29 +10,40 @@ 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; +import javax.validation.constraints.Pattern; import java.sql.JDBCType; import java.util.List; import java.util.Map; @Getter @Setter -@Table(name = "s_dimension",indexes = { - @Index(name = "idx_dims_path",columnList = "path") +@Table(name = "s_dimension", indexes = { + @Index(name = "idx_dims_path", columnList = "path") }) public class DimensionEntity extends GenericTreeSortSupportEntity { + @Override + @Pattern( + regexp = "^[0-9a-zA-Z_\\-]+$", + message = "ID只能由数字,字母,下划线和中划线组成", + groups = CreateGroup.class) + public String getId() { + return super.getId(); + } + @Comment("维度类型ID") - @Column(length = 32,name = "type_id") + @Column(length = 32, name = "type_id") @Schema(description = "维度类型ID") private String typeId; @Comment("维度名称") @Column(length = 32) @Schema(description = "维度名称") - @NotBlank(message = "名称不能为空",groups = CreateGroup.class) + @NotBlank(message = "名称不能为空", groups = CreateGroup.class) private String name; @Comment("描述") @@ -45,7 +56,7 @@ public class DimensionEntity extends GenericTreeSortSupportEntity { @Comment("其他配置") @JsonCodec @Schema(description = "其他配置") - private Map properties; + private Map properties; @Schema(description = "子节点") private List children; From 112ab3d3f5a70353f068c4559b76c95de28b4c2b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 31 Mar 2021 11:52:05 +0800 Subject: [PATCH 011/542] =?UTF-8?q?=E4=BC=98=E5=8C=96id=E7=A9=BA=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/service/ReactiveTreeSortEntityService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index e49225f1b..2cf5f6c8c 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -89,6 +89,9 @@ default Mono applyTreeProperty(E ele) { //校验是否有循环依赖,修改父节点为自己的子节点? default Mono checkCyclicDependency(K id, E ele) { + if (StringUtils.isEmpty(id)) { + return Mono.empty(); + } return this .queryIncludeChildren(Collections.singletonList(id)) .doOnNext(e -> { From 5a7d5e8deecf3bad727751f0f4e03a655664a1db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Mar 2021 22:27:42 +0000 Subject: [PATCH 012/542] Bump guava in /hsweb-concurrent/hsweb-concurrent-cache Bumps [guava](https://github.com/google/guava) from 28.0-jre to 29.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] --- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 49d833290..1dfb65d4c 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -40,7 +40,7 @@ com.google.guava guava - 28.0-jre + 29.0-jre true From 29e965925c86395d4238258bd987b3600efb7318 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Mar 2021 22:38:53 +0000 Subject: [PATCH 013/542] Bump guava in /hsweb-commons/hsweb-commons-crud Bumps [guava](https://github.com/google/guava) from 28.0-jre to 29.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot[bot] --- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 48f9dc8d9..b1aeddd14 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -88,7 +88,7 @@ com.google.guava guava - 28.0-jre + 29.0-jre test From f77c3302d7a9b858c8078b434629690b0870332e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 09:08:51 +0800 Subject: [PATCH 014/542] upgrade guava version to 30.1.1 --- hsweb-commons/hsweb-commons-crud/pom.xml | 1 - hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 1 - pom.xml | 6 ++++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 51e708817..66f08720a 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -88,7 +88,6 @@ com.google.guava guava - 28.0-jre test diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 467552031..aca207902 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -40,7 +40,6 @@ com.google.guava guava - 28.0-jre true diff --git a/pom.xml b/pom.xml index 3173b1f85..df680c362 100644 --- a/pom.xml +++ b/pom.xml @@ -338,6 +338,12 @@ 1.0.2.Final + + com.google.guava + guava + 30.1.1-jre + + io.vavr vavr From af1f5d01471444d445c6f6f7e57dbf672b406731 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 09:11:30 +0800 Subject: [PATCH 015/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cbedd20d5..1a37ca797 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # hsweb4 基于spring-boot2,全响应式的后台管理框架 [![Codecov](https://codecov.io/gh/hs-web/hsweb-framework/branch/4.0.x/graph/badge.svg)](https://codecov.io/gh/hs-web/hsweb-framework/branch/master) -[![Build Status](https://travis-ci.org/hs-web/hsweb-framework.svg?branch=4.0.x)](https://travis-ci.org/hs-web/hsweb-framework) +[![Build Status](https://api.travis-ci.com/hs-web/hsweb-framework.svg?branch=4.0.x)](https://travis-ci. +com/hs-web/hsweb-framework) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg?style=flat-square)](https://www.apache.org/licenses/LICENSE-2.0.html) # 功能,特性 -- [x] 基于[r2dbc](https://github.com/r2dbc) ,[easy-orm](https://github.com/hs-web/hsweb-easy-orm/tree/4.0.x)的通用响应式CRUD +- [x] 基于[r2dbc](https://github.com/r2dbc) ,[easy-orm](https://github.com/hs-web/hsweb-easy-orm/tree/4.0.x) 的通用响应式CRUD - [x] H2,Mysql,SqlServer,PostgreSQL - [x] 响应式r2dbc事务控制 - [x] 响应式权限控制,以及权限信息获取 From 5c76668d2ef74d26cc59d86cf8174f62aa2de8d7 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 09:14:32 +0800 Subject: [PATCH 016/542] upgrade guava version to 30.1.1 --- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 1dfb65d4c..2a8f36891 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -40,7 +40,6 @@ com.google.guava guava - 29.0-jre true From 3f60a28d78890fef5b030f7b1d1639cb33a924fe Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 09:15:14 +0800 Subject: [PATCH 017/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 92081f872..9ca7dcc37 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # hsweb4 基于spring-boot2,全响应式的后台管理框架 [![Codecov](https://codecov.io/gh/hs-web/hsweb-framework/branch/4.0.x/graph/badge.svg)](https://codecov.io/gh/hs-web/hsweb-framework/branch/master) -[![Build Status](https://api.travis-ci.com/hs-web/hsweb-framework.svg?branch=4.0.x)](https://travis-ci. -com/hs-web/hsweb-framework) +[![Build Status](https://api.travis-ci.com/hs-web/hsweb-framework.svg?branch=4.0.x)](https://travis-ci.com/hs-web/hsweb-framework) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg?style=flat-square)](https://www.apache.org/licenses/LICENSE-2.0.html) # 功能,特性 From 93d132aacfcb382fd7abcd4de745e13a55d74cd2 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 09:28:12 +0800 Subject: [PATCH 018/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- .../main/java/org/hswebframework/web/bean/CompareUtils.java | 4 ---- pom.xml | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 2a8f36891..aca207902 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.9 + 4.0.10-SNAPSHOT 4.0.0 diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/CompareUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/CompareUtils.java index d61acac80..736920d0e 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/CompareUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/CompareUtils.java @@ -156,10 +156,6 @@ public static boolean compare(Object[] number, Object target) { return compare(Arrays.asList(number), target); } - public static boolean compare(Boolean bool, Object target) { - return bool.equals(target) || String.valueOf(bool).equals(target); - } - public static boolean compare(Number number, Object target) { if (number == target) { diff --git a/pom.xml b/pom.xml index df680c362..7c5d99cfa 100644 --- a/pom.xml +++ b/pom.xml @@ -353,7 +353,7 @@ org.projectlombok lombok - 1.16.18 + 1.16.22 From 419225615dc9a9d357086f804832c4452891028c Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 17:12:02 +0800 Subject: [PATCH 019/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC=E5=92=8C=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/authorization/api/entity/PermissionEntity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 23c89b341..b145b1e5e 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -4,11 +4,14 @@ import lombok.*; import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType; import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; +import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.validator.CreateGroup; import javax.persistence.Column; import javax.persistence.Table; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.sql.JDBCType; import java.util.List; @@ -25,6 +28,7 @@ public class PermissionEntity extends GenericEntity { @Column @Comment("权限名称") @Schema(description = "权限名称") + @NotBlank(message = "权限名称不能为空",groups = CreateGroup.class) private String name; @Column @@ -35,6 +39,7 @@ public class PermissionEntity extends GenericEntity { @Column(nullable = false) @Comment("状态") @Schema(description = "状态") + @DefaultValue("1") private Byte status; @Column From 04c7e733e5553a490ddc1fca24643b119ab33f72 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 17:18:03 +0800 Subject: [PATCH 020/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/webflux/WebFluxUserController.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java index 2cbc23d94..805dbcba1 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java @@ -7,10 +7,7 @@ import lombok.Setter; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.User; -import org.hswebframework.web.authorization.annotation.Authorize; -import org.hswebframework.web.authorization.annotation.DeleteAction; -import org.hswebframework.web.authorization.annotation.Resource; -import org.hswebframework.web.authorization.annotation.SaveAction; +import org.hswebframework.web.authorization.annotation.*; import org.hswebframework.web.authorization.exception.UnAuthorizedException; import org.hswebframework.web.crud.web.reactive.ReactiveServiceQueryController; import org.hswebframework.web.system.authorization.api.entity.UserEntity; @@ -46,8 +43,8 @@ public Mono saveUser(@RequestBody Mono user) { @PutMapping("/me") - @Authorize(merge = false) @Operation(summary = "修改当前用户信息") + @ResourceAction(id = "update-self-info",name = "修改当前用户信息") public Mono updateLoginUserInfo(@RequestBody UserEntity request) { return Authentication .currentReactive() @@ -73,8 +70,7 @@ public Mono deleteUser(@PathVariable String id) { } @PutMapping("/passwd") - @Authorize(merge = false) - @Operation(summary = "修改当前用户密码") + @ResourceAction(id = "update-self-pwd",name = "修改当前用户密码") public Mono changePassword(@RequestBody ChangePasswordRequest request) { return Authentication .currentReactive() From bed89a47c7ac7652443e65a7caad203b9e8944c6 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 18:18:20 +0800 Subject: [PATCH 021/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/defaults/webflux/WebFluxUserController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java index 805dbcba1..3c51a8057 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java @@ -71,6 +71,7 @@ public Mono deleteUser(@PathVariable String id) { @PutMapping("/passwd") @ResourceAction(id = "update-self-pwd",name = "修改当前用户密码") + @Operation(summary = "修改当前用户密码") public Mono changePassword(@RequestBody ChangePasswordRequest request) { return Authentication .currentReactive() From ef100a62b2f0d87e9aa34727b28da3792682f32a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Apr 2021 18:18:48 +0800 Subject: [PATCH 022/542] =?UTF-8?q?=E4=BC=98=E5=8C=96redis=E4=BB=A4?= =?UTF-8?q?=E7=89=8C=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../token/redis/RedisUserTokenManager.java | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index 06e2916e2..38342e380 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -41,12 +41,12 @@ public RedisUserTokenManager(ReactiveRedisOperations operations) @SuppressWarnings("all") public RedisUserTokenManager(ReactiveRedisConnectionFactory connectionFactory) { this(new ReactiveRedisTemplate<>(connectionFactory, - RedisSerializationContext.newSerializationContext() - .key((RedisSerializer) RedisSerializer.string()) - .value(RedisSerializer.java()) - .hashKey(RedisSerializer.string()) - .hashValue(RedisSerializer.java()) - .build() + RedisSerializationContext.newSerializationContext() + .key((RedisSerializer) RedisSerializer.string()) + .value(RedisSerializer.java()) + .hashKey(RedisSerializer.string()) + .hashValue(RedisSerializer.java()) + .build() )); } @@ -105,37 +105,45 @@ public Mono tokenIsLoggedIn(String token) { @Override public Mono totalUser() { - return totalToken(); + return operations + .scan(ScanOptions + .scanOptions() + .match("*user-token-user:*") + .build()) + .count() + .map(Long::intValue); } @Override public Mono totalToken() { - return operations.scan(ScanOptions - .scanOptions() - .match("user-token:*") - .build()) + return operations + .scan(ScanOptions + .scanOptions() + .match("*user-token:*") + .build()) .count() .map(Long::intValue); } @Override public Flux allLoggedUser() { - return operations.scan(ScanOptions - .scanOptions() - .match("user-token:*") - .build()) - .map(String::valueOf) + return operations + .scan(ScanOptions + .scanOptions() + .match("*user-token:*") + .build()) + .map(val -> String.valueOf(val).substring(11)) .flatMap(this::getByToken); } @Override public Mono signOutByUserId(String userId) { - String key = getUserRedisKey(userId); - return getByUserId(key) + return this + .getByUserId(userId) .flatMap(userToken -> operations .delete(getTokenRedisKey(userToken.getToken())) .then(onTokenRemoved(userToken))) - .then(operations.delete(key)) + .then(operations.delete(getUserRedisKey(userId))) .then(); } @@ -244,11 +252,13 @@ public Mono touch(String token) { public Mono checkExpiredToken() { return operations - .scan(ScanOptions.scanOptions().match("user-token-user:*").build()) + .scan(ScanOptions.scanOptions().match("*user-token-user:*").build()) .map(String::valueOf) - .flatMap(key -> userTokenMapping.members(key) + .flatMap(key -> userTokenMapping + .members(key) .map(String::valueOf) - .flatMap(token -> operations.hasKey(getTokenRedisKey(token)) + .flatMap(token -> operations + .hasKey(getTokenRedisKey(token)) .flatMap(exists -> { if (!exists) { return userTokenMapping.remove(key, token); From 16a002d90c55e8d2a3e074dc83047593468d9b57 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 9 Apr 2021 15:18:25 +0800 Subject: [PATCH 023/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9C=A8=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BA=8B=E5=8A=A1=E6=97=B6=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E8=B0=83=E7=94=A8ReactiveSqlExecutor=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=B3=84=E6=BC=8F=E9=83=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/sql/DefaultR2dbcExecutor.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) 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 9eeca4e05..3897824c6 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 @@ -2,6 +2,7 @@ import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.Result; import io.r2dbc.spi.Statement; import lombok.Setter; import org.hswebframework.ezorm.rdb.executor.SqlRequest; @@ -21,6 +22,7 @@ import java.time.ZoneOffset; import java.util.Date; +import java.util.Map; public class DefaultR2dbcExecutor extends R2dbcReactiveSqlExecutor { @@ -81,7 +83,13 @@ protected Mono getConnection() { @Override protected void releaseConnection(SignalType type, Connection connection) { + //所有方法都被事务接管,不用手动释放 + } + @Override + @Transactional(propagation = Propagation.NOT_SUPPORTED, transactionManager = TransactionManagers.r2dbcTransactionManager) + public Mono execute(SqlRequest request) { + return super.execute(request); } @Override @@ -96,9 +104,39 @@ public Mono update(Publisher request) { return super.update(request); } + @Override + @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + public Mono update(SqlRequest request) { + return super.update(request); + } + + @Override + @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + public Mono update(String sql, Object... args) { + return super.update(sql,args); + } + @Override @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) public Flux select(Publisher request, ResultWrapper wrapper) { return super.select(request, wrapper); } + + @Override + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + public Flux> select(String sql, Object... args) { + return super.select(sql,args); + } + + @Override + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + public Flux select(String sql, ResultWrapper wrapper) { + return super.select(sql,wrapper); + } + + @Override + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + public Flux select(SqlRequest sqlRequest, ResultWrapper wrapper) { + return super.select(sqlRequest,wrapper); + } } From a42ebe24813721a238a8be9207a9d5aa60792049 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 12 Apr 2021 15:38:26 +0800 Subject: [PATCH 024/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/hswebframework/web/bean/FastBeanCopier.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index 7f69ccf9c..e00ba28d4 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -567,8 +567,10 @@ public T convert(Object source, Class targetClass, Class[] genericType) { } return convert(val, targetClass, genericType); } + String strSource=String.valueOf(source); for (T t : targetClass.getEnumConstants()) { - if (((Enum) t).name().equalsIgnoreCase(String.valueOf(source))) { + if (((Enum) t).name().equalsIgnoreCase(strSource) + ||Objects.equals(String.valueOf(((Enum) t).ordinal()),strSource)) { return t; } } From 115f0db2d9bf2128423eb79fa9d8572e6fb34a7c Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 12 Apr 2021 19:05:06 +0800 Subject: [PATCH 025/542] execute use REQUIRES_NEW --- .../org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 3897824c6..558b31404 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 @@ -87,13 +87,13 @@ protected void releaseConnection(SignalType type, Connection connection) { } @Override - @Transactional(propagation = Propagation.NOT_SUPPORTED, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.r2dbcTransactionManager) public Mono execute(SqlRequest request) { return super.execute(request); } @Override - @Transactional(propagation = Propagation.NOT_SUPPORTED, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.r2dbcTransactionManager) public Mono execute(Publisher request) { return super.execute(request); } From 1546d7c9de5a13b45ef1411db14d07edf92396fe Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 13 Apr 2021 18:17:27 +0800 Subject: [PATCH 026/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0path=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-commons/hsweb-commons-api/pom.xml | 4 ++++ .../web/api/crud/entity/GenericTreeSortSupportEntity.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 03a295967..eab4a0cba 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -33,6 +33,10 @@ io.swagger.core.v3 swagger-annotations + + org.hibernate.validator + hibernate-validator + diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java index 80abd3081..6a37ebf61 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java @@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import org.hibernate.validator.constraints.Length; import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import javax.persistence.Column; @@ -48,6 +49,7 @@ public abstract class GenericTreeSortSupportEntity extends GenericEntity @Column(name = "path", length = 128) @Comment("树路径") @Schema(description = "树结构路径") + @Length(max = 128, message = "目录层级太深") private String path; /** From c2a1d4e78821874d93995880d775951be69b33a6 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 14 Apr 2021 18:02:23 +0800 Subject: [PATCH 027/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=B9=B6=E8=A1=8C?= =?UTF-8?q?=E5=88=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/crud/entity/QueryParamEntity.java | 5 +++++ .../web/crud/service/ReactiveCrudService.java | 9 +++++++++ .../web/reactive/ReactiveServiceQueryController.java | 7 +------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index 20525b946..d252bd494 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -52,6 +52,11 @@ public class QueryParamEntity extends QueryParam { @Schema(description = "设置了此值后将不重复执行count查询总数") private Integer total; + @Getter + @Setter + @Schema(description = "是否进行并行分页") + private boolean parallelPager = false; + @Override @Hidden public boolean isForUpdate() { 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 73ccb8f7f..cf7bda040 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 @@ -116,6 +116,15 @@ default Mono> queryPager(QueryParamEntity query, Function PagerResult.of(query.getTotal(), list, query)); } + //并行分页 + if (query.isParallelPager()) { + return Mono + .zip( + createQuery().setParam(query).count(), + createQuery().setParam(query.clone()).fetch().map(mapper).collectList(), + (total, data) -> PagerResult.of(total, data, query) + ); + } return getRepository() .createQuery() .setParam(query) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java index 592499a91..de760afbb 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java @@ -100,12 +100,7 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti .collectList() .map(list -> PagerResult.of(query.getTotal(), list, query)); } - - return Mono.zip( - getService().createQuery().setParam(query).count(), - getService().createQuery().setParam(query).fetch().collectList(), - (total, data) -> PagerResult.of(total, data, query) - ); + return getService().queryPager(query); } From 4e520b89655e2274b513dc3ce957a14ae02ceb29 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 26 Apr 2021 15:17:56 +0800 Subject: [PATCH 028/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/event/UserCreatedEvent.java | 3 +- .../api/event/UserDeletedEvent.java | 3 +- .../api/event/UserModifiedEvent.java | 3 +- .../service/DefaultDimensionUserService.java | 9 +- .../service/DefaultReactiveUserService.java | 111 ++++++++++-------- 5 files changed, 71 insertions(+), 58 deletions(-) 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 index 1dbcef9e0..70690e2d4 100644 --- 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 @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.hswebframework.web.system.authorization.api.entity.UserEntity; /** @@ -10,6 +11,6 @@ */ @Getter @AllArgsConstructor -public class UserCreatedEvent { +public class UserCreatedEvent extends DefaultAsyncEvent { UserEntity userEntity; } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java index ab15377a5..8bb299139 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java @@ -4,13 +4,14 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.hswebframework.web.system.authorization.api.entity.UserEntity; @Getter @Setter @AllArgsConstructor @NoArgsConstructor -public class UserDeletedEvent { +public class UserDeletedEvent extends DefaultAsyncEvent { private UserEntity user; 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 index 06e43fd89..d38b91d4e 100644 --- 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 @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.hswebframework.web.system.authorization.api.entity.UserEntity; /** @@ -14,7 +15,7 @@ */ @AllArgsConstructor @Getter -public class UserModifiedEvent { +public class UserModifiedEvent extends DefaultAsyncEvent { private UserEntity userEntity; private boolean passwordModified; diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index 5b8b2f7e4..5adef3479 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -28,10 +28,11 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService log.debug("user deleted,clear user dimension!")); + event.async(this.createDelete() + .where(DimensionUserEntity::getUserId, event.getUser().getId()) + .execute() + .doOnSuccess(i -> log.debug("user deleted,clear user dimension!")) + ); } @Override 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 index 8cdafdc73..d412178be 100644 --- 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 @@ -69,41 +69,45 @@ public Mono saveUser(Mono request) { protected Mono doAdd(UserEntity userEntity) { - return Mono.defer(() -> { - userEntity.setSalt(IDGenerator.RANDOM.generate()); - usernameValidator.validate(userEntity.getUsername()); - passwordValidator.validate(userEntity.getPassword()); - 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))); - }); + return Mono + .defer(() -> { + userEntity.setSalt(IDGenerator.RANDOM.generate()); + usernameValidator.validate(userEntity.getUsername()); + passwordValidator.validate(userEntity.getPassword()); + 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) + .flatMap(user -> new UserCreatedEvent(user) + .publish(eventPublisher) + .thenReturn(user)); + }); } protected Mono doUpdate(UserEntity userEntity) { - return Mono.defer(() -> { - boolean passwordChanged = StringUtils.hasText(userEntity.getPassword()); - if (passwordChanged) { - userEntity.setSalt(IDGenerator.RANDOM.generate()); - passwordValidator.validate(userEntity.getPassword()); - 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); - }); + return Mono + .defer(() -> { + boolean passwordChanged = StringUtils.hasText(userEntity.getPassword()); + if (passwordChanged) { + userEntity.setSalt(IDGenerator.RANDOM.generate()); + passwordValidator.validate(userEntity.getPassword()); + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); + } + return getRepository() + .createUpdate() + .set(userEntity) + .where(userEntity::getId) + .execute() + .flatMap(__ -> new UserModifiedEvent(userEntity, passwordChanged).publish(eventPublisher)) + .thenReturn(userEntity); + }); } @@ -117,36 +121,38 @@ public Mono findById(String id) { @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) public Mono findByUsername(String username) { return Mono.justOrEmpty(username) - .flatMap(_name -> repository.createQuery() - .where(UserEntity::getUsername, _name) - .fetchOne()); + .flatMap(_name -> repository + .createQuery() + .where(UserEntity::getUsername, _name) + .fetchOne()); } @Override @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) 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())); + .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 = TransactionManagers.r2dbcTransactionManager) public Mono changeState(Publisher userId, byte state) { return Flux.from(userId) - .collectList() - .filter(CollectionUtils::isNotEmpty) - .flatMap(list -> repository - .createUpdate() - .set(UserEntity::getStatus, state) - .where() - .in(UserEntity::getId, list) - .execute()) - .defaultIfEmpty(0); + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> repository + .createUpdate() + .set(UserEntity::getStatus, state) + .where() + .in(UserEntity::getId, list) + .execute()) + .defaultIfEmpty(0); } @Override @@ -157,7 +163,8 @@ public Mono changePassword(String userId, String oldPassword, String ne .switchIfEmpty(Mono.error(NotFoundException::new)) .filter(user -> passwordEncoder.encode(oldPassword, user.getSalt()).equals(user.getPassword())) .switchIfEmpty(Mono.error(() -> new ValidationException("密码错误"))) - .flatMap(user -> repository.createUpdate() + .flatMap(user -> repository + .createUpdate() .set(UserEntity::getPassword, passwordEncoder.encode(newPassword, user.getSalt())) .where(user::getId) .execute()) @@ -183,11 +190,13 @@ public Mono countUser(QueryParam queryParam) { } @Override + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) public Mono deleteUser(String userId) { - return this.findById(userId) + return this + .findById(userId) .flatMap(user -> this .deleteById(Mono.just(userId)) - .doOnNext(i -> eventPublisher.publishEvent(new UserDeletedEvent(user))) + .flatMap(i -> new UserDeletedEvent(user).publish(eventPublisher)) .thenReturn(true)); } } From ec53ee89af6eb8c226cdedb9229ca27ce2ef65d7 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 27 Apr 2021 18:40:43 +0800 Subject: [PATCH 029/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/annotation/EnableEntityEvent.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java index 5af8d7ced..55b731085 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java @@ -3,9 +3,22 @@ import java.lang.annotation.*; /** + * 在实体类上添加此注解,表示开启实体操作事件,当实体类发生类修改,更新,删除等操作时,会触发事件。 + * 可以通过spring event监听事件: + *
+ *     @EventListener
+ *     public void handleEvent(EntitySavedEvent<UserEntity> event){
+ *         event
+ *         .async( //组合响应式操作
+ *              deleteByUser(event.getEntity())
+ *         )
+ *     }
+ * 
+ * * @see org.hswebframework.web.crud.events.EntityModifyEvent * @see org.hswebframework.web.crud.events.EntityDeletedEvent * @see org.hswebframework.web.crud.events.EntityCreatedEvent + * @see org.hswebframework.web.crud.events.EntitySavedEvent */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) From bfe93109bfc58cee85a6c05264aafc43f8c5dc94 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sat, 8 May 2021 13:55:52 +0800 Subject: [PATCH 030/542] doNotSort --- .../hswebframework/web/api/crud/entity/QueryParamEntity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index d252bd494..66311d3fa 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -207,6 +207,11 @@ public QueryParamEntity noPaging() { return this; } + public QueryParamEntity doNotSort(){ + this.setSorts(new ArrayList<>()); + return this; + } + @Override public QueryParamEntity clone() { return (QueryParamEntity) super.clone(); From e0f82c06a8bf60b2b22f1e38ee2d1f663db9ef99 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 10 May 2021 13:48:04 +0800 Subject: [PATCH 031/542] =?UTF-8?q?=E4=BD=BF=E7=94=A8Schema=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E4=BD=9C=E4=B8=BA=E5=AD=97=E6=AE=B5=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/PermissionSynchronization.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java index b530b5bca..8c83e344a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java @@ -1,5 +1,6 @@ package org.hswebframework.web.system.authorization.defaults.service; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.extern.slf4j.Slf4j; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; @@ -60,8 +61,8 @@ public void handleResourceParseEvent(AuthorizeDefinitionInitializedEvent event) if (null != field.getAnnotation(Column.class) && !"id".equals(field.getName())) { OptionalField optionalField = new OptionalField(); optionalField.setName(field.getName()); - Optional.ofNullable(field.getAnnotation(Comment.class)) - .map(Comment::value) + Optional.ofNullable(field.getAnnotation(Schema.class)) + .map(Schema::description) .ifPresent(optionalField::setDescribe); fields.add(optionalField); } From d84f08c6176ce44a9d81b0b8fc21b4bb94dbbcfe Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 10 May 2021 13:48:54 +0800 Subject: [PATCH 032/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=BF=87=E6=BB=A4:=E8=B5=8B=E6=9D=83=E6=97=B6=E9=98=B2?= =?UTF-8?q?=E6=AD=A2=E8=B6=8A=E6=9D=83=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/AuthorizationSettingEntity.java | 16 ++++ .../api/entity/PermissionEntity.java | 23 ++++- ...AuthorizationServiceAutoConfiguration.java | 4 + .../configuration/PermissionProperties.java | 89 +++++++++++++++++++ .../DefaultAuthorizationSettingService.java | 1 + ...WebFluxAuthorizationSettingController.java | 21 ++++- .../webflux/WebFluxPermissionController.java | 45 +++++++--- 7 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index e07059b88..f22009d01 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -8,7 +8,9 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.bean.FastBeanCopier; import org.hswebframework.web.validator.CreateGroup; +import org.springframework.util.CollectionUtils; import javax.persistence.*; import javax.validation.constraints.NotBlank; @@ -16,6 +18,8 @@ import java.sql.JDBCType; import java.util.List; import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; @Table(name = "s_autz_setting_info", indexes = { @Index(name = "idx_sasi_dss", columnList = "dimension_type,dimension_target,state desc"), @@ -86,4 +90,16 @@ public class AuthorizationSettingEntity implements Entity { @Comment("是否合并") @Schema(description = "冲突时,是否合并") private Boolean merge; + + public AuthorizationSettingEntity copy(Predicate actionFilter, + Predicate dataAccessFilter){ + AuthorizationSettingEntity newSetting= FastBeanCopier.copy(this,new AuthorizationSettingEntity()); + if(!CollectionUtils.isEmpty(newSetting.getActions())){ + newSetting.setActions(newSetting.getActions().stream().filter(actionFilter).collect(Collectors.toSet())); + } + if(!CollectionUtils.isEmpty(newSetting.getDataAccesses())){ + newSetting.setDataAccesses(newSetting.getDataAccesses().stream().filter(dataAccessFilter).collect(Collectors.toList())); + } + return newSetting; + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index b145b1e5e..7b558a10a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -7,7 +7,9 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.bean.FastBeanCopier; import org.hswebframework.web.validator.CreateGroup; +import org.springframework.util.CollectionUtils; import javax.persistence.Column; import javax.persistence.Table; @@ -16,6 +18,9 @@ import java.sql.JDBCType; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; @Table(name = "s_permission") @Getter @@ -28,7 +33,7 @@ public class PermissionEntity extends GenericEntity { @Column @Comment("权限名称") @Schema(description = "权限名称") - @NotBlank(message = "权限名称不能为空",groups = CreateGroup.class) + @NotBlank(message = "权限名称不能为空", groups = CreateGroup.class) private String name; @Column @@ -70,4 +75,20 @@ public class PermissionEntity extends GenericEntity { @Schema(description = "其他配置") private Map properties; + public PermissionEntity copy(Predicate actionFilter, + Predicate fieldFilter) { + PermissionEntity entity = FastBeanCopier.copy(this, new PermissionEntity()); + + if (!CollectionUtils.isEmpty(entity.getActions())) { + entity.setActions(entity.getActions().stream().filter(actionFilter).collect(Collectors.toList())); + } + if (!CollectionUtils.isEmpty(entity.getOptionalFields())) { + entity.setOptionalFields(entity + .getOptionalFields() + .stream() + .filter(fieldFilter) + .collect(Collectors.toList())); + } + return entity; + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java index eef11dd30..5526487b9 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java @@ -76,4 +76,8 @@ public UserDimensionTerm userDimensionTerm() { return new UserDimensionTerm(); } + @Bean + public PermissionProperties permissionProperties(){ + return new PermissionProperties(); + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java new file mode 100644 index 000000000..23c5f232f --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java @@ -0,0 +1,89 @@ +package org.hswebframework.web.system.authorization.defaults.configuration; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.Permission; +import org.hswebframework.web.authorization.exception.AccessDenyException; +import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; +import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Flux; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Getter +@Setter +@ConfigurationProperties(prefix = "hsweb.permission") +public class PermissionProperties { + + private PermissionFilter filter = new PermissionFilter(); + + @Getter + @Setter + public static class PermissionFilter { + //开启权限过滤 + private boolean enabled = false; + //越权赋权时处理逻辑 + private UnAuthStrategy unAuthStrategy = UnAuthStrategy.error; + + private Set excludeUsername = new HashSet<>(); + + public AuthorizationSettingEntity handleSetting(Authentication authentication, + AuthorizationSettingEntity setting) { + if (!enabled || excludeUsername.contains(authentication.getUser().getUsername())) { + return setting; + } + //有全部权限 + if (authentication.hasPermission(setting.getPermission(), setting.getActions())) { + return setting; + } + //交给具体的策略处理 + return unAuthStrategy.handle(authentication, setting); + } + + public Flux doFilter(Flux flux, Authentication authentication) { + if (!enabled || excludeUsername.contains(authentication.getUser().getUsername())) { + return flux; + } + return flux + .map(entity -> entity + .copy(action -> authentication.hasPermission(entity.getId(), action.getAction()), + optionalField -> true)) + .filter(entity -> !CollectionUtils.isEmpty(entity.getActions())); + } + + public enum UnAuthStrategy { + //忽略赋权 + ignore { + @Override + public AuthorizationSettingEntity handle(Authentication authentication, AuthorizationSettingEntity setting) { + + return setting.copy(action -> authentication.hasPermission(setting.getPermission(), action), access -> true); + } + }, + //抛出错误 + error { + @Override + public AuthorizationSettingEntity handle(Authentication authentication, AuthorizationSettingEntity setting) { + if (!authentication.hasPermission(setting.getPermission())) { + throw new AccessDenyException("当前用户无权限:" + setting.getPermission()); + } + Set actions = new HashSet<>(setting.getActions()); + actions.removeAll(authentication + .getPermission(setting.getPermission()) + .map(Permission::getActions) + .orElseGet(Collections::emptySet)); + + throw new AccessDenyException("当前用户无权限:" + setting.getPermission() + "" +actions); + } + }; + + public abstract AuthorizationSettingEntity handle(Authentication authentication, + AuthorizationSettingEntity setting); + } + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index e98f0119c..a79576ae6 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -9,6 +9,7 @@ import org.hswebframework.web.crud.service.GenericReactiveCrudService; import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; +import org.hswebframework.web.system.authorization.defaults.configuration.PermissionProperties; import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java index 1162ee232..644dbabe5 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java @@ -2,28 +2,47 @@ import io.swagger.v3.oas.annotations.tags.Tag; +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.annotation.Resource; import org.hswebframework.web.crud.service.ReactiveCrudService; import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController; import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; +import org.hswebframework.web.system.authorization.defaults.configuration.PermissionProperties; import org.hswebframework.web.system.authorization.defaults.service.DefaultAuthorizationSettingService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @RestController @RequestMapping("/autz-setting") @Authorize -@Resource(id = "autz-setting",name = "权限分配",group = "system") +@Resource(id = "autz-setting", name = "权限分配", group = "system") @Tag(name = "权限分配") public class WebFluxAuthorizationSettingController implements ReactiveServiceCrudController { @Autowired private DefaultAuthorizationSettingService settingService; + @Autowired + private PermissionProperties permissionProperties; + @Override public ReactiveCrudService getService() { return settingService; } + + @Override + public AuthorizationSettingEntity applyAuthentication(AuthorizationSettingEntity entity, + Authentication authentication) { + AuthorizationSettingEntity setting = ReactiveServiceCrudController.super.applyAuthentication(entity, authentication); + + return permissionProperties + .getFilter() + .handleSetting(authentication, setting); + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java index bb9ba1788..b2137c937 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java @@ -4,15 +4,20 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.collections.CollectionUtils; -import org.hswebframework.web.authorization.annotation.Authorize; -import org.hswebframework.web.authorization.annotation.QueryAction; -import org.hswebframework.web.authorization.annotation.Resource; +import org.hswebframework.ezorm.rdb.operator.dml.query.SortOrder; +import org.hswebframework.web.api.crud.entity.QueryNoPagingOperation; +import org.hswebframework.web.api.crud.entity.QueryOperation; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.annotation.*; import org.hswebframework.web.crud.service.ReactiveCrudService; import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController; import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; +import org.hswebframework.web.system.authorization.defaults.configuration.PermissionProperties; import org.hswebframework.web.system.authorization.defaults.service.DefaultPermissionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; @@ -27,24 +32,40 @@ public class WebFluxPermissionController implements ReactiveServiceCrudControlle @Autowired private DefaultPermissionService permissionService; + @Autowired + private PermissionProperties permissionProperties; + @Override public ReactiveCrudService getService() { return permissionService; } @PutMapping("/status/{status}") - @QueryAction + @SaveAction @Operation(summary = "批量修改权限状态") - public Mono changePermissionState(@PathVariable @Parameter(description = "状态值:0禁用,1启用.") Byte status, @RequestBody List idList) { + public Mono changePermissionState(@PathVariable @Parameter(description = "状态值:0禁用,1启用.") Byte status, + @RequestBody List idList) { return Mono.just(idList) - .filter(CollectionUtils::isNotEmpty) - .flatMap(list -> permissionService.createUpdate() - .set(PermissionEntity::getStatus, status) - .where() - .in(PermissionEntity::getId, list) - .execute()) - .defaultIfEmpty(0); + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> permissionService + .createUpdate() + .set(PermissionEntity::getStatus, status) + .where() + .in(PermissionEntity::getId, list) + .execute()) + .defaultIfEmpty(0); + + } + @GetMapping("/_query/for-grant") + @ResourceAction(id = "grant", name = "赋权") + @QueryNoPagingOperation(summary = "获取用于赋权的权限列表") + public Flux queryForGrant(QueryParamEntity query) { + return Authentication + .currentReactive() + .flatMapMany(auth -> permissionProperties + .getFilter() + .doFilter(permissionService.query(query.noPaging()), auth)); } } From dd07aba4a46cee647707365e2571d51a7d7205a0 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 10 May 2021 13:53:03 +0800 Subject: [PATCH 033/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/entity/TermExpressionParserTest.java | 56 +++++++++++++++++++ .../service/PermissionSynchronization.java | 6 -- 2 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java diff --git a/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java new file mode 100644 index 000000000..b91588483 --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java @@ -0,0 +1,56 @@ +package org.hswebframework.web.api.crud.entity; + +import org.hswebframework.ezorm.core.param.Term; +import org.hswebframework.ezorm.core.param.TermType; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +public class TermExpressionParserTest { + + @Test + public void test() { + { + List terms = TermExpressionParser.parse("name = 1"); + + assertEquals(terms.get(0).getTermType(), TermType.eq); + + } + +// { +// List terms = TermExpressionParser.parse("name = 1"); +// +// assertEquals(terms.get(0).getTermType(), TermType.not); +// +// } + { + List terms = TermExpressionParser.parse("name > 1"); + + assertEquals(terms.get(0).getTermType(), TermType.gt); + } + + { + List terms = TermExpressionParser.parse("name >= 1"); + + assertEquals(terms.get(0).getTermType(), TermType.gte); + } + + { + List terms = TermExpressionParser.parse("name gte 1 and name not 1"); + + assertEquals(terms.get(0).getTermType(), TermType.gte); + assertEquals(terms.get(1).getTermType(), TermType.not); + } + + { + List terms = TermExpressionParser.parse("name gte 1 and (name not 1 or age gt 0)"); + + assertEquals(terms.get(0).getTermType(), TermType.gte); + assertEquals(terms.get(1).getTerms().get(0).getTermType(), TermType.not); + assertEquals(terms.get(1).getTerms().get(1).getTermType(), TermType.gt); + } + } + +} \ 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/PermissionSynchronization.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java index 8c83e344a..7a153619e 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java @@ -3,28 +3,22 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.extern.slf4j.Slf4j; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; -import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.utils.ClassUtils; import org.hswebframework.web.api.crud.entity.Entity; import org.hswebframework.web.authorization.define.*; -import org.hswebframework.web.crud.web.reactive.ReactiveCrudController; import org.hswebframework.web.crud.web.reactive.ReactiveQueryController; -import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController; import org.hswebframework.web.crud.web.reactive.ReactiveServiceQueryController; import org.hswebframework.web.system.authorization.api.entity.ActionEntity; import org.hswebframework.web.system.authorization.api.entity.OptionalField; import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; -import org.hswebframework.web.utils.AnnotationUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.event.EventListener; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import javax.persistence.Column; -import java.lang.reflect.Field; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; From 2fb33ee6103e2f6e19fff6b32ba7f9d3ff0ce17f Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 11 May 2021 10:03:48 +0800 Subject: [PATCH 034/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90ID?= =?UTF-8?q?=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/api/entity/PermissionEntity.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 7b558a10a..b3957ddd0 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -14,11 +14,10 @@ import javax.persistence.Column; import javax.persistence.Table; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; import java.sql.JDBCType; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -30,6 +29,12 @@ @AllArgsConstructor public class PermissionEntity extends GenericEntity { + @Override + @Pattern(regexp = "^[0-9a-zA-Z_\\-]+$", message = "ID只能由数字,字母,下划线和中划线组成", groups = CreateGroup.class) + public String getId() { + return super.getId(); + } + @Column @Comment("权限名称") @Schema(description = "权限名称") From 0a8f48080c8c8d0dcc5f7e1ba20c1f5b3c33bbc2 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 11 May 2021 10:04:00 +0800 Subject: [PATCH 035/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/configuration/PermissionProperties.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java index 23c5f232f..7f37d667f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java @@ -69,9 +69,6 @@ public AuthorizationSettingEntity handle(Authentication authentication, Authoriz error { @Override public AuthorizationSettingEntity handle(Authentication authentication, AuthorizationSettingEntity setting) { - if (!authentication.hasPermission(setting.getPermission())) { - throw new AccessDenyException("当前用户无权限:" + setting.getPermission()); - } Set actions = new HashSet<>(setting.getActions()); actions.removeAll(authentication .getPermission(setting.getPermission()) From e41dbaba6aff11052a80d655d2d15516dd05adb1 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 11 May 2021 14:22:07 +0800 Subject: [PATCH 036/542] =?UTF-8?q?=E4=BC=98=E5=8C=96OAuth2=E8=AE=A4?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/OAuth2Request.java | 6 +- .../server/code/AuthorizationCodeRequest.java | 2 +- .../code/AuthorizationCodeTokenRequest.java | 2 +- .../credential/ClientCredentialRequest.java | 2 +- .../server/web/OAuth2AuthorizeController.java | 61 +++++++++++++++---- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Request.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Request.java index ab21e5753..c0e86ceb0 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Request.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Request.java @@ -13,15 +13,15 @@ @AllArgsConstructor public class OAuth2Request { - private Map parameters; + private Map parameters; - public Optional getParameter(String key) { + public Optional getParameter(String key) { return Optional.ofNullable(parameters) .map(params -> params.get(key)); } - public OAuth2Request with(String parameter, Object key) { + public OAuth2Request with(String parameter, String key) { if (parameters == null) { parameters = new HashMap<>(); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeRequest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeRequest.java index 0fe299319..11b7e3196 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeRequest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeRequest.java @@ -19,7 +19,7 @@ public class AuthorizationCodeRequest extends OAuth2Request { public AuthorizationCodeRequest(OAuth2Client client, Authentication authentication, - Map parameters) { + Map parameters) { super(parameters); this.client = client; this.authentication = authentication; diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java index d3ba3a4fb..df4089dd6 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java @@ -15,7 +15,7 @@ public class AuthorizationCodeTokenRequest extends OAuth2Request { private OAuth2Client client; - public AuthorizationCodeTokenRequest(OAuth2Client client, Map parameters) { + public AuthorizationCodeTokenRequest(OAuth2Client client, Map parameters) { super(parameters); this.client = client; } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/ClientCredentialRequest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/ClientCredentialRequest.java index 2579909f9..5203baf88 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/ClientCredentialRequest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/ClientCredentialRequest.java @@ -11,7 +11,7 @@ public class ClientCredentialRequest extends OAuth2Request { private final OAuth2Client client; - public ClientCredentialRequest(OAuth2Client client, Map parameters) { + public ClientCredentialRequest(OAuth2Client client, Map parameters) { super(parameters); this.client = client; } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java index b30caa38b..557827e85 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java @@ -19,7 +19,9 @@ import org.hswebframework.web.oauth2.server.code.AuthorizationCodeRequest; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeTokenRequest; import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @@ -48,29 +50,30 @@ public class OAuth2AuthorizeController { @Parameter(name = "response_type", description = "固定值为code") }) public Mono authorizeByCode(ServerWebExchange exchange) { - Map param = new HashMap<>(exchange.getRequest().getQueryParams().toSingleValueMap()); + Map param = new HashMap<>(exchange.getRequest().getQueryParams().toSingleValueMap()); return Authentication .currentReactive() .switchIfEmpty(Mono.error(UnAuthorizedException::new)) .flatMap(auth -> this - .getOAuth2Client((String) param.get("client_id")) - .switchIfEmpty(Mono.error(() -> new OAuth2Exception(ErrorType.ILLEGAL_CLIENT_ID))) + .getOAuth2Client(param.get("client_id")) .flatMap(client -> { - String redirectUri = (String) param.getOrDefault("redirect_uri", client.getRedirectUrl()); + String redirectUri = param.getOrDefault("redirect_uri", client.getRedirectUrl()); client.validateRedirectUri(redirectUri); return oAuth2GrantService .authorizationCode() .requestCode(new AuthorizationCodeRequest(client, auth, param)) .doOnNext(response -> { - Optional.ofNullable(param.get("state")).ifPresent(state -> response.with("state", state)); + Optional + .ofNullable(param.get("state")) + .ifPresent(state -> response.with("state", state)); }) .map(response -> buildRedirect(redirectUri, response.getParameters())); })); } @GetMapping(value = "/token") - @Operation(summary = "使用申请token", parameters = { + @Operation(summary = "(GET)申请token", parameters = { @Parameter(name = "client_id"), @Parameter(name = "client_secret"), @Parameter(name = "code", description = "grantType为authorization_code时不能为空"), @@ -89,10 +92,33 @@ public Mono> requestTokenByCode( .map(ResponseEntity::ok); } + + @PostMapping(value = "/token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @Operation(summary = "(POST)申请token", parameters = { + @Parameter(name = "client_id"), + @Parameter(name = "client_secret"), + @Parameter(name = "code", description = "grantType为authorization_code时不能为空"), + @Parameter(name = "grant_type", schema = @Schema(implementation = GrantType.class)) + }) + @Authorize(ignore = true) + public Mono> requestTokenByCode(ServerWebExchange exchange) { + return exchange + .getFormData() + .map(MultiValueMap::toSingleValueMap) + .flatMap(params -> { + GrantType grantType = GrantType.of(params.get("grant_type")); + return this + .getOAuth2Client(params.get("client_id")) + .doOnNext(client -> client.validateSecret(params.get("client_secret"))) + .flatMap(client -> grantType.requestToken(oAuth2GrantService, client, new HashMap<>(params))) + .map(ResponseEntity::ok); + }); + } + public enum GrantType { authorization_code { @Override - Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { + Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { return service .authorizationCode() .requestToken(new AuthorizationCodeTokenRequest(client, param)); @@ -100,14 +126,22 @@ Mono requestToken(OAuth2GrantService service, OAuth2Client client, }, client_credentials { @Override - Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { + Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { return service .clientCredential() .requestToken(new ClientCredentialRequest(client, param)); } }; - abstract Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param); + abstract Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param); + + static GrantType of(String name){ + try { + return GrantType.valueOf(name); + }catch (Throwable e){ + throw new OAuth2Exception(ErrorType.UNSUPPORTED_GRANT_TYPE); + } + } } @SneakyThrows @@ -117,9 +151,9 @@ public static String urlEncode(String url) { static String buildRedirect(String redirectUri, Map params) { String paramsString = params.entrySet() - .stream() - .map(e -> e.getKey() + "=" + urlEncode(String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + .stream() + .map(e -> e.getKey() + "=" + urlEncode(String.valueOf(e.getValue()))) + .collect(Collectors.joining("&")); if (redirectUri.contains("?")) { return redirectUri + "&" + paramsString; } @@ -128,6 +162,7 @@ static String buildRedirect(String redirectUri, Map params) { private Mono getOAuth2Client(String id) { return clientManager - .getClient(id); + .getClient(id) + .switchIfEmpty(Mono.error(() -> new OAuth2Exception(ErrorType.ILLEGAL_CLIENT_ID))); } } From 86c35136ce94ed81d6f2bf99162b7fec0af0d10e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 13 May 2021 16:48:59 +0800 Subject: [PATCH 037/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0DimensionTerm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...AuthorizationServiceAutoConfiguration.java | 6 +- .../defaults/service/terms/DimensionTerm.java | 87 +++++++++++++++++++ .../service/terms/UserDimensionTerm.java | 2 +- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java index 5526487b9..92c3ad910 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java @@ -7,8 +7,8 @@ import org.hswebframework.web.system.authorization.api.UserDimensionProvider; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.hswebframework.web.system.authorization.defaults.service.*; +import org.hswebframework.web.system.authorization.defaults.service.terms.DimensionTerm; import org.hswebframework.web.system.authorization.defaults.service.terms.UserDimensionTerm; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; @@ -76,6 +76,10 @@ public UserDimensionTerm userDimensionTerm() { return new UserDimensionTerm(); } + @Bean + public DimensionTerm dimensionTerm(){ + return new DimensionTerm(); + } @Bean public PermissionProperties permissionProperties(){ return new PermissionProperties(); diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java new file mode 100644 index 000000000..9760376d2 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java @@ -0,0 +1,87 @@ +package org.hswebframework.web.system.authorization.defaults.service.terms; + +import org.apache.commons.collections4.CollectionUtils; +import org.hswebframework.ezorm.core.Conditional; +import org.hswebframework.ezorm.core.dsl.Query; +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.ezorm.core.param.Term; +import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.EmptySqlFragments; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.PrepareSqlFragments; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.SqlFragments; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.term.AbstractTermFragmentBuilder; + +import java.util.List; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +/** + * 查询和用户维度绑定的数据,如: 查询某个用户的机构 + * where id$dimension$org = userID + * + * @author zhouhao + * @since 4.0.10 + */ +public class DimensionTerm extends AbstractTermFragmentBuilder { + public DimensionTerm() { + super("dimension", "和维度关联的数据"); + } + + public static > T inject(T query, + String column, + String dimensionType, + List userId) { + return inject(query, column, dimensionType, false, false, userId); + } + + public static > T inject(T query, + String column, + String dimensionType, + boolean not, + boolean any, + List userId) { + return (T)query.accept(column, createTermType(dimensionType, not, any), userId); + } + + public static String createTermType(String dimensionType, boolean not, boolean any) { + StringJoiner joiner = new StringJoiner("$"); + joiner.add("dimension"); + joiner.add(dimensionType); + if (not) { + joiner.add("not"); + } + if (any) { + joiner.add("any"); + } + return joiner.toString(); + } + + @Override + public SqlFragments createFragments(String columnFullName, RDBColumnMetadata column, Term term) { + + List values = convertList(column, term); + if (values.isEmpty()) { + return EmptySqlFragments.INSTANCE; + } + List options = term.getOptions(); + if (CollectionUtils.isEmpty(options)) { + throw new IllegalArgumentException("查询条件错误,正确格式:" + column.getAlias() + "$dimension${type}$[not]"); + } + PrepareSqlFragments fragments = PrepareSqlFragments.of(); + + if (options.contains("not")) { + fragments.addSql("not "); + } + fragments + .addSql("exists(select 1 from s_dimension_user d where d.dimension_type_id = ? and d.dimension_id =", columnFullName) + .addParameter(options.get(0)); + + if (!options.contains("any")) { + fragments.addSql("and d.user_id in(", values.stream().map(r -> "?").collect(Collectors.joining(",")), ")") + .addParameter(values); + } + + fragments.addSql(")"); + return fragments; + } +} \ 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/terms/UserDimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java index 6d952d180..e73bc8028 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java @@ -12,7 +12,7 @@ public class UserDimensionTerm extends AbstractTermFragmentBuilder { public UserDimensionTerm() { - super("in-dimension", "在维度中的用户"); + super("in-dimension", "在维度中的用户数据"); } @Override From 0e4d4016d9cd8e4e8c8cd5c236155a4856aacb35 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 13 May 2021 19:03:46 +0800 Subject: [PATCH 038/542] =?UTF-8?q?RedisUserTokenManager=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E6=95=88=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/token/UserToken.java | 18 ++++- .../token/redis/RedisUserTokenManager.java | 81 +++++++++++++++---- .../token/redis/SimpleUserToken.java | 11 +++ 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java index c257163f6..84d25bc7d 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java @@ -49,8 +49,25 @@ public interface UserToken extends Serializable, Comparable { */ String getType(); + /** + * @return 会话过期时间, 单位毫秒 + */ long getMaxInactiveInterval(); + /** + * 检查会话是否过期 + * + * @return 是否过期 + * @since 4.0.10 + */ + default boolean checkExpired() { + long maxInactiveInterval = getMaxInactiveInterval(); + if (maxInactiveInterval > 0) { + return System.currentTimeMillis() - getLastRequestTime() > maxInactiveInterval; + } + return false; + } + default boolean isNormal() { return getState() == TokenState.normal; } @@ -77,7 +94,6 @@ default boolean isDeny() { return getState() == TokenState.deny; } - default boolean validate() { if (!isNormal()) { throw new UnAuthorizedException(getState()); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index 38342e380..d1cac3f31 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -17,11 +17,16 @@ import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; import reactor.core.publisher.Flux; +import reactor.core.publisher.FluxSink; import reactor.core.publisher.Mono; import java.time.Duration; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; import java.util.stream.Collectors; public class RedisUserTokenManager implements UserTokenManager { @@ -32,21 +37,41 @@ public class RedisUserTokenManager implements UserTokenManager { private final ReactiveSetOperations userTokenMapping; + @Setter + private Map localCache = new ConcurrentHashMap<>(); + + private FluxSink touchSink; + public RedisUserTokenManager(ReactiveRedisOperations operations) { this.operations = operations; this.userTokenStore = operations.opsForHash(); this.userTokenMapping = operations.opsForSet(); + this.operations + .listenToChannel("_user_token_removed") + .subscribe(msg -> localCache.remove(String.valueOf(msg.getMessage()))); + + Flux.create(sink -> this.touchSink = sink) + .buffer(Flux.interval(Duration.ofSeconds(10)), HashSet::new) + .flatMap(list -> Flux + .fromIterable(list) + .flatMap(token -> operations + .expire(getTokenRedisKey(token.getToken()), Duration.ofMillis(token.getMaxInactiveInterval())) + .then()) + .onErrorResume(err -> Mono.empty())) + .subscribe(); + } @SuppressWarnings("all") public RedisUserTokenManager(ReactiveRedisConnectionFactory connectionFactory) { this(new ReactiveRedisTemplate<>(connectionFactory, - RedisSerializationContext.newSerializationContext() - .key((RedisSerializer) RedisSerializer.string()) - .value(RedisSerializer.java()) - .hashKey(RedisSerializer.string()) - .hashValue(RedisSerializer.java()) - .build() + RedisSerializationContext + .newSerializationContext() + .key((RedisSerializer) RedisSerializer.string()) + .value(RedisSerializer.java()) + .hashKey(RedisSerializer.string()) + .hashValue(RedisSerializer.java()) + .build() )); } @@ -72,11 +97,17 @@ private String getUserRedisKey(String key) { @Override public Mono getByToken(String token) { + SimpleUserToken inCache = localCache.get(token); + if (inCache != null && inCache.isNormal()) { + return Mono.just(inCache); + } return userTokenStore .entries(getTokenRedisKey(token)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) .filter(map -> !map.isEmpty()) - .map(SimpleUserToken::of); + .map(SimpleUserToken::of) + .doOnNext(userToken -> localCache.put(userToken.getToken(), userToken)) + .cast(UserToken.class); } @Override @@ -185,7 +216,7 @@ public Mono changeTokenState(String token, TokenState state) { public Mono signIn(String token, String type, String userId, long maxInactiveInterval) { return Mono .defer(() -> { - Mono doSign = Mono.defer(() -> { + Mono doSign = Mono.defer(() -> { Map map = new HashMap<>(); map.put("token", token); map.put("type", type); @@ -237,12 +268,17 @@ public Mono signIn(String token, String type, String userId, long max @Override public Mono touch(String token) { + SimpleUserToken inCache = localCache.get(token); + if (inCache != null && inCache.isNormal()) { + inCache.setLastRequestTime(System.currentTimeMillis()); + //异步touch + touchSink.next(inCache); + return Mono.empty(); + } return getByToken(token) .flatMap(userToken -> { if (userToken.getMaxInactiveInterval() > 0) { - return operations - .expire(getTokenRedisKey(token), Duration.ofMillis(userToken.getMaxInactiveInterval())) - .then(); + touchSink.next(userToken); } return Mono.empty(); }); @@ -268,26 +304,37 @@ public Mono checkExpiredToken() { .then(); } + private Mono notifyTokenRemoved(String token) { + return operations.convertAndSend("_user_token_removed", token).then(); + } + private Mono onTokenRemoved(UserToken token) { + localCache.remove(token.getToken()); + if (eventPublisher == null) { - return Mono.empty(); + return notifyTokenRemoved(token.getToken()); } - return Mono.fromRunnable(() -> eventPublisher.publishEvent(new UserTokenRemovedEvent(token))); + return Mono.fromRunnable(() -> eventPublisher.publishEvent(new UserTokenRemovedEvent(token))) + .then(notifyTokenRemoved(token.getToken())); } - private Mono onTokenChanged(UserToken old, UserToken newToken) { + private Mono onTokenChanged(UserToken old, SimpleUserToken newToken) { + localCache.put(newToken.getToken(), newToken); if (eventPublisher == null) { - return Mono.empty(); + return notifyTokenRemoved(newToken.getToken()); } return Mono.fromRunnable(() -> eventPublisher.publishEvent(new UserTokenChangedEvent(old, newToken))); } - private Mono onUserTokenCreated(UserToken token) { + private Mono onUserTokenCreated(SimpleUserToken token) { + localCache.put(token.getToken(), token); if (eventPublisher == null) { - return Mono.just(token); + return notifyTokenRemoved(token.getToken()) + .thenReturn(token); } return Mono .fromRunnable(() -> eventPublisher.publishEvent(new UserTokenCreatedEvent(token))) + .then(notifyTokenRemoved(token.getToken())) .thenReturn(token); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java index 129867450..83742ba3b 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java @@ -1,5 +1,6 @@ package org.hswebframework.web.authorization.token.redis; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -12,6 +13,7 @@ @Getter @Setter @ToString(exclude = "token") +@EqualsAndHashCode(of = "token") public class SimpleUserToken implements UserToken { private String userId; @@ -34,4 +36,13 @@ public static SimpleUserToken of(Map map) { return FastBeanCopier.copy(map, new SimpleUserToken()); } + + @Override + public boolean isNormal() { + if (checkExpired()) { + setState(TokenState.expired); + return false; + } + return UserToken.super.isNormal(); + } } From 64ad82275a25f1f98d988b9117983feabfa87f8d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 13 May 2021 19:04:01 +0800 Subject: [PATCH 039/542] =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=8E=B7=E5=8F=96IP?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E8=80=8C=E4=B8=8D=E6=98=AF=E8=8E=B7=E5=8F=96?= =?UTF-8?q?host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/utils/ReactiveWebUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/ReactiveWebUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/ReactiveWebUtils.java index 67dbf1d4f..ced5b8630 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/ReactiveWebUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/ReactiveWebUtils.java @@ -30,7 +30,7 @@ public static String getIpAddr(ServerHttpRequest request) { } } return Optional.ofNullable(request.getRemoteAddress()) - .map(InetSocketAddress::getHostName) + .map(addr->addr.getAddress().getHostAddress()) .orElse("unknown"); } From 430678e5a8764ad000378f1b3bb29785aff03ed4 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 13 May 2021 19:04:25 +0800 Subject: [PATCH 040/542] =?UTF-8?q?=E4=BC=98=E5=8C=96OAuth2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/OAuth2GrantService.java | 2 ++ .../server/OAuth2ServerAutoConfiguration.java | 12 +++++++++- .../code/AuthorizationCodeResponse.java | 3 ++- .../code/AuthorizationCodeTokenRequest.java | 5 ++-- .../code/DefaultAuthorizationCodeGranter.java | 3 ++- .../impl/CompositeOAuth2GrantService.java | 8 +++++++ .../refresh/DefaultRefreshTokenGranter.java | 24 +++++++++++++++++++ .../server/refresh/RefreshTokenGranter.java | 18 ++++++++++++++ .../server/refresh/RefreshTokenRequest.java | 23 ++++++++++++++++++ .../server/web/OAuth2AuthorizeController.java | 10 +++++++- 10 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/DefaultRefreshTokenGranter.java create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenGranter.java create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenRequest.java diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2GrantService.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2GrantService.java index e723f1632..e49508173 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2GrantService.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2GrantService.java @@ -3,6 +3,7 @@ import org.hswebframework.web.oauth2.server.code.AuthorizationCodeGranter; import org.hswebframework.web.oauth2.server.credential.ClientCredentialGranter; +import org.hswebframework.web.oauth2.server.refresh.RefreshTokenGranter; public interface OAuth2GrantService { @@ -10,4 +11,5 @@ public interface OAuth2GrantService { ClientCredentialGranter clientCredential(); + RefreshTokenGranter refreshToken(); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index e2cd3205d..66228cc79 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -10,6 +10,8 @@ import org.hswebframework.web.oauth2.server.credential.DefaultClientCredentialGranter; import org.hswebframework.web.oauth2.server.impl.CompositeOAuth2GrantService; import org.hswebframework.web.oauth2.server.impl.RedisAccessTokenManager; +import org.hswebframework.web.oauth2.server.refresh.DefaultRefreshTokenGranter; +import org.hswebframework.web.oauth2.server.refresh.RefreshTokenGranter; import org.hswebframework.web.oauth2.server.web.OAuth2AuthorizeController; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -62,13 +64,21 @@ public AuthorizationCodeGranter authorizationCodeGranter(AccessTokenManager toke return new DefaultAuthorizationCodeGranter(tokenManager, redisConnectionFactory); } + @Bean + @ConditionalOnMissingBean + public RefreshTokenGranter refreshTokenGranter(AccessTokenManager tokenManager) { + return new DefaultRefreshTokenGranter(tokenManager); + } + @Bean @ConditionalOnMissingBean public OAuth2GrantService oAuth2GrantService(ObjectProvider codeProvider, - ObjectProvider credentialProvider) { + ObjectProvider credentialProvider, + ObjectProvider refreshProvider) { CompositeOAuth2GrantService grantService = new CompositeOAuth2GrantService(); grantService.setAuthorizationCodeGranter(codeProvider.getIfAvailable()); grantService.setClientCredentialGranter(credentialProvider.getIfAvailable()); + grantService.setRefreshTokenGranter(refreshProvider.getIfAvailable()); return grantService; } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeResponse.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeResponse.java index da3cb769d..13e72e780 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeResponse.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeResponse.java @@ -4,6 +4,7 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.hswebframework.web.oauth2.OAuth2Constants; import org.hswebframework.web.oauth2.server.OAuth2Client; import org.hswebframework.web.oauth2.server.OAuth2Request; import org.hswebframework.web.oauth2.server.OAuth2Response; @@ -18,6 +19,6 @@ public class AuthorizationCodeResponse extends OAuth2Response { public AuthorizationCodeResponse(String code) { this.code = code; - with("code", code); + with(OAuth2Constants.code, code); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java index df4089dd6..896981b5a 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/AuthorizationCodeTokenRequest.java @@ -2,6 +2,7 @@ import lombok.Getter; import lombok.Setter; +import org.hswebframework.web.oauth2.OAuth2Constants; import org.hswebframework.web.oauth2.server.OAuth2Client; import org.hswebframework.web.oauth2.server.OAuth2Request; @@ -21,10 +22,10 @@ public AuthorizationCodeTokenRequest(OAuth2Client client, Map pa } public Optional code() { - return getParameter("code").map(String::valueOf); + return getParameter(OAuth2Constants.code).map(String::valueOf); } public Optional scope() { - return getParameter("scope").map(String::valueOf); + return getParameter(OAuth2Constants.scope).map(String::valueOf); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java index a74c13be4..c3b53cabd 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java @@ -4,6 +4,7 @@ import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.id.IDGenerator; import org.hswebframework.web.oauth2.ErrorType; +import org.hswebframework.web.oauth2.OAuth2Constants; import org.hswebframework.web.oauth2.OAuth2Exception; import org.hswebframework.web.oauth2.server.AccessToken; import org.hswebframework.web.oauth2.server.AccessTokenManager; @@ -44,7 +45,7 @@ public Mono requestCode(AuthorizationCodeRequest requ Authentication authentication = request.getAuthentication(); AuthorizationCodeCache codeCache = new AuthorizationCodeCache(); String code = IDGenerator.MD5.generate(); - request.getParameter("scope").map(String::valueOf).ifPresent(codeCache::setScope); + request.getParameter(OAuth2Constants.scope).map(String::valueOf).ifPresent(codeCache::setScope); codeCache.setCode(code); codeCache.setClientId(client.getClientId()); ScopePredicate permissionPredicate = OAuth2ScopeUtils.createScopePredicate(codeCache.getScope()); diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/CompositeOAuth2GrantService.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/CompositeOAuth2GrantService.java index 5b37bb7d9..bf9a1ee70 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/CompositeOAuth2GrantService.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/CompositeOAuth2GrantService.java @@ -5,6 +5,7 @@ import org.hswebframework.web.oauth2.server.credential.ClientCredentialGranter; import org.hswebframework.web.oauth2.server.OAuth2GrantService; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeGranter; +import org.hswebframework.web.oauth2.server.refresh.RefreshTokenGranter; @Getter @Setter @@ -14,6 +15,8 @@ public class CompositeOAuth2GrantService implements OAuth2GrantService { private ClientCredentialGranter clientCredentialGranter; + private RefreshTokenGranter refreshTokenGranter; + @Override public AuthorizationCodeGranter authorizationCode() { return authorizationCodeGranter; @@ -23,4 +26,9 @@ public AuthorizationCodeGranter authorizationCode() { public ClientCredentialGranter clientCredential() { return clientCredentialGranter; } + + @Override + public RefreshTokenGranter refreshToken() { + return refreshTokenGranter; + } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/DefaultRefreshTokenGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/DefaultRefreshTokenGranter.java new file mode 100644 index 000000000..5bdc9a56f --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/DefaultRefreshTokenGranter.java @@ -0,0 +1,24 @@ +package org.hswebframework.web.oauth2.server.refresh; + +import lombok.AllArgsConstructor; +import org.hswebframework.web.oauth2.ErrorType; +import org.hswebframework.web.oauth2.OAuth2Exception; +import org.hswebframework.web.oauth2.server.AccessToken; +import org.hswebframework.web.oauth2.server.AccessTokenManager; +import reactor.core.publisher.Mono; + +@AllArgsConstructor +public class DefaultRefreshTokenGranter implements RefreshTokenGranter { + + private final AccessTokenManager accessTokenManager; + + @Override + public Mono requestToken(RefreshTokenRequest request) { + + return accessTokenManager + .refreshAccessToken( + request.getClient().getClientId(), + request.refreshToken().orElseThrow(()->new OAuth2Exception(ErrorType.ILLEGAL_REFRESH_TOKEN)) + ); + } +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenGranter.java new file mode 100644 index 000000000..b09b44535 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenGranter.java @@ -0,0 +1,18 @@ +package org.hswebframework.web.oauth2.server.refresh; + +import org.hswebframework.web.oauth2.server.AccessToken; +import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; +import reactor.core.publisher.Mono; + +public interface RefreshTokenGranter { + + /** + * 刷新token + * + * @param request 请求 + * @return token + */ + Mono requestToken(RefreshTokenRequest request); + + +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenRequest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenRequest.java new file mode 100644 index 000000000..a9b4c5074 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/refresh/RefreshTokenRequest.java @@ -0,0 +1,23 @@ +package org.hswebframework.web.oauth2.server.refresh; + +import lombok.Getter; +import org.hswebframework.web.oauth2.OAuth2Constants; +import org.hswebframework.web.oauth2.server.OAuth2Client; +import org.hswebframework.web.oauth2.server.OAuth2Request; + +import java.util.Map; +import java.util.Optional; + +@Getter +public class RefreshTokenRequest extends OAuth2Request { + private final OAuth2Client client; + + public RefreshTokenRequest(OAuth2Client client, Map parameters) { + super(parameters); + this.client = client; + } + + public Optional refreshToken(){ + return getParameter(OAuth2Constants.refresh_token); + } +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java index 557827e85..2629686f4 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java @@ -7,7 +7,6 @@ import lombok.AllArgsConstructor; import lombok.SneakyThrows; import org.hswebframework.web.authorization.Authentication; -import org.hswebframework.web.authorization.ReactiveAuthenticationManager; import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.exception.UnAuthorizedException; import org.hswebframework.web.oauth2.ErrorType; @@ -19,6 +18,7 @@ import org.hswebframework.web.oauth2.server.code.AuthorizationCodeRequest; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeTokenRequest; import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; +import org.hswebframework.web.oauth2.server.refresh.RefreshTokenRequest; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; @@ -131,6 +131,14 @@ Mono requestToken(OAuth2GrantService service, OAuth2Client client, .clientCredential() .requestToken(new ClientCredentialRequest(client, param)); } + }, + refresh_token{ + @Override + Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { + return service + .refreshToken() + .requestToken(new RefreshTokenRequest(client, param)); + } }; abstract Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param); From 6b8455e3a3765d1dd3e41537f15522573818adac Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 14 May 2021 16:20:19 +0800 Subject: [PATCH 041/542] =?UTF-8?q?=E4=BC=98=E5=8C=96swagger=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/reactive/ReactiveQueryController.java | 15 ++++++++------- .../ReactiveServiceQueryController.java | 17 +++++++++-------- .../ReactiveTreeServiceQueryController.java | 13 ++++++------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java index 1a7bcbd07..ec01cca9e 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.Parameter; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.QueryNoPagingOperation; import org.hswebframework.web.api.crud.entity.QueryOperation; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.authorization.annotation.Authorize; @@ -77,9 +78,9 @@ default Flux query(@Parameter(hidden = true) QueryParamEntity query) { */ @PostMapping("/_query/no-paging") @QueryAction - @Operation(summary = "使用POST方式分页动态查询(不返回总数)", + @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") - default Flux query(@RequestBody Mono query) { + default Flux query(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMapMany(this::query); } @@ -120,15 +121,15 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti @PostMapping("/_query") @QueryAction @SuppressWarnings("all") - @Operation(summary = "使用POST方式分页动态查询") - default Mono> queryPager(@RequestBody Mono query) { + @QueryOperation(summary = "使用POST方式分页动态查询") + default Mono> queryPager(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMap(q -> queryPager(q)); } @PostMapping("/_count") @QueryAction - @Operation(summary = "使用POST方式查询总数") - default Mono count(@RequestBody Mono query) { + @QueryNoPagingOperation(summary = "使用POST方式查询总数") + default Mono count(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMap(this::count); } @@ -144,7 +145,7 @@ default Mono count(@RequestBody Mono query) { */ @GetMapping("/_count") @QueryAction - @QueryOperation(summary = "使用GET方式查询总数") + @QueryNoPagingOperation(summary = "使用GET方式查询总数") default Mono count(@Parameter(hidden = true) QueryParamEntity query) { return getRepository() .createQuery() diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java index de760afbb..d1dd307e4 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.QueryNoPagingOperation; import org.hswebframework.web.api.crud.entity.QueryOperation; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.authorization.annotation.Authorize; @@ -35,7 +36,7 @@ public interface ReactiveServiceQueryController { */ @GetMapping("/_query/no-paging") @QueryAction - @QueryOperation(summary = "使用GET方式分页动态查询(不返回总数)", + @QueryNoPagingOperation(summary = "使用GET方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") default Flux query(@Parameter(hidden = true) QueryParamEntity query) { return getService() @@ -71,9 +72,9 @@ default Flux query(@Parameter(hidden = true) QueryParamEntity query) { */ @PostMapping("/_query/no-paging") @QueryAction - @Operation(summary = "使用POST方式分页动态查询(不返回总数)", + @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") - default Flux query(@RequestBody Mono query) { + default Flux query(@Parameter(hidden = true)@RequestBody Mono query) { return query.flatMapMany(this::query); } @@ -107,15 +108,15 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti @PostMapping("/_query") @QueryAction @SuppressWarnings("all") - @Operation(summary = "使用POST方式分页动态查询") - default Mono> queryPager(@RequestBody Mono query) { + @QueryOperation(summary = "使用POST方式分页动态查询") + default Mono> queryPager(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMap(q -> queryPager(q)); } @PostMapping("/_count") @QueryAction - @Operation(summary = "使用POST方式查询总数") - default Mono count(@RequestBody Mono query) { + @QueryNoPagingOperation(summary = "使用POST方式查询总数") + default Mono count(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMap(this::count); } @@ -131,7 +132,7 @@ default Mono count(@RequestBody Mono query) { */ @GetMapping("/_count") @QueryAction - @QueryOperation(summary = "使用GET方式查询总数") + @QueryNoPagingOperation(summary = "使用GET方式查询总数") default Mono count(@Parameter(hidden = true) QueryParamEntity query) { return getService() .createQuery() diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java index 80fa21ee5..63c4a195a 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.web.reactive; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import org.hswebframework.web.api.crud.entity.QueryOperation; import org.hswebframework.web.api.crud.entity.QueryParamEntity; @@ -43,22 +42,22 @@ default Mono> findAllChildrenTree(@Parameter(hidden = true) QueryParamEn @PostMapping("/_query/tree") @QueryAction - @Operation(summary = "使用POST动态查询并返回树形结构") - default Mono> findAllTree(Mono paramEntity) { + @QueryOperation(summary = "使用POST动态查询并返回树形结构") + default Mono> findAllTree(@Parameter(hidden = true) Mono paramEntity) { return getService().queryResultToTree(paramEntity); } @PostMapping("/_query/_children") @QueryAction - @Operation(summary = "使用POST动态查询并返回子节点数据") - default Flux findAllChildren(Mono paramEntity) { + @QueryOperation(summary = "使用POST动态查询并返回子节点数据") + default Flux findAllChildren(@Parameter(hidden = true) Mono paramEntity) { return paramEntity.flatMapMany(param -> getService().queryIncludeChildren(param)); } @PostMapping("/_query/_children/tree") @QueryAction - @Operation(summary = "使用POST动态查询并返回子节点树形结构数据") - default Mono> findAllChildrenTree(Mono paramEntity) { + @QueryOperation(summary = "使用POST动态查询并返回子节点树形结构数据") + default Mono> findAllChildrenTree(@Parameter(hidden = true) Mono paramEntity) { return paramEntity.flatMap(param -> getService().queryIncludeChildrenTree(param)); } From 14a958cf2b5116651642e9a92483a61722cfa49b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 14 May 2021 16:20:48 +0800 Subject: [PATCH 042/542] =?UTF-8?q?=E4=BC=98=E5=8C=96touch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/token/redis/RedisUserTokenManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index d1cac3f31..4002379a1 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -271,8 +271,10 @@ public Mono touch(String token) { SimpleUserToken inCache = localCache.get(token); if (inCache != null && inCache.isNormal()) { inCache.setLastRequestTime(System.currentTimeMillis()); - //异步touch - touchSink.next(inCache); + if (inCache.getMaxInactiveInterval() > 0) { + //异步touch + touchSink.next(inCache); + } return Mono.empty(); } return getByToken(token) From 521aeaac28afb60105cf592a8c52a00e7ccc8408 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 14 May 2021 16:21:04 +0800 Subject: [PATCH 043/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/AuthorizationWebAutoConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java index 2085d8be0..76a0be605 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java @@ -1,6 +1,7 @@ package org.hswebframework.web.system.authorization.defaults.configuration; import org.hswebframework.web.system.authorization.defaults.webflux.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -30,6 +31,7 @@ public WebFluxDimensionController webFluxDimensionController() { @Bean + @ConditionalOnMissingBean public WebFluxUserController webFluxUserController() { return new WebFluxUserController(); } From 5417041de421872b517dabfcf0a092c1432d8d1b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 14 May 2021 16:26:34 +0800 Subject: [PATCH 044/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/api/entity/UserEntity.java | 9 +++ .../service/reactive/ReactiveUserService.java | 68 ++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 40995f406..09dd75907 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -17,6 +17,15 @@ import javax.persistence.Table; import javax.validation.constraints.NotBlank; +/** + * 系统用户实体 + * + * @author zhouhao + * @see org.hswebframework.web.system.authorization.api.event.UserDeletedEvent + * @see org.hswebframework.web.system.authorization.api.event.UserCreatedEvent + * @see org.hswebframework.web.system.authorization.api.event.UserModifiedEvent + * @since 4.0.0 + */ @Getter @Setter @Table(name = "s_user", 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 index 28c03f279..d7d3ace6d 100644 --- 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 @@ -6,27 +6,93 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; - +/** + * 响应式用户服务 + * + * @author zhouhao + * @since 4.0.0 + */ public interface ReactiveUserService { + /** + * 创建一个新的用户实例 + * + * @return 用户实例 + */ Mono newUserInstance(); + /** + * 保存用户 + * + * @param userEntity 用户实体 + * @return 是否成功 + */ Mono saveUser(Mono userEntity); + /** + * 根据用户名查询用户实体,如果用户不存在则返回{@link Mono#empty()} + * + * @param username 用户名 + * @return 用户实体 + */ Mono findByUsername(String username); + /** + * 根据用户名查询用户实体,如果用户不存在则返回{@link Mono#empty()} + * + * @param id 用户名 + * @return 用户实体 + */ Mono findById(String id); + /** + * 根据用户名和密码查询用户实体,如果用户不存在或者密码不匹配则返回{@link Mono#empty()} + * + * @param username 用户名 + * @param plainPassword 明文密码 + * @return 用户实体 + */ Mono findByUsernameAndPassword(String username, String plainPassword); + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param state 状态 + * @return 修改数量 + */ Mono changeState(Publisher userId, byte state); + /** + * 修改用户密码 + * + * @param userId 用户ID + * @param oldPassword 旧密码 + * @param newPassword 新密码 + * @return 是否成功 + */ Mono changePassword(String userId, String oldPassword, String newPassword); + /** + * 根据查询条件查询用户 + * @param queryParam 动态查询条件 + * @return 用户列表 + */ Flux findUser(QueryParam queryParam); + /** + * 根据查询条件查询用户数量 + * @param queryParam 查询条件 + * @return 用户数量 + */ Mono countUser(QueryParam queryParam); + /** + * 删除用户 + * @param userId 用户ID + * @return 是否成功 + * @see org.hswebframework.web.system.authorization.api.event.UserDeletedEvent + */ Mono deleteUser(String userId); } From 22624626507036bd6294afb92e572da8827b3a6a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 18 May 2021 08:59:46 +0800 Subject: [PATCH 045/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E8=A7=A3=E7=BB=91=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/event/DimensionBindEvent.java | 19 +++ .../api/event/DimensionUnbindEvent.java | 18 +++ .../service/DefaultDimensionUserService.java | 113 +++++++++++------- 3 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionBindEvent.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionUnbindEvent.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionBindEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionBindEvent.java new file mode 100644 index 000000000..9f33d2b2e --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionBindEvent.java @@ -0,0 +1,19 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.authorization.DimensionType; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.util.List; + +@AllArgsConstructor +@Getter +public class DimensionBindEvent extends DefaultAsyncEvent { + + private final String type; + + private final String dimensionId; + + private final List userId; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionUnbindEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionUnbindEvent.java new file mode 100644 index 000000000..3aa766029 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionUnbindEvent.java @@ -0,0 +1,18 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.util.List; + +@AllArgsConstructor +@Getter +public class DimensionUnbindEvent extends DefaultAsyncEvent { + + private final String type; + + private final String dimensionId; + + private final List userId; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index 5adef3479..20b0263f0 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -6,9 +6,12 @@ import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; import org.hswebframework.web.crud.service.GenericReactiveCrudService; +import org.hswebframework.web.event.AsyncEvent; import org.hswebframework.web.exception.BusinessException; import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; +import org.hswebframework.web.system.authorization.api.event.DimensionBindEvent; +import org.hswebframework.web.system.authorization.api.event.DimensionUnbindEvent; import org.hswebframework.web.system.authorization.api.event.UserDeletedEvent; import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; @@ -16,9 +19,11 @@ import org.springframework.context.event.EventListener; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.function.Function3; import java.util.Collection; -import java.util.stream.Collectors; +import java.util.List; +import java.util.function.Function; @Slf4j public class DefaultDimensionUserService extends GenericReactiveCrudService { @@ -37,10 +42,9 @@ public void handleUserDeleteEntity(UserDeletedEvent event) { @Override public Mono save(Publisher entityPublisher) { - return Flux.from(entityPublisher) - .doOnNext(DimensionUserEntity::generateId) - .doOnNext(entity -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(entity.getUserId()))) - .as(super::save); + return this + .publishEvent(entityPublisher, DimensionBindEvent::new) + .as(super::save); } @Override @@ -52,62 +56,79 @@ public Mono updateById(String id, Mono entityPubli @Override public Mono insert(Publisher entityPublisher) { - return Flux.from(entityPublisher) - .doOnNext(DimensionUserEntity::generateId) - .doOnNext(entity -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(entity.getUserId()))) - .as(super::insert) - .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("重复的绑定请求")); + return this + .publishEvent(entityPublisher, DimensionBindEvent::new) + .as(super::insert) + .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("重复的绑定请求")); } @Override public Mono insertBatch(Publisher> entityPublisher) { - return Flux.from(entityPublisher) - .doOnNext(entity -> eventPublisher - .publishEvent(ClearUserAuthorizationCacheEvent - .of(entity.stream() - .map(DimensionUserEntity::getUserId) - .collect(Collectors.toSet())))) - .as(super::insertBatch); + + Flux> cache = Flux.from(entityPublisher).cache(); + + return this + .publishEvent(cache.flatMapIterable(Function.identity()), DimensionBindEvent::new) + .then(super.insertBatch(cache)); } - @Override - public Mono deleteById(Publisher idPublisher) { - return findById(Flux.from(idPublisher)) - .doOnNext(entity -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(entity.getUserId()))) - .map(DimensionUserEntity::getId) - .as(super::deleteById); + private Flux publishEvent(Publisher stream, + Function3, AsyncEvent> event) { + Flux cache = Flux.from(stream).doOnNext(DimensionUserEntity::generateId).cache(); + return cache + .groupBy(DimensionUserEntity::getDimensionTypeId) + .flatMap(typeGroup -> { + String type = typeGroup.key(); + return typeGroup + .groupBy(DimensionUserEntity::getDimensionId) + .flatMap(dimensionIdGroup -> { + String dimensionId = dimensionIdGroup.key(); + + return dimensionIdGroup + .map(DimensionUserEntity::getUserId) + .collectList() + .flatMap(userIdList -> { + eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(userIdList)); + return event.apply(type, dimensionId, userIdList).publish(eventPublisher); + }); + }); + }) + .thenMany(cache); } @Override @SuppressWarnings("all") public ReactiveUpdate createUpdate() { - return super.createUpdate() - .onExecute((update, r) -> r - .doOnSuccess(i -> { - this.createQuery() - .select(DimensionUserEntity::getUserId) - .setParam(update.toQueryParam()) - .fetch() - .map(DimensionUserEntity::getUserId) - .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .subscribe(); - })); + return super + .createUpdate() + .onExecute((update, r) -> r + .flatMap(result -> this + .createQuery() + .select(DimensionUserEntity::getUserId) + .setParam(update.toQueryParam()) + .fetch() + .map(DimensionUserEntity::getUserId) + .distinct() + .collectList() + .map(ClearUserAuthorizationCacheEvent::of) + .doOnNext(eventPublisher::publishEvent) + .thenReturn(result) + ) + ); } @Override @SuppressWarnings("all") public ReactiveDelete createDelete() { - return super.createDelete() - .onExecute((delete, r) -> r.doOnSuccess(i -> { - this.createQuery() - .select(DimensionUserEntity::getUserId) - .setParam(delete.toQueryParam()) - .fetch() - .map(DimensionUserEntity::getUserId) - .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .subscribe(); - })); + return super + .createDelete() + .onExecute((delete, r) -> this + .publishEvent(this.createQuery() + .select(DimensionUserEntity::getUserId) + .setParam(delete.toQueryParam()) + .fetch(), + DimensionUnbindEvent::new + ).then(r) + ); } } From 41f7f1487a7137e30e11f82ec555087b06834759 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 21 May 2021 14:50:51 +0800 Subject: [PATCH 046/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/service/ReactiveCrudService.java | 52 +++++++++ .../DefaultAuthorizationSettingService.java | 100 ++++++++++-------- 2 files changed, 106 insertions(+), 46 deletions(-) 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 cf7bda040..2b8b89dd6 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 @@ -16,22 +16,74 @@ import java.util.Collection; import java.util.function.Function; +/** + * 响应式增删改查通用服务类,增删改查,实现此接口. + * 利用{@link ReactiveRepository}来实现. + * + * @param 实体类类型 + * @param 主键类型 + * @see ReactiveRepository + * @see GenericReactiveCrudService + * @see GenericReactiveTreeSupportCrudService + * @see EnableCacheReactiveCrudService + */ public interface ReactiveCrudService { + /** + * @return 响应式实体操作仓库 + */ ReactiveRepository getRepository(); + /** + * 创建一个DSL的动态查询接口,可使用DSL方式进行链式调用来构造动态查询条件.例如: + *
+     *Flux<MyEntity> flux=
+     *     service
+     *     .createQuery()
+     *     .where(MyEntity::getName,name)
+     *     .in(MyEntity::getState,state1,state2)
+     *     .fetch()
+     * 
+ * @return 动态查询接口 + */ default ReactiveQuery createQuery() { return getRepository().createQuery(); } + /** + * 创建一个DSL动态更新接口,可使用DSL方式进行链式调用来构造动态更新条件.例如: + *
+     *Mono<Integer> flux=
+     *     service
+     *     .createUpdate()
+     *     .set(entity::getState)
+     *     .where(MyEntity::getName,name)
+     *     .in(MyEntity::getState,state1,state2)
+     *     .execute()
+     * 
+ * @return 动态更新接口 + */ default ReactiveUpdate createUpdate() { return getRepository().createUpdate(); } + /** + * 创建一个DSL动态删除接口,可使用DSL方式进行链式调用来构造动态删除条件.例如: + *
+     *Mono<Integer> flux=
+     *     service
+     *     .createDelete()
+     *     .where(MyEntity::getName,name)
+     *     .in(MyEntity::getState,state1,state2)
+     *     .execute()
+     * 
+ * @return 动态更新接口 + */ default ReactiveDelete createDelete() { return getRepository().createDelete(); } + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) default Mono findById(K id) { return getRepository() diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index a79576ae6..ad5350040 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -41,90 +41,98 @@ protected AuthorizationSettingEntity generateId(AuthorizationSettingEntity entit @Override public Mono save(Publisher entityPublisher) { return Flux.from(entityPublisher) - .map(this::generateId) - .collectList() - .flatMap(autz -> super.save(Flux.fromIterable(autz)).doOnSuccess(r -> clearUserAuthCache(autz))); + .map(this::generateId) + .collectList() + .flatMap(autz -> super.save(Flux.fromIterable(autz)).doOnSuccess(r -> clearUserAuthCache(autz))); } @Override public Mono updateById(String id, Mono entityPublisher) { return entityPublisher .flatMap(autz -> super.updateById(id, Mono.just(autz)) - .doOnSuccess((r) -> clearUserAuthCache(Collections.singletonList(autz)))); + .doOnSuccess((r) -> clearUserAuthCache(Collections.singletonList(autz)))); } @Override public Mono deleteById(Publisher idPublisher) { - return Flux.from(idPublisher) + Flux cache = Flux.from(idPublisher); + + return this + .findById(cache) .collectList() - .flatMap(list -> super.deleteById(Flux.fromIterable(list)) - .flatMap(r -> findById(Flux.fromIterable(list)) - .collectList() - .doOnSuccess(this::clearUserAuthCache) - .thenReturn(r))); + .flatMap(list -> this + .deleteById(cache) + .doOnSuccess((i) -> clearUserAuthCache(list)) + ); } @Override public Mono insert(Publisher entityPublisher) { return Flux.from(entityPublisher) - .map(this::generateId) - .collectList() - .flatMap(list -> super.insert(Flux.fromIterable(list)) - .doOnSuccess(i -> clearUserAuthCache(list))); + .map(this::generateId) + .collectList() + .flatMap(list -> super + .insert(Flux.fromIterable(list)) + .doOnSuccess(i -> clearUserAuthCache(list))); } @Override public Mono insertBatch(Publisher> entityPublisher) { - return Flux.from(entityPublisher) + return Flux + .from(entityPublisher) .collectList() - .flatMap(list -> super.insertBatch(Flux.fromStream(list.stream() - .map(lst -> lst.stream() - .map(this::generateId) - .collect(Collectors.toList())))) - .doOnSuccess(i -> clearUserAuthCache(list.stream().flatMap(Collection::stream).collect(Collectors.toList())))); + .flatMap(list -> super + .insertBatch(Flux.fromStream(list.stream() + .map(lst -> lst.stream() + .map(this::generateId) + .collect(Collectors.toList())))) + .doOnSuccess(i -> clearUserAuthCache(list + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toList())))); } @Override public ReactiveUpdate createUpdate() { - return super.createUpdate().onExecute((update, r) -> - r.doOnSuccess(i -> { - createQuery() - .setParam(update.toQueryParam()) - .fetch() - .collectList() - .subscribe(this::clearUserAuthCache); - })); + return super + .createUpdate() + .onExecute((update, r) -> r + .doOnSuccess(i -> this + .createQuery() + .setParam(update.toQueryParam()) + .fetch() + .collectList() + .subscribe(this::clearUserAuthCache))); } @Override public ReactiveDelete createDelete() { return super.createDelete() - .onExecute((delete, r) -> - r.doOnSuccess(i -> { - createQuery() + .onExecute((delete, r) -> r + .doOnSuccess(i -> this + .createQuery() .setParam(delete.toQueryParam()) .fetch() .collectList() - .subscribe(this::clearUserAuthCache); - })); + .subscribe(this::clearUserAuthCache))); } protected void clearUserAuthCache(List settings) { Flux.fromIterable(providers) - .flatMap(provider -> - //按维度类型进行映射 - provider.getAllType() - .map(DimensionType::getId) - .map(t -> Tuples.of(t, provider))) - .collect(Collectors.toMap(Tuple2::getT1, Tuple2::getT2)) - .flatMapMany(typeProviderMapping -> Flux - .fromIterable(settings)//根据维度获取所有userId - .flatMap(setting -> Mono.justOrEmpty(typeProviderMapping.get(setting.getDimensionType())) - .flatMapMany(provider -> provider.getUserIdByDimensionId(setting.getDimensionTarget())))) - .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .subscribe(eventPublisher::publishEvent); + .flatMap(provider -> + //按维度类型进行映射 + provider.getAllType() + .map(DimensionType::getId) + .map(t -> Tuples.of(t, provider))) + .collect(Collectors.toMap(Tuple2::getT1, Tuple2::getT2)) + .flatMapMany(typeProviderMapping -> Flux + .fromIterable(settings)//根据维度获取所有userId + .flatMap(setting -> Mono.justOrEmpty(typeProviderMapping.get(setting.getDimensionType())) + .flatMapMany(provider -> provider.getUserIdByDimensionId(setting.getDimensionTarget())))) + .collectList() + .map(ClearUserAuthorizationCacheEvent::of) + .subscribe(eventPublisher::publishEvent); } } From d68a455a5b4de900c74cc02a10cc56bc3bb88adc Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 25 May 2021 11:01:03 +0800 Subject: [PATCH 047/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/terms/UserDimensionTerm.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java index e73bc8028..7078b197d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java @@ -10,6 +10,13 @@ import java.util.List; import java.util.stream.Collectors; +/** + * 查询和用户维度绑定的数据,如: 查询机构下的用户 + * where id$in-dimension$org = orgId + * + * @author zhouhao + * @since 4.0.10 + */ public class UserDimensionTerm extends AbstractTermFragmentBuilder { public UserDimensionTerm() { super("in-dimension", "在维度中的用户数据"); @@ -24,11 +31,27 @@ public SqlFragments createFragments(String columnFullName, RDBColumnMetadata col } PrepareSqlFragments fragments = PrepareSqlFragments.of(); + List options = term.getOptions(); - fragments.addSql("exists(select 1 from s_dimension_user d where d.user_id =", columnFullName, "and d.dimension_id in(", - values.stream().map(r -> "?").collect(Collectors.joining(",")), "))") - .addParameter(values); + if (options.contains("not")) { + fragments.addSql("not"); + } + + fragments.addSql("exists(select 1 from s_dimension_user d where d.user_id =", columnFullName); + if (options.size() > 0) { + String typeId = options.get(0); + if (!"not".equals(typeId) && !"any".equals(typeId)) { + fragments.addSql("and d.dimension_type_id = ?").addParameter(typeId); + } + } + + if (!options.contains("any")) { + fragments.addSql("and d.dimension_id in(", + values.stream().map(r -> "?").collect(Collectors.joining(",")), ")") + .addParameter(values); + } + fragments.addSql(")"); return fragments; } From 099f6c9008a52bdbadf490353afb92c716a2337e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 25 May 2021 11:32:17 +0800 Subject: [PATCH 048/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=A3=E9=99=A4?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=85=B3=E8=81=94=E7=9A=84=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E7=BB=B4=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebFluxDimensionUserController.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java index 29be550fc..c8e2a7965 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java @@ -11,12 +11,11 @@ import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity; import org.hswebframework.web.system.authorization.defaults.service.DefaultDimensionUserService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; +import java.util.List; + @RestController @RequestMapping("/dimension-user") @Authorize @@ -68,4 +67,21 @@ public Mono deleteByDimension(@PathVariable .where(DimensionUserEntity::getDimensionId, dimensionId) .execute(); } + + @DeleteAction + @PostMapping("/user/{dimensionType}/{dimensionId}/_unbind") + @Operation(summary = "解除用户关联的指定维度") + public Mono deleteUserDimension(@PathVariable + @Parameter(description = "维度类型") String dimensionType, + @PathVariable + @Parameter(description = "维度ID") String dimensionId, + @Parameter(description = "用户ID") Mono> userId) { + return userId + .flatMap(userIdList -> dimensionUserService + .createDelete() + .where(DimensionUserEntity::getDimensionId, dimensionId) + .and(DimensionUserEntity::getDimensionTypeId, dimensionType) + .in(DimensionUserEntity::getUserId, userIdList) + .execute()); + } } From c47e92ae3a3827323338d9029b66569b1a764282 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 25 May 2021 11:52:24 +0800 Subject: [PATCH 049/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A7=A3=E7=BB=91?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/webflux/WebFluxDimensionUserController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java index c8e2a7965..d98d022f9 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java @@ -72,10 +72,10 @@ public Mono deleteByDimension(@PathVariable @PostMapping("/user/{dimensionType}/{dimensionId}/_unbind") @Operation(summary = "解除用户关联的指定维度") public Mono deleteUserDimension(@PathVariable - @Parameter(description = "维度类型") String dimensionType, + @Parameter(description = "维度类型,比如: role") String dimensionType, @PathVariable - @Parameter(description = "维度ID") String dimensionId, - @Parameter(description = "用户ID") Mono> userId) { + @Parameter(description = "维度ID,比如: 角色ID") String dimensionId, + @Parameter(description = "用户ID") @RequestBody Mono> userId) { return userId .flatMap(userIdList -> dimensionUserService .createDelete() From 97e0924203f76324a4e36dbbae069e7db5e4e255 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 27 May 2021 15:58:57 +0800 Subject: [PATCH 050/542] =?UTF-8?q?=E5=8F=96=E6=B6=88eq=E5=AF=B9mask?= =?UTF-8?q?=E7=9A=84=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/hswebframework/web/dict/EnumDict.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index 686f42179..d87fd52d5 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -99,9 +99,9 @@ default boolean eq(Object v) { return this == v || getValue() == v || getValue().equals(v) - || (v instanceof Number ? in(((Number) v).longValue()) : false) +// || (v instanceof Number ? in(((Number) v).longValue()) : false) || String.valueOf(getValue()).equalsIgnoreCase(String.valueOf(v)) - || v.equals(getMask()) +// || v.equals(getMask()) || getText().equalsIgnoreCase(String.valueOf(v) ); } From bee368201d873762ce10b5529c093190677f8edd Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 27 May 2021 16:01:04 +0800 Subject: [PATCH 051/542] =?UTF-8?q?=E4=BC=98=E5=8C=96test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/dict/EnumDictTest.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java index 590ab4956..b133673f7 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java @@ -27,21 +27,33 @@ public void testJackson() { System.out.println(val); TestEntity testEntity = mapper.readerFor(TestEntity.class) - .readValue(val); + .readValue(val); Assert.assertEquals(testEntity.testEnum, TestEnum.E1); testEntity = mapper.readerFor(TestEntity.class) - .readValue("{\"testEnum\":\"E1\"}"); + .readValue("{\"testEnum\":\"E1\"}"); Assert.assertEquals(testEntity.testEnum, TestEnum.E1); testEntity = mapper.readerFor(TestEntity.class) - .readValue("{\"testEnum\":\"e1\"}"); + .readValue("{\"testEnum\":\"e1\"}"); Assert.assertEquals(testEntity.testEnum, TestEnum.E1); System.out.println((Object) mapper.readerFor(TestEnum.class).readValue("\"E1\"")); } + @Test + public void testEq() { + assertFalse(EnumDict.find(TestEnum.class, 1) + .isPresent()); + + assertTrue(EnumDict.find(TestEnum.class, "e1") + .isPresent()); + assertTrue(EnumDict.find(TestEnum.class, "E1") + .isPresent()); + + } + @Getter @Setter public static class TestEntity { @@ -50,8 +62,8 @@ public static class TestEntity { private SimpleEnum simpleEnum = SimpleEnum.A; } - public enum SimpleEnum{ - A,B + public enum SimpleEnum { + A, B } } \ No newline at end of file From 710c5dc4af9ac0faefc6b7189fa070760006a942 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 27 May 2021 16:29:39 +0800 Subject: [PATCH 052/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=B4=E6=8E=A5cop?= =?UTF-8?q?y=E5=88=B0=E5=AE=9E=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/api/crud/entity/Entity.java | 4 ++++ 1 file changed, 4 insertions(+) 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 8a55f4acf..52d100b81 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 @@ -40,6 +40,10 @@ default T copyTo(Class target, String... ignoreProperties) { return FastBeanCopier.copy(this, target, ignoreProperties); } + default T copyTo(T 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); From 12f25dd045fe0f427479807edb63f15dc37e3741 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 28 May 2021 09:25:15 +0800 Subject: [PATCH 053/542] 4.0.10 release --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 81acffd8e..70cd68045 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index b7618225a..bebdfd337 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index fedc0eba4..35f10765f 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index b5f2236d6..cf7c4e496 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index eab4a0cba..bcb503837 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 66f08720a..7be49a30b 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index d8214549d..febc1859f 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index aca207902..322016080 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 7428b1c97..e583e3a58 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index f4a86905e..93d09b87c 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 5a570c348..0d92ff4f6 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 5148627d7..2694064f9 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index d9689d365..7abc66a00 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 471ee8b6d..ecd8e5063 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 1f82b474f..95e7c192e 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index dec654fd9..8ac58199f 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 57e3ea011..e4eebf29e 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 3eb8613e6..419939274 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 466241364..8a9823b45 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 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 ba3528840..e3626b233 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 8eb3898bd..7323e22ea 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 4578f02c6..0972cddeb 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 04b435cc5..da642cf6b 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index d9000a375..a60c12d58 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index dde251c8f..0fe13db36 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10-SNAPSHOT + 4.0.10 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 7c5d99cfa..e566320a4 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.10-SNAPSHOT + 4.0.10 hsweb-starter hsweb-core From 194ad0f55e11079eefb53eb2a44f55598157bb1d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 11 Jun 2021 15:34:06 +0800 Subject: [PATCH 054/542] 4.0.11-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 70cd68045..29b604d2c 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index bebdfd337..c84ed38d3 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index 35f10765f..bd6a19dad 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index cf7c4e496..648940783 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index bcb503837..a6d66a6e5 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 7be49a30b..86e6e0e8d 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index febc1859f..8bb72abb4 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 322016080..e61c36d5c 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index e583e3a58..e6d347806 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 93d09b87c..25a891231 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 0d92ff4f6..ac94d6cec 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 2694064f9..7e1dfc09d 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 7abc66a00..07cc4dc04 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index ecd8e5063..f3325bfdc 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 95e7c192e..9f8ee910e 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 8ac58199f..6032079d3 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index e4eebf29e..09a4df8d2 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 419939274..6d00cc827 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 8a9823b45..0a671e77e 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 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 e3626b233..54a12b8d9 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 7323e22ea..df8b63484 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 0972cddeb..1d69d60ec 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index da642cf6b..98b247541 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index a60c12d58..8e41af9dc 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index 0fe13db36..f5e10ce48 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.10 + 4.0.11-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index e566320a4..1210b721d 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.10 + 4.0.11-SNAPSHOT hsweb-starter hsweb-core From a5a82fc13071c00c066b3c0af848aae57b445f41 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 11 Jun 2021 15:34:24 +0800 Subject: [PATCH 055/542] =?UTF-8?q?=E4=BC=98=E5=8C=96ddl=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/configuration/AutoDDLProcessor.java | 49 ++++++++++--------- .../configuration/EasyormConfiguration.java | 4 +- .../EasyormRepositoryRegistrar.java | 33 +++++++------ 3 files changed, 48 insertions(+), 38 deletions(-) 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 21fc44312..1a96e4b61 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 @@ -57,33 +57,36 @@ public void afterPropertiesSet() { List entities = this.entities.stream().map(EntityInfo::getRealType).collect(Collectors.toList()); if (properties.isAutoDdl()) { //加载全部表信息 -// if (reactive) { -// Flux.fromIterable(entities) -// .doOnNext(type -> log.info("auto ddl for {}", type)) -// .map(resolver::resolve) -// .flatMap(meta->operator.ddl() -// .createOrAlter(meta) -// .commit() -// .reactive()) -// .doOnError((err) -> log.error(err.getMessage(), err)) -// .then() -// .toFuture().get(2, TimeUnit.MINUTES); -// -// } else { - for (Class entity : entities) { - log.trace("auto ddl for {}", entity); - try { - operator.ddl() - .createOrAlter(resolver.resolve(entity)) + if (reactive) { + Flux.fromIterable(entities) + .doOnNext(type -> log.trace("auto ddl for {}", type)) + .map(resolver::resolve) + .flatMap(meta -> operator + .ddl() + .createOrAlter(meta) .autoLoad(false) .commit() - .sync(); - } catch (Exception e) { - log.error(e.getMessage(), e); - throw e; + .reactive() + .subscribeOn(Schedulers.elastic()) + ) + .doOnError((err) -> log.error(err.getMessage(), err)) + .then() + .block(Duration.ofMinutes(5)); + } else { + for (Class entity : entities) { + log.trace("auto ddl for {}", entity); + try { + operator.ddl() + .createOrAlter(resolver.resolve(entity)) + .autoLoad(false) + .commit() + .sync(); + } catch (Exception e) { + log.error(e.getMessage(), e); + throw e; + } } } -// } } else { for (Class entity : entities) { RDBTableMetadata metadata = resolver.resolve(entity); 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 cfe6f92c2..458ee13aa 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 @@ -34,6 +34,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.time.Duration; import java.util.List; import java.util.Optional; @@ -108,7 +109,8 @@ public RDBDatabaseMetadata databaseMetadata(Optional syncSqlExe reactiveSqlExecutor.ifPresent(metadata::addFeature); if (properties.isAutoDdl()) { for (RDBSchemaMetadata schema : metadata.getSchemas()) { - schema.loadAllTable(); + schema.loadAllTableReactive() + .block(Duration.ofSeconds(30)); } } return metadata; 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 1f4922154..161c38389 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 @@ -28,6 +28,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -145,23 +146,27 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B } - - try { - BeanDefinition definition = registry.getBeanDefinition(AutoDDLProcessor.class.getName()); - Set infos = (Set) definition.getPropertyValues().get("entities"); - infos.addAll(entityInfos); - } catch (NoSuchBeanDefinitionException e) { - RootBeanDefinition definition = new RootBeanDefinition(); - definition.setTargetType(AutoDDLProcessor.class); - definition.setBeanClass(AutoDDLProcessor.class); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - definition.getPropertyValues().add("entities", entityInfos); - definition.getPropertyValues().add("reactive", reactive); - registry.registerBeanDefinition(AutoDDLProcessor.class.getName(), definition); - } + RootBeanDefinition definition = new RootBeanDefinition(); + definition.setTargetType(AutoDDLProcessor.class); + definition.setBeanClass(AutoDDLProcessor.class); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + definition.getPropertyValues().add("entities", entityInfos); + definition.getPropertyValues().add("reactive", reactive); + definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + definition.setSynthetic(true); + 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(); } From 9dcf81e154b220a6faf2ad874fbe325571e26c86 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 11 Jun 2021 16:03:12 +0800 Subject: [PATCH 056/542] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1210b721d..5f84ea3f2 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 1.8 ${java.version} - 2.3.3.RELEASE + 2.3.11.RELEASE 3.20.0-GA 5.19.0.2 @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.9 + 4.0.11-SNAPSHOT 3.0.2 3.0.2 2.7.0 From 208f9b34dd4830ba1ec5d05330db7276dda5044a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 15 Jun 2021 16:29:14 +0800 Subject: [PATCH 057/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BD=93=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E6=9F=A5=E8=AF=A2=E6=97=A0=E6=95=B0=E6=8D=AE=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E8=BF=94=E5=9B=9EpageSize=E4=B8=BA0=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/service/ReactiveCrudService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 2b8b89dd6..60d7de25d 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 @@ -13,6 +13,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.ArrayList; import java.util.Collection; import java.util.function.Function; @@ -37,13 +38,14 @@ public interface ReactiveCrudService { /** * 创建一个DSL的动态查询接口,可使用DSL方式进行链式调用来构造动态查询条件.例如: *
-     *Flux<MyEntity> flux=
+     * Flux<MyEntity> flux=
      *     service
      *     .createQuery()
      *     .where(MyEntity::getName,name)
      *     .in(MyEntity::getState,state1,state2)
      *     .fetch()
      * 
+ * * @return 动态查询接口 */ default ReactiveQuery createQuery() { @@ -53,7 +55,7 @@ default ReactiveQuery createQuery() { /** * 创建一个DSL动态更新接口,可使用DSL方式进行链式调用来构造动态更新条件.例如: *
-     *Mono<Integer> flux=
+     * Mono<Integer> flux=
      *     service
      *     .createUpdate()
      *     .set(entity::getState)
@@ -61,6 +63,7 @@ default ReactiveQuery createQuery() {
      *     .in(MyEntity::getState,state1,state2)
      *     .execute()
      * 
+ * * @return 动态更新接口 */ default ReactiveUpdate createUpdate() { @@ -70,13 +73,14 @@ default ReactiveUpdate createUpdate() { /** * 创建一个DSL动态删除接口,可使用DSL方式进行链式调用来构造动态删除条件.例如: *
-     *Mono<Integer> flux=
+     * Mono<Integer> flux=
      *     service
      *     .createDelete()
      *     .where(MyEntity::getName,name)
      *     .in(MyEntity::getState,state1,state2)
      *     .execute()
      * 
+ * * @return 动态更新接口 */ default ReactiveDelete createDelete() { @@ -183,7 +187,7 @@ default Mono> queryPager(QueryParamEntity query, Function { if (total == 0) { - return Mono.just(PagerResult.empty()); + return Mono.just(PagerResult.of(0, new ArrayList<>(), query)); } return query(query.clone().rePaging(total)) .map(mapper) From c6effa9f0fd31d7450828ada0e7f67a8e520ea92 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 21 Jun 2021 18:21:00 +0800 Subject: [PATCH 058/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8B=93=E5=B1=95?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-commons/hsweb-commons-api/pom.xml | 7 +++ .../web/api/crud/entity/EntityFactory.java | 13 +++-- .../api/crud/entity/EntityFactoryHolder.java | 30 +++++++++++ .../EntityFactoryHolderConfiguration.java | 16 ++++++ .../web/api/crud/entity/PagerResult.java | 13 +++-- .../main/resources/META-INF/spring.factories | 3 ++ .../configuration/EasyormConfiguration.java | 10 +++- .../factory/EntityMappingCustomizer.java | 7 +++ .../entity/factory/MapperEntityFactory.java | 24 +++++---- .../web/crud/web/ResponseMessage.java | 43 +++++++++------ .../web/crud/web/ResponseMessageWrapper.java | 3 +- hsweb-starter/pom.xml | 6 +++ .../CustomCodecsAutoConfiguration.java | 5 +- .../jackson/CustomJackson2JsonDecoder.java | 36 +++++++++---- .../CustomJackson2JsonDecoderTest.java | 53 +++++++++++++++++++ 15 files changed, 218 insertions(+), 51 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolder.java create mode 100644 hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java create mode 100644 hsweb-commons/hsweb-commons-api/src/main/resources/META-INF/spring.factories create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/EntityMappingCustomizer.java create mode 100644 hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index a6d66a6e5..58d710013 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -38,6 +38,13 @@ hibernate-validator + + com.google.code.findbugs + jsr305 + 3.0.2 + compile + + \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java index b378a3a59..5f0947795 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java @@ -13,12 +13,14 @@ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. - * + * */ package org.hswebframework.web.api.crud.entity; +import javax.annotation.Nullable; + /** * 实体工厂接口,系统各个地方使用此接口来创建实体,在实际编码中也应该使用此接口来创建实体,而不是使用new方式来创建 * @@ -97,11 +99,12 @@ default T newInstance(Class entityClass, Class defaultCla * @param 泛型 * @return 实体类型 */ - default Class getInstanceType(Class entityClass){ - return getInstanceType(entityClass,false); - } + default Class getInstanceType(Class entityClass) { + return getInstanceType(entityClass, false); + } - Class getInstanceType(Class entityClass,boolean autoRegister); + @Nullable + Class getInstanceType(Class entityClass, boolean autoRegister); /** * 拷贝对象的属性 diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolder.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolder.java new file mode 100644 index 000000000..4d893d4ca --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolder.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.api.crud.entity; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.stereotype.Component; + +import java.util.function.Supplier; + +@Component +@Slf4j +public final class EntityFactoryHolder { + + static EntityFactory FACTORY; + + public static EntityFactory get() { + if (FACTORY == null) { + throw new IllegalStateException("EntityFactory Not Ready Yet"); + } + return FACTORY; + } + + public static T newInstance(Class type, + Supplier mapper) { + if (FACTORY != null) { + return FACTORY.newInstance(type); + } + return mapper.get(); + } + +} diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java new file mode 100644 index 000000000..8dc3d6ceb --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java @@ -0,0 +1,16 @@ +package org.hswebframework.web.api.crud.entity; + +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class EntityFactoryHolderConfiguration { + + + @Bean + public ApplicationContextAware entityFactoryHolder() { + return context -> EntityFactoryHolder.FACTORY = context.getBean(EntityFactory.class); + } + +} diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java index 8be9b1f4d..d6dfdd934 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java @@ -20,7 +20,9 @@ import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.hswebframework.ezorm.core.param.QueryParam; @@ -33,15 +35,20 @@ public class PagerResult { private static final long serialVersionUID = -6171751136953308027L; public static PagerResult empty() { - return new PagerResult<>(0, new ArrayList<>()); + return of(0, new ArrayList<>()); } + @SuppressWarnings("all") public static PagerResult of(int total, List list) { - return new PagerResult<>(total, list); + PagerResult result; + result = EntityFactoryHolder.newInstance(PagerResult.class, PagerResult::new); + result.setTotal(total); + result.setData(list); + return result; } public static PagerResult of(int total, List list, QueryParam entity) { - PagerResult pagerResult = new PagerResult<>(total, list); + PagerResult pagerResult = of(total, list); pagerResult.setPageIndex(entity.getThinkPageIndex()); pagerResult.setPageSize(entity.getPageSize()); return pagerResult; diff --git a/hsweb-commons/hsweb-commons-api/src/main/resources/META-INF/spring.factories b/hsweb-commons/hsweb-commons-api/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..90971163a --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.hswebframework.web.api.crud.entity.EntityFactoryHolderConfiguration \ No newline at end of file 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 458ee13aa..5287f17d2 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 @@ -17,6 +17,7 @@ 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.EntityMappingCustomizer; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; import org.hswebframework.web.crud.events.CompositeEventListener; import org.hswebframework.web.crud.events.EntityEventListener; @@ -26,6 +27,7 @@ import org.hswebframework.web.crud.generator.MD5Generator; import org.hswebframework.web.crud.generator.SnowFlakeStringIdGenerator; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -52,8 +54,12 @@ public class EasyormConfiguration { @Bean @ConditionalOnMissingBean - public EntityFactory entityFactory() { - return new MapperEntityFactory(); + public EntityFactory entityFactory(ObjectProvider customizers) { + MapperEntityFactory factory= new MapperEntityFactory(); + for (EntityMappingCustomizer customizer : customizers) { + customizer.custom(factory); + } + return factory; } @Bean diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/EntityMappingCustomizer.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/EntityMappingCustomizer.java new file mode 100644 index 000000000..986d1a480 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/EntityMappingCustomizer.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.crud.entity.factory; + +public interface EntityMappingCustomizer { + + void custom(MapperEntityFactory factory); + +} 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 ce327055b..f3d90d72b 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 @@ -44,7 +44,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { private static final DefaultMapperFactory DEFAULT_MAPPER_FACTORY = clazz -> { String simpleClassName = clazz.getPackage().getName().concat(".Simple").concat(clazz.getSimpleName()); try { - return defaultMapper(org.springframework.util.ClassUtils.forName(simpleClassName,null)); + return defaultMapper(org.springframework.util.ClassUtils.forName(simpleClassName, null)); } catch (ClassNotFoundException ignore) { // throw new NotFoundException(e.getMessage()); } @@ -64,7 +64,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { public MapperEntityFactory() { } - public MapperEntityFactory(Map, Mapper> realTypeMapper) { + public MapperEntityFactory(Map, Mapper> realTypeMapper) { this.realTypeMapper.putAll(realTypeMapper); } @@ -73,9 +73,9 @@ public MapperEntityFactory addMapping(Class target, Mapper m return this; } - public MapperEntityFactory addCopier(PropertyCopier copier) { - Class source = ClassUtils.getGenericType(copier.getClass(), 0); - Class target = ClassUtils.getGenericType(copier.getClass(), 1); + public MapperEntityFactory addCopier(PropertyCopier copier) { + Class source = (Class) ClassUtils.getGenericType(copier.getClass(), 0); + Class target = (Class) ClassUtils.getGenericType(copier.getClass(), 1); if (source == null || source == Object.class) { throw new UnsupportedOperationException("generic type " + source + " not support"); } @@ -91,7 +91,7 @@ public MapperEntityFactory addCopier(Class source, Class target, Pr return this; } - private String getCopierCacheKey(Class source, Class target) { + private String getCopierCacheKey(Class source, Class target) { return source.getName().concat("->").concat(target.getName()); } @@ -122,11 +122,13 @@ protected Mapper initCache(Class beanClass) { } if (realType == null) { - mapper = defaultMapperFactory.apply(beanClass); - } - if (!Modifier.isInterface(beanClass.getModifiers()) && !Modifier.isAbstract(beanClass.getModifiers())) { - realType = beanClass; + if (!Modifier.isInterface(beanClass.getModifiers()) && !Modifier.isAbstract(beanClass.getModifiers())) { + realType = beanClass; + }else { + mapper = defaultMapperFactory.apply(beanClass); + } } + if (mapper == null && realType != null) { if (logger.isDebugEnabled() && realType != beanClass) { logger.debug("use instance {} for {}", realType, beanClass); @@ -170,7 +172,7 @@ public T newInstance(Class beanClass, Class defaultClass) { return (T) new HashSet<>(); } - throw new NotFoundException("can't create instance for " + beanClass); + throw new NotFoundException("error.cant_create_instance",beanClass); } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java index 2c9dd7580..c3d799d00 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java @@ -2,34 +2,36 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.api.crud.entity.EntityFactoryHolder; import java.io.Serializable; @Getter @Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseMessage implements Serializable { private static final long serialVersionUID = 8992436576262574064L; @Schema(description = "消息提示") - protected String message; + private String message; @Schema(description = "数据内容") - protected T result; + private T result; @Schema(description = "状态码") private int status; @Schema(description = "业务码") - protected String code; + private String code; @Schema(description = "时间戳(毫秒)") - protected Long timestamp = System.currentTimeMillis(); + private Long timestamp = System.currentTimeMillis(); + + public ResponseMessage() { + } public static ResponseMessage ok() { return ok(null); @@ -37,11 +39,7 @@ public static ResponseMessage ok() { @SuppressWarnings("all") public static ResponseMessage ok(T result) { - return (ResponseMessage) ResponseMessage.builder() - .result(result) - .status(200) - .code("success") - .build(); + return of("success", null, 200, null, System.currentTimeMillis()); } public static ResponseMessage error(String message) { @@ -53,10 +51,21 @@ public static ResponseMessage error(String code, String message) { } public static ResponseMessage error(int status, String code, String message) { - ResponseMessage msg = new ResponseMessage<>(); - msg.message = message; - msg.code = code; - msg.status = status; + return of(message, null, status, code, System.currentTimeMillis()); + } + + public static ResponseMessage of(String message, + T result, + int status, + String code, + Long timestamp) { + @SuppressWarnings("all") + ResponseMessage msg = EntityFactoryHolder.newInstance(ResponseMessage.class, ResponseMessage::new); + msg.setMessage(message); + msg.setResult(result); + msg.setStatus(status); + msg.setCode(code); + msg.setTimestamp(timestamp); return msg; } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapper.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapper.java index 200ac6e59..37e058d48 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapper.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapper.java @@ -7,6 +7,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; import org.springframework.web.bind.annotation.RequestMapping; @@ -51,7 +52,7 @@ private static Mono> methodForParams() { private Set excludes = new HashSet<>(); @Override - public boolean supports(HandlerResult result) { + public boolean supports(@NonNull HandlerResult result) { if (!CollectionUtils.isEmpty(excludes) && result.getHandler() instanceof HandlerMethod) { HandlerMethod method = (HandlerMethod) result.getHandler(); diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 6d00cc827..bec7c5ff3 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -68,5 +68,11 @@ r2dbc-h2 test + + com.google.code.findbugs + jsr305 + 3.0.2 + compile + \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java index 56b21dc64..fc3d521ca 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -29,14 +29,15 @@ static class JacksonDecoderConfiguration { CodecCustomizer jacksonDecoderCustomizer(EntityFactory entityFactory, ObjectMapper objectMapper) { // objectMapper.setTypeFactory(new CustomTypeFactory(entityFactory)); SimpleModule module = new SimpleModule(); - JsonDeserializer deserializer = new EnumDict.EnumDictJSONDeserializer(); + @SuppressWarnings("all") + JsonDeserializer> deserializer = new EnumDict.EnumDictJSONDeserializer(); module.addDeserializer(Enum.class, deserializer); objectMapper.registerModule(module); return (configurer) -> { CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); - defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(objectMapper)); + defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(entityFactory,objectMapper)); }; } diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index 5370f3fa8..0c7d3bc56 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.util.TokenBuffer; +import org.hswebframework.web.api.crud.entity.EntityFactory; import org.reactivestreams.Publisher; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -19,12 +20,14 @@ import org.springframework.http.codec.json.Jackson2CodecSupport; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MimeType; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import javax.annotation.Nonnull; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -33,11 +36,14 @@ public class CustomJackson2JsonDecoder extends Jackson2CodecSupport implements HttpMessageDecoder { + private final EntityFactory entityFactory; + /** * Constructor with a Jackson {@link ObjectMapper} to use. */ - public CustomJackson2JsonDecoder(ObjectMapper mapper, MimeType... mimeTypes) { + public CustomJackson2JsonDecoder(EntityFactory entityFactory, ObjectMapper mapper, MimeType... mimeTypes) { super(mapper, mimeTypes); + this.entityFactory = entityFactory; } @@ -51,7 +57,8 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType } @Override - public Flux decode(Publisher input, ResolvableType elementType, + @NonNull + public Flux decode(@NonNull Publisher input, @NonNull ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { ObjectMapper mapper = getObjectMapper(); @@ -74,15 +81,17 @@ public Flux decode(Publisher input, ResolvableType elementTy } @Override - public Mono decodeToMono(Publisher input, ResolvableType elementType, + @NonNull + public Mono decodeToMono(@NonNull Publisher input, @NonNull ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { return DataBufferUtils.join(input) - .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); + .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); } @Override - public Object decode(DataBuffer dataBuffer, ResolvableType targetType, + @NonNull + public Object decode(@NonNull DataBuffer dataBuffer, @NonNull ResolvableType targetType, @Nullable MimeType mimeType, @Nullable Map hints) throws DecodingException { try { @@ -101,8 +110,13 @@ private ObjectReader getObjectReader(ResolvableType elementType, @Nullable Map contextClass = (param != null ? param.getContainingClass() : null); - Type type = elementType.resolve() == null ? elementType.getType() : elementType.resolve(); - + Type type = elementType.resolve() == null ? elementType.getType() : elementType.toClass(); + if (type instanceof Class) { + Class realType = entityFactory.getInstanceType(((Class) type), false); + if (realType != null) { + type = realType; + } + } JavaType javaType = getJavaType(type, contextClass); Class jsonView = (hints != null ? (Class) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null); return jsonView != null ? @@ -135,13 +149,15 @@ private CodecException processException(IOException ex) { // HttpMessageDecoder... @Override - public Map getDecodeHints(ResolvableType actualType, ResolvableType elementType, - ServerHttpRequest request, ServerHttpResponse response) { + @NonNull + public Map getDecodeHints(@NonNull ResolvableType actualType, @NonNull ResolvableType elementType, + @NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) { return getHints(actualType); } @Override + @NonNull public List getDecodableMimeTypes() { return getMimeTypes(); } @@ -149,7 +165,7 @@ public List getDecodableMimeTypes() { // Jackson2CodecSupport ... @Override - protected A getAnnotation(MethodParameter parameter, Class annotType) { + protected A getAnnotation(MethodParameter parameter, @NonNull Class annotType) { return parameter.getParameterAnnotation(annotType); } diff --git a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java new file mode 100644 index 000000000..d70421e16 --- /dev/null +++ b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java @@ -0,0 +1,53 @@ +package org.hswebframework.web.starter.jackson; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; +import org.hswebframework.web.crud.web.reactive.ReactiveQueryController; +import org.junit.Test; +import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DefaultDataBuffer; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.MediaType; +import org.springframework.util.MimeType; +import reactor.core.publisher.Mono; + +import java.util.Collections; + +import static org.junit.Assert.*; + +public class CustomJackson2JsonDecoderTest { + + @Test + @SneakyThrows + public void testDecodeCustomType() { + + MapperEntityFactory entityFactory = new MapperEntityFactory(); + + entityFactory.addMapping(QueryParamEntity.class,MapperEntityFactory.defaultMapper(CustomQueryParamEntity.class)); + + + ObjectMapper mapper = new ObjectMapper(); + CustomJackson2JsonDecoder decoder = new CustomJackson2JsonDecoder(entityFactory, mapper); + + ResolvableType type = ResolvableType.forMethodParameter( + ReactiveQueryController.class.getMethod("query", QueryParamEntity.class), 0 + ); + + DataBuffer buffer = new DefaultDataBufferFactory().wrap("{}".getBytes()); + + Object object = decoder.decode(buffer, type, MediaType.APPLICATION_JSON, Collections.emptyMap()); + + assertTrue(object instanceof CustomQueryParamEntity); + + } + + public static class CustomQueryParamEntity extends QueryParamEntity { + + } + +} \ No newline at end of file From e664d680233d5da9dfb56d1d8e38e7dbaac0f2a5 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 21 Jun 2021 18:21:20 +0800 Subject: [PATCH 059/542] =?UTF-8?q?i18n=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/annotation/TwoFactor.java | 2 +- .../exception/AccessDenyException.java | 12 +++- .../exception/AuthenticationException.java | 7 +- .../exception/UnAuthorizedException.java | 3 +- .../token/DefaultUserTokenManager.java | 2 +- .../web/authorization/token/TokenState.java | 14 ++-- .../token/redis/RedisUserTokenManager.java | 2 +- .../resources/i18n/messages_zh_CN.properties | 14 ++++ .../DefaultBasicAuthorizeDefinition.java | 2 +- .../TwoFactorHandlerInterceptorAdapter.java | 6 +- .../basic/web/AuthorizationController.java | 6 +- .../crud/web/CommonErrorControllerAdvice.java | 18 +++-- .../crud/web/CommonWebFluxConfiguration.java | 32 +++++++-- .../web/exception/BusinessException.java | 18 ++--- .../web/exception/I18nSupportException.java | 27 ++++++++ .../web/exception/NotFoundException.java | 6 +- .../hswebframework/web/i18n/LocaleUtils.java | 67 +++++++++++++++++++ .../web/i18n/WebFluxLocaleFilter.java | 18 +++++ .../resources/i18n/messages_zh_CN.properties | 2 + .../configuration/PermissionProperties.java | 2 +- .../service/DefaultDimensionUserService.java | 2 +- .../resources/i18n/messages_zh_CN.properties | 1 + 22 files changed, 218 insertions(+), 45 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java create mode 100644 hsweb-core/src/main/resources/i18n/messages_zh_CN.properties create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java index ae03f13ad..1d3d6b98f 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java @@ -55,5 +55,5 @@ * @return 错误提示 * @since 3.0.6 */ - String message() default "需要进行双因子验证"; + String message() default "assert.verify_code_error"; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java index 240ed822e..e9f118475 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java @@ -1,9 +1,12 @@ package org.hswebframework.web.authorization.exception; import lombok.Getter; +import org.hswebframework.web.exception.I18nSupportException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; +import java.util.Set; + /** * 权限验证异常 * @@ -11,7 +14,7 @@ * @since 3.0 */ @ResponseStatus(HttpStatus.FORBIDDEN) -public class AccessDenyException extends RuntimeException { +public class AccessDenyException extends I18nSupportException { private static final long serialVersionUID = -5135300127303801430L; @@ -19,16 +22,21 @@ public class AccessDenyException extends RuntimeException { private String code; public AccessDenyException() { - this("权限不足,拒绝访问!"); + this("error.access_denied"); } public AccessDenyException(String message) { super(message); } + public AccessDenyException(String permission, Set actions) { + super("error.permission_denied", permission, actions); + } + public AccessDenyException(String message, String code) { this(message, code, null); } + public AccessDenyException(String message, Throwable cause) { this(message, "access_denied", cause); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AuthenticationException.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AuthenticationException.java index dce94a7bf..767166d5e 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AuthenticationException.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AuthenticationException.java @@ -1,9 +1,10 @@ package org.hswebframework.web.authorization.exception; import lombok.Getter; +import org.hswebframework.web.exception.I18nSupportException; @Getter -public class AuthenticationException extends RuntimeException { +public class AuthenticationException extends I18nSupportException { public static String ILLEGAL_PASSWORD = "illegal_password"; @@ -13,6 +14,10 @@ public class AuthenticationException extends RuntimeException { private final String code; + public AuthenticationException(String code) { + this(code, "error." + code); + } + public AuthenticationException(String code, String message) { super(message); this.code = code; diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/UnAuthorizedException.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/UnAuthorizedException.java index 025d72c72..75dd34fd6 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/UnAuthorizedException.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/UnAuthorizedException.java @@ -19,6 +19,7 @@ package org.hswebframework.web.authorization.exception; import org.hswebframework.web.authorization.token.TokenState; +import org.hswebframework.web.exception.I18nSupportException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @@ -29,7 +30,7 @@ * @since 3.0 */ @ResponseStatus(HttpStatus.UNAUTHORIZED) -public class UnAuthorizedException extends RuntimeException { +public class UnAuthorizedException extends I18nSupportException { private static final long serialVersionUID = 2422918455013900645L; private final TokenState state; diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java index b7ba54b1c..05e61807f 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java @@ -253,7 +253,7 @@ public Mono signIn(String token, String type, String userId, long max .flatMap(this::checkTimeout) .filterWhen(t -> { if (t.isNormal()) { - return Mono.error(new AccessDenyException("该用户已在其他地方登陆")); + return Mono.error(new AccessDenyException("error.logged_in_elsewhere")); } return Mono.empty(); }) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java index a35973dbc..6c9ac63af 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java @@ -13,30 +13,30 @@ public enum TokenState implements EnumDict { /** * 正常,有效 */ - normal("normal","正常"), + normal("normal","message.token_state_normal"), /** * 已被禁止访问 */ - deny("deny", "已被禁止访问"), + deny("deny", "message.token_state_deny"), /** * 已过期 */ - expired("expired", "用户未登录"), + expired("expired", "message.token_state_expired"), /** * 已被踢下线 * @see AllopatricLoginMode#offlineOther */ - offline("offline", "用户已在其他地方登录"), + offline("offline", "message.token_state_offline"), /** * 锁定 */ - lock("lock", "登录状态已被锁定"); + lock("lock", "message.token_state_lock"); - private String value; + private final String value; - private String text; + private final String text; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index 4002379a1..a3def4cb4 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -244,7 +244,7 @@ public Mono signIn(String token, String type, String userId, long max return userIsLoggedIn(userId) .flatMap(r -> { if (r) { - return Mono.error(new AccessDenyException("已在其他地方登录", TokenState.deny.getValue(), null)); + return Mono.error(new AccessDenyException("error.logged_in_elsewhere", TokenState.deny.getValue(), null)); } return doSign; }); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 000000000..412d3de60 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,14 @@ +error.access_denied=权限不足,拒绝访问! +error.permission_denied=当前用户无权限[{0}]:{1} +error.logged_in_elsewhere=该用户已在其他地方登陆 +# +message.token_state_normal=正常 +message.token_state_deny=已被禁止访问 +message.token_state_expired=用户未登录 +message.token_state_offline=用户已在其他地方登录 +message.token_state_lock=登录状态已被锁定 +# +assert.need_two_factor_verify=需要双因子验证 +assert.username_must_not_be_empty=用户名不能为空 +assert.password_must_not_be_empty=密码不能为空 +assert.verify_code_error=验证码错误 \ No newline at end of file diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java index ca42b8184..d5c556493 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java @@ -36,7 +36,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { private ResourcesDefinition resources = new ResourcesDefinition(); private DimensionsDefinition dimensions = new DimensionsDefinition(); - private String message = "权限不足,拒绝访问"; + private String message = "error.access_denied"; private Phased phased; diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java index d1eea30c6..5aa9efbcb 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java @@ -22,7 +22,7 @@ @AllArgsConstructor public class TwoFactorHandlerInterceptorAdapter extends HandlerInterceptorAdapter { - private TwoFactorValidatorManager validatorManager; + private final TwoFactorValidatorManager validatorManager; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -45,9 +45,9 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons code = request.getHeader(factor.parameter()); } if (StringUtils.isEmpty(code)) { - throw new NeedTwoFactorException(factor.message(), factor.provider()); + throw new NeedTwoFactorException("assert.need_two_factor_verify", factor.provider()); } else if (!validator.verify(code, factor.timeout())) { - throw new NeedTwoFactorException("验证码错误", factor.provider()); + throw new NeedTwoFactorException(factor.message(), factor.provider()); } } return super.preHandle(request, response, handler); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java index 4347c46f0..659fe9879 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java @@ -85,8 +85,8 @@ private Mono> doLogin(Mono> parameter) { String username_ = (String) parameters.get("username"); String password_ = (String) parameters.get("password"); - Assert.hasLength(username_, "用户名不能为空"); - Assert.hasLength(password_, "密码不能为空"); + Assert.hasLength(username_, "assert.username_must_not_be_empty"); + Assert.hasLength(password_, "assert.password_must_not_be_empty"); Function parameterGetter = parameters::get; return Mono.defer(() -> { @@ -101,7 +101,7 @@ private Mono> doLogin(Mono> parameter) { .publish(eventPublisher) .then(authenticationManager .authenticate(Mono.just(new PlainTextUsernamePasswordAuthenticationRequest(username, password))) - .switchIfEmpty(Mono.error(() -> new AuthenticationException(AuthenticationException.ILLEGAL_PASSWORD,"密码错误"))) + .switchIfEmpty(Mono.error(() -> new AuthenticationException(AuthenticationException.ILLEGAL_PASSWORD))) .flatMap(auth -> { //触发授权成功事件 AuthorizationSuccessEvent event = new AuthorizationSuccessEvent(auth, parameterGetter); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 673442ebf..9f9b44b98 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -1,7 +1,6 @@ package org.hswebframework.web.crud.web; import io.r2dbc.spi.R2dbcDataIntegrityViolationException; -import io.r2dbc.spi.R2dbcNonTransientException; import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.exception.AuthenticationException; @@ -10,11 +9,11 @@ import org.hswebframework.web.exception.BusinessException; import org.hswebframework.web.exception.NotFoundException; import org.hswebframework.web.exception.ValidationException; +import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.logger.ReactiveLogger; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.core.Ordered; +import org.springframework.context.MessageSource; import org.springframework.core.annotation.Order; -import org.springframework.core.codec.DecodingException; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; @@ -40,11 +39,20 @@ @Order public class CommonErrorControllerAdvice { + + private final MessageSource messageSource; + + public CommonErrorControllerAdvice(MessageSource messageSource) { + this.messageSource = messageSource; + } + @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(BusinessException e) { - return Mono.just(ResponseMessage.error(e.getCode(), e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + return LocaleUtils + .resolveThrowable(messageSource, + e, + (err, msg) -> ResponseMessage.error(err.getStatus(), err.getCode(), msg)); } @ExceptionHandler diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index af48922dd..755d8a915 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -1,14 +1,22 @@ package org.hswebframework.web.crud.web; +import org.hswebframework.web.i18n.WebFluxLocaleFilter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @@ -16,17 +24,31 @@ public class CommonWebFluxConfiguration { @Bean @ConditionalOnMissingBean - public CommonErrorControllerAdvice commonErrorControllerAdvice(){ - return new CommonErrorControllerAdvice(); + public CommonErrorControllerAdvice commonErrorControllerAdvice(MessageSource messageSource) { + return new CommonErrorControllerAdvice(messageSource); } @Bean - @ConditionalOnProperty(prefix = "hsweb.webflux.response-wrapper",name = "enabled",havingValue = "true",matchIfMissing = true) + @ConditionalOnProperty(prefix = "hsweb.webflux.response-wrapper", name = "enabled", havingValue = "true", matchIfMissing = true) @ConfigurationProperties(prefix = "hsweb.webflux.response-wrapper") public ResponseMessageWrapper responseMessageWrapper(ServerCodecConfigurer codecConfigurer, RequestedContentTypeResolver resolver, - ReactiveAdapterRegistry registry){ - return new ResponseMessageWrapper(codecConfigurer.getWriters(),resolver,registry); + ReactiveAdapterRegistry registry) { + return new ResponseMessageWrapper(codecConfigurer.getWriters(), resolver, registry); } + + @Bean + public MessageSource messageSource() { + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.setBasenames("i18n/messages"); + messageSource.setDefaultEncoding("UTF-8"); + return messageSource; + } + + @Bean + public WebFilter localeWebFilter() { + return new WebFluxLocaleFilter(); + } + } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java index 4dea9edb3..b46301e58 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java @@ -26,7 +26,7 @@ * @author zhouhao * @since 2.0 */ -public class BusinessException extends RuntimeException { +public class BusinessException extends I18nSupportException { private static final long serialVersionUID = 5441923856899380112L; @Getter @@ -39,21 +39,21 @@ public BusinessException(String message) { this(message, 500); } - public BusinessException(String message, String code) { - this(message, code, 500); + public BusinessException(String message, int status, Object... args) { + this(message, null, status, args); } - public BusinessException(String message, String code, int status) { - super(message); - this.code = code; - this.status = status; + public BusinessException(String message, String code, Object... args) { + this(message, code, 500, args); } - public BusinessException(String message, int status) { - super(message); + public BusinessException(String message, String code, int status, Object... args) { + super(message, args); + this.code = code; this.status = status; } + public BusinessException(String message, Throwable cause) { super(message, cause); } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java new file mode 100644 index 000000000..12a180ebe --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -0,0 +1,27 @@ +package org.hswebframework.web.exception; + + +import lombok.Getter; + +@Getter +public class I18nSupportException extends RuntimeException { + + private final Object[] args; + + public I18nSupportException(String code, Object... args) { + super(code); + this.args = args; + } + + public I18nSupportException(String code, Throwable cause, Object... args) { + super(code, cause); + this.args = args; + } + + + @Override + public String getLocalizedMessage() { + // TODO: 2021/6/21 + return super.getLocalizedMessage(); + } +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/NotFoundException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/NotFoundException.java index 819481e79..b005303e4 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/NotFoundException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/NotFoundException.java @@ -24,11 +24,11 @@ @ResponseStatus(HttpStatus.NOT_FOUND) public class NotFoundException extends BusinessException { - public NotFoundException(String message) { - super(message, 404); + public NotFoundException(String message, Object... args) { + super(message, 404, args); } public NotFoundException() { - this("记录不存在"); + this("error.not_found"); } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java new file mode 100644 index 000000000..4a6137f66 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -0,0 +1,67 @@ +package org.hswebframework.web.i18n; + +import org.hswebframework.web.exception.I18nSupportException; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.SimpleLocaleContext; +import reactor.core.publisher.Mono; + +import java.util.Locale; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class LocaleUtils { + + public static final LocaleContext DEFAULT_CONTEXT = new SimpleLocaleContext(Locale.getDefault()); + + public static Mono reactive() { + return Mono + .subscriberContext() + .map(ctx -> ctx + .getOrEmpty(LocaleContext.class) + .orElse(DEFAULT_CONTEXT)); + } + + + public static Mono resolveThrowable(MessageSource messageSource, + S source, + BiFunction mapper) { + return doWithReactive(messageSource, source, Throwable::getMessage, mapper, source.getArgs()); + } + + public static Mono resolveThrowable(MessageSource messageSource, + S source, + BiFunction mapper, + Object... args) { + return doWithReactive(messageSource, source, Throwable::getMessage, mapper, args); + } + + public static Mono doWithReactive(MessageSource messageSource, + S source, + Function message, + BiFunction mapper, + Object... args) { + return reactive() + .map(ctx -> { + String msg = message.apply(source); + String newMsg = resolveMessage(messageSource, msg, ctx.getLocale(), msg, args); + return mapper.apply(source, newMsg); + }); + } + + public static Mono reactiveMessage(MessageSource messageSource, + String code, + Object... args) { + return reactive() + .map(ctx -> resolveMessage(messageSource, code, ctx.getLocale(), code, args)); + } + + public static String resolveMessage(MessageSource messageSource, + String code, + Locale locale, + String defaultMessage, + Object... args) { + return messageSource.getMessage(code, args, defaultMessage, locale); + } + +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java new file mode 100644 index 000000000..8b4347a6a --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java @@ -0,0 +1,18 @@ +package org.hswebframework.web.i18n; + +import org.springframework.context.i18n.LocaleContext; +import org.springframework.lang.NonNull; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +public class WebFluxLocaleFilter implements WebFilter { + @Override + @NonNull + public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { + return chain + .filter(exchange) + .subscriberContext(ctx -> ctx.put(LocaleContext.class, exchange.getLocaleContext())); + } +} diff --git a/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 000000000..a60689754 --- /dev/null +++ b/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,2 @@ +error.not_found=数据不存在 +error.cant_create_instance=无法创建实例:{0} \ 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/configuration/PermissionProperties.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java index 7f37d667f..e4765108d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/PermissionProperties.java @@ -75,7 +75,7 @@ public AuthorizationSettingEntity handle(Authentication authentication, Authoriz .map(Permission::getActions) .orElseGet(Collections::emptySet)); - throw new AccessDenyException("当前用户无权限:" + setting.getPermission() + "" +actions); + throw new AccessDenyException(setting.getPermission(), actions); } }; diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index 20b0263f0..f3c8d7e7c 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -59,7 +59,7 @@ public Mono insert(Publisher entityPublisher) { return this .publishEvent(entityPublisher, DimensionBindEvent::new) .as(super::insert) - .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("重复的绑定请求")); + .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("error.duplicate_key")); } @Override diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 000000000..0fade07c1 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1 @@ +error.duplicate_key=重复的请求 \ No newline at end of file From 126c54cfb47869fc28748b35d62d9c8b149a6c31 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 21 Jun 2021 18:30:57 +0800 Subject: [PATCH 060/542] rollback --- .../web/crud/entity/factory/MapperEntityFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f3d90d72b..39e156887 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 @@ -172,7 +172,7 @@ public T newInstance(Class beanClass, Class defaultClass) { return (T) new HashSet<>(); } - throw new NotFoundException("error.cant_create_instance",beanClass); + throw new NotFoundException("无法初始化实体类:"+beanClass); } @Override From 01bcd247bd18694f2f1022d0e031591eb816d16a Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 23 Jun 2021 18:26:35 +0800 Subject: [PATCH 061/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/dict/EnumDict.java | 20 ++++-- .../hswebframework/web/dict/EnumDictTest.java | 64 +++++++++++++------ .../org/hswebframework/web/dict/TestEnum.java | 1 - .../CustomCodecsAutoConfiguration.java | 63 +++++++++++------- 4 files changed, 99 insertions(+), 49 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index d87fd52d5..e98330323 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -16,6 +16,8 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.exception.ValidationException; @@ -25,6 +27,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.util.*; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -123,11 +126,6 @@ default String getComments() { return getText(); } - @JsonCreator - default EnumDict fromJsonNode(Object val) { - - return null; - } /** @@ -294,7 +292,10 @@ default void write(JSONSerializer jsonSerializer, Object o, Type type, int i) th * 自定义fastJson枚举序列化 */ @Slf4j + @AllArgsConstructor + @NoArgsConstructor class EnumDictJSONDeserializer extends JsonDeserializer implements ObjectDeserializer { + private Function mapper; @Override @SuppressWarnings("all") @@ -346,7 +347,14 @@ public int getFastMatchToken() { @SneakyThrows public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jp.getCodec().readTree(jp); - + if(mapper!=null){ + if(node.isTextual()){ + return mapper.apply(node.asText()); + } + if(node.isNumber()){ + return mapper.apply(node.asLong()); + } + } String currentName = jp.currentName(); Object currentValue = jp.getCurrentValue(); Class findPropertyType; diff --git a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java index b133673f7..3eb6298bb 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java @@ -1,14 +1,19 @@ package org.hswebframework.web.dict; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.EnumDeserializer; +import com.fasterxml.jackson.databind.module.SimpleDeserializers; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.ClassKey; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; import org.junit.Assert; import org.junit.Test; +import java.util.List; + import static org.junit.Assert.*; public class EnumDictTest { @@ -18,27 +23,46 @@ public class EnumDictTest { public void testJackson() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); - JsonDeserializer deserialize = new EnumDict.EnumDictJSONDeserializer(); - module.addDeserializer(Enum.class, (JsonDeserializer) deserialize); + module.setDeserializers(new SimpleDeserializers() { + @Override + public JsonDeserializer findEnumDeserializer(Class type, + DeserializationConfig config, + BeanDescription beanDesc) throws JsonMappingException { + JsonDeserializer deser = null; + if (type.isEnum()) { + if (EnumDict.class.isAssignableFrom(type)) { + deser = new EnumDict.EnumDictJSONDeserializer(val -> EnumDict + .find((Class) type, val) + .orElse(null)); + } + } + return deser; + } + }); mapper.registerModule(module); - String val = mapper.writer().writeValueAsString(new TestEntity()); +// String val = mapper.writer().writeValueAsString(new TestEntity()); +// +// System.out.println(val); +// TestEntity testEntity = mapper.readerFor(TestEntity.class) +// .readValue(val); +// +// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); +// testEntity = mapper.readerFor(TestEntity.class) +// .readValue("{\"testEnum\":\"E1\"}"); +// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); +// +// testEntity = mapper.readerFor(TestEntity.class) +// .readValue("{\"testEnum\":\"e1\"}"); +// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); +// +// System.out.println((Object) mapper.readerFor(TestEnum.class).readValue("\"E1\"")); - System.out.println(val); TestEntity testEntity = mapper.readerFor(TestEntity.class) - .readValue(val); - - Assert.assertEquals(testEntity.testEnum, TestEnum.E1); - testEntity = mapper.readerFor(TestEntity.class) - .readValue("{\"testEnum\":\"E1\"}"); - Assert.assertEquals(testEntity.testEnum, TestEnum.E1); - - testEntity = mapper.readerFor(TestEntity.class) - .readValue("{\"testEnum\":\"e1\"}"); - Assert.assertEquals(testEntity.testEnum, TestEnum.E1); - - System.out.println((Object) mapper.readerFor(TestEnum.class).readValue("\"E1\"")); + .readValue("{\"testEnums\":[\"E1\"]}"); + System.out.println(testEntity.getTestEnums()); +// Assert.assertArrayEquals(testEntity.getSimpleEnums(), new TestEnum[]{TestEnum.E1}); } @@ -49,9 +73,11 @@ public void testEq() { assertTrue(EnumDict.find(TestEnum.class, "e1") .isPresent()); + assertTrue(EnumDict.find(TestEnum.class, "E1") .isPresent()); + } @Getter @@ -60,6 +86,8 @@ public static class TestEntity { private TestEnum testEnum = TestEnum.E1; private SimpleEnum simpleEnum = SimpleEnum.A; + + private TestEnum[] testEnums; } public enum SimpleEnum { diff --git a/hsweb-core/src/test/java/org/hswebframework/web/dict/TestEnum.java b/hsweb-core/src/test/java/org/hswebframework/web/dict/TestEnum.java index de22bddf4..b2069d498 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/dict/TestEnum.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/dict/TestEnum.java @@ -1,7 +1,6 @@ package org.hswebframework.web.dict; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java index 56b21dc64..17fa60a8d 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -1,8 +1,10 @@ package org.hswebframework.web.starter.jackson; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.deser.std.EnumDeserializer; +import com.fasterxml.jackson.databind.module.SimpleDeserializers; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.ClassKey; import org.hswebframework.web.api.crud.entity.EntityFactory; import org.hswebframework.web.dict.EnumDict; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -19,28 +21,41 @@ @AutoConfigureAfter(JacksonAutoConfiguration.class) public class CustomCodecsAutoConfiguration { - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(ObjectMapper.class) - static class JacksonDecoderConfiguration { - - @Bean - @Order(1) - @ConditionalOnBean(ObjectMapper.class) - CodecCustomizer jacksonDecoderCustomizer(EntityFactory entityFactory, ObjectMapper objectMapper) { - // objectMapper.setTypeFactory(new CustomTypeFactory(entityFactory)); - SimpleModule module = new SimpleModule(); - JsonDeserializer deserializer = new EnumDict.EnumDictJSONDeserializer(); - module.addDeserializer(Enum.class, deserializer); - objectMapper.registerModule(module); - - - return (configurer) -> { - CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); - defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(objectMapper)); - }; - } - - } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ObjectMapper.class) + static class JacksonDecoderConfiguration { + + @Bean + @Order(1) + @ConditionalOnBean(ObjectMapper.class) + CodecCustomizer jacksonDecoderCustomizer(EntityFactory entityFactory, ObjectMapper objectMapper) { + // objectMapper.setTypeFactory(new CustomTypeFactory(entityFactory)); + SimpleModule module = new SimpleModule(); + module.setDeserializers(new SimpleDeserializers() { + @Override + public JsonDeserializer findEnumDeserializer(Class type, + DeserializationConfig config, + BeanDescription beanDesc) { + JsonDeserializer deser = null; + if (type.isEnum()) { + if (EnumDict.class.isAssignableFrom(type)) { + deser = new EnumDict.EnumDictJSONDeserializer(val -> EnumDict + .find((Class) type, val) + .orElse(null)); + } + } + return deser; + } + }); + objectMapper.registerModule(module); + + return (configurer) -> { + CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); + defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(objectMapper)); + }; + } + + } } From 8aa65eb23195af8b90b6600adf6c6c0e7d39df15 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 23 Jun 2021 18:28:41 +0800 Subject: [PATCH 062/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/dict/EnumDictTest.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java index 3eb6298bb..f4c2be887 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/dict/EnumDictTest.java @@ -42,27 +42,27 @@ public JsonDeserializer findEnumDeserializer(Class type, mapper.registerModule(module); -// String val = mapper.writer().writeValueAsString(new TestEntity()); -// -// System.out.println(val); -// TestEntity testEntity = mapper.readerFor(TestEntity.class) -// .readValue(val); -// -// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); -// testEntity = mapper.readerFor(TestEntity.class) -// .readValue("{\"testEnum\":\"E1\"}"); -// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); -// -// testEntity = mapper.readerFor(TestEntity.class) -// .readValue("{\"testEnum\":\"e1\"}"); -// Assert.assertEquals(testEntity.testEnum, TestEnum.E1); -// -// System.out.println((Object) mapper.readerFor(TestEnum.class).readValue("\"E1\"")); + String val = mapper.writer().writeValueAsString(new TestEntity()); + System.out.println(val); TestEntity testEntity = mapper.readerFor(TestEntity.class) - .readValue("{\"testEnums\":[\"E1\"]}"); - System.out.println(testEntity.getTestEnums()); -// Assert.assertArrayEquals(testEntity.getSimpleEnums(), new TestEnum[]{TestEnum.E1}); + .readValue(val); + + Assert.assertEquals(testEntity.testEnum, TestEnum.E1); + testEntity = mapper.readerFor(TestEntity.class) + .readValue("{\"testEnum\":\"E1\"}"); + Assert.assertEquals(testEntity.testEnum, TestEnum.E1); + + testEntity = mapper.readerFor(TestEntity.class) + .readValue("{\"testEnum\":\"e1\"}"); + Assert.assertEquals(testEntity.testEnum, TestEnum.E1); + + System.out.println((Object) mapper.readerFor(TestEnum.class).readValue("\"E1\"")); + + testEntity = mapper.readerFor(TestEntity.class) + .readValue("{\"testEnums\":[\"E1\"]}"); +// System.out.println(testEntity.getTestEnums()); + Assert.assertArrayEquals(testEntity.getTestEnums(), new TestEnum[]{TestEnum.E1}); } From 913dfa5dd8773066e7ccb9f6548f934e51667009 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 24 Jun 2021 08:53:27 +0800 Subject: [PATCH 063/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomCodecsAutoConfiguration.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java index a9ec48df5..8e1f57bd1 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -21,13 +21,14 @@ @AutoConfigureAfter(JacksonAutoConfiguration.class) public class CustomCodecsAutoConfiguration { - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(ObjectMapper.class) - static class JacksonDecoderConfiguration { + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ObjectMapper.class) + static class JacksonDecoderConfiguration { @Bean @Order(1) @ConditionalOnBean(ObjectMapper.class) + @SuppressWarnings("all") CodecCustomizer jacksonDecoderCustomizer(EntityFactory entityFactory, ObjectMapper objectMapper) { // objectMapper.setTypeFactory(new CustomTypeFactory(entityFactory)); SimpleModule module = new SimpleModule(); @@ -37,26 +38,23 @@ public JsonDeserializer findEnumDeserializer(Class type, DeserializationConfig config, BeanDescription beanDesc) { JsonDeserializer deser = null; - if (type.isEnum()) { - if (EnumDict.class.isAssignableFrom(type)) { - deser = new EnumDict.EnumDictJSONDeserializer(val -> EnumDict - .find((Class) type, val) - .orElse(null)); - } + if (type.isEnum() && EnumDict.class.isAssignableFrom(type)) { + deser = new EnumDict.EnumDictJSONDeserializer(val -> EnumDict + .find((Class) type, val) + .orElse(null)); } return deser; } }); objectMapper.registerModule(module); + return (configurer) -> { + CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); + defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(entityFactory, objectMapper)); + }; + } - return (configurer) -> { - CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); - defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(entityFactory,objectMapper)); - }; - } - - } + } } From 255cb48729cec57d6088054264172dc3110b1844 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 24 Jun 2021 10:55:01 +0800 Subject: [PATCH 064/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=AA=E8=BF=94?= =?UTF-8?q?=E5=9B=9Eresult?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/crud/web/ResponseMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java index c3d799d00..76ff70584 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessage.java @@ -39,7 +39,7 @@ public static ResponseMessage ok() { @SuppressWarnings("all") public static ResponseMessage ok(T result) { - return of("success", null, 200, null, System.currentTimeMillis()); + return of("success", result, 200, null, System.currentTimeMillis()); } public static ResponseMessage error(String message) { From 8b211de5e47a739d3149efd287636a5352fddecd Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 25 Jun 2021 10:54:58 +0800 Subject: [PATCH 065/542] =?UTF-8?q?=E4=BC=98=E5=8C=96i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/annotation/TwoFactor.java | 2 +- .../AuthorizationI18nConfiguration.java | 20 ++++ .../main/resources/META-INF/spring.factories | 3 +- .../authentication/messages_en_US.properties | 16 ++++ .../messages_zh_CN.properties | 10 +- .../TwoFactorHandlerInterceptorAdapter.java | 3 +- .../basic/web/AuthorizationController.java | 5 +- .../web/oauth2/OAuth2Exception.java | 2 +- .../Commons18nConfiguration.java | 20 ++++ .../crud/web/CommonErrorControllerAdvice.java | 91 ++++++++++++------- .../crud/web/CommonWebFluxConfiguration.java | 9 +- .../main/resources/META-INF/spring.factories | 3 +- .../i18n/commons/messages_en_US.properties | 5 + .../i18n/commons/messages_zh_CN.properties | 5 + .../org/hswebframework/web/dict/EnumDict.java | 49 +++++----- .../web/exception/BusinessException.java | 4 - .../web/exception/ValidationException.java | 4 +- .../hswebframework/web/i18n/LocaleUtils.java | 6 +- .../web/i18n/WebFluxLocaleFilter.java | 17 +++- .../i18n/core/messages_en_US.properties | 3 + .../i18n/core/messages_zh_CN.properties | 4 + .../resources/i18n/messages_zh_CN.properties | 2 - .../starter/i18n/CompositeMessageSource.java | 70 ++++++++++++++ .../web/starter/i18n/I18nConfiguration.java | 38 ++++++++ .../main/resources/META-INF/spring.factories | 3 +- 25 files changed, 306 insertions(+), 88 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties rename hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/{ => authentication}/messages_zh_CN.properties (56%) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties create mode 100644 hsweb-core/src/main/resources/i18n/core/messages_en_US.properties create mode 100644 hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties delete mode 100644 hsweb-core/src/main/resources/i18n/messages_zh_CN.properties create mode 100644 hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java create mode 100644 hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java index 1d3d6b98f..7805bb966 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/TwoFactor.java @@ -55,5 +55,5 @@ * @return 错误提示 * @since 3.0.6 */ - String message() default "assert.verify_code_error"; + String message() default "validation.verify_code_error"; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java new file mode 100644 index 000000000..13430e3fe --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java @@ -0,0 +1,20 @@ +package org.hswebframework.web.authorization.configuration; + +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ResourceBundleMessageSource; + +@Configuration +public class AuthorizationI18nConfiguration { + + @Bean + public MessageSource authorizationMessageSource(){ + ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); + messageSource.setDefaultEncoding("UTF-8"); + messageSource.setBundleClassLoader(AuthorizationI18nConfiguration.class.getClassLoader()); + messageSource.setBasenames("i18n/authentication/messages"); + return messageSource; + } + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories b/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories index cb2dcecb0..374161647 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories @@ -1,3 +1,4 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration \ No newline at end of file +org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration,\ +org.hswebframework.web.authorization.configuration.AuthorizationI18nConfiguration \ No newline at end of file diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties new file mode 100644 index 000000000..9e1bcb7d1 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties @@ -0,0 +1,16 @@ +error.access_denied=Access Denied +error.permission_denied=Permission Denied [{0}]:{1} +error.logged_in_elsewhere=User logged in elsewhere +error.illegal_password=Bad username or password +error.user_disabled=User is disabled +# +message.token_state_normal=Normal +message.token_state_deny=Login has denied +message.token_state_expired=Login has expired +message.token_state_offline=User logged in elsewhere +message.token_state_lock=User Locked +# +validation.need_two_factor_verify=Two factor verification required +validation.username_must_not_be_empty=Username must not be empty +validation.password_must_not_be_empty=Password must not be empty +validation.verify_code_error=Verification code error \ No newline at end of file diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh_CN.properties similarity index 56% rename from hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties rename to hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh_CN.properties index 412d3de60..a9bd62303 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/messages_zh_CN.properties +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh_CN.properties @@ -1,6 +1,8 @@ error.access_denied=权限不足,拒绝访问! error.permission_denied=当前用户无权限[{0}]:{1} error.logged_in_elsewhere=该用户已在其他地方登陆 +error.illegal_password=用户名或密码错误 +error.user_disabled=用户已被禁用 # message.token_state_normal=正常 message.token_state_deny=已被禁止访问 @@ -8,7 +10,7 @@ message.token_state_expired=用户未登录 message.token_state_offline=用户已在其他地方登录 message.token_state_lock=登录状态已被锁定 # -assert.need_two_factor_verify=需要双因子验证 -assert.username_must_not_be_empty=用户名不能为空 -assert.password_must_not_be_empty=密码不能为空 -assert.verify_code_error=验证码错误 \ No newline at end of file +validation.need_two_factor_verify=需要双因子验证 +validation.username_must_not_be_empty=用户名不能为空 +validation.password_must_not_be_empty=密码不能为空 +validation.verify_code_error=验证码错误 \ No newline at end of file diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java index 5aa9efbcb..c76076d5f 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/twofactor/TwoFactorHandlerInterceptorAdapter.java @@ -7,7 +7,6 @@ import org.hswebframework.web.authorization.exception.NeedTwoFactorException; import org.hswebframework.web.authorization.twofactor.TwoFactorValidator; import org.hswebframework.web.authorization.twofactor.TwoFactorValidatorManager; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @@ -45,7 +44,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons code = request.getHeader(factor.parameter()); } if (StringUtils.isEmpty(code)) { - throw new NeedTwoFactorException("assert.need_two_factor_verify", factor.provider()); + throw new NeedTwoFactorException("validation.need_two_factor_verify", factor.provider()); } else if (!validator.verify(code, factor.timeout())) { throw new NeedTwoFactorException(factor.message(), factor.provider()); } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java index 659fe9879..a8f553f04 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java @@ -34,7 +34,6 @@ import org.hswebframework.web.logging.AccessLogger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.event.EventListener; import org.springframework.http.MediaType; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; @@ -85,8 +84,8 @@ private Mono> doLogin(Mono> parameter) { String username_ = (String) parameters.get("username"); String password_ = (String) parameters.get("password"); - Assert.hasLength(username_, "assert.username_must_not_be_empty"); - Assert.hasLength(password_, "assert.password_must_not_be_empty"); + Assert.hasLength(username_, "validation.username_must_not_be_empty"); + Assert.hasLength(password_, "validation.password_must_not_be_empty"); Function parameterGetter = parameters::get; return Mono.defer(() -> { diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/OAuth2Exception.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/OAuth2Exception.java index fc48ad3e1..41d8a62a5 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/OAuth2Exception.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/OAuth2Exception.java @@ -8,7 +8,7 @@ public class OAuth2Exception extends BusinessException { private final ErrorType type; public OAuth2Exception(ErrorType type) { - super(type.message(), type.name(), type.code()); + super(type.message(), type.name(), type.code(), (Object[]) null); this.type = type; } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java new file mode 100644 index 000000000..fe73ac510 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java @@ -0,0 +1,20 @@ +package org.hswebframework.web.crud.configuration; + +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ResourceBundleMessageSource; + +@Configuration +public class Commons18nConfiguration { + + @Bean + public MessageSource commonsMessageSource(){ + ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); + messageSource.setDefaultEncoding("UTF-8"); + messageSource.setBundleClassLoader(Commons18nConfiguration.class.getClassLoader()); + messageSource.setBasenames("i18n/commons/messages"); + return messageSource; + } + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 9f9b44b98..27943ce59 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -22,10 +22,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.support.WebExchangeBindException; -import org.springframework.web.server.MediaTypeNotSupportedStatusException; -import org.springframework.web.server.MethodNotAllowedException; -import org.springframework.web.server.NotAcceptableStatusException; -import org.springframework.web.server.ServerWebInputException; +import org.springframework.web.server.*; import reactor.core.publisher.Mono; import javax.validation.ConstraintViolationException; @@ -39,7 +36,6 @@ @Order public class CommonErrorControllerAdvice { - private final MessageSource messageSource; public CommonErrorControllerAdvice(MessageSource messageSource) { @@ -58,25 +54,31 @@ public Mono> handleException(BusinessException e) { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(UnsupportedOperationException e) { - return Mono.just(ResponseMessage.error("unsupported", e.getMessage())); + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unsupported", msg))); } @ExceptionHandler @ResponseStatus(HttpStatus.UNAUTHORIZED) public Mono> handleException(UnAuthorizedException e) { - return Mono.just(ResponseMessage.error(401, "unauthorized", e.getMessage()).result(e.getState())); + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unauthorized", msg).result(e.getState()))); } @ExceptionHandler @ResponseStatus(HttpStatus.FORBIDDEN) - public Mono> handleException(AccessDenyException e) { - return Mono.just(ResponseMessage.error(403, e.getCode(), e.getMessage())); + public Mono> handleException(AccessDenyException e) { + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(403, e.getCode(), e.getMessage())) + ; } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) - public Mono> handleException(NotFoundException e) { - return Mono.just(ResponseMessage.error(404, "not_found", e.getMessage())); + public Mono> handleException(NotFoundException e) { + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(404, "not_found", msg)) + ; } @ExceptionHandler @@ -138,6 +140,7 @@ public Mono> handleException(javax.validation.ValidationExcep @ExceptionHandler @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) public Mono> handleException(TimeoutException e) { + return Mono.just(ResponseMessage.error(504, "timeout", e.getMessage())) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); @@ -163,51 +166,70 @@ public Mono> handleException(NullPointerException e) { @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(IllegalArgumentException e) { - return Mono.just(ResponseMessage.error(400, "illegal_argument", e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(400, "illegal_argument", msg)) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))) + ; } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(AuthenticationException e) { - return Mono.just(ResponseMessage.error(400, e.getCode(), e.getMessage())); + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(400, e.getCode(), msg)) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))) + ; } @ExceptionHandler @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - public Mono> handleException(MediaTypeNotSupportedStatusException e) { - return Mono.just(ResponseMessage - .error(415, "unsupported_media_type", "不支持的请求类型") - .result(e.getSupportedMediaTypes())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + public Mono> handleException(UnsupportedMediaTypeStatusException e) { + return LocaleUtils + .resolveMessage(messageSource, "error.unsupported_media_type") + .map(msg -> ResponseMessage + .error(415, "unsupported_media_type", msg) + .result(e.getSupportedMediaTypes())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(NotAcceptableStatusException e) { - return Mono.just(ResponseMessage - .error(406, "not_acceptable_media_type", "不支持的响应类型") - .result(e.getSupportedMediaTypes())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + + return LocaleUtils + .resolveMessage(messageSource, "error.not_acceptable_media_type") + .map(msg -> ResponseMessage + .error(406, "not_acceptable_media_type", msg) + .result(e.getSupportedMediaTypes())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(MethodNotAllowedException e) { - return Mono.just(ResponseMessage - .error(405, "method_not_allowed", "不支持的请求方法:" + e.getHttpMethod()) - .result(e.getSupportedMethods())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + return LocaleUtils + .resolveMessage(messageSource, "error.method_not_allowed") + .map(msg -> ResponseMessage + .error(406, "method_not_allowed", msg) + .result(e.getSupportedMethods())) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) - public Mono> handleException(R2dbcDataIntegrityViolationException exception) { - if (exception.getMessage().contains("Duplicate")) { - return Mono.just(ResponseMessage.error("存在重复的数据")); + public Mono> handleException(R2dbcDataIntegrityViolationException e) { + String code; + + if (e.getMessage().contains("Duplicate")) { + code = "error.duplicate_data"; + } else { + code = "error.data_error"; + log.warn(e.getMessage(), e); } - log.warn(exception.getMessage(), exception); - return Mono.just(ResponseMessage.error("数据错误")); + return LocaleUtils + .resolveMessage(messageSource, code) + .map(msg -> ResponseMessage.error(400, code, msg)); } @@ -223,7 +245,10 @@ public Mono>> handleException(S } while (exception != null && exception != e); - return Mono.just(ResponseMessage.error(400, "illegal_argument", e.getMessage())); + return LocaleUtils + .resolveThrowable(messageSource, + exception, + (err, msg) -> ResponseMessage.error(400, "illegal_argument", msg)); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index 755d8a915..df47c43ce 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -10,12 +10,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.i18n.LocaleContext; import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; +import org.springframework.web.server.i18n.LocaleContextResolver; import reactor.core.publisher.Mono; @Configuration @@ -38,13 +40,6 @@ public ResponseMessageWrapper responseMessageWrapper(ServerCodecConfigurer codec return new ResponseMessageWrapper(codecConfigurer.getWriters(), resolver, registry); } - @Bean - public MessageSource messageSource() { - ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); - messageSource.setBasenames("i18n/messages"); - messageSource.setDefaultEncoding("UTF-8"); - return messageSource; - } @Bean public WebFilter localeWebFilter() { 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 3a51d2ae5..c17a4b2d6 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 @@ -3,4 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.hswebframework.web.crud.configuration.EasyormConfiguration,\ org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration,\ -org.hswebframework.web.crud.web.CommonWebFluxConfiguration \ No newline at end of file +org.hswebframework.web.crud.web.CommonWebFluxConfiguration,\ +org.hswebframework.web.crud.configuration.Commons18nConfiguration \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties new file mode 100644 index 000000000..f35bfc889 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties @@ -0,0 +1,5 @@ +error.unsupported_media_type=Unsupported media type +error.not_acceptable_media_type=Not acceptable media type +error.method_not_allowed=Method not allowed +error.duplicate_data=Duplicate data +error.data_error=Data error \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties new file mode 100644 index 000000000..e988c8dee --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties @@ -0,0 +1,5 @@ +error.unsupported_media_type=不支持的请求类型 +error.not_acceptable_media_type=不支持的响应类型 +error.method_not_allowed=不支持的请求方法 +error.duplicate_data=重复的数据 +error.data_error=数据错误 \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index e98330323..e1d4ce2e1 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -127,7 +127,6 @@ default String getComments() { } - /** * 从指定的枚举类中查找想要的枚举,并返回一个{@link Optional},如果未找到,则返回一个{@link Optional#empty()} * @@ -150,8 +149,8 @@ static Optional find(Class type, Predicate static List findList(Class type, Predicate predicate) { if (type.isEnum()) { return Arrays.stream(type.getEnumConstants()) - .filter(predicate) - .collect(Collectors.toList()); + .filter(predicate) + .collect(Collectors.toList()); } return Collections.emptyList(); } @@ -162,7 +161,9 @@ static List findList(Class type, Predicate * @see this#find(Class, Predicate) */ static > Optional findByValue(Class type, Object value) { - return find(type, e -> e.getValue() == value || e.getValue().equals(value) || String.valueOf(e.getValue()).equalsIgnoreCase(String.valueOf(value))); + return find(type, e -> e.getValue() == value || e.getValue().equals(value) || String + .valueOf(e.getValue()) + .equalsIgnoreCase(String.valueOf(value))); } /** @@ -203,8 +204,8 @@ static boolean in(T target, T... t) { if (all.length >= 64) { List list = Arrays.asList(t); return Arrays.stream(all) - .map(EnumDict.class::cast) - .anyMatch(list::contains); + .map(EnumDict.class::cast) + .anyMatch(list::contains); } return maskIn(toMask(t), target); } @@ -295,7 +296,7 @@ default void write(JSONSerializer jsonSerializer, Object o, Type type, int i) th @AllArgsConstructor @NoArgsConstructor class EnumDictJSONDeserializer extends JsonDeserializer implements ObjectDeserializer { - private Function mapper; + private Function mapper; @Override @SuppressWarnings("all") @@ -324,8 +325,10 @@ public T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { value = parser.parse(); if (value instanceof Map) { return (T) EnumDict.find(((Class) type), ((Map) value).get("value")) - .orElseGet(() -> - EnumDict.find(((Class) type), ((Map) value).get("text")).orElse(null)); + .orElseGet(() -> + EnumDict + .find(((Class) type), ((Map) value).get("text")) + .orElse(null)); } } @@ -347,11 +350,11 @@ public int getFastMatchToken() { @SneakyThrows public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jp.getCodec().readTree(jp); - if(mapper!=null){ - if(node.isTextual()){ + if (mapper != null) { + if (node.isTextual()) { return mapper.apply(node.asText()); } - if(node.isNumber()){ + if (node.isNumber()) { return mapper.apply(node.asLong()); } } @@ -364,19 +367,20 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE findPropertyType = BeanUtils.findPropertyType(currentName, currentValue.getClass()); } Supplier exceptionSupplier = () -> { - List values= Stream.of(findPropertyType.getEnumConstants()) + List values = Stream + .of(findPropertyType.getEnumConstants()) .map(Enum.class::cast) - .map(e->{ - if(e instanceof EnumDict){ + .map(e -> { + if (e instanceof EnumDict) { return ((EnumDict) e).getValue(); } return e.name(); }).collect(Collectors.toList()); - return new ValidationException("参数[" + currentName + "]在选项中不存在", - Arrays.asList( - new ValidationException.Detail(currentName, "选项中不存在此值", values) - )); + return new ValidationException("validation.parameter_does_not_exist_in_enums", + Arrays.asList( + new ValidationException.Detail(currentName, "选项中不存在此值", values) + ), currentName); }; if (EnumDict.class.isAssignableFrom(findPropertyType) && findPropertyType.isEnum()) { if (node.isObject()) { @@ -394,12 +398,13 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE .find(findPropertyType, node.textValue()) .orElseThrow(exceptionSupplier); } - throw new ValidationException("参数[" + currentName + "]在选项中不存在", Arrays.asList( + throw new ValidationException("validation.parameter_does_not_exist_in_enums", Arrays.asList( new ValidationException.Detail(currentName, "选项中不存在此值", null) - )); + ), currentName); } if (findPropertyType.isEnum()) { - return Stream.of(findPropertyType.getEnumConstants()) + return Stream + .of(findPropertyType.getEnumConstants()) .filter(o -> { if (node.isTextual()) { return node.textValue().equalsIgnoreCase(((Enum) o).name()); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java index b46301e58..de3110580 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java @@ -43,10 +43,6 @@ public BusinessException(String message, int status, Object... args) { this(message, null, status, args); } - public BusinessException(String message, String code, Object... args) { - this(message, code, 500, args); - } - public BusinessException(String message, String code, int status, Object... args) { super(message, args); this.code = code; 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 index ba0802a8b..492631ab0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -28,8 +28,8 @@ public ValidationException(String property, String message) { this(message, Collections.singletonList(new Detail(property, message, null))); } - public ValidationException(String message, List details) { - super(message); + public ValidationException(String message, List details,Object... args) { + super(message,400,args); this.details = details; } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 4a6137f66..028d0bbd1 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -49,9 +49,9 @@ public static Mono doWithReactive(MessageSource messageSource, }); } - public static Mono reactiveMessage(MessageSource messageSource, - String code, - Object... args) { + public static Mono resolveMessage(MessageSource messageSource, + String code, + Object... args) { return reactive() .map(ctx -> resolveMessage(messageSource, code, ctx.getLocale(), code, args)); } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java index 8b4347a6a..4f788800f 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java @@ -1,18 +1,33 @@ package org.hswebframework.web.i18n; import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.SimpleLocaleContext; import org.springframework.lang.NonNull; +import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; +import java.util.Locale; +import java.util.Optional; + public class WebFluxLocaleFilter implements WebFilter { @Override @NonNull public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { return chain .filter(exchange) - .subscriberContext(ctx -> ctx.put(LocaleContext.class, exchange.getLocaleContext())); + .subscriberContext(ctx -> ctx.put(LocaleContext.class, getLocaleContext(exchange))); + } + + public LocaleContext getLocaleContext(ServerWebExchange exchange) { + String lang = exchange.getRequest() + .getQueryParams() + .getFirst(":lang"); + if (StringUtils.hasText(lang)) { + return new SimpleLocaleContext(Locale.forLanguageTag(lang)); + } + return exchange.getLocaleContext(); } } diff --git a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties new file mode 100644 index 000000000..37d8fb0a5 --- /dev/null +++ b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties @@ -0,0 +1,3 @@ +error.not_found=The data does not exist +error.cant_create_instance=Unable to create instance:{0} +validation.parameter_does_not_exist_in_enums=Parameter {0} does not exist in option \ No newline at end of file diff --git a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties new file mode 100644 index 000000000..a51a0485d --- /dev/null +++ b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties @@ -0,0 +1,4 @@ +error.not_found=数据不存在 +error.cant_create_instance=无法创建实例:{0} + +validation.parameter_does_not_exist_in_enums=参数[{0}]在选择中不存在 \ No newline at end of file diff --git a/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties deleted file mode 100644 index a60689754..000000000 --- a/hsweb-core/src/main/resources/i18n/messages_zh_CN.properties +++ /dev/null @@ -1,2 +0,0 @@ -error.not_found=数据不存在 -error.cant_create_instance=无法创建实例:{0} \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java new file mode 100644 index 000000000..fcb22af11 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java @@ -0,0 +1,70 @@ +package org.hswebframework.web.starter.i18n; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CopyOnWriteArrayList; + +public class CompositeMessageSource implements MessageSource { + + private final List messageSources = new CopyOnWriteArrayList<>(); + + public void addMessageSources(Collection source) { + messageSources.addAll(source); + } + + public void addMessageSource(MessageSource source) { + messageSources.add(source); + } + + @Override + public String getMessage(@Nonnull String code, Object[] args, String defaultMessage, @Nonnull Locale locale) { + for (MessageSource messageSource : messageSources) { + String result = messageSource.getMessage(code, args, defaultMessage, locale); + if (StringUtils.hasText(result)) { + return result; + } + } + return null; + } + + @Override + @Nonnull + public String getMessage(@Nonnull String code, Object[] args, @Nonnull Locale locale) throws NoSuchMessageException { + for (MessageSource messageSource : messageSources) { + try { + String result = messageSource.getMessage(code, args, locale); + if (StringUtils.hasText(result)) { + return result; + } + } catch (NoSuchMessageException ignore) { + + } + } + throw new NoSuchMessageException(code, locale); + } + + @Override + @Nonnull + public String getMessage(@Nonnull MessageSourceResolvable resolvable, @Nonnull Locale locale) throws NoSuchMessageException { + for (MessageSource messageSource : messageSources) { + try { + String result = messageSource.getMessage(resolvable, locale); + if (StringUtils.hasText(result)) { + return result; + } + } catch (NoSuchMessageException ignore) { + + } + } + String[] codes = resolvable.getCodes(); + throw new NoSuchMessageException(!ObjectUtils.isEmpty(codes) ? codes[codes.length - 1] : "", locale); + } +} diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java new file mode 100644 index 000000000..796500c47 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java @@ -0,0 +1,38 @@ +package org.hswebframework.web.starter.i18n; + +import org.hswebframework.web.exception.BusinessException; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.support.ResourceBundleMessageSource; +import org.springframework.core.Ordered; + +import java.util.stream.Collectors; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +public class I18nConfiguration { + + + @Bean + public MessageSource coreMessageSource(){ + ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); + messageSource.setDefaultEncoding("UTF-8"); + messageSource.setBundleClassLoader(BusinessException.class.getClassLoader()); + messageSource.setBasenames("i18n/core/messages"); + return messageSource; + } + + @Bean + @Primary + public MessageSource compositeMessageSource(ObjectProvider objectProvider) { + CompositeMessageSource messageSource = new CompositeMessageSource(); + messageSource.addMessageSources(objectProvider.stream().collect(Collectors.toList())); + return messageSource; + } + + +} diff --git a/hsweb-starter/src/main/resources/META-INF/spring.factories b/hsweb-starter/src/main/resources/META-INF/spring.factories index 8357d086b..43f2e42db 100644 --- a/hsweb-starter/src/main/resources/META-INF/spring.factories +++ b/hsweb-starter/src/main/resources/META-INF/spring.factories @@ -2,4 +2,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.hswebframework.web.starter.jackson.CustomCodecsAutoConfiguration,\ org.hswebframework.web.starter.HswebAutoConfiguration,\ -org.hswebframework.web.starter.CorsAutoConfiguration \ No newline at end of file +org.hswebframework.web.starter.CorsAutoConfiguration,\ +org.hswebframework.web.starter.i18n.I18nConfiguration \ No newline at end of file From afa33af59d335cc8228848a68715c413239e9e89 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 25 Jun 2021 10:56:07 +0800 Subject: [PATCH 066/542] =?UTF-8?q?=E4=BD=BF=E7=94=A8CopyOnWriteArrayList?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveAuthenticationHolder.java | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java index bd8dfa038..fc4c45227 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java @@ -22,10 +22,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Function; import java.util.stream.Collectors; @@ -45,15 +43,15 @@ * @since 4.0 */ public final class ReactiveAuthenticationHolder { - private static final List suppliers = new ArrayList<>(); - - private static final ReadWriteLock lock = new ReentrantReadWriteLock(); + private static final List suppliers = new CopyOnWriteArrayList<>(); private static Mono get(Function> function) { - return Flux.concat(suppliers.stream() - .map(function) - .collect(Collectors.toList())) + return Flux + .concat(suppliers + .stream() + .map(function) + .collect(Collectors.toList())) .reduceWith(SimpleAuthentication::new, Authentication::merge) .filter(a -> a.getUser() != null); } @@ -82,22 +80,12 @@ public static Mono get(String userId) { * @param supplier */ public static void addSupplier(ReactiveAuthenticationSupplier supplier) { - lock.writeLock().lock(); - try { - suppliers.add(supplier); - } finally { - lock.writeLock().unlock(); - } + suppliers.add(supplier); } - public static void setSupplier(ReactiveAuthenticationSupplier supplier){ - lock.writeLock().lock(); - try { - suppliers.clear(); - suppliers.add(supplier); - } finally { - lock.writeLock().unlock(); - } + public static void setSupplier(ReactiveAuthenticationSupplier supplier) { + suppliers.clear(); + suppliers.add(supplier); } } From d5a01ce922658f42e317cd7ab7f96249c89f70c2 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Jul 2021 14:16:48 +0800 Subject: [PATCH 067/542] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/factory/MapperEntityFactory.java | 2 +- .../crud/web/CommonErrorControllerAdvice.java | 8 +- .../i18n/commons/messages_zh_CN.properties | 2 +- .../org/hswebframework/web/dict/EnumDict.java | 14 +- .../hswebframework/web/i18n/LocaleUtils.java | 114 +++++- .../web/i18n/MessageSourceInitializer.java | 12 + .../starter/i18n/CompositeMessageSource.java | 5 +- .../web/starter/i18n/I18nConfiguration.java | 2 + .../CustomCodecsAutoConfiguration.java | 1 + .../jackson/CustomJackson2jsonEncoder.java | 340 ++++++++++++++++++ .../CustomJackson2jsonEncoderTest.java | 88 +++++ .../resources/i18n/messages_en_US.properties | 2 + .../resources/i18n/messages_zh_CN.properties | 2 + 13 files changed, 570 insertions(+), 22 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java create mode 100644 hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java create mode 100644 hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java create mode 100644 hsweb-starter/src/test/resources/i18n/messages_en_US.properties create mode 100644 hsweb-starter/src/test/resources/i18n/messages_zh_CN.properties 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 39e156887..61ac7cd2b 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 @@ -172,7 +172,7 @@ public T newInstance(Class beanClass, Class defaultClass) { return (T) new HashSet<>(); } - throw new NotFoundException("无法初始化实体类:"+beanClass); + throw new NotFoundException("can not create instance:"+beanClass); } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 27943ce59..fd320afe5 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -186,7 +186,7 @@ public Mono> handleException(AuthenticationException e) @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) public Mono> handleException(UnsupportedMediaTypeStatusException e) { return LocaleUtils - .resolveMessage(messageSource, "error.unsupported_media_type") + .resolveMessageReactive(messageSource, "error.unsupported_media_type") .map(msg -> ResponseMessage .error(415, "unsupported_media_type", msg) .result(e.getSupportedMediaTypes())) @@ -198,7 +198,7 @@ public Mono> handleException(UnsupportedMediaTypeStatusE public Mono> handleException(NotAcceptableStatusException e) { return LocaleUtils - .resolveMessage(messageSource, "error.not_acceptable_media_type") + .resolveMessageReactive(messageSource, "error.not_acceptable_media_type") .map(msg -> ResponseMessage .error(406, "not_acceptable_media_type", msg) .result(e.getSupportedMediaTypes())) @@ -209,7 +209,7 @@ public Mono> handleException(NotAcceptableStatusExceptio @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(MethodNotAllowedException e) { return LocaleUtils - .resolveMessage(messageSource, "error.method_not_allowed") + .resolveMessageReactive(messageSource, "error.method_not_allowed") .map(msg -> ResponseMessage .error(406, "method_not_allowed", msg) .result(e.getSupportedMethods())) @@ -228,7 +228,7 @@ public Mono> handleException(R2dbcDataIntegrityViolation log.warn(e.getMessage(), e); } return LocaleUtils - .resolveMessage(messageSource, code) + .resolveMessageReactive(messageSource, code) .map(msg -> ResponseMessage.error(400, code, msg)); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties index e988c8dee..9b9331846 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties +++ b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties @@ -1,5 +1,5 @@ error.unsupported_media_type=不支持的请求类型 -error.not_acceptable_media_type=不支持的响应类型 +error.not_acceptable_media_type=不支持的媒体类型 error.method_not_allowed=不支持的请求方法 error.duplicate_data=重复的数据 error.data_error=数据错误 \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index e1d4ce2e1..23f98caa0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -8,7 +8,6 @@ import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; import com.alibaba.fastjson.serializer.JSONSerializable; import com.alibaba.fastjson.serializer.JSONSerializer; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; @@ -21,6 +20,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.exception.ValidationException; +import org.hswebframework.web.i18n.LocaleUtils; import org.springframework.beans.BeanUtils; import org.springframework.util.StringUtils; @@ -260,6 +260,14 @@ default boolean isWriteJSONObjectEnabled() { return DEFAULT_WRITE_JSON_OBJECT; } + default String getI18nCode() { + return getText(); + } + + default String getI18nMessage(Locale locale) { + return LocaleUtils.resolveMessage(getI18nCode(), locale, getText()); + } + /** * 当{@link this#isWriteJSONObjectEnabled()}返回true时,在序列化为json的时候,会写出此方法返回的对象 * @@ -271,7 +279,7 @@ default Object getWriteJSONObject() { if (isWriteJSONObjectEnabled()) { Map jsonObject = new HashMap<>(); jsonObject.put("value", getValue()); - jsonObject.put("text", getText()); + jsonObject.put("text", getI18nMessage(LocaleUtils.current())); // jsonObject.put("index", index()); // jsonObject.put("mask", getMask()); return jsonObject; @@ -281,7 +289,7 @@ default Object getWriteJSONObject() { } @Override - default void write(JSONSerializer jsonSerializer, Object o, Type type, int i) throws IOException { + default void write(JSONSerializer jsonSerializer, Object o, Type type, int i) { if (isWriteJSONObjectEnabled()) { jsonSerializer.write(getWriteJSONObject()); } else { diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 028d0bbd1..a36a68eb5 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -10,25 +10,86 @@ import java.util.function.BiFunction; import java.util.function.Function; +/** + * 用于进行国际化消息转换 + * + * @author zhouhao + * @since 4.0.11 + */ public class LocaleUtils { public static final LocaleContext DEFAULT_CONTEXT = new SimpleLocaleContext(Locale.getDefault()); - public static Mono reactive() { + private static final ThreadLocal CONTEXT_THREAD_LOCAL = new ThreadLocal<>(); + + static MessageSource messageSource; + + /** + * 获取当前的语言地区,如果没有设置则返回系统默认语言 + * + * @return Locale + */ + public static Locale current() { + LocaleContext context = CONTEXT_THREAD_LOCAL.get(); + if (context == null || context.getLocale() == null) { + context = DEFAULT_CONTEXT; + } + return context.getLocale(); + } + + /** + * 在指定的语言环境中执行函数,只能在非响应式同步操作时使用,如:转换实体类中某些属性的国际化消息。 + *

+ * 在函数的逻辑中可以通过{@link LocaleUtils#current()}来获取当前语言. + * + * @param data 参数 + * @param locale 语言地区 + * @param mapper 函数 + * @param 参数类型 + * @param 函数返回类型 + * @return 返回值 + */ + public static R doWith(T data, Locale locale, BiFunction mapper) { + try { + CONTEXT_THREAD_LOCAL.set(new SimpleLocaleContext(locale)); + return mapper.apply(data, locale); + } finally { + CONTEXT_THREAD_LOCAL.remove(); + } + } + + /** + * 响应式方式获取当前语言地区 + * @return 语言地区 + */ + public static Mono currentReactive() { return Mono .subscriberContext() .map(ctx -> ctx .getOrEmpty(LocaleContext.class) - .orElse(DEFAULT_CONTEXT)); + .map(LocaleContext::getLocale) + .orElseGet(Locale::getDefault) + ); } + public static Mono resolveThrowable(S source, + BiFunction mapper) { + return resolveThrowable(messageSource, source, mapper); + } + public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper) { return doWithReactive(messageSource, source, Throwable::getMessage, mapper, source.getArgs()); } + public static Mono resolveThrowable(S source, + BiFunction mapper, + Object... args) { + return resolveThrowable(messageSource, source, mapper, args); + } + public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper, @@ -36,32 +97,63 @@ public static Mono resolveThrowable(MessageSource me return doWithReactive(messageSource, source, Throwable::getMessage, mapper, args); } + public static Mono doWithReactive(S source, + Function message, + BiFunction mapper, + Object... args) { + return doWithReactive(messageSource, source, message, mapper, args); + } + public static Mono doWithReactive(MessageSource messageSource, S source, Function message, BiFunction mapper, Object... args) { - return reactive() - .map(ctx -> { + return currentReactive() + .map(locale -> { String msg = message.apply(source); - String newMsg = resolveMessage(messageSource, msg, ctx.getLocale(), msg, args); + String newMsg = resolveMessage(messageSource, locale, msg, msg, args); return mapper.apply(source, newMsg); }); } - public static Mono resolveMessage(MessageSource messageSource, - String code, - Object... args) { - return reactive() - .map(ctx -> resolveMessage(messageSource, code, ctx.getLocale(), code, args)); + public static Mono resolveMessageReactive(MessageSource messageSource, + String code, + Object... args) { + return currentReactive() + .map(locale -> resolveMessage(messageSource, locale, code, code, args)); + } + + public static String resolveMessage(String code, + Locale locale, + String defaultMessage, + Object... args) { + return resolveMessage(messageSource, locale, code, defaultMessage, args); } public static String resolveMessage(MessageSource messageSource, - String code, Locale locale, + String code, String defaultMessage, Object... args) { return messageSource.getMessage(code, args, defaultMessage, locale); } + public static String resolveMessage(String code, Object... args) { + return resolveMessage(messageSource, current(), code, code, args); + } + + public static String resolveMessage(String code, + String defaultMessage, + Object... args) { + return resolveMessage(messageSource, current(), code, defaultMessage, args); + } + + public static String resolveMessage(MessageSource messageSource, + String code, + String defaultMessage, + Object... args) { + return resolveMessage(messageSource, current(), code, defaultMessage, args); + } + } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java new file mode 100644 index 000000000..a30fcaca4 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java @@ -0,0 +1,12 @@ +package org.hswebframework.web.i18n; + +import org.springframework.context.MessageSource; + +public class MessageSourceInitializer { + + public static void init(MessageSource messageSource) { + if (LocaleUtils.messageSource == null) { + LocaleUtils.messageSource = messageSource; + } + } +} diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java index fcb22af11..aa96385ac 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/CompositeMessageSource.java @@ -10,6 +10,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; public class CompositeMessageSource implements MessageSource { @@ -27,12 +28,12 @@ public void addMessageSource(MessageSource source) { @Override public String getMessage(@Nonnull String code, Object[] args, String defaultMessage, @Nonnull Locale locale) { for (MessageSource messageSource : messageSources) { - String result = messageSource.getMessage(code, args, defaultMessage, locale); + String result = messageSource.getMessage(code, args, null, locale); if (StringUtils.hasText(result)) { return result; } } - return null; + return defaultMessage; } @Override diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java index 796500c47..b098245d6 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java @@ -1,6 +1,7 @@ package org.hswebframework.web.starter.i18n; import org.hswebframework.web.exception.BusinessException; +import org.hswebframework.web.i18n.MessageSourceInitializer; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.context.MessageSource; @@ -31,6 +32,7 @@ public MessageSource coreMessageSource(){ public MessageSource compositeMessageSource(ObjectProvider objectProvider) { CompositeMessageSource messageSource = new CompositeMessageSource(); messageSource.addMessageSources(objectProvider.stream().collect(Collectors.toList())); + MessageSourceInitializer.init(messageSource); return messageSource; } diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java index 8e1f57bd1..b6605d30f 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -51,6 +51,7 @@ public JsonDeserializer findEnumDeserializer(Class type, return (configurer) -> { CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(entityFactory, objectMapper)); + defaults.jackson2JsonEncoder(new CustomJackson2jsonEncoder(objectMapper)); }; } diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java new file mode 100644 index 000000000..a999fb9f6 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java @@ -0,0 +1,340 @@ +package org.hswebframework.web.starter.jackson; + +import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.http.codec.json.Jackson2CodecSupport; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.nio.charset.Charset; +import java.util.*; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.util.ByteArrayBuilder; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; +import org.springframework.core.codec.CodecException; +import org.springframework.core.codec.EncodingException; +import org.springframework.core.codec.Hints; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.log.LogFormatUtils; +import org.springframework.http.MediaType; +import org.springframework.http.codec.HttpMessageEncoder; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.MimeType; + +/** + * Base class providing support methods for Jackson 2.9 encoding. For non-streaming use + * cases, {@link Flux} elements are collected into a {@link List} before serialization for + * performance reason. + * + * @author Sebastien Deleuze + * @author Arjen Poutsma + * @since 5.0 + */ +public class CustomJackson2jsonEncoder extends Jackson2CodecSupport implements HttpMessageEncoder { + + private static final byte[] NEWLINE_SEPARATOR = {'\n'}; + + private static final Map STREAM_SEPARATORS; + + private static final Map ENCODINGS; + + static { + STREAM_SEPARATORS = new HashMap<>(4); + STREAM_SEPARATORS.put(MediaType.APPLICATION_STREAM_JSON, NEWLINE_SEPARATOR); + STREAM_SEPARATORS.put(MediaType.parseMediaType("application/stream+x-jackson-smile"), new byte[0]); + + ENCODINGS = new HashMap<>(JsonEncoding.values().length + 1); + for (JsonEncoding encoding : JsonEncoding.values()) { + ENCODINGS.put(encoding.getJavaName(), encoding); + } + ENCODINGS.put("US-ASCII", JsonEncoding.UTF8); + } + + + private final List streamingMediaTypes = new ArrayList<>(1); + + + /** + * Constructor with a Jackson {@link ObjectMapper} to use. + */ + protected CustomJackson2jsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) { + super(mapper, mimeTypes); + } + + + /** + * Configure "streaming" media types for which flushing should be performed + * automatically vs at the end of the stream. + *

By default this is set to {@link MediaType#APPLICATION_STREAM_JSON}. + * + * @param mediaTypes one or more media types to add to the list + * @see HttpMessageEncoder#getStreamingMediaTypes() + */ + public void setStreamingMediaTypes(List mediaTypes) { + this.streamingMediaTypes.clear(); + this.streamingMediaTypes.addAll(mediaTypes); + } + + + @Override + public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) { + Class clazz = elementType.toClass(); + if (!supportsMimeType(mimeType)) { + return false; + } + if (mimeType != null && mimeType.getCharset() != null) { + Charset charset = mimeType.getCharset(); + if (!ENCODINGS.containsKey(charset.name())) { + return false; + } + } + return (Object.class == clazz || + (!String.class.isAssignableFrom(elementType.resolve(clazz)) && getObjectMapper().canSerialize(clazz))); + } + + @Override + public Flux encode(Publisher inputStream, DataBufferFactory bufferFactory, + ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { + + Assert.notNull(inputStream, "'inputStream' must not be null"); + Assert.notNull(bufferFactory, "'bufferFactory' must not be null"); + Assert.notNull(elementType, "'elementType' must not be null"); + + return LocaleUtils + .currentReactive() + .flatMapMany(locale -> { + if (inputStream instanceof Mono) { + return Mono.from(inputStream) + .map(value -> LocaleUtils + .doWith(value, locale, + ((val, loc) -> + encodeValue(val, bufferFactory, elementType, mimeType, hints) + ) + )) + .flux(); + } else { + byte[] separator = streamSeparator(mimeType); + if (separator != null) { // streaming + try { + ObjectWriter writer = createObjectWriter(elementType, mimeType, hints); + ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer + .getFactory() + ._getBufferRecycler()); + JsonEncoding encoding = getJsonEncoding(mimeType); + JsonGenerator generator = getObjectMapper() + .getFactory() + .createGenerator(byteBuilder, encoding); + SequenceWriter sequenceWriter = writer.writeValues(generator); + + return Flux + .from(inputStream) + .map(value -> LocaleUtils + .doWith(value, + locale, + ((val, loc) -> this + .encodeStreamingValue(val, + bufferFactory, + hints, + sequenceWriter, + byteBuilder, + separator) + ) + )) + .doAfterTerminate(() -> { + try { + byteBuilder.release(); + generator.close(); + } catch (IOException ex) { + logger.error("Could not close Encoder resources", ex); + } + }); + } catch (IOException ex) { + return Flux.error(ex); + } + } else { // non-streaming + ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); + return Flux.from(inputStream) + .collectList() + .map(value -> LocaleUtils + .doWith(value, locale, + ((val, loc) -> + encodeValue(val, bufferFactory, listType, mimeType, hints) + ) + )) + .flux(); + } + + } + }); + } + + @Override + public DataBuffer encodeValue(Object value, DataBufferFactory bufferFactory, + ResolvableType valueType, @Nullable MimeType mimeType, @Nullable Map hints) { + + ObjectWriter writer = createObjectWriter(valueType, mimeType, hints); + ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer.getFactory()._getBufferRecycler()); + try { + JsonEncoding encoding = getJsonEncoding(mimeType); + + logValue(hints, value); + + try (JsonGenerator generator = getObjectMapper().getFactory().createGenerator(byteBuilder, encoding)) { + writer.writeValue(generator, value); + generator.flush(); + } catch (InvalidDefinitionException ex) { + throw new CodecException("Type definition error: " + ex.getType(), ex); + } catch (JsonProcessingException ex) { + throw new EncodingException("JSON encoding error: " + ex.getOriginalMessage(), ex); + } catch (IOException ex) { + throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", ex); + } + + byte[] bytes = byteBuilder.toByteArray(); + DataBuffer buffer = bufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + + return buffer; + } finally { + byteBuilder.release(); + } + } + + private DataBuffer encodeStreamingValue(Object value, DataBufferFactory bufferFactory, @Nullable Map hints, + SequenceWriter sequenceWriter, ByteArrayBuilder byteArrayBuilder, byte[] separator) { + + logValue(hints, value); + + try { + sequenceWriter.write(value); + sequenceWriter.flush(); + } catch (InvalidDefinitionException ex) { + throw new CodecException("Type definition error: " + ex.getType(), ex); + } catch (JsonProcessingException ex) { + throw new EncodingException("JSON encoding error: " + ex.getOriginalMessage(), ex); + } catch (IOException ex) { + throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", ex); + } + + byte[] bytes = byteArrayBuilder.toByteArray(); + byteArrayBuilder.reset(); + + int offset; + int length; + if (bytes.length > 0 && bytes[0] == ' ') { + // SequenceWriter writes an unnecessary space in between values + offset = 1; + length = bytes.length - 1; + } else { + offset = 0; + length = bytes.length; + } + DataBuffer buffer = bufferFactory.allocateBuffer(length + separator.length); + buffer.write(bytes, offset, length); + buffer.write(separator); + + return buffer; + } + + private void logValue(@Nullable Map hints, Object value) { + if (!Hints.isLoggingSuppressed(hints)) { + LogFormatUtils.traceDebug(logger, traceOn -> { + String formatted = LogFormatUtils.formatValue(value, !traceOn); + return Hints.getLogPrefix(hints) + "Encoding [" + formatted + "]"; + }); + } + } + + private ObjectWriter createObjectWriter(ResolvableType valueType, @Nullable MimeType mimeType, + @Nullable Map hints) { + + JavaType javaType = getJavaType(valueType.getType(), null); + Class jsonView = (hints != null ? (Class) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null); + ObjectWriter writer = (jsonView != null ? + getObjectMapper().writerWithView(jsonView) : getObjectMapper().writer()); + + if (javaType.isContainerType()) { + writer = writer.forType(javaType); + } + + return customizeWriter(writer, mimeType, valueType, hints); + } + + protected ObjectWriter customizeWriter(ObjectWriter writer, @Nullable MimeType mimeType, + ResolvableType elementType, @Nullable Map hints) { + + return writer; + } + + @Nullable + private byte[] streamSeparator(@Nullable MimeType mimeType) { + for (MediaType streamingMediaType : this.streamingMediaTypes) { + if (streamingMediaType.isCompatibleWith(mimeType)) { + return STREAM_SEPARATORS.getOrDefault(streamingMediaType, NEWLINE_SEPARATOR); + } + } + return null; + } + + /** + * Determine the JSON encoding to use for the given mime type. + * + * @param mimeType the mime type as requested by the caller + * @return the JSON encoding to use (never {@code null}) + * @since 5.0.5 + */ + protected JsonEncoding getJsonEncoding(@Nullable MimeType mimeType) { + if (mimeType != null && mimeType.getCharset() != null) { + Charset charset = mimeType.getCharset(); + JsonEncoding result = ENCODINGS.get(charset.name()); + if (result != null) { + return result; + } + } + return JsonEncoding.UTF8; + } + + + // HttpMessageEncoder + + @Override + public List getEncodableMimeTypes() { + return getMimeTypes(); + } + + @Override + public List getStreamingMediaTypes() { + return Collections.unmodifiableList(this.streamingMediaTypes); + } + + @Override + public Map getEncodeHints(@Nullable ResolvableType actualType, ResolvableType elementType, + @Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) { + + return (actualType != null ? getHints(actualType) : Hints.none()); + } + + + // Jackson2CodecSupport + + @Override + protected A getAnnotation(MethodParameter parameter, Class annotType) { + return parameter.getMethodAnnotation(annotType); + } +} \ No newline at end of file diff --git a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java new file mode 100644 index 000000000..8fdbce763 --- /dev/null +++ b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java @@ -0,0 +1,88 @@ +package org.hswebframework.web.starter.jackson; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hswebframework.web.dict.EnumDict; +import org.hswebframework.web.i18n.MessageSourceInitializer; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.SimpleLocaleContext; +import org.springframework.context.support.ResourceBundleMessageSource; +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.MediaType; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Locale; +import java.util.function.Predicate; + +public class CustomJackson2jsonEncoderTest { + + + @Before + public void init(){ + ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); + messageSource.setDefaultEncoding("utf-8"); + messageSource.setBasenames("i18n.messages"); + MessageSourceInitializer.init(messageSource); + } + + @Test + public void testI18n() { + + doTest(new TestEntity(TestEnum.e1),Locale.forLanguageTag("en-US"),s->s.contains("Option1")); + doTest(new TestEntity(TestEnum.e1),Locale.forLanguageTag("zh-CN"),s->s.contains("选项1")); + + } + + public void doTest(TestEntity entity, Locale locale, Predicate verify){ + + CustomJackson2jsonEncoder encoder = new CustomJackson2jsonEncoder(new ObjectMapper()); + + encoder.encode(Mono.just(entity), + new DefaultDataBufferFactory(), + ResolvableType.forType(TestEntity.class), + MediaType.APPLICATION_JSON, + Collections.emptyMap()) + .as(DataBufferUtils::join) + .map(buf -> buf.toString(StandardCharsets.UTF_8)) + .doOnNext(System.out::println) + .subscriberContext(ctx->ctx.put(LocaleContext.class,new SimpleLocaleContext(locale))) + .as(StepVerifier::create) + .expectNextMatches(verify) + .verifyComplete(); + } + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class TestEntity { + + private TestEnum testEnum; + } + + + @Getter + @AllArgsConstructor + public enum TestEnum implements EnumDict { + e1("enum.e1"), + e2("enum.e2"); + + private final String text; + + @Override + public String getValue() { + return name(); + } + + } +} \ No newline at end of file diff --git a/hsweb-starter/src/test/resources/i18n/messages_en_US.properties b/hsweb-starter/src/test/resources/i18n/messages_en_US.properties new file mode 100644 index 000000000..04bf44168 --- /dev/null +++ b/hsweb-starter/src/test/resources/i18n/messages_en_US.properties @@ -0,0 +1,2 @@ +enum.e1=Option1 +enum.e2=Option2 \ No newline at end of file diff --git a/hsweb-starter/src/test/resources/i18n/messages_zh_CN.properties b/hsweb-starter/src/test/resources/i18n/messages_zh_CN.properties new file mode 100644 index 000000000..2a8d80a92 --- /dev/null +++ b/hsweb-starter/src/test/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,2 @@ +enum.e1=选项1 +enum.e2=选项2 \ No newline at end of file From 05e86743d12cd1ebc706eabb17f4f7b7775b9a3a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Jul 2021 15:25:35 +0800 Subject: [PATCH 068/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/dict/EnumDict.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index 23f98caa0..22439010d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -118,7 +118,7 @@ default boolean in(EnumDict... dict) { } /** - * 枚举选项的描述,对一个选项进行详细的描述有时候是必要的.默认值为{@link this#getText()} + * 枚举选项的描述,对一个选项进行详细的描述有时候是必要的.默认值为{@link EnumDict#getText()} * * @return 描述 */ @@ -158,7 +158,7 @@ static List findList(Class type, Predicate /** * 根据枚举的{@link EnumDict#getValue()}来查找. * - * @see this#find(Class, Predicate) + * @see EnumDict#find(Class, Predicate) */ static > Optional findByValue(Class type, Object value) { return find(type, e -> e.getValue() == value || e.getValue().equals(value) || String @@ -169,7 +169,7 @@ static > Optional findByValue(Class type, Obj /** * 根据枚举的{@link EnumDict#getText()} 来查找. * - * @see this#find(Class, Predicate) + * @see EnumDict#find(Class, Predicate) */ static Optional findByText(Class type, String text) { return find(type, e -> e.getText().equalsIgnoreCase(text)); @@ -178,7 +178,7 @@ static Optional findByText(Class type, String /** * 根据枚举的{@link EnumDict#getValue()},{@link EnumDict#getText()}来查找. * - * @see this#find(Class, Predicate) + * @see EnumDict#find(Class, Predicate) */ static Optional find(Class type, Object target) { return find(type, v -> v.eq(target)); @@ -254,7 +254,7 @@ static List getByMask(Class tClass, long mask) /** * @return 是否在序列化为json的时候, 将枚举以对象方式序列化 - * @see this#DEFAULT_WRITE_JSON_OBJECT + * @see EnumDict#DEFAULT_WRITE_JSON_OBJECT */ default boolean isWriteJSONObjectEnabled() { return DEFAULT_WRITE_JSON_OBJECT; @@ -269,10 +269,10 @@ default String getI18nMessage(Locale locale) { } /** - * 当{@link this#isWriteJSONObjectEnabled()}返回true时,在序列化为json的时候,会写出此方法返回的对象 + * 当{@link EnumDict#isWriteJSONObjectEnabled()}返回true时,在序列化为json的时候,会写出此方法返回的对象 * * @return 最终序列化的值 - * @see this#isWriteJSONObjectEnabled() + * @see EnumDict#isWriteJSONObjectEnabled() */ @JsonValue default Object getWriteJSONObject() { From 6e0a9915ff7fbd0a3d9c5f13ab308ba6b3541346 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Jul 2021 15:25:51 +0800 Subject: [PATCH 069/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hsweb-system-authorization-api/pom.xml | 4 ++++ .../authorization/api/entity/UserEntity.java | 5 +++++ .../service/DefaultReactiveUserService.java | 22 +++++++++---------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 0a671e77e..bf2868bf2 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -30,6 +30,10 @@ org.hibernate.javax.persistence hibernate-jpa-2.1-api + + commons-codec + commons-codec + \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 09dd75907..0b05f6c9d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import org.apache.commons.codec.digest.DigestUtils; import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.web.api.crud.entity.GenericEntity; import org.hswebframework.web.api.crud.entity.RecordCreationEntity; @@ -78,4 +79,8 @@ public class UserEntity extends GenericEntity implements RecordCreationE public String getId() { return super.getId(); } + + public void generateId(){ + setId(DigestUtils.md5Hex(username)); + } } 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 index d412178be..8b4f34be3 100644 --- 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 @@ -71,21 +71,19 @@ protected Mono doAdd(UserEntity userEntity) { return Mono .defer(() -> { - userEntity.setSalt(IDGenerator.RANDOM.generate()); usernameValidator.validate(userEntity.getUsername()); passwordValidator.validate(userEntity.getPassword()); + userEntity.generateId(); + 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) - .flatMap(user -> new UserCreatedEvent(user) - .publish(eventPublisher) - .thenReturn(user)); + return Mono + .just(userEntity) + .doOnNext(e -> e.tryValidate(CreateGroup.class)) + .as(getRepository()::save) + .thenReturn(userEntity) + .flatMap(user -> new UserCreatedEvent(user) + .publish(eventPublisher) + .thenReturn(user)); }); } From 438543f12b4d2d6f524478cd20ca41baabbf672e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Jul 2021 15:47:31 +0800 Subject: [PATCH 070/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/DefaultReactiveUserService.java | 23 +++++-- .../DefaultReactiveUserServiceTest.java | 68 ++++++++++++++----- 2 files changed, 66 insertions(+), 25 deletions(-) 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 index 8b4f34be3..5fadaae38 100644 --- 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 @@ -3,6 +3,7 @@ import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.collections4.CollectionUtils; import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.ezorm.rdb.exception.DuplicateKeyException; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.web.api.crud.entity.TransactionManagers; import org.hswebframework.web.crud.service.GenericReactiveCrudService; @@ -63,7 +64,7 @@ public Mono saveUser(Mono request) { } return findById(userEntity.getId()) .flatMap(ignore -> doUpdate(userEntity)) - .switchIfEmpty(doAdd(userEntity)); + .switchIfEmpty(Mono.error(NotFoundException::new)); }).thenReturn(true); } @@ -76,14 +77,22 @@ protected Mono doAdd(UserEntity userEntity) { userEntity.generateId(); userEntity.setSalt(IDGenerator.RANDOM.generate()); userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword(), userEntity.getSalt())); - return Mono - .just(userEntity) + return this + .createQuery() + .where(userEntity::getUsername) + .fetch() + .doOnNext(u -> { + throw new org.hswebframework.web.exception.ValidationException("用户已存在"); + }) + .then(Mono.just(userEntity)) .doOnNext(e -> e.tryValidate(CreateGroup.class)) - .as(getRepository()::save) + .as(getRepository()::insert) + .onErrorMap(DuplicateKeyException.class, e -> { + throw new org.hswebframework.web.exception.ValidationException("用户已存在"); + }) .thenReturn(userEntity) - .flatMap(user -> new UserCreatedEvent(user) - .publish(eventPublisher) - .thenReturn(user)); + .flatMap(user -> new UserCreatedEvent(user).publish(eventPublisher)) + .thenReturn(userEntity); }); } 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 index c8e6f56ce..533539ea8 100644 --- 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 @@ -1,5 +1,6 @@ package org.hswebframework.web.system.authorization.defaults.service.reactive; +import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.system.authorization.api.entity.UserEntity; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.junit.Assert; @@ -10,8 +11,11 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; +import java.util.function.Supplier; + @RunWith(SpringRunner.class) @SpringBootTest(classes = ReactiveTestApplication.class) public class DefaultReactiveUserServiceTest { @@ -19,6 +23,34 @@ public class DefaultReactiveUserServiceTest { @Autowired private ReactiveUserService userService; + + @Test + public void testParallel() { + Supplier userBuilder = () -> { + UserEntity userEntity = userService + .newUserInstance() + .blockOptional() + .orElseThrow(NullPointerException::new); + userEntity.setName("test"); + userEntity.setUsername("parallel"); + userEntity.setPassword("parallel"); + return userEntity; + }; + + Mono + .zip( + userService + .saveUser(Mono.just(userBuilder.get())) + .subscribeOn(Schedulers.newSingle("newSingle")), + userService + .saveUser(Mono.just(userBuilder.get())) + .subscribeOn(Schedulers.newSingle("newSingle")) + ) + .as(StepVerifier::create) + .expectError(ValidationException.class) + .verify(); + } + @Test public void testCrud() { UserEntity userEntity = userService.newUserInstance().blockOptional().orElseThrow(NullPointerException::new); @@ -27,38 +59,38 @@ public void testCrud() { userEntity.setPassword("admin"); userService.saveUser(Mono.just(userEntity)) - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .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(); + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); userService.changeState(Mono.just(userEntity.getId()), (byte) 1) - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); userService.changePassword(userEntity.getId(), "admin2", "admin") - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); userService.findByUsernameAndPassword("admin", "admin") - .as(StepVerifier::create) - .expectNextCount(1) - .verifyComplete(); + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); userService.deleteUser(userEntity.getId()) - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); } From f3808589dba971d539fa01cf96e89eb4714d9d50 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 1 Jul 2021 18:33:24 +0800 Subject: [PATCH 071/542] =?UTF-8?q?jsr303=E6=94=AF=E6=8C=81i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/events/ValidateEventListener.java | 49 +++++++++++------ .../crud/web/CommonErrorControllerAdvice.java | 16 +++--- hsweb-core/pom.xml | 6 ++- .../org/hswebframework/web/dict/EnumDict.java | 9 +--- .../web/exception/BusinessException.java | 6 ++- .../web/exception/I18nSupportException.java | 15 ++++-- .../web/exception/ValidationException.java | 47 ++++++++++------ .../web/i18n/ContextLocaleResolver.java | 13 +++++ .../hswebframework/web/i18n/LocaleUtils.java | 53 +++++++++++++------ .../web/i18n/WebFluxLocaleFilter.java | 15 +++--- .../web/validator/ValidatorUtils.java | 21 +++++--- .../i18n/core/messages_en_US.properties | 3 +- .../i18n/core/messages_zh_CN.properties | 3 +- .../web/validator/ValidatorUtilsTest.java | 42 +++++++++++++++ .../jackson/CustomJackson2JsonDecoder.java | 40 +++++++++----- .../service/DefaultReactiveUserService.java | 5 +- .../messages_en_US.properties | 2 + .../messages_zh_CN.properties | 2 + .../resources/i18n/messages_zh_CN.properties | 1 - 19 files changed, 251 insertions(+), 97 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/i18n/ContextLocaleResolver.java create mode 100644 hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties delete mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 88bb3fc2f..96b292136 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -5,11 +5,14 @@ import org.hswebframework.ezorm.rdb.events.EventType; import org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys; import org.hswebframework.ezorm.rdb.mapping.events.MappingEventTypes; +import org.hswebframework.ezorm.rdb.mapping.events.ReactiveResultHolder; import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.validator.CreateGroup; import org.hswebframework.web.validator.UpdateGroup; import java.util.List; +import java.util.Optional; public class ValidateEventListener implements EventListener { @@ -24,33 +27,49 @@ public String getName() { } @Override - @SuppressWarnings("all") + public void onEvent(EventType type, EventContext context) { + Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); + + if (resultHolder.isPresent()) { + resultHolder + .ifPresent(holder -> holder + .before(LocaleUtils + .currentReactive() + .doOnNext(locale -> LocaleUtils.doWith(locale, (l) -> tryValidate(type, context))) + .then() + )); + } else { + tryValidate(type, context); + } + } + + @SuppressWarnings("all") + public void tryValidate(EventType type, EventContext context) { if (type == MappingEventTypes.insert_before || type == MappingEventTypes.save_before) { boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false); if (single) { context.get(MappingContextKeys.instance) - .filter(Entity.class::isInstance) - .map(Entity.class::cast) - .ifPresent(entity -> entity.tryValidate(CreateGroup.class)); + .filter(Entity.class::isInstance) + .map(Entity.class::cast) + .ifPresent(entity -> entity.tryValidate(CreateGroup.class)); } else { context.get(MappingContextKeys.instance) - .filter(List.class::isInstance) - .map(List.class::cast) - .ifPresent(lst -> lst.stream() - .filter(Entity.class::isInstance) - .map(Entity.class::cast) - .forEach(e -> ((Entity) e).tryValidate(CreateGroup.class)) - ); + .filter(List.class::isInstance) + .map(List.class::cast) + .ifPresent(lst -> lst.stream() + .filter(Entity.class::isInstance) + .map(Entity.class::cast) + .forEach(e -> ((Entity) e).tryValidate(CreateGroup.class)) + ); } } else if (type == MappingEventTypes.update_before) { context.get(MappingContextKeys.instance) - .filter(Entity.class::isInstance) - .map(Entity.class::cast) - .ifPresent(entity -> entity.tryValidate(UpdateGroup.class)); + .filter(Entity.class::isInstance) + .map(Entity.class::cast) + .ifPresent(entity -> entity.tryValidate(UpdateGroup.class)); } - } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index fd320afe5..8e7c63347 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -62,7 +62,8 @@ public Mono> handleException(UnsupportedOperationException e) @ResponseStatus(HttpStatus.UNAUTHORIZED) public Mono> handleException(UnAuthorizedException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unauthorized", msg).result(e.getState()))); + .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unauthorized", msg) + .result(e.getState()))); } @ExceptionHandler @@ -84,14 +85,17 @@ public Mono> handleException(NotFoundException e) { @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ValidationException e) { - return Mono.just(ResponseMessage.>error(400, "illegal_argument", e.getMessage()) - .result(e.getDetails())); + return LocaleUtils + .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage + .>error(400, "illegal_argument",msg) + .result(e.getDetails())) + ; } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ConstraintViolationException e) { - return handleException(new ValidationException(e.getMessage(), e.getConstraintViolations())); + return handleException(new ValidationException(e.getConstraintViolations())); } @ExceptionHandler @@ -178,7 +182,7 @@ public Mono> handleException(IllegalArgumentException e) public Mono> handleException(AuthenticationException e) { return LocaleUtils .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(400, e.getCode(), msg)) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getLocalizedMessage(), e))) ; } @@ -190,7 +194,7 @@ public Mono> handleException(UnsupportedMediaTypeStatusE .map(msg -> ResponseMessage .error(415, "unsupported_media_type", msg) .result(e.getSupportedMediaTypes())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getLocalizedMessage(), e))); } @ExceptionHandler diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 25a891231..3e3287c15 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -35,7 +35,6 @@ org.springframework spring-web - @@ -97,5 +96,10 @@ 3.0.0 + + org.hibernate.validator + hibernate-validator + + \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index 22439010d..ac5494c0b 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -385,10 +385,7 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE return e.name(); }).collect(Collectors.toList()); - return new ValidationException("validation.parameter_does_not_exist_in_enums", - Arrays.asList( - new ValidationException.Detail(currentName, "选项中不存在此值", values) - ), currentName); + return new ValidationException(currentName,"validation.parameter_does_not_exist_in_enums", currentName); }; if (EnumDict.class.isAssignableFrom(findPropertyType) && findPropertyType.isEnum()) { if (node.isObject()) { @@ -406,9 +403,7 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE .find(findPropertyType, node.textValue()) .orElseThrow(exceptionSupplier); } - throw new ValidationException("validation.parameter_does_not_exist_in_enums", Arrays.asList( - new ValidationException.Detail(currentName, "选项中不存在此值", null) - ), currentName); + return exceptionSupplier.get(); } if (findPropertyType.isEnum()) { return Stream diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java index de3110580..16a09d7a7 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/BusinessException.java @@ -31,7 +31,6 @@ public class BusinessException extends I18nSupportException { @Getter private int status = 500; - @Getter private String code; @@ -43,6 +42,11 @@ public BusinessException(String message, int status, Object... args) { this(message, null, status, args); } + public BusinessException(String message, String code) { + this(message, code, 500); + } + + public BusinessException(String message, String code, int status, Object... args) { super(message, args); this.code = code; diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 12a180ebe..ce7e3a6d0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -1,27 +1,36 @@ package org.hswebframework.web.exception; +import lombok.AccessLevel; import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.i18n.LocaleUtils; @Getter +@Setter(AccessLevel.PROTECTED) public class I18nSupportException extends RuntimeException { + private String code; + private Object[] args; - private final Object[] args; + protected I18nSupportException() { + + } public I18nSupportException(String code, Object... args) { super(code); + this.code = code; this.args = args; } public I18nSupportException(String code, Throwable cause, Object... args) { super(code, cause); this.args = args; + this.code = code; } @Override public String getLocalizedMessage() { - // TODO: 2021/6/21 - return super.getLocalizedMessage(); + return LocaleUtils.resolveMessage(code, args); } } 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 index 492631ab0..c3dfaa005 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -4,19 +4,17 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import org.hswebframework.web.i18n.LocaleUtils; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; import javax.validation.ConstraintViolation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; @Getter @Setter @ResponseStatus(HttpStatus.BAD_REQUEST) -public class ValidationException extends BusinessException { +public class ValidationException extends I18nSupportException { private List details; @@ -24,25 +22,36 @@ public ValidationException(String message) { super(message); } - public ValidationException(String property, String message) { - this(message, Collections.singletonList(new Detail(property, message, null))); + public ValidationException(String property, String message, Object... args) { + this(message, Collections.singletonList(new Detail(property, message, null)), args); } - public ValidationException(String message, List details,Object... args) { - super(message,400,args); + public ValidationException(String message, List details, Object... args) { + super(message, 400, args); this.details = details; + for (Detail detail : this.details) { + detail.translateI18n(args); + } } - 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(), null)); - } + public ValidationException(Set> violations) { + ConstraintViolation first = violations.iterator().next(); + if (Objects.equals(first.getMessageTemplate(), first.getMessage())) { + //模版和消息相同,说明是自定义的message,而不是已经通过i18n获取的. + setCode(first.getMessage()); + } else { + setCode("validation.property_validate_failed"); + } + //{0} 属性 ,{1} 验证消息 + setArgs(new Object[]{first.getPropertyPath().toString(), first.getMessage()}); + + details = new ArrayList<>(violations.size()); + for (ConstraintViolation violation : violations) { + details.add(new Detail(violation.getPropertyPath().toString(), violation.getMessage(), null)); } } + @Getter @Setter @AllArgsConstructor @@ -55,5 +64,11 @@ public static class Detail { @Schema(description = "详情") Object detail; + + public void translateI18n(Object... args) { + if (message.contains(".")) { + message = LocaleUtils.resolveMessage(message, message, args); + } + } } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/ContextLocaleResolver.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/ContextLocaleResolver.java new file mode 100644 index 000000000..cfc7b986f --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/ContextLocaleResolver.java @@ -0,0 +1,13 @@ +package org.hswebframework.web.i18n; + +import org.hibernate.validator.spi.messageinterpolation.LocaleResolver; +import org.hibernate.validator.spi.messageinterpolation.LocaleResolverContext; + +import java.util.Locale; + +public class ContextLocaleResolver implements LocaleResolver { + @Override + public Locale resolve(LocaleResolverContext context) { + return LocaleUtils.current(); + } +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index a36a68eb5..c4c18817d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -2,12 +2,15 @@ import org.hswebframework.web.exception.I18nSupportException; import org.springframework.context.MessageSource; -import org.springframework.context.i18n.LocaleContext; -import org.springframework.context.i18n.SimpleLocaleContext; import reactor.core.publisher.Mono; +import reactor.core.publisher.Signal; +import reactor.core.publisher.SignalType; +import reactor.util.context.Context; import java.util.Locale; +import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -18,9 +21,9 @@ */ public class LocaleUtils { - public static final LocaleContext DEFAULT_CONTEXT = new SimpleLocaleContext(Locale.getDefault()); + public static final Locale DEFAULT_LOCALE = Locale.getDefault(); - private static final ThreadLocal CONTEXT_THREAD_LOCAL = new ThreadLocal<>(); + private static final ThreadLocal CONTEXT_THREAD_LOCAL = new ThreadLocal<>(); static MessageSource messageSource; @@ -30,11 +33,11 @@ public class LocaleUtils { * @return Locale */ public static Locale current() { - LocaleContext context = CONTEXT_THREAD_LOCAL.get(); - if (context == null || context.getLocale() == null) { - context = DEFAULT_CONTEXT; + Locale locale = CONTEXT_THREAD_LOCAL.get(); + if (locale == null) { + locale = DEFAULT_LOCALE; } - return context.getLocale(); + return locale; } /** @@ -51,27 +54,47 @@ public static Locale current() { */ public static R doWith(T data, Locale locale, BiFunction mapper) { try { - CONTEXT_THREAD_LOCAL.set(new SimpleLocaleContext(locale)); + CONTEXT_THREAD_LOCAL.set(locale); return mapper.apply(data, locale); } finally { CONTEXT_THREAD_LOCAL.remove(); } } + public static Function useLocale(Locale locale) { + return ctx -> ctx.put(Locale.class, locale); + } + + public static void doWith(Locale locale, Consumer consumer) { + try { + CONTEXT_THREAD_LOCAL.set(locale); + consumer.accept(locale); + } finally { + CONTEXT_THREAD_LOCAL.remove(); + } + } + /** * 响应式方式获取当前语言地区 + * * @return 语言地区 */ + @SuppressWarnings("all") public static Mono currentReactive() { return Mono .subscriberContext() - .map(ctx -> ctx - .getOrEmpty(LocaleContext.class) - .map(LocaleContext::getLocale) - .orElseGet(Locale::getDefault) - ); + .map(ctx -> ctx.getOrDefault(Locale.class, DEFAULT_LOCALE)); } + public static void onNext(Signal signal, BiConsumer consumer) { + if (signal.getType() != SignalType.ON_NEXT) { + return; + } + Locale locale = signal.getContext().getOrDefault(Locale.class, DEFAULT_LOCALE); + + doWith(locale, l -> consumer.accept(signal.get(), l)); + + } public static Mono resolveThrowable(S source, BiFunction mapper) { @@ -81,7 +104,7 @@ public static Mono resolveThrowable(S sou public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper) { - return doWithReactive(messageSource, source, Throwable::getMessage, mapper, source.getArgs()); + return doWithReactive(messageSource, source, I18nSupportException::getCode, mapper, source.getArgs()); } public static Mono resolveThrowable(S source, diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java index 4f788800f..748d7faee 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java @@ -1,7 +1,5 @@ package org.hswebframework.web.i18n; -import org.springframework.context.i18n.LocaleContext; -import org.springframework.context.i18n.SimpleLocaleContext; import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; @@ -10,7 +8,6 @@ import reactor.core.publisher.Mono; import java.util.Locale; -import java.util.Optional; public class WebFluxLocaleFilter implements WebFilter { @Override @@ -18,16 +15,20 @@ public class WebFluxLocaleFilter implements WebFilter { public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { return chain .filter(exchange) - .subscriberContext(ctx -> ctx.put(LocaleContext.class, getLocaleContext(exchange))); + .subscriberContext(LocaleUtils.useLocale(getLocaleContext(exchange))); } - public LocaleContext getLocaleContext(ServerWebExchange exchange) { + public Locale getLocaleContext(ServerWebExchange exchange) { String lang = exchange.getRequest() .getQueryParams() .getFirst(":lang"); if (StringUtils.hasText(lang)) { - return new SimpleLocaleContext(Locale.forLanguageTag(lang)); + return Locale.forLanguageTag(lang); } - return exchange.getLocaleContext(); + Locale locale = exchange.getLocaleContext().getLocale(); + if (locale == null) { + return Locale.getDefault(); + } + return locale; } } 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 index 13b9a16a0..e578f1b4d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -1,12 +1,10 @@ package org.hswebframework.web.validator; +import org.hibernate.validator.BaseHibernateValidatorConfiguration; import org.hswebframework.web.exception.ValidationException; +import org.hswebframework.web.i18n.ContextLocaleResolver; -import javax.el.ExpressionFactory; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; +import javax.validation.*; import java.util.Set; public final class ValidatorUtils { @@ -19,17 +17,26 @@ private ValidatorUtils() { public static Validator getValidator() { if (validator == null) { synchronized (ValidatorUtils.class) { - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + Configuration configuration = Validation + .byDefaultProvider() + .configure(); + configuration.addProperty(BaseHibernateValidatorConfiguration.LOCALE_RESOLVER_CLASSNAME, + ContextLocaleResolver.class.getName()); + configuration.messageInterpolator(configuration.getDefaultMessageInterpolator()); + + ValidatorFactory factory = configuration.buildValidatorFactory(); + return validator = factory.getValidator(); } } return validator; } + @SuppressWarnings("all") 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); + throw new ValidationException(violations); } return bean; diff --git a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties index 37d8fb0a5..b39f8b8dc 100644 --- a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties +++ b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties @@ -1,3 +1,4 @@ error.not_found=The data does not exist error.cant_create_instance=Unable to create instance:{0} -validation.parameter_does_not_exist_in_enums=Parameter {0} does not exist in option \ No newline at end of file +validation.parameter_does_not_exist_in_enums=Parameter {0} does not exist in option +validation.property_validate_failed=Parameter '{0}' {1} \ No newline at end of file diff --git a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties index a51a0485d..b222feca2 100644 --- a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties +++ b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties @@ -1,4 +1,5 @@ error.not_found=数据不存在 error.cant_create_instance=无法创建实例:{0} -validation.parameter_does_not_exist_in_enums=参数[{0}]在选择中不存在 \ No newline at end of file +validation.parameter_does_not_exist_in_enums=参数[{0}]在选择中不存在 +validation.property_validate_failed=参数'{0}'{1} \ No newline at end of file diff --git a/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java new file mode 100644 index 000000000..07ac1d5b9 --- /dev/null +++ b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java @@ -0,0 +1,42 @@ +package org.hswebframework.web.validator; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.exception.ValidationException; +import org.hswebframework.web.i18n.LocaleUtils; +import org.junit.Test; + +import javax.validation.constraints.NotBlank; + +import java.util.Locale; + +import static org.junit.Assert.*; + +public class ValidatorUtilsTest { + + + @Test + public void test(){ + test(Locale.CHINA,"不能为空"); + test(Locale.ENGLISH,"must not be blank"); + } + + public void test(Locale locale,String msg){ + try { + LocaleUtils.doWith(locale,en->{ + ValidatorUtils.tryValidate(new TestEntity()); + }); + throw new IllegalStateException(); + }catch (ValidationException e){ + assertEquals(msg,e.getDetails().get(0).getMessage()); + } + } + + @Getter + @Setter + public static class TestEntity{ + + @NotBlank + private String notBlank; + } +} \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index 0c7d3bc56..576817be3 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.util.TokenBuffer; import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.hswebframework.web.i18n.LocaleUtils; import org.reactivestreams.Publisher; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -67,17 +68,23 @@ public Flux decode(@NonNull Publisher input, @NonNull Resolv ObjectReader reader = getObjectReader(elementType, hints); - return tokens.handle((tokenBuffer, sink) -> { - try { - Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); - logValue(value, hints); - if (value != null) { - sink.next(value); - } - } catch (IOException ex) { - sink.error(processException(ex)); - } - }); + return LocaleUtils + .currentReactive() + .flatMapMany(locale -> tokens + .handle((tokenBuffer, sink) -> { + LocaleUtils.doWith(locale, l -> { + try { + Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); + logValue(value, hints); + if (value != null) { + sink.next(value); + } + } catch (IOException ex) { + sink.error(processException(ex)); + } + }); + + })); } @Override @@ -85,8 +92,15 @@ public Flux decode(@NonNull Publisher input, @NonNull Resolv public Mono decodeToMono(@NonNull Publisher input, @NonNull ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { - return DataBufferUtils.join(input) - .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); + return LocaleUtils + .currentReactive() + .flatMap(locale -> DataBufferUtils + .join(input) + .map(dataBuffer -> LocaleUtils + .doWith(dataBuffer, + locale, + (buf, l) -> decode(buf, elementType, mimeType, hints))) + ); } @Override 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 index 5fadaae38..43bfe03d8 100644 --- 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 @@ -82,13 +82,12 @@ protected Mono doAdd(UserEntity userEntity) { .where(userEntity::getUsername) .fetch() .doOnNext(u -> { - throw new org.hswebframework.web.exception.ValidationException("用户已存在"); + throw new org.hswebframework.web.exception.ValidationException("error.user_already_exists"); }) .then(Mono.just(userEntity)) - .doOnNext(e -> e.tryValidate(CreateGroup.class)) .as(getRepository()::insert) .onErrorMap(DuplicateKeyException.class, e -> { - throw new org.hswebframework.web.exception.ValidationException("用户已存在"); + throw new org.hswebframework.web.exception.ValidationException("error.user_already_exists"); }) .thenReturn(userEntity) .flatMap(user -> new UserCreatedEvent(user).publish(eventPublisher)) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties new file mode 100644 index 000000000..280214ac6 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties @@ -0,0 +1,2 @@ +error.duplicate_key=Duplicate Data +error.user_already_exists=User already exists \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties new file mode 100644 index 000000000..16da067f5 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties @@ -0,0 +1,2 @@ +error.duplicate_key=重复的请求 +error.user_already_exists=用户已存在 \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties deleted file mode 100644 index 0fade07c1..000000000 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/messages_zh_CN.properties +++ /dev/null @@ -1 +0,0 @@ -error.duplicate_key=重复的请求 \ No newline at end of file From 8a140bc8535a667b9638c9a30fcdefa538ddf843 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 10:58:18 +0800 Subject: [PATCH 072/542] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=89=AB=E6=8F=8Fcla?= =?UTF-8?q?sspath*:i18n/**=E4=B8=8B=E7=9A=84messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthorizationI18nConfiguration.java | 20 ------------ .../Commons18nConfiguration.java | 20 ------------ .../entity/factory/MapperEntityFactory.java | 4 +-- .../crud/web/CommonWebFluxConfiguration.java | 7 ----- .../web/exception/I18nSupportException.java | 4 +++ .../web/exception/ValidationException.java | 11 ++++++- .../hswebframework/web/i18n/LocaleUtils.java | 2 +- .../web/i18n/MessageSourceInitializer.java | 2 +- .../web/i18n/UnsupportedMessageSource.java | 31 +++++++++++++++++++ .../i18n/core/messages_en_US.properties | 2 +- .../i18n/core/messages_zh_CN.properties | 2 +- .../web/starter/i18n/I18nConfiguration.java | 28 +++++++++++++---- 12 files changed, 73 insertions(+), 60 deletions(-) delete mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java delete mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/i18n/UnsupportedMessageSource.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java deleted file mode 100644 index 13430e3fe..000000000 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/configuration/AuthorizationI18nConfiguration.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.hswebframework.web.authorization.configuration; - -import org.springframework.context.MessageSource; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.ResourceBundleMessageSource; - -@Configuration -public class AuthorizationI18nConfiguration { - - @Bean - public MessageSource authorizationMessageSource(){ - ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); - messageSource.setDefaultEncoding("UTF-8"); - messageSource.setBundleClassLoader(AuthorizationI18nConfiguration.class.getClassLoader()); - messageSource.setBasenames("i18n/authentication/messages"); - return messageSource; - } - -} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java deleted file mode 100644 index fe73ac510..000000000 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/Commons18nConfiguration.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.hswebframework.web.crud.configuration; - -import org.springframework.context.MessageSource; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.ResourceBundleMessageSource; - -@Configuration -public class Commons18nConfiguration { - - @Bean - public MessageSource commonsMessageSource(){ - ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); - messageSource.setDefaultEncoding("UTF-8"); - messageSource.setBundleClassLoader(Commons18nConfiguration.class.getClassLoader()); - messageSource.setBasenames("i18n/commons/messages"); - return messageSource; - } - -} 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 61ac7cd2b..1d2667584 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 @@ -124,7 +124,7 @@ protected Mapper initCache(Class beanClass) { if (realType == null) { if (!Modifier.isInterface(beanClass.getModifiers()) && !Modifier.isAbstract(beanClass.getModifiers())) { realType = beanClass; - }else { + } else { mapper = defaultMapperFactory.apply(beanClass); } } @@ -172,7 +172,7 @@ public T newInstance(Class beanClass, Class defaultClass) { return (T) new HashSet<>(); } - throw new NotFoundException("can not create instance:"+beanClass); + throw new NotFoundException("error.cant_create_instance", beanClass); } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index df47c43ce..1c814012f 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -8,17 +8,10 @@ import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.i18n.LocaleContext; -import org.springframework.context.support.ReloadableResourceBundleMessageSource; -import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; -import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import org.springframework.web.server.i18n.LocaleContextResolver; -import reactor.core.publisher.Mono; @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index ce7e3a6d0..5ebf1925b 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -28,6 +28,10 @@ public I18nSupportException(String code, Throwable cause, Object... args) { this.code = code; } + @Override + public String getMessage() { + return code; + } @Override public String getLocalizedMessage() { 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 index c3dfaa005..be5936ff0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -16,6 +16,8 @@ @ResponseStatus(HttpStatus.BAD_REQUEST) public class ValidationException extends I18nSupportException { + private static final boolean propertyI18nEnabled = Boolean.getBoolean("i18n.validation.property.enabled"); + private List details; public ValidationException(String message) { @@ -42,8 +44,15 @@ public ValidationException(Set> violations) { } else { setCode("validation.property_validate_failed"); } + String property = first.getPropertyPath().toString(); + //{0} 属性 ,{1} 验证消息 - setArgs(new Object[]{first.getPropertyPath().toString(), first.getMessage()}); + //property也支持国际化? + String resolveMessage = propertyI18nEnabled ? + LocaleUtils.resolveMessage(first.getRootBeanClass().getName() + "." + property, property) + : property; + + setArgs(new Object[]{resolveMessage, first.getMessage()}); details = new ArrayList<>(violations.size()); for (ConstraintViolation violation : violations) { diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index c4c18817d..2a64e1d12 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -25,7 +25,7 @@ public class LocaleUtils { private static final ThreadLocal CONTEXT_THREAD_LOCAL = new ThreadLocal<>(); - static MessageSource messageSource; + static MessageSource messageSource = UnsupportedMessageSource.instance(); /** * 获取当前的语言地区,如果没有设置则返回系统默认语言 diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java index a30fcaca4..59072c03d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/MessageSourceInitializer.java @@ -5,7 +5,7 @@ public class MessageSourceInitializer { public static void init(MessageSource messageSource) { - if (LocaleUtils.messageSource == null) { + if (LocaleUtils.messageSource == null || LocaleUtils.messageSource instanceof UnsupportedMessageSource) { LocaleUtils.messageSource = messageSource; } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/UnsupportedMessageSource.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/UnsupportedMessageSource.java new file mode 100644 index 000000000..8c040606d --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/UnsupportedMessageSource.java @@ -0,0 +1,31 @@ +package org.hswebframework.web.i18n; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; + +import java.util.Locale; + +public class UnsupportedMessageSource implements MessageSource { + + private static final UnsupportedMessageSource INSTANCE = new UnsupportedMessageSource(); + + public static MessageSource instance() { + return INSTANCE; + } + + @Override + public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) { + return defaultMessage; + } + + @Override + public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException { + return code; + } + + @Override + public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { + return resolvable.getDefaultMessage(); + } +} diff --git a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties index b39f8b8dc..27ba5f25b 100644 --- a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties +++ b/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties @@ -1,4 +1,4 @@ error.not_found=The data does not exist error.cant_create_instance=Unable to create instance:{0} validation.parameter_does_not_exist_in_enums=Parameter {0} does not exist in option -validation.property_validate_failed=Parameter '{0}' {1} \ No newline at end of file +validation.property_validate_failed={0} {1} \ No newline at end of file diff --git a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties index b222feca2..181700341 100644 --- a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties +++ b/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties @@ -2,4 +2,4 @@ error.not_found=数据不存在 error.cant_create_instance=无法创建实例:{0} validation.parameter_does_not_exist_in_enums=参数[{0}]在选择中不存在 -validation.property_validate_failed=参数'{0}'{1} \ No newline at end of file +validation.property_validate_failed={0}{1} \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java index b098245d6..c7b38a83e 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java @@ -1,6 +1,7 @@ package org.hswebframework.web.starter.i18n; -import org.hswebframework.web.exception.BusinessException; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.i18n.MessageSourceInitializer; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureOrder; @@ -10,20 +11,35 @@ import org.springframework.context.annotation.Primary; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.core.Ordered; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.util.StringUtils; import java.util.stream.Collectors; @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +@Slf4j public class I18nConfiguration { - @Bean - public MessageSource coreMessageSource(){ - ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource(); + @SneakyThrows + public MessageSource autoResolveI18nMessageSource() { + + ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setDefaultEncoding("UTF-8"); - messageSource.setBundleClassLoader(BusinessException.class.getClassLoader()); - messageSource.setBasenames("i18n/core/messages"); + Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:i18n/**"); + + for (Resource resource : resources) { + String path = resource.getURL().getPath(); + if (StringUtils.hasText(path) && (path.endsWith(".properties") || path.endsWith(".xml"))) { + String name = path.substring(path.lastIndexOf("i18n"),path.indexOf("_")); + + log.info("register i18n message resource {} -> {}", path,name); + + messageSource.addBasenames(name); + } + } return messageSource; } From b1eba306e409a020ddaf122cd33d0216c07db905 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 11:20:24 +0800 Subject: [PATCH 073/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8Di18n=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/META-INF/spring.factories | 3 +-- .../src/main/resources/META-INF/spring.factories | 3 +-- .../org/hswebframework/web/exception/I18nSupportException.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories b/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories index 374161647..cb2dcecb0 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/META-INF/spring.factories @@ -1,4 +1,3 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration,\ -org.hswebframework.web.authorization.configuration.AuthorizationI18nConfiguration \ No newline at end of file +org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration \ No newline at end of file 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 c17a4b2d6..3a51d2ae5 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 @@ -3,5 +3,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.hswebframework.web.crud.configuration.EasyormConfiguration,\ org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration,\ -org.hswebframework.web.crud.web.CommonWebFluxConfiguration,\ -org.hswebframework.web.crud.configuration.Commons18nConfiguration \ No newline at end of file +org.hswebframework.web.crud.web.CommonWebFluxConfiguration \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 5ebf1925b..ae2df4abe 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -30,7 +30,7 @@ public I18nSupportException(String code, Throwable cause, Object... args) { @Override public String getMessage() { - return code; + return super.getMessage() != null ? super.getMessage() : getLocalizedMessage(); } @Override From 462af2fe9084c231492abb62b2021f9cb02b580b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 11:20:44 +0800 Subject: [PATCH 074/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/BasicAuthorizationTokenParser.java | 4 ++-- .../basic/configuration/EnableAopAuthorize.java | 8 +++++++- .../basic/embed/EmbedReactiveAuthenticationManager.java | 5 ++--- .../basic/handler/UserAllowPermissionHandler.java | 2 +- .../src/main/resources/META-INF/spring.factories | 3 +++ 5 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-basic/src/main/resources/META-INF/spring.factories diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/BasicAuthorizationTokenParser.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/BasicAuthorizationTokenParser.java index c482d4cf8..0a896adfa 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/BasicAuthorizationTokenParser.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/BasicAuthorizationTokenParser.java @@ -15,9 +15,9 @@ public class BasicAuthorizationTokenParser implements UserTokenForTypeParser { - private AuthenticationManager authenticationManager; + private final AuthenticationManager authenticationManager; - private UserTokenManager userTokenManager; + private final UserTokenManager userTokenManager; @Override public String getTokenType() { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/EnableAopAuthorize.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/EnableAopAuthorize.java index 0942a18e9..e0063da8d 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/EnableAopAuthorize.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/EnableAopAuthorize.java @@ -5,13 +5,19 @@ import java.lang.annotation.*; /** + * 开启基于AOP的权限控制 + * * @author zhouhao + * @see org.hswebframework.web.authorization.Authentication + * @see org.hswebframework.web.authorization.annotation.Authorize + * @see org.hswebframework.web.authorization.annotation.Resource + * @see org.hswebframework.web.authorization.annotation.ResourceAction */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@ImportAutoConfiguration({AopAuthorizeAutoConfiguration.class, AuthorizingHandlerAutoConfiguration.class}) +@ImportAutoConfiguration({AopAuthorizeAutoConfiguration.class}) public @interface EnableAopAuthorize { } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java index a9505d527..6aabf28d9 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java @@ -12,14 +12,13 @@ /** * @author zhouhao - * @since 3.0.0-RC + * @since 4.0.0 */ - @Order(10) @AllArgsConstructor public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticationManagerProvider { - private EmbedAuthenticationProperties properties; + private final EmbedAuthenticationProperties properties; @Override public Mono authenticate(Mono request) { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/UserAllowPermissionHandler.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/UserAllowPermissionHandler.java index 9126e4765..100134581 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/UserAllowPermissionHandler.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/UserAllowPermissionHandler.java @@ -37,7 +37,7 @@ public class UserAllowPermissionHandler { @Setter private Map> allows = new HashMap<>(); - private PathMatcher pathMatcher = new AntPathMatcher("."); + private final PathMatcher pathMatcher = new AntPathMatcher("."); @EventListener public void handEvent(AuthorizingHandleBeforeEvent event) { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/resources/META-INF/spring.factories b/hsweb-authorization/hsweb-authorization-basic/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..47a5ff6e8 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.hswebframework.web.authorization.basic.configuration.AuthorizingHandlerAutoConfiguration \ No newline at end of file From 5d517fe27d6ff3fc48ca4c97acb950bc5448844b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 11:29:33 +0800 Subject: [PATCH 075/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0I18nEnumDict?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/dict/I18nEnumDict.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java new file mode 100644 index 000000000..b66b2c805 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java @@ -0,0 +1,16 @@ +package org.hswebframework.web.dict; + +/** + * 国际化支持的枚举数据字典,自动根据 : 类名.name()来获取text + * + * @param + */ +public interface I18nEnumDict extends EnumDict { + + String name(); + + @Override + default String getI18nCode() { + return this.getClass().getName() + "." + name(); + } +} From f9b66bc71756e82ca6fa1ff2c13fdf0b754574be Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 12:00:13 +0800 Subject: [PATCH 076/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/dict/I18nEnumDict.java | 47 ++++++++++++++++++- .../web/exception/I18nSupportException.java | 17 +++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java index b66b2c805..a3ea45928 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java @@ -1,12 +1,55 @@ package org.hswebframework.web.dict; /** - * 国际化支持的枚举数据字典,自动根据 : 类名.name()来获取text + * 国际化支持的枚举数据字典,自动根据 : 类名.name()来获取text.如果没有定义则获取{@link EnumDict#getText()}的值. + * 例: + * 定义枚举并实现{@link I18nEnumDict}接口 + *
+ * package com.domain.dict;
  *
- * @param 
+ * @AllArgsConstructor
+ * @Getter
+ * @Dict("device-state")
+ * public enum DeviceState implements I18nEnumDict {
+ *     notActive("未启用"),
+ *     offline("离线"),
+ *     online("在线");
+ *
+ *     private final String text;
+ *
+ *     @Override
+ *     public String getValue() {
+ *         return name();
+ *     }
+ * 
+ *

+ * 在resources下添加文件: i18n/{path}/{name}_zh_CN.properties + *

+ * 注意: {path}修改为自己的名称。{name}不能包含下划线(_)。不能存在完全重名的文件。 + *

+ * 正确的格式: i18n/my-module/messages_zh_CN.properties + *

+ * 错误的格式: i18n/my-module/messages_msg_zh_CN.properties + *

+ * 文件内容: + *

+ * com.domain.dict.DeviceState.notActive=未启用
+ * com.domain.dict.DeviceState.offline=离线
+ * com.domain.dict.DeviceState.online=在线
+ * 
+ * + * @param 值类型 + * @author zhouhao + * @since 4.0.11 */ public interface I18nEnumDict extends EnumDict { + /** + * 枚举name + * + * @return name + * @see Enum#name() + */ String name(); @Override diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index ae2df4abe..c4161e0e2 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -6,10 +6,27 @@ import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; +import java.util.Locale; + +/** + * 支持国际化消息的异常,code为 + * + * @author zhouhao + * @see LocaleUtils#resolveMessage(String, Object...) + * @since 4.0.11 + */ @Getter @Setter(AccessLevel.PROTECTED) public class I18nSupportException extends RuntimeException { + + /** + * 消息code,在message.properties文件中定义的key + */ private String code; + + /** + * 消息参数 + */ private Object[] args; protected I18nSupportException() { From deae87750688e87739b85af380bd1c31b71198e8 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 13:45:52 +0800 Subject: [PATCH 077/542] change maven download url --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 1c5dfe274..6c414f9e7 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=http://mirrors.hust.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip \ No newline at end of file +distributionUrl=https://downloads.apache.org/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip \ No newline at end of file From a3c5b779f41ebfad06c0367c18e93e7fcb160a79 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 13:52:54 +0800 Subject: [PATCH 078/542] fix test error --- .../web/starter/jackson/CustomJackson2jsonEncoderTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java index 8fdbce763..c9a6c79b4 100644 --- a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java +++ b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoderTest.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import org.hswebframework.web.dict.EnumDict; +import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.i18n.MessageSourceInitializer; import org.junit.Before; import org.junit.Test; @@ -55,7 +56,7 @@ public void doTest(TestEntity entity, Locale locale, Predicate verify){ .as(DataBufferUtils::join) .map(buf -> buf.toString(StandardCharsets.UTF_8)) .doOnNext(System.out::println) - .subscriberContext(ctx->ctx.put(LocaleContext.class,new SimpleLocaleContext(locale))) + .subscriberContext(LocaleUtils.useLocale(locale)) .as(StepVerifier::create) .expectNextMatches(verify) .verifyComplete(); From 7cf73e48aa59ce38dae5db17518bed7efa87d9d9 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 15:17:15 +0800 Subject: [PATCH 079/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/web/CommonErrorControllerAdvice.java | 10 + .../hswebframework/web/dict/I18nEnumDict.java | 3 +- .../hswebframework/web/i18n/LocaleUtils.java | 217 ++++++++++++++++-- 3 files changed, 211 insertions(+), 19 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 8e7c63347..c782d8bc8 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -7,6 +7,7 @@ import org.hswebframework.web.authorization.exception.UnAuthorizedException; import org.hswebframework.web.authorization.token.TokenState; import org.hswebframework.web.exception.BusinessException; +import org.hswebframework.web.exception.I18nSupportException; import org.hswebframework.web.exception.NotFoundException; import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.i18n.LocaleUtils; @@ -255,4 +256,13 @@ public Mono>> handleException(S (err, msg) -> ResponseMessage.error(400, "illegal_argument", msg)); } + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Mono> handleException(I18nSupportException e) { + return LocaleUtils + .resolveThrowable(messageSource, + e, + (err, msg) -> ResponseMessage.error(400, err.getCode(), msg)); + } + } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java index a3ea45928..aa3835247 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/I18nEnumDict.java @@ -10,7 +10,7 @@ * @AllArgsConstructor * @Getter * @Dict("device-state") - * public enum DeviceState implements I18nEnumDict { + * public enum DeviceState implements I18nEnumDict<String> { * notActive("未启用"), * offline("离线"), * online("在线"); @@ -21,6 +21,7 @@ * public String getValue() { * return name(); * } + * } * *

* 在resources下添加文件: i18n/{path}/{name}_zh_CN.properties diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 2a64e1d12..de271230f 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -41,12 +41,12 @@ public static Locale current() { } /** - * 在指定的语言环境中执行函数,只能在非响应式同步操作时使用,如:转换实体类中某些属性的国际化消息。 + * 在指定的区域中执行函数,只能在非响应式同步操作时使用,如:转换实体类中某些属性的国际化消息。 *

* 在函数的逻辑中可以通过{@link LocaleUtils#current()}来获取当前语言. * * @param data 参数 - * @param locale 语言地区 + * @param locale 区域 * @param mapper 函数 * @param 参数类型 * @param 函数返回类型 @@ -61,10 +61,12 @@ public static R doWith(T data, Locale locale, BiFunction ma } } - public static Function useLocale(Locale locale) { - return ctx -> ctx.put(Locale.class, locale); - } - + /** + * 使用指定的区域来执行某些操作 + * + * @param locale 区域 + * @param consumer 任务 + */ public static void doWith(Locale locale, Consumer consumer) { try { CONTEXT_THREAD_LOCAL.set(locale); @@ -75,9 +77,24 @@ public static void doWith(Locale locale, Consumer consumer) { } /** - * 响应式方式获取当前语言地区 + * 在响应式作用,使用指定的区域作为语言环境,在下游则可以使用{@link LocaleUtils#currentReactive()}来获取 + *

+ *

+     * monoOrFlux
+     * .subscriberContext(LocaleUtils.useLocale(locale))
+     * 
+ * + * @param locale 区域 + * @return 上下为构造函数 + */ + public static Function useLocale(Locale locale) { + return ctx -> ctx.put(Locale.class, locale); + } + + /** + * 响应式方式获取当前区域 * - * @return 语言地区 + * @return 区域 */ @SuppressWarnings("all") public static Mono currentReactive() { @@ -86,33 +103,96 @@ public static Mono currentReactive() { .map(ctx -> ctx.getOrDefault(Locale.class, DEFAULT_LOCALE)); } - public static void onNext(Signal signal, BiConsumer consumer) { - if (signal.getType() != SignalType.ON_NEXT) { - return; - } - Locale locale = signal.getContext().getOrDefault(Locale.class, DEFAULT_LOCALE); - - doWith(locale, l -> consumer.accept(signal.get(), l)); - - } - + /** + * 响应式方式解析出异常的区域消息,并进行结果转换. + *

+ * + *

+     * LocaleUtils
+     *  .resolveThrowable(error,(err,msg)-> createResponse(err,msg) );
+     * 
+ * + * @param source 异常 + * @param mapper 结果转换器 + * @param 异常类型 + * @param 转换结果类型 + * @return 转换后的结果 + * @see LocaleUtils#doWithReactive(Object, Function, BiFunction, Object...) + */ public static Mono resolveThrowable(S source, BiFunction mapper) { return resolveThrowable(messageSource, source, mapper); } + /** + * 指定消息源,响应式方式解析出异常的区域消息,并进行结果转换. + *

+ * + *

+     * LocaleUtils
+     *  .resolveThrowable(source,error,(err,msg)-> createResponse(err,msg) );
+     * 
+ * + * @param messageSource 消息源 + * @param source 异常 + * @param mapper 结果转换器 + * @param 异常类型 + * @param 转换结果类型 + * @return 转换后的结果 + * @see LocaleUtils#doWithReactive(Object, Function, BiFunction, Object...) + */ public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper) { return doWithReactive(messageSource, source, I18nSupportException::getCode, mapper, source.getArgs()); } + /** + * 使用参数,响应式方式解析出异常的区域消息,并进行结果转换. + *

+ * 参数对应消息模版中的{n} + *

+ * + *

+     * LocaleUtils
+     *  .resolveThrowable(source,error,(err,msg)-> createResponse(err,msg) );
+     * 
+ * + * @param source 异常 + * @param mapper 结果转换器 + * @param args 参数 + * @param 异常类型 + * @param 转换结果类型 + * @return 转换后的结果 + * @see LocaleUtils#doWithReactive(Object, Function, BiFunction, Object...) + * @see java.text.MessageFormat + */ public static Mono resolveThrowable(S source, BiFunction mapper, Object... args) { return resolveThrowable(messageSource, source, mapper, args); } + /** + * 使用参数,指定消息源,响应式方式解析出异常的区域消息,并进行结果转换. + *

+ * 参数对应消息模版中的{n} + *

+ * + *

+     * LocaleUtils
+     *  .resolveThrowable(source,error,(err,msg)-> createResponse(err,msg) );
+     * 
+ * + * @param source 异常 + * @param mapper 结果转换器 + * @param args 参数 + * @param 异常类型 + * @param 转换结果类型 + * @return 转换后的结果 + * @see LocaleUtils#doWithReactive(Object, Function, BiFunction, Object...) + * @see java.text.MessageFormat + */ public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper, @@ -120,6 +200,18 @@ public static Mono resolveThrowable(MessageSource me return doWithReactive(messageSource, source, Throwable::getMessage, mapper, args); } + /** + * 在响应式环境中处理区域消息并转换为新的结果 + * + * @param source 数据 + * @param message 消息转换 + * @param mapper 数据转换 + * @param args 参数 + * @param 数据类型 + * @param 结果类型 + * @return 转换结果 + * @see java.text.MessageFormat + */ public static Mono doWithReactive(S source, Function message, BiFunction mapper, @@ -127,6 +219,18 @@ public static Mono doWithReactive(S source, return doWithReactive(messageSource, source, message, mapper, args); } + /** + * 指定消息源,在响应式环境中处理区域消息并转换为新的结果 + * + * @param source 数据 + * @param message 消息转换 + * @param mapper 数据转换 + * @param args 参数 + * @param 数据类型 + * @param 结果类型 + * @return 转换结果 + * @see java.text.MessageFormat + */ public static Mono doWithReactive(MessageSource messageSource, S source, Function message, @@ -140,6 +244,14 @@ public static Mono doWithReactive(MessageSource messageSource, }); } + /** + * 使用指定的消息源,响应式方式解析消息 + * + * @param messageSource 消息源 + * @param code 消息编码 + * @param args 参数 + * @return 解析后的消息 + */ public static Mono resolveMessageReactive(MessageSource messageSource, String code, Object... args) { @@ -147,6 +259,15 @@ public static Mono resolveMessageReactive(MessageSource messageSource, .map(locale -> resolveMessage(messageSource, locale, code, code, args)); } + /** + * 解析消息 + * + * @param code 消息编码 + * @param locale 地区 + * @param defaultMessage 默认消息 + * @param args 参数 + * @return 解析后的消息 + */ public static String resolveMessage(String code, Locale locale, String defaultMessage, @@ -154,6 +275,16 @@ public static String resolveMessage(String code, return resolveMessage(messageSource, locale, code, defaultMessage, args); } + /** + * 使用指定的消息源解析消息 + * + * @param messageSource + * @param code 消息编码 + * @param locale 地区 + * @param defaultMessage 默认消息 + * @param args 参数 + * @return 解析后的消息 + */ public static String resolveMessage(MessageSource messageSource, Locale locale, String code, @@ -162,16 +293,38 @@ public static String resolveMessage(MessageSource messageSource, return messageSource.getMessage(code, args, defaultMessage, locale); } + /** + * 使用默认消息源和当前地区解析消息 + * + * @param code 消息编码 + * @param args 参数 + * @return 解析后的消息 + */ public static String resolveMessage(String code, Object... args) { return resolveMessage(messageSource, current(), code, code, args); } + /** + * 使用默认消息源和当前地区解析消息 + * + * @param code 消息编码 + * @param args 参数 + * @param defaultMessage 默认消息 + * @return 解析后的消息 + */ public static String resolveMessage(String code, String defaultMessage, Object... args) { return resolveMessage(messageSource, current(), code, defaultMessage, args); } + /** + * 使用指定消息源和当前地区解析消息 + * + * @param code 消息编码 + * @param args 参数 + * @return 解析后的消息 + */ public static String resolveMessage(MessageSource messageSource, String code, String defaultMessage, @@ -179,4 +332,32 @@ public static String resolveMessage(MessageSource messageSource, return resolveMessage(messageSource, current(), code, defaultMessage, args); } + + /** + * 在响应式中获取区域并执行指定的操作 + * + * @param operation 操作 + * @param 元素类型 + */ + public static Consumer> on(SignalType type, BiConsumer, Locale> operation) { + return signal -> { + if (signal.getType() != type) { + return; + } + Locale locale = signal.getContext().getOrDefault(Locale.class, DEFAULT_LOCALE); + + doWith(locale, l -> operation.accept(signal, l)); + }; + } + + /* SignalType.ON_NEXT */ + public static Consumer> onNext(BiConsumer operation) { + return on(SignalType.ON_NEXT, (s, l) -> operation.accept(s.get(), l)); + } + + /* SignalType.ON_ERROR */ + public static Consumer> onError(BiConsumer operation) { + return on(SignalType.ON_ERROR, (s, l) -> operation.accept(s.getThrowable(), l)); + } + } From e4187d3d9c44809e7d993bb125b3283b94f8261b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 2 Jul 2021 15:49:16 +0800 Subject: [PATCH 080/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/web/CommonErrorControllerAdvice.java | 47 ++++---- .../crud/web/CommonWebFluxConfiguration.java | 5 +- .../org/hswebframework/web/CodeConstants.java | 17 +++ .../hswebframework/web/i18n/LocaleUtils.java | 100 ++++++++++++++++-- .../web/i18n/LocaleUtilsTest.java | 25 +++++ 5 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/CodeConstants.java create mode 100644 hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index c782d8bc8..ae5b05ab6 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -2,6 +2,7 @@ import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.CodeConstants; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.exception.AuthenticationException; import org.hswebframework.web.authorization.exception.UnAuthorizedException; @@ -13,7 +14,6 @@ import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.logger.ReactiveLogger; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.context.MessageSource; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; @@ -37,18 +37,11 @@ @Order public class CommonErrorControllerAdvice { - private final MessageSource messageSource; - - public CommonErrorControllerAdvice(MessageSource messageSource) { - this.messageSource = messageSource; - } - @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(BusinessException e) { return LocaleUtils - .resolveThrowable(messageSource, - e, + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(err.getStatus(), err.getCode(), msg)); } @@ -56,14 +49,14 @@ public Mono> handleException(BusinessException e) { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(UnsupportedOperationException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unsupported", msg))); + .resolveThrowable(e, (err, msg) -> (ResponseMessage.error(401, CodeConstants.Error.unsupported, msg))); } @ExceptionHandler @ResponseStatus(HttpStatus.UNAUTHORIZED) public Mono> handleException(UnAuthorizedException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> (ResponseMessage.error(401, "unauthorized", msg) + .resolveThrowable(e, (err, msg) -> (ResponseMessage.error(401, CodeConstants.Error.unauthorized, msg) .result(e.getState()))); } @@ -71,7 +64,7 @@ public Mono> handleException(UnAuthorizedException e @ResponseStatus(HttpStatus.FORBIDDEN) public Mono> handleException(AccessDenyException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(403, e.getCode(), e.getMessage())) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(403, e.getCode(), e.getMessage())) ; } @@ -79,7 +72,7 @@ public Mono> handleException(AccessDenyException e) { @ResponseStatus(HttpStatus.NOT_FOUND) public Mono> handleException(NotFoundException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(404, "not_found", msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(404, CodeConstants.Error.not_found, msg)) ; } @@ -87,8 +80,8 @@ public Mono> handleException(NotFoundException e) { @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ValidationException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage - .>error(400, "illegal_argument",msg) + .resolveThrowable(e, (err, msg) -> ResponseMessage + .>error(400, CodeConstants.Error.illegal_argument, msg) .result(e.getDetails())) ; } @@ -139,14 +132,14 @@ public Mono>> handleException(M @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(javax.validation.ValidationException e) { - return Mono.just(ResponseMessage.error(400, "illegal_argument", e.getMessage())); + return Mono.just(ResponseMessage.error(400, CodeConstants.Error.illegal_argument, e.getMessage())); } @ExceptionHandler @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) public Mono> handleException(TimeoutException e) { - return Mono.just(ResponseMessage.error(504, "timeout", e.getMessage())) + return Mono.just(ResponseMessage.error(504, CodeConstants.Error.timeout, e.getMessage())) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @@ -173,7 +166,7 @@ public Mono> handleException(NullPointerException e) { public Mono> handleException(IllegalArgumentException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(400, "illegal_argument", msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, CodeConstants.Error.illegal_argument, msg)) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))) ; } @@ -182,7 +175,7 @@ public Mono> handleException(IllegalArgumentException e) @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(AuthenticationException e) { return LocaleUtils - .resolveThrowable(messageSource, e, (err, msg) -> ResponseMessage.error(400, e.getCode(), msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, e.getCode(), msg)) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getLocalizedMessage(), e))) ; } @@ -191,7 +184,7 @@ public Mono> handleException(AuthenticationException e) @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) public Mono> handleException(UnsupportedMediaTypeStatusException e) { return LocaleUtils - .resolveMessageReactive(messageSource, "error.unsupported_media_type") + .resolveMessageReactive("error.unsupported_media_type") .map(msg -> ResponseMessage .error(415, "unsupported_media_type", msg) .result(e.getSupportedMediaTypes())) @@ -203,7 +196,7 @@ public Mono> handleException(UnsupportedMediaTypeStatusE public Mono> handleException(NotAcceptableStatusException e) { return LocaleUtils - .resolveMessageReactive(messageSource, "error.not_acceptable_media_type") + .resolveMessageReactive("error.not_acceptable_media_type") .map(msg -> ResponseMessage .error(406, "not_acceptable_media_type", msg) .result(e.getSupportedMediaTypes())) @@ -214,7 +207,7 @@ public Mono> handleException(NotAcceptableStatusExceptio @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public Mono> handleException(MethodNotAllowedException e) { return LocaleUtils - .resolveMessageReactive(messageSource, "error.method_not_allowed") + .resolveMessageReactive("error.method_not_allowed") .map(msg -> ResponseMessage .error(406, "method_not_allowed", msg) .result(e.getSupportedMethods())) @@ -233,7 +226,7 @@ public Mono> handleException(R2dbcDataIntegrityViolation log.warn(e.getMessage(), e); } return LocaleUtils - .resolveMessageReactive(messageSource, code) + .resolveMessageReactive(code) .map(msg -> ResponseMessage.error(400, code, msg)); } @@ -251,17 +244,15 @@ public Mono>> handleException(S } while (exception != null && exception != e); return LocaleUtils - .resolveThrowable(messageSource, - exception, - (err, msg) -> ResponseMessage.error(400, "illegal_argument", msg)); + .resolveThrowable(exception, + (err, msg) -> ResponseMessage.error(400, CodeConstants.Error.illegal_argument, msg)); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(I18nSupportException e) { return LocaleUtils - .resolveThrowable(messageSource, - e, + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, err.getCode(), msg)); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index 1c814012f..5df067c73 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -5,7 +5,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.ReactiveAdapterRegistry; @@ -19,8 +18,8 @@ public class CommonWebFluxConfiguration { @Bean @ConditionalOnMissingBean - public CommonErrorControllerAdvice commonErrorControllerAdvice(MessageSource messageSource) { - return new CommonErrorControllerAdvice(messageSource); + public CommonErrorControllerAdvice commonErrorControllerAdvice() { + return new CommonErrorControllerAdvice(); } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/CodeConstants.java b/hsweb-core/src/main/java/org/hswebframework/web/CodeConstants.java new file mode 100644 index 000000000..388b5df05 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/CodeConstants.java @@ -0,0 +1,17 @@ +package org.hswebframework.web; + +public interface CodeConstants { + + interface Error { + String illegal_argument = "illegal_argument"; + + String timeout = "timeout"; + + String unsupported = "unsupported"; + + String unauthorized = "unauthorized"; + + String not_found="not_found"; + } + +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index de271230f..d2cec86f0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -1,7 +1,9 @@ package org.hswebframework.web.i18n; import org.hswebframework.web.exception.I18nSupportException; +import org.reactivestreams.Publisher; import org.springframework.context.MessageSource; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.Signal; import reactor.core.publisher.SignalType; @@ -15,11 +17,19 @@ /** * 用于进行国际化消息转换 + * 常用方法: + * + *
    + *
  • {@link LocaleUtils#current()}
  • + *
  • {@link LocaleUtils#currentReactive()}
  • + *
  • {@link LocaleUtils#resolveMessageReactive(String, Object...)}
  • + *
  • {@link LocaleUtils#doOnNext(BiConsumer)}
  • + *
* * @author zhouhao * @since 4.0.11 */ -public class LocaleUtils { +public final class LocaleUtils { public static final Locale DEFAULT_LOCALE = Locale.getDefault(); @@ -244,6 +254,19 @@ public static Mono doWithReactive(MessageSource messageSource, }); } + /** + * 使用默认的消息源,响应式方式解析消息 + * + * @param code 消息编码 + * @param args 参数 + * @return 解析后的消息 + */ + public static Mono resolveMessageReactive(String code, + Object... args) { + return currentReactive() + .map(locale -> resolveMessage(messageSource, locale, code, code, args)); + } + /** * 使用指定的消息源,响应式方式解析消息 * @@ -350,14 +373,77 @@ public static Consumer> on(SignalType type, BiConsumer, }; } - /* SignalType.ON_NEXT */ - public static Consumer> onNext(BiConsumer operation) { - return on(SignalType.ON_NEXT, (s, l) -> operation.accept(s.get(), l)); + /** + * 在响应式的各个周期获取地区并执行指定的操作 + * + *
+     *     monoOrFlux
+     *     .as(LocaleUtils.doOn(ON_NEXT,(signal,locale)-> ... ))
+     *     ...
+     * 
+ * + * @param type 周期类型 + * @param operation 操作 + * @param 响应式流中元素类型 + * @param 响应式流类型 + * @return 原始流 + */ + @SuppressWarnings("all") + public static > Function doOn(SignalType type, BiConsumer, Locale> operation) { + return publisher -> { + if (publisher instanceof Mono) { + return (T) Mono + .from(publisher) + .doOnEach(on(type, operation)); + } + return (T) Flux + .from(publisher) + .doOnEach(on(type, operation)); + }; + } + + /** + *
+     * monoOrFlux
+     * .as(LocaleUtils.doOnNext(element-> .... ))
+     * ...
+     * 
+ */ + public static > Function doOnNext(Consumer operation) { + return doOn(SignalType.ON_NEXT, (s, l) -> operation.accept(s.get())); + } + + /** + *
+     * monoOrFlux
+     * .as(LocaleUtils.doOnNext((element,locale)-> .... ))
+     * ...
+     * 
+ */ + public static > Function doOnNext(BiConsumer operation) { + return doOn(SignalType.ON_NEXT, (s, l) -> operation.accept(s.get(), l)); } - /* SignalType.ON_ERROR */ - public static Consumer> onError(BiConsumer operation) { - return on(SignalType.ON_ERROR, (s, l) -> operation.accept(s.getThrowable(), l)); + /** + *
+     * monoOrFlux
+     * .as(LocaleUtils.doOnError(error-> .... ))
+     * ...
+     * 
+ */ + public static > Function doOnError(Consumer operation) { + return doOn(SignalType.ON_ERROR, (s, l) -> operation.accept(s.getThrowable())); + } + + /** + *
+     * monoOrFlux
+     * .as(LocaleUtils.doOnError((error,locale)-> .... ))
+     * ...
+     * 
+ */ + public static > Function doOnError(BiConsumer operation) { + return doOn(SignalType.ON_ERROR, (s, l) -> operation.accept(s.getThrowable(), l)); } } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java new file mode 100644 index 000000000..e68469bf4 --- /dev/null +++ b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java @@ -0,0 +1,25 @@ +package org.hswebframework.web.i18n; + +import org.junit.Test; +import reactor.core.publisher.Flux; + +import java.util.Locale; + +import static org.junit.Assert.*; + +public class LocaleUtilsTest { + + + @Test + public void testOnNext() { + Flux.just(1) + .as(LocaleUtils.doOnNext((i, l) -> { + assertEquals(i.intValue(), 1); + assertEquals(l, Locale.CHINA); + })) + .subscriberContext(LocaleUtils.useLocale(Locale.CHINA)) + .blockLast(); + } + + +} \ No newline at end of file From 40cd2f45e8dca930f4bb5757f1169986d0304396 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 7 Jul 2021 11:43:30 +0800 Subject: [PATCH 081/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8DAccessDenyException?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=9C=AA=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index ae5b05ab6..911b6864b 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -64,7 +64,7 @@ public Mono> handleException(UnAuthorizedException e @ResponseStatus(HttpStatus.FORBIDDEN) public Mono> handleException(AccessDenyException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> ResponseMessage.error(403, e.getCode(), e.getMessage())) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(403, e.getCode(),msg)) ; } @@ -175,7 +175,7 @@ public Mono> handleException(IllegalArgumentException e) @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(AuthenticationException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, e.getCode(), msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, err.getCode(), msg)) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getLocalizedMessage(), e))) ; } From 162249c037a14f72584a52407d3e0581775e5660 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 7 Jul 2021 14:14:43 +0800 Subject: [PATCH 082/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/api/crud/entity/PagerResult.java | 3 +-- .../hswebframework/web/api/crud/entity/QueryParamEntity.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java index d6dfdd934..77d473772 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java @@ -20,14 +20,13 @@ import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import org.hswebframework.ezorm.core.param.QueryParam; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Getter @Setter diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index 66311d3fa..716a84f5a 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -98,7 +98,7 @@ public static QueryParamEntity of() { /** - * @see this#of(String, Object) + * @see QueryParamEntity#of(String, Object) */ public static QueryParamEntity of(String field, Object value) { return of().and(field, TermType.eq, value); From c0a863c4301f8236d49ff9151ee6ab22b5c45164 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 8 Jul 2021 15:13:57 +0800 Subject: [PATCH 083/542] =?UTF-8?q?=E4=BC=98=E5=8C=96i18n=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8A=A0=E8=BD=BD=E4=BC=98=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/starter/i18n/I18nConfiguration.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java index c7b38a83e..419efd887 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/i18n/I18nConfiguration.java @@ -15,6 +15,7 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.util.StringUtils; +import java.util.Arrays; import java.util.stream.Collectors; @Configuration(proxyBeanMethods = false) @@ -33,11 +34,14 @@ public MessageSource autoResolveI18nMessageSource() { for (Resource resource : resources) { String path = resource.getURL().getPath(); if (StringUtils.hasText(path) && (path.endsWith(".properties") || path.endsWith(".xml"))) { - String name = path.substring(path.lastIndexOf("i18n"),path.indexOf("_")); - - log.info("register i18n message resource {} -> {}", path,name); - - messageSource.addBasenames(name); + path = path.substring(path.lastIndexOf("i18n")); + String[] split = path.split("[/|\\\\]"); + String name = split[split.length - 1]; + name = name.contains("_") ? name.substring(0, name.indexOf("_")) : name; + split[split.length - 1] = name; + log.info("register i18n message resource {} -> {}", path, name); + + messageSource.addBasenames(String.join("/", split)); } } return messageSource; From 1d58a9e1edb605d87e764b07f24fd0e26a7d7896 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 8 Jul 2021 15:14:29 +0800 Subject: [PATCH 084/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 15 +++++++-------- .../hswebframework/web/context/ContextKey.java | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 911b6864b..834f9785f 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -64,7 +64,7 @@ public Mono> handleException(UnAuthorizedException e @ResponseStatus(HttpStatus.FORBIDDEN) public Mono> handleException(AccessDenyException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> ResponseMessage.error(403, e.getCode(),msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(403, e.getCode(), msg)) ; } @@ -138,19 +138,18 @@ public Mono> handleException(javax.validation.ValidationExcep @ExceptionHandler @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) public Mono> handleException(TimeoutException e) { - - return Mono.just(ResponseMessage.error(504, CodeConstants.Error.timeout, e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); - + return LocaleUtils + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(504, CodeConstants.Error.timeout,msg)) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @Order public Mono> handleException(RuntimeException e) { - return Mono.just(ResponseMessage.error(e.getMessage())) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); - + return LocaleUtils + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(msg)) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler diff --git a/hsweb-core/src/main/java/org/hswebframework/web/context/ContextKey.java b/hsweb-core/src/main/java/org/hswebframework/web/context/ContextKey.java index c9a6ae6b9..e2386df63 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/context/ContextKey.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/context/ContextKey.java @@ -7,7 +7,7 @@ public final class ContextKey { @Getter - private String key; + private final String key; public static ContextKey of(String key) { return new ContextKey<>(key); From 794c159557c1725daad4fe92034b9d8b53a78fc2 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 9 Jul 2021 19:19:14 +0800 Subject: [PATCH 085/542] =?UTF-8?q?=E4=BC=98=E5=8C=96UnsupportedOperationE?= =?UTF-8?q?xception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 834f9785f..ba020d5c8 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -47,9 +47,10 @@ public Mono> handleException(BusinessException e) { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public Mono> handleException(UnsupportedOperationException e) { + public Mono> handleException(UnsupportedOperationException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> (ResponseMessage.error(401, CodeConstants.Error.unsupported, msg))); + .resolveThrowable(e, (err, msg) -> (ResponseMessage.error(500, CodeConstants.Error.unsupported, msg))) + .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @ExceptionHandler From 69962f8afc2ce7f4684954e41fb05605779716c5 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 13 Jul 2021 15:20:30 +0800 Subject: [PATCH 086/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/exception/AccessDenyException.java | 2 +- .../token/redis/RedisUserTokenManager.java | 2 +- .../web/crud/web/CommonErrorControllerAdvice.java | 2 +- .../web/exception/I18nSupportException.java | 10 ++++------ .../web/exception/ValidationException.java | 4 ++-- .../java/org/hswebframework/web/i18n/LocaleUtils.java | 2 +- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java index e9f118475..bb774e45f 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/exception/AccessDenyException.java @@ -42,7 +42,7 @@ public AccessDenyException(String message, Throwable cause) { } public AccessDenyException(String message, String code, Throwable cause) { - super(message, cause); + super(message, cause,code); this.code = code; } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index a3def4cb4..d508ee1d1 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -244,7 +244,7 @@ public Mono signIn(String token, String type, String userId, long max return userIsLoggedIn(userId) .flatMap(r -> { if (r) { - return Mono.error(new AccessDenyException("error.logged_in_elsewhere", TokenState.deny.getValue(), null)); + return Mono.error(new AccessDenyException("error.logged_in_elsewhere", TokenState.deny.getValue())); } return doSign; }); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index ba020d5c8..33ae63740 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -253,7 +253,7 @@ public Mono>> handleException(S public Mono> handleException(I18nSupportException e) { return LocaleUtils .resolveThrowable(e, - (err, msg) -> ResponseMessage.error(400, err.getCode(), msg)); + (err, msg) -> ResponseMessage.error(400, err.getI18nCode(), msg)); } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index c4161e0e2..ea77021c3 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -6,8 +6,6 @@ import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; -import java.util.Locale; - /** * 支持国际化消息的异常,code为 * @@ -22,7 +20,7 @@ public class I18nSupportException extends RuntimeException { /** * 消息code,在message.properties文件中定义的key */ - private String code; + private String i18nCode; /** * 消息参数 @@ -35,14 +33,14 @@ protected I18nSupportException() { public I18nSupportException(String code, Object... args) { super(code); - this.code = code; + this.i18nCode = code; this.args = args; } public I18nSupportException(String code, Throwable cause, Object... args) { super(code, cause); this.args = args; - this.code = code; + this.i18nCode = code; } @Override @@ -52,6 +50,6 @@ public String getMessage() { @Override public String getLocalizedMessage() { - return LocaleUtils.resolveMessage(code, args); + return LocaleUtils.resolveMessage(i18nCode, args); } } 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 index be5936ff0..e37dc7742 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -40,9 +40,9 @@ public ValidationException(Set> violations) { ConstraintViolation first = violations.iterator().next(); if (Objects.equals(first.getMessageTemplate(), first.getMessage())) { //模版和消息相同,说明是自定义的message,而不是已经通过i18n获取的. - setCode(first.getMessage()); + setI18nCode(first.getMessage()); } else { - setCode("validation.property_validate_failed"); + setI18nCode("validation.property_validate_failed"); } String property = first.getPropertyPath().toString(); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index d2cec86f0..4ae721cfc 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -154,7 +154,7 @@ public static Mono resolveThrowable(S sou public static Mono resolveThrowable(MessageSource messageSource, S source, BiFunction mapper) { - return doWithReactive(messageSource, source, I18nSupportException::getCode, mapper, source.getArgs()); + return doWithReactive(messageSource, source, I18nSupportException::getI18nCode, mapper, source.getArgs()); } /** From 4f61323d2db55c6530cc36d4c0cfda1fc4934feb Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 13 Jul 2021 17:53:58 +0800 Subject: [PATCH 087/542] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{messages_en_US.properties => messages_en.properties} | 0 .../{messages_zh_CN.properties => messages_zh.properties} | 0 .../commons/{messages_en_US.properties => messages_en.properties} | 0 .../commons/{messages_zh_CN.properties => messages_zh.properties} | 0 .../core/{messages_en_US.properties => messages_en.properties} | 0 .../core/{messages_zh_CN.properties => messages_zh.properties} | 0 .../{messages_en_US.properties => messages_en.properties} | 0 .../{messages_zh_CN.properties => messages_zh.properties} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/{messages_en_US.properties => messages_en.properties} (100%) rename hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/{messages_zh_CN.properties => messages_zh.properties} (100%) rename hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/{messages_en_US.properties => messages_en.properties} (100%) rename hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/{messages_zh_CN.properties => messages_zh.properties} (100%) rename hsweb-core/src/main/resources/i18n/core/{messages_en_US.properties => messages_en.properties} (100%) rename hsweb-core/src/main/resources/i18n/core/{messages_zh_CN.properties => messages_zh.properties} (100%) rename hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/{messages_en_US.properties => messages_en.properties} (100%) rename hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/{messages_zh_CN.properties => messages_zh.properties} (100%) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en.properties similarity index 100% rename from hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en_US.properties rename to hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_en.properties diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh_CN.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties similarity index 100% rename from hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh_CN.properties rename to hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en.properties similarity index 100% rename from hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en_US.properties rename to hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_en.properties diff --git a/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties b/hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh.properties similarity index 100% rename from hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh_CN.properties rename to hsweb-commons/hsweb-commons-crud/src/main/resources/i18n/commons/messages_zh.properties diff --git a/hsweb-core/src/main/resources/i18n/core/messages_en_US.properties b/hsweb-core/src/main/resources/i18n/core/messages_en.properties similarity index 100% rename from hsweb-core/src/main/resources/i18n/core/messages_en_US.properties rename to hsweb-core/src/main/resources/i18n/core/messages_en.properties diff --git a/hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties b/hsweb-core/src/main/resources/i18n/core/messages_zh.properties similarity index 100% rename from hsweb-core/src/main/resources/i18n/core/messages_zh_CN.properties rename to hsweb-core/src/main/resources/i18n/core/messages_zh.properties diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en.properties similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en_US.properties rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_en.properties diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties similarity index 100% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh_CN.properties rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties From 8f009a08b86dacbe07999ef0d71c06e857695d82 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 15 Jul 2021 11:59:12 +0800 Subject: [PATCH 088/542] =?UTF-8?q?=E4=BC=98=E5=8C=96exception=E5=8F=AF?= =?UTF-8?q?=E8=83=BDnull?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 33ae63740..ac6500f97 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -140,7 +140,7 @@ public Mono> handleException(javax.validation.ValidationExcep @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) public Mono> handleException(TimeoutException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> ResponseMessage.error(504, CodeConstants.Error.timeout,msg)) + .resolveThrowable(e, (err, msg) -> ResponseMessage.error(504, CodeConstants.Error.timeout, msg)) .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } @@ -242,7 +242,11 @@ public Mono>> handleException(S } } while (exception != null && exception != e); - + if (exception == null) { + return Mono.just( + ResponseMessage.error(400, CodeConstants.Error.illegal_argument, e.getMessage()) + ); + } return LocaleUtils .resolveThrowable(exception, (err, msg) -> ResponseMessage.error(400, CodeConstants.Error.illegal_argument, msg)); From 10a05c516d576515fcf3e5c97f0325da09892799 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 22 Jul 2021 15:44:15 +0800 Subject: [PATCH 089/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=EF=BC=8C=E9=81=BF=E5=85=8D=E6=97=A0=E6=84=8F?= =?UTF-8?q?=E4=B9=89=E7=9A=84=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveAuthenticationHolder.java | 23 +++++++--- ...ompositeReactiveAuthenticationManager.java | 46 +++++++++++-------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java index fc4c45227..de756e4aa 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java @@ -18,6 +18,7 @@ package org.hswebframework.web.authorization; +import org.apache.commons.collections.CollectionUtils; import org.hswebframework.web.authorization.simple.SimpleAuthentication; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -48,12 +49,22 @@ public final class ReactiveAuthenticationHolder { private static Mono get(Function> function) { return Flux - .concat(suppliers - .stream() - .map(function) - .collect(Collectors.toList())) - .reduceWith(SimpleAuthentication::new, Authentication::merge) - .filter(a -> a.getUser() != null); + .merge(suppliers + .stream() + .map(function) + .collect(Collectors.toList())) + .collectList() + .filter(CollectionUtils::isNotEmpty) + .map(all -> { + if (all.size() == 1) { + return all.get(0); + } + SimpleAuthentication authentication = new SimpleAuthentication(); + for (Authentication auth : all) { + authentication.merge(auth); + } + return authentication; + }); } /** diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java index d48ea6429..7a1d5502e 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -1,6 +1,7 @@ package org.hswebframework.web.authorization.simple; import lombok.AllArgsConstructor; +import org.apache.commons.collections.CollectionUtils; import org.hswebframework.web.authorization.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -12,32 +13,41 @@ @AllArgsConstructor public class CompositeReactiveAuthenticationManager implements ReactiveAuthenticationManager { - private List providers; + private final List providers; @Override public Mono authenticate(Mono request) { - return Flux.concat(providers.stream() - .map(manager -> manager - .authenticate(request) - .onErrorResume((err) -> { - return Mono.empty(); - })).collect(Collectors.toList())) - .take(1) - .next(); + return Flux.concat(providers + .stream() + .map(manager -> manager + .authenticate(request) + .onErrorResume((err) -> Mono.empty())) + .collect(Collectors.toList())) + .take(1) + .next(); } @Override public Mono getByUserId(String userId) { return Flux - .fromStream(providers.stream() - .map(manager -> manager - .getByUserId(userId) - .onErrorResume((err) -> { - return Mono.empty(); - }) - )) + .fromStream(providers + .stream() + .map(manager -> manager + .getByUserId(userId) + .onErrorResume((err) -> Mono.empty()) + )) .flatMap(Function.identity()) - .reduceWith(SimpleAuthentication::of, Authentication::merge) - .filter(a -> a.getUser() != null); + .collectList() + .filter(CollectionUtils::isNotEmpty) + .map(all -> { + if (all.size() == 1) { + return all.get(0); + } + SimpleAuthentication authentication = new SimpleAuthentication(); + for (Authentication auth : all) { + authentication.merge(auth); + } + return authentication; + }); } } From 477f981e562a3e0e679e470724596664aa2c51f5 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 23 Jul 2021 20:37:27 +0800 Subject: [PATCH 090/542] =?UTF-8?q?=E4=BC=98=E5=8C=96POST=E6=A0=91?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveTreeServiceQueryController.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java index 63c4a195a..28db0e77e 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveTreeServiceQueryController.java @@ -1,5 +1,6 @@ package org.hswebframework.web.crud.web.reactive; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import org.hswebframework.web.api.crud.entity.QueryOperation; import org.hswebframework.web.api.crud.entity.QueryParamEntity; @@ -9,6 +10,7 @@ import org.hswebframework.web.crud.service.ReactiveTreeSortEntityService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -42,22 +44,22 @@ default Mono> findAllChildrenTree(@Parameter(hidden = true) QueryParamEn @PostMapping("/_query/tree") @QueryAction - @QueryOperation(summary = "使用POST动态查询并返回树形结构") - default Mono> findAllTree(@Parameter(hidden = true) Mono paramEntity) { + @Operation(summary = "使用POST动态查询并返回树形结构") + default Mono> findAllTree(@RequestBody Mono paramEntity) { return getService().queryResultToTree(paramEntity); } @PostMapping("/_query/_children") @QueryAction - @QueryOperation(summary = "使用POST动态查询并返回子节点数据") - default Flux findAllChildren(@Parameter(hidden = true) Mono paramEntity) { + @Operation(summary = "使用POST动态查询并返回子节点数据") + default Flux findAllChildren(@RequestBody Mono paramEntity) { return paramEntity.flatMapMany(param -> getService().queryIncludeChildren(param)); } @PostMapping("/_query/_children/tree") @QueryAction - @QueryOperation(summary = "使用POST动态查询并返回子节点树形结构数据") - default Mono> findAllChildrenTree(@Parameter(hidden = true) Mono paramEntity) { + @Operation(summary = "使用POST动态查询并返回子节点树形结构数据") + default Mono> findAllChildrenTree(@RequestBody Mono paramEntity) { return paramEntity.flatMap(param -> getService().queryIncludeChildrenTree(param)); } From 56e29bee1e17e048a28a1276939b5ab573a7fec9 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 28 Jul 2021 09:23:53 +0800 Subject: [PATCH 091/542] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E9=9D=9E=E5=93=8D=E5=BA=94=E5=BC=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/crud/entity/TransactionManagers.java | 10 +- hsweb-commons/hsweb-commons-crud/pom.xml | 19 ++ .../annotation/EnableEasyormRepository.java | 3 + .../EasyormRepositoryRegistrar.java | 43 ++-- .../web/crud/configuration/EntityInfo.java | 2 + .../web/crud/service/CrudService.java | 17 ++ .../GenericTreeSupportCrudService.java | 17 ++ .../web/crud/service/ReactiveCrudService.java | 65 +++-- .../crud/service/TreeSortEntityService.java | 171 +++++++++++++ .../crud/sql/DefaultJdbcReactiveExecutor.java | 70 +++++- .../web/crud/sql/DefaultR2dbcExecutor.java | 19 +- .../crud/web/CommonErrorControllerAdvice.java | 19 +- .../crud/web/CommonWebFluxConfiguration.java | 6 + .../crud/web/CommonWebMvcConfiguration.java | 30 +++ .../CommonWebMvcErrorControllerAdvice.java | 234 ++++++++++++++++++ .../web/crud/web/CrudController.java | 7 + .../web/crud/web/DeleteController.java | 27 ++ .../web/crud/web/QueryController.java | 172 ++++++++++++- .../crud/web/R2dbcErrorControllerAdvice.java | 30 +++ .../web/ResponseMessageWrapperAdvice.java | 101 ++++++++ .../web/crud/web/SaveController.java | 109 ++++++++ .../web/crud/web/ServiceCrudController.java | 7 + .../web/crud/web/ServiceDeleteController.java | 26 ++ .../web/crud/web/ServiceQueryController.java | 171 +++++++++++++ .../web/crud/web/ServiceSaveController.java | 109 ++++++++ .../web/reactive/ReactiveQueryController.java | 12 +- .../main/resources/META-INF/spring.factories | 3 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 + hsweb-starter/pom.xml | 2 + .../CustomCodecsAutoConfiguration.java | 7 +- ...omMappingJackson2HttpMessageConverter.java | 72 ++++++ .../service/DefaultReactiveUserService.java | 19 +- 32 files changed, 1506 insertions(+), 95 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericTreeSupportCrudService.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/TreeSortEntityService.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcErrorControllerAdvice.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CrudController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/DeleteController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/R2dbcErrorControllerAdvice.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/SaveController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceCrudController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceDeleteController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceSaveController.java create mode 100644 hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomMappingJackson2HttpMessageConverter.java 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 index ece0e3794..694347d77 100644 --- 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 @@ -2,8 +2,14 @@ public interface TransactionManagers { - String r2dbcTransactionManager = "connectionFactoryTransactionManager";// System.getProperty(""); - + /** + * 响应式的事务管理器 + */ + String reactiveTransactionManager = "connectionFactoryTransactionManager"; + + /** + * JDBC事务管理器 + */ String jdbcTransactionManager = "transactionManager"; } diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 86e6e0e8d..48738a4f4 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -73,10 +73,23 @@ ${project.version} + + org.springframework + spring-jdbc + true + + + + io.r2dbc + r2dbc-spi + true + + org.springframework.data spring-data-r2dbc compile + true @@ -124,6 +137,12 @@ io.swagger.core.v3 swagger-annotations + + + org.springframework + spring-webmvc + true + \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java index 9ec9d57f5..c7c9a60f8 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java @@ -30,5 +30,8 @@ */ Class[] annotation() default Table.class; + boolean reactive() default true; + + boolean nonReactive() default false; } 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 161c38389..0947c94c2 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 @@ -56,9 +56,9 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B if (attr == null) { return; } - boolean reactivePrecent = org.springframework.util.ClassUtils.isPresent("io.r2dbc.spi.ConnectionFactory", this - .getClass() - .getClassLoader()); + boolean reactiveEnabled = Boolean.TRUE.equals(attr.get("reactive")); + boolean nonReactiveEnabled = Boolean.TRUE.equals(attr.get("nonReactive")); + String[] arr = (String[]) attr.get("value"); Set resources = Arrays .stream(arr) @@ -91,7 +91,6 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B .orElse(entityType); }); - Class idType = null; if (implementFor == null || implementFor.idType() == Void.class) { try { @@ -109,20 +108,21 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B idType = implementFor.idType(); } - EntityInfo entityInfo = new EntityInfo(genericType, entityType, idType, reactivePrecent && (reactive == null || reactive - .enable())); + EntityInfo entityInfo = new EntityInfo(genericType, + entityType, + idType, + reactiveEnabled, + nonReactiveEnabled); if (!entityInfos.contains(entityInfo) || implementFor != null) { entityInfos.add(entityInfo); } } - boolean reactive = false; for (EntityInfo entityInfo : entityInfos) { Class entityType = entityInfo.getEntityType(); Class idType = entityInfo.getIdType(); Class realType = entityInfo.getRealType(); if (entityInfo.isReactive()) { - reactive = true; log.trace("register ReactiveRepository<{},{}>", entityType.getName(), idType.getSimpleName()); ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultReactiveRepository.class, entityType, idType); @@ -133,7 +133,8 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); definition.getPropertyValues().add("entityType", realType); registry.registerBeanDefinition(realType.getSimpleName().concat("ReactiveRepository"), definition); - } else { + } + if (entityInfo.isNonReactive()) { log.trace("register SyncRepository<{},{}>", entityType.getName(), idType.getSimpleName()); ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultSyncRepository.class, entityType, idType); RootBeanDefinition definition = new RootBeanDefinition(); @@ -146,15 +147,21 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B } - RootBeanDefinition definition = new RootBeanDefinition(); - definition.setTargetType(AutoDDLProcessor.class); - definition.setBeanClass(AutoDDLProcessor.class); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - definition.getPropertyValues().add("entities", entityInfos); - definition.getPropertyValues().add("reactive", reactive); - definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - definition.setSynthetic(true); - registry.registerBeanDefinition(AutoDDLProcessor.class.getName() + "_" + count.incrementAndGet(), definition); + Map> group = entityInfos + .stream() + .collect(Collectors.groupingBy(EntityInfo::isReactive, Collectors.toSet())); + + for (Map.Entry> entry : group.entrySet()) { + RootBeanDefinition definition = new RootBeanDefinition(); + definition.setTargetType(AutoDDLProcessor.class); + definition.setBeanClass(AutoDDLProcessor.class); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + definition.getPropertyValues().add("entities", entityInfos); + definition.getPropertyValues().add("reactive", entry.getKey()); + definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + definition.setSynthetic(true); + registry.registerBeanDefinition(AutoDDLProcessor.class.getName() + "_" + count.incrementAndGet(), definition); + } // try { // BeanDefinition definition = registry.getBeanDefinition(AutoDDLProcessor.class.getName()); 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 6b8913106..179dd4c3f 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 @@ -17,4 +17,6 @@ public class EntityInfo { private Class idType; private boolean reactive; + + private boolean nonReactive; } \ No newline at end of file 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 6ebdc489f..7ffd1b106 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 @@ -72,11 +72,28 @@ default int updateById(K id, E entityArr) { .updateById(id, entityArr); } + @Transactional(transactionManager = TransactionManagers.jdbcTransactionManager) + default SaveResult save(E entity) { + return getRepository() + .save(Collections.singletonList(entity)); + } + + @Transactional(transactionManager = TransactionManagers.jdbcTransactionManager) + default SaveResult save(List entities) { + return getRepository() + .save(entities); + } + @Transactional(transactionManager = TransactionManagers.jdbcTransactionManager) default int deleteById(Collection idArr) { return getRepository().deleteById(idArr); } + @Transactional(transactionManager = TransactionManagers.jdbcTransactionManager) + default int deleteById(K idArr) { + return deleteById(Collections.singletonList(idArr)); + } + @Transactional(readOnly = true, transactionManager = TransactionManagers.jdbcTransactionManager) default List query(QueryParamEntity queryParam) { return createQuery().setParam(queryParam).fetch(); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericTreeSupportCrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericTreeSupportCrudService.java new file mode 100644 index 000000000..084588869 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/GenericTreeSupportCrudService.java @@ -0,0 +1,17 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.ezorm.rdb.mapping.SyncRepository; +import org.hswebframework.web.api.crud.entity.TreeSortSupportEntity; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class GenericTreeSupportCrudService,K> implements TreeSortEntityService { + + @Autowired + private SyncRepository repository; + + @Override + public SyncRepository getRepository() { + return 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 60d7de25d..fc0f5bf6e 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 @@ -88,67 +88,98 @@ default ReactiveDelete createDelete() { } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono findById(K id) { return getRepository() .findById(id); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Flux findById(Collection publisher) { return getRepository() .findById(publisher); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono findById(Mono publisher) { return getRepository() .findById(publisher); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Flux findById(Flux publisher) { return getRepository() .findById(publisher); } - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) default Mono save(Publisher entityPublisher) { return getRepository() .save(entityPublisher); } - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) + default Mono save(E data) { + return getRepository() + .save(data); + } + + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) + default Mono save(Collection collection) { + return getRepository() + .save(collection); + } + + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) default Mono updateById(K id, Mono entityPublisher) { return getRepository() .updateById(id, entityPublisher); } - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) + default Mono updateById(K id, E data) { + return getRepository() + .updateById(id, Mono.just(data)); + } + + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) default Mono insertBatch(Publisher> entityPublisher) { return getRepository() .insertBatch(entityPublisher); } - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) default Mono insert(Publisher entityPublisher) { return getRepository() .insert(entityPublisher); } - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) + default Mono insert(E data) { + return getRepository() + .insert(Mono.just(data)); + } + + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) default Mono deleteById(Publisher idPublisher) { return getRepository() .deleteById(idPublisher); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) + default Mono deleteById(K id) { + return getRepository() + .deleteById(Mono.just(id)); + } + + + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Flux query(Mono queryParamMono) { return queryParamMono .flatMapMany(this::query); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Flux query(QueryParamEntity param) { return getRepository() .createQuery() @@ -156,12 +187,12 @@ default Flux query(QueryParamEntity param) { .fetch(); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono> queryPager(QueryParamEntity queryParamMono) { return queryPager(queryParamMono, Function.identity()); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono> queryPager(QueryParamEntity query, Function mapper) { if (query.getTotal() != null) { return getRepository() @@ -196,19 +227,19 @@ default Mono> queryPager(QueryParamEntity query, Function Mono> queryPager(Mono queryParamMono, Function mapper) { return queryParamMono .cast(QueryParamEntity.class) .flatMap(param -> queryPager(param, mapper)); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono> queryPager(Mono queryParamMono) { return queryPager(queryParamMono, Function.identity()); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono count(QueryParamEntity queryParam) { return getRepository() .createQuery() @@ -216,7 +247,7 @@ default Mono count(QueryParamEntity queryParam) { .count(); } - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono count(Mono queryParamMono) { return queryParamMono.flatMap(this::count); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/TreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/TreeSortEntityService.java new file mode 100644 index 000000000..4f0507228 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/TreeSortEntityService.java @@ -0,0 +1,171 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.utils.RandomUtil; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.api.crud.entity.TransactionManagers; +import org.hswebframework.web.api.crud.entity.TreeSortSupportEntity; +import org.hswebframework.web.api.crud.entity.TreeSupportEntity; +import org.hswebframework.web.id.IDGenerator; +import org.reactivestreams.Publisher; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @param TreeSortSupportEntity + * @param ID + * @see GenericReactiveTreeSupportCrudService + */ +public interface TreeSortEntityService, K> + extends CrudService { + + @Transactional(readOnly = true, transactionManager = TransactionManagers.jdbcTransactionManager) + default List queryResultToTree(QueryParamEntity paramEntity) { + return TreeSupportEntity + .list2tree(query(paramEntity), + this::setChildren, + this::createRootNodePredicate); + } + + @Transactional(readOnly = true, transactionManager = TransactionManagers.jdbcTransactionManager) + default List queryIncludeChildrenTree(QueryParamEntity paramEntity) { + + return TreeSupportEntity + .list2tree(queryIncludeChildren(paramEntity), + this::setChildren, + this::createRootNodePredicate); + } + + @Transactional(readOnly = true, transactionManager = TransactionManagers.jdbcTransactionManager) + default List queryIncludeChildren(Collection idList) { + return findById(idList) + .stream() + .flatMap(e -> createQuery() + .where() + .like$("path", e.getPath()) + .fetch() + .stream()) + .collect(Collectors.toList()); + } + + @Transactional(readOnly = true, transactionManager = TransactionManagers.jdbcTransactionManager) + default List queryIncludeChildren(QueryParamEntity queryParam) { + return query(queryParam) + .stream() + .flatMap(e -> createQuery() + .where() + .like$("path", e.getPath()) + .fetch() + .stream()) + .collect(Collectors.toList()); + } + + @Override + default void insert(E entityPublisher) { + insert(Collections.singletonList(entityPublisher)); + } + + @Override + default int insert(Collection entityPublisher) { + return this + .getRepository() + .insertBatch(entityPublisher + .stream() + .flatMap(this::applyTreeProperty) + .flatMap(e -> TreeSupportEntity + .expandTree2List(e, getIDGenerator()) + .stream()) + .collect(Collectors.toList()) + ); + } + + default Stream applyTreeProperty(E ele) { + if (StringUtils.hasText(ele.getPath()) || + StringUtils.isEmpty(ele.getParentId())) { + return Stream.of(ele); + } + + this.checkCyclicDependency(ele.getId(), ele); + this.findById(ele.getParentId()) + .ifPresent(parent -> ele.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4))); + return Stream.of(ele); + } + + //校验是否有循环依赖,修改父节点为自己的子节点? + default void checkCyclicDependency(K id, E ele) { + if (StringUtils.isEmpty(id)) { + return; + } + for (E e : this.queryIncludeChildren(Collections.singletonList(id))) { + if (Objects.equals(ele.getParentId(), e.getId())) { + throw new IllegalArgumentException("不能修改父节点为自己或者自己的子节点"); + } + } + + } + + @Override + default SaveResult save(List entities) { + return this.getRepository() + .save(entities + .stream() + .flatMap(this::applyTreeProperty) + //把树结构平铺 + .flatMap(e -> TreeSupportEntity + .expandTree2List(e, getIDGenerator()) + .stream()) + .collect(Collectors.toList()) + ); + } + + @Override + default int updateById(K id, E entity) { + entity.setId(id); + return this.save(entity).getTotal(); + } + + @Override + default int deleteById(Collection idPublisher) { + List dataList = findById(idPublisher); + return dataList + .stream() + .map(e -> createDelete() + .where() + .like$(e::getPath) + .execute()) + .mapToInt(Integer::intValue) + .sum(); + } + + IDGenerator getIDGenerator(); + + void setChildren(E entity, List children); + + default List getChildren(E entity) { + return entity.getChildren(); + } + + default Predicate createRootNodePredicate(TreeSupportEntity.TreeHelper helper) { + return node -> { + if (isRootNode(node)) { + return true; + } + //有父节点,但是父节点不存在 + if (!StringUtils.isEmpty(node.getParentId())) { + return helper.getNode(node.getParentId()) == null; + } + return false; + }; + } + + default boolean isRootNode(E entity) { + return StringUtils.isEmpty(entity.getParentId()) || "-1".equals(String.valueOf(entity.getParentId())); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultJdbcReactiveExecutor.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultJdbcReactiveExecutor.java index 823e5a480..7bff2e938 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultJdbcReactiveExecutor.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/sql/DefaultJdbcReactiveExecutor.java @@ -1,35 +1,89 @@ package org.hswebframework.web.crud.sql; +import lombok.extern.slf4j.Slf4j; import org.hswebframework.ezorm.rdb.executor.SqlRequest; import org.hswebframework.ezorm.rdb.executor.jdbc.JdbcReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; +import org.hswebframework.web.api.crud.entity.TransactionManagers; import org.hswebframework.web.datasource.DataSourceHolder; +import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.transaction.annotation.Transactional; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import javax.sql.DataSource; import java.sql.Connection; +@Slf4j public class DefaultJdbcReactiveExecutor extends JdbcReactiveSqlExecutor { @Autowired private DataSource dataSource; - @Override - public Mono getConnection(SqlRequest sqlRequest) { + protected String getDatasourceId() { + return DataSourceHolder.switcher().datasource().current().orElse("default"); + } + private Tuple2 getDataSourceAndConnection() { DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ? DataSourceHolder.currentDataSource().getNative() : this.dataSource; Connection connection = DataSourceUtils.getConnection(dataSource); - return Mono.just(connection); + boolean isConnectionTransactional = DataSourceUtils.isConnectionTransactional(connection, dataSource); + if (log.isDebugEnabled()) { + log.debug("DataSource ({}) JDBC Connection [{}] will {}be managed by Spring", getDatasourceId(), connection, (isConnectionTransactional ? "" : "not ")); + } + return Tuples.of(dataSource, connection); + } + @Override + public Mono getConnection() { + return Mono + .using( + this::getDataSourceAndConnection + , + tp2 -> Mono.just(tp2.getT2()), + tp2 -> DataSourceUtils.releaseConnection(tp2.getT2(), tp2.getT1()), + false + ); } @Override - public void releaseConnection(Connection connection, SqlRequest sqlRequest) { - DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ? - DataSourceHolder.currentDataSource().getNative() : - this.dataSource; - DataSourceUtils.releaseConnection(connection, dataSource); + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,readOnly = true) + public Flux select(String sql, ResultWrapper wrapper) { + return super.select(sql,wrapper); + } + + @Override + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,rollbackFor = Throwable.class) + public Mono update(Publisher request) { + return super.update(request); + } + + @Override + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,rollbackFor = Throwable.class) + public Mono update(String sql, Object... args) { + return super.update(sql,args); + } + + @Override + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,rollbackFor = Throwable.class) + public Mono update(SqlRequest request) { + return super.update(request); + } + + @Override + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,rollbackFor = Throwable.class) + public Mono execute(Publisher request) { + return super.execute(request); + } + + @Override + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager,rollbackFor = Throwable.class) + public Mono execute(SqlRequest request) { + return super.execute(request); } } 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 558b31404..7c6c8d300 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 @@ -2,7 +2,6 @@ import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.Result; import io.r2dbc.spi.Statement; import lombok.Setter; import org.hswebframework.ezorm.rdb.executor.SqlRequest; @@ -87,55 +86,55 @@ protected void releaseConnection(SignalType type, Connection connection) { } @Override - @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono execute(SqlRequest request) { return super.execute(request); } @Override - @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono execute(Publisher request) { return super.execute(request); } @Override - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) public Mono update(Publisher request) { return super.update(request); } @Override - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) public Mono update(SqlRequest request) { return super.update(request); } @Override - @Transactional(transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(transactionManager = TransactionManagers.reactiveTransactionManager) public Mono update(String sql, Object... args) { return super.update(sql,args); } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Flux select(Publisher request, ResultWrapper wrapper) { return super.select(request, wrapper); } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Flux> select(String sql, Object... args) { return super.select(sql,args); } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Flux select(String sql, ResultWrapper wrapper) { return super.select(sql,wrapper); } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Flux select(SqlRequest sqlRequest, ResultWrapper wrapper) { return super.select(sqlRequest,wrapper); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index ac6500f97..9f4ad00dd 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.web; -import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import lombok.extern.slf4j.Slf4j; import org.hswebframework.web.CodeConstants; import org.hswebframework.web.authorization.exception.AccessDenyException; @@ -32,7 +31,7 @@ import java.util.stream.Collectors; @RestControllerAdvice -@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +//@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @Slf4j @Order public class CommonErrorControllerAdvice { @@ -214,22 +213,6 @@ public Mono> handleException(MethodNotAllowedException e .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getMessage(), e))); } - @ExceptionHandler - @ResponseStatus(HttpStatus.BAD_REQUEST) - public Mono> handleException(R2dbcDataIntegrityViolationException e) { - String code; - - if (e.getMessage().contains("Duplicate")) { - code = "error.duplicate_data"; - } else { - code = "error.data_error"; - log.warn(e.getMessage(), e); - } - return LocaleUtils - .resolveMessageReactive(code) - .map(msg -> ResponseMessage.error(400, code, msg)); - } - @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index 5df067c73..9a2c8e7b6 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -1,5 +1,6 @@ package org.hswebframework.web.crud.web; +import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import org.hswebframework.web.i18n.WebFluxLocaleFilter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -32,6 +33,11 @@ public ResponseMessageWrapper responseMessageWrapper(ServerCodecConfigurer codec return new ResponseMessageWrapper(codecConfigurer.getWriters(), resolver, registry); } + @Bean + public R2dbcDataIntegrityViolationException r2dbcDataIntegrityViolationException(){ + return new R2dbcDataIntegrityViolationException(); + } + @Bean public WebFilter localeWebFilter() { diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java new file mode 100644 index 000000000..b310160e8 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.crud.web; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +public class CommonWebMvcConfiguration { + + @Bean + @ConditionalOnMissingBean + public CommonWebMvcErrorControllerAdvice commonErrorControllerAdvice() { + return new CommonWebMvcErrorControllerAdvice(); + } + + + @SuppressWarnings("all") + @Bean + @ConditionalOnProperty(prefix = "hsweb.webflux.response-wrapper", name = "enabled", havingValue = "true", matchIfMissing = true) + @ConfigurationProperties(prefix = "hsweb.webflux.response-wrapper") + public ResponseMessageWrapperAdvice responseMessageWrapper() { + return new ResponseMessageWrapperAdvice(); + } + + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcErrorControllerAdvice.java new file mode 100644 index 000000000..d95770942 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcErrorControllerAdvice.java @@ -0,0 +1,234 @@ +package org.hswebframework.web.crud.web; + +import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.CodeConstants; +import org.hswebframework.web.authorization.exception.AccessDenyException; +import org.hswebframework.web.authorization.exception.AuthenticationException; +import org.hswebframework.web.authorization.exception.UnAuthorizedException; +import org.hswebframework.web.authorization.token.TokenState; +import org.hswebframework.web.exception.BusinessException; +import org.hswebframework.web.exception.I18nSupportException; +import org.hswebframework.web.exception.NotFoundException; +import org.hswebframework.web.exception.ValidationException; +import org.hswebframework.web.i18n.LocaleUtils; +import org.hswebframework.web.logger.ReactiveLogger; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.bind.support.WebExchangeBindException; +import org.springframework.web.server.MethodNotAllowedException; +import org.springframework.web.server.NotAcceptableStatusException; +import org.springframework.web.server.ServerWebInputException; +import org.springframework.web.server.UnsupportedMediaTypeStatusException; +import reactor.core.publisher.Mono; + +import javax.validation.ConstraintViolationException; +import java.util.List; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +@RestControllerAdvice +@Slf4j +@Order +public class CommonWebMvcErrorControllerAdvice { + + private String resolveMessage(Throwable e) { + if (e instanceof I18nSupportException) { + return LocaleUtils.resolveMessage(((I18nSupportException) e).getI18nCode()); + } + return e.getMessage() == null ? null : LocaleUtils.resolveMessage(e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseMessage handleException(BusinessException err) { + String msg = resolveMessage(err); + return ResponseMessage.error(err.getStatus(), err.getCode(), msg); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseMessage handleException(UnsupportedOperationException e) { + log.error(e.getMessage(), e); + String msg = resolveMessage(e); + return ResponseMessage.error(500, CodeConstants.Error.unsupported, msg); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public ResponseMessage handleException(UnAuthorizedException e) { + return ResponseMessage + .error(401, CodeConstants.Error.unauthorized, resolveMessage(e)) + .result(e.getState()); + + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.FORBIDDEN) + public ResponseMessage handleException(AccessDenyException e) { + return ResponseMessage.error(403, e.getCode(), resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ResponseMessage handleException(NotFoundException e) { + return ResponseMessage.error(404, CodeConstants.Error.not_found, resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(ValidationException e) { + + return ResponseMessage + .>error(400, CodeConstants.Error.illegal_argument, resolveMessage(e)) + .result(e.getDetails()) + ; + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(ConstraintViolationException e) { + return handleException(new ValidationException(e.getConstraintViolations())); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(BindException e) { + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() + .stream() + .filter(FieldError.class::isInstance) + .map(FieldError.class::cast) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) + .collect(Collectors.toList()))); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(WebExchangeBindException e) { + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() + .stream() + .filter(FieldError.class::isInstance) + .map(FieldError.class::cast) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) + .collect(Collectors.toList()))); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(MethodArgumentNotValidException e) { + return handleException(new ValidationException(e.getMessage(), e + .getBindingResult().getAllErrors() + .stream() + .filter(FieldError.class::isInstance) + .map(FieldError.class::cast) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) + .collect(Collectors.toList()))); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage handleException(javax.validation.ValidationException e) { + return ResponseMessage.error(400, CodeConstants.Error.illegal_argument, e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) + public ResponseMessage handleException(TimeoutException e) { + return ResponseMessage.error(504, CodeConstants.Error.timeout, resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @Order + public ResponseMessage handleException(RuntimeException e) { + log.error(e.getMessage(), e); + return ResponseMessage.error(resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseMessage handleException(NullPointerException e) { + log.error(e.getMessage(), e); + return ResponseMessage.error(e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage handleException(IllegalArgumentException e) { + log.error(e.getMessage(), e); + + return ResponseMessage.error(400, CodeConstants.Error.illegal_argument, resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage handleException(AuthenticationException e) { + log.error(e.getLocalizedMessage(), e); + + return ResponseMessage.error(400, e.getCode(), resolveMessage(e)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) + public ResponseMessage handleException(UnsupportedMediaTypeStatusException e) { + log.error(e.getLocalizedMessage(), e); + + return ResponseMessage + .error(415, "unsupported_media_type", LocaleUtils.resolveMessage("error.unsupported_media_type")) + .result(e.getSupportedMediaTypes()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) + public ResponseMessage handleException(NotAcceptableStatusException e) { + log.error(e.getMessage(), e); + + return ResponseMessage + .error(406, "not_acceptable_media_type", LocaleUtils + .resolveMessage("error.not_acceptable_media_type")) + .result(e.getSupportedMediaTypes()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) + public ResponseMessage handleException(MethodNotAllowedException e) { + log.error(e.getMessage(), e); + + return ResponseMessage + .error(406, "method_not_allowed", LocaleUtils.resolveMessage("error.method_not_allowed")) + .result(e.getSupportedMethods()); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage> handleException(ServerWebInputException e) { + Throwable exception = e; + do { + exception = exception.getCause(); + if (exception instanceof ValidationException) { + return handleException(((ValidationException) exception)); + } + + } while (exception != null && exception != e); + if (exception == null) { + return ResponseMessage.error(400, CodeConstants.Error.illegal_argument, e.getMessage()); + } + return ResponseMessage.error(400, CodeConstants.Error.illegal_argument, resolveMessage(exception)); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseMessage handleException(I18nSupportException e) { + return ResponseMessage.error(400, e.getI18nCode(), resolveMessage(e)); + } + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CrudController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CrudController.java new file mode 100644 index 000000000..4799dadee --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CrudController.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.crud.web; + +public interface CrudController extends + SaveController, + QueryController, + DeleteController { +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/DeleteController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/DeleteController.java new file mode 100644 index 000000000..95c35bd68 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/DeleteController.java @@ -0,0 +1,27 @@ +package org.hswebframework.web.crud.web; + +import io.swagger.v3.oas.annotations.Operation; +import org.hswebframework.ezorm.rdb.mapping.SyncRepository; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.DeleteAction; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.Collections; + +public interface DeleteController { + @Authorize(ignore = true) + SyncRepository getRepository(); + + @DeleteMapping("/{id:.+}") + @DeleteAction + @Operation(summary = "根据ID删除") + default E delete(@PathVariable K id) { + E data = getRepository() + .findById(id) + .orElseThrow(NotFoundException::new); + getRepository().deleteById(Collections.singletonList(id)); + return data; + } +} 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 index 4e66951cf..c796dc6f8 100644 --- 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 @@ -1,9 +1,175 @@ package org.hswebframework.web.crud.web; -import org.hswebframework.web.crud.service.CrudService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.ezorm.rdb.mapping.SyncRepository; +import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.QueryNoPagingOperation; +import org.hswebframework.web.api.crud.entity.QueryOperation; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; -public interface QueryController { +import java.util.Collections; +import java.util.List; - CrudService getService(); +/** + * 基于{@link SyncRepository}的查询控制器. + * + * @param 实体类 + * @param 主键类型 + * @see SyncRepository + */ +public interface QueryController { + + @Authorize(ignore = true) + SyncRepository getRepository(); + + /** + * 查询,但是不返回分页结果. + * + *
+     *     GET /_query/no-paging?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
+     * 
+ * + * @param query 动态查询条件 + * @return 结果流 + * @see QueryParamEntity + */ + @GetMapping("/_query/no-paging") + @QueryAction + @QueryOperation(summary = "使用GET方式分页动态查询(不返回总数)", + description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") + default List query(@Parameter(hidden = true) QueryParamEntity query) { + return getRepository() + .createQuery() + .setParam(query) + .fetch(); + } + + /** + * POST方式查询.不返回分页结果 + * + *
+     *     POST /_query/no-paging
+     *
+     *     {
+     *         "pageIndex":0,
+     *         "pageSize":20,
+     *         "where":"name like 张%", //放心使用,没有SQL注入
+     *         "orderBy":"id desc",
+     *         "terms":[ //高级条件
+     *             {
+     *                 "column":"name",
+     *                 "termType":"like",
+     *                 "value":"张%"
+     *             }
+     *         ]
+     *     }
+     * 
+ * + * @param query 查询条件 + * @return 结果流 + * @see QueryParamEntity + */ + @PostMapping("/_query/no-paging") + @QueryAction + @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)", + description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") + default List postQuery(@Parameter(hidden = true) @RequestBody QueryParamEntity query) { + return this.query(query); + } + + + /** + * GET方式分页查询 + * + *
+     *    GET /_query/no-paging?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
+     * 
+ * + * @param query 查询条件 + * @return 分页查询结果 + * @see PagerResult + */ + @GetMapping("/_query") + @QueryAction + @QueryOperation(summary = "使用GET方式分页动态查询") + default PagerResult queryPager(@Parameter(hidden = true) QueryParamEntity query) { + if (query.getTotal() != null) { + return PagerResult + .of(query.getTotal(), + getRepository() + .createQuery() + .setParam(query.rePaging(query.getTotal())) + .fetch(), query) + ; + } + int total = getRepository().createQuery().setParam(query).count(); + if (total == 0) { + return PagerResult.of(0, Collections.emptyList(), query); + } + query.rePaging(total); + + return PagerResult + .of(total, + getRepository() + .createQuery() + .setParam(query.rePaging(query.getTotal())) + .fetch(), query); + } + + + @PostMapping("/_query") + @QueryAction + @SuppressWarnings("all") + @QueryOperation(summary = "使用POST方式分页动态查询") + default PagerResult postQueryPager(@Parameter(hidden = true) @RequestBody QueryParamEntity query) { + return queryPager(query); + } + + @PostMapping("/_count") + @QueryAction + @QueryNoPagingOperation(summary = "使用POST方式查询总数") + default int postCount(@Parameter(hidden = true) @RequestBody QueryParamEntity query) { + return this.count(query); + } + + /** + * 统计查询 + * + *
+     *     GET /_count
+     * 
+ * + * @param query 查询条件 + * @return 统计结果 + */ + @GetMapping("/_count") + @QueryAction + @QueryNoPagingOperation(summary = "使用GET方式查询总数") + default int count(@Parameter(hidden = true) QueryParamEntity query) { + return getRepository() + .createQuery() + .setParam(query) + .count(); + } + + @GetMapping("/{id:.+}") + @QueryAction + @Operation(summary = "根据ID查询") + default E getById(@PathVariable K id) { + return getRepository() + .findById(id) + .orElseThrow(NotFoundException::new); + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/R2dbcErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/R2dbcErrorControllerAdvice.java new file mode 100644 index 000000000..50d3477e1 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/R2dbcErrorControllerAdvice.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.crud.web; + +import io.r2dbc.spi.R2dbcDataIntegrityViolationException; +import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import reactor.core.publisher.Mono; + +@Slf4j +@RestControllerAdvice +public class R2dbcErrorControllerAdvice { + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Mono> handleException(R2dbcDataIntegrityViolationException e) { + String code; + + if (e.getMessage().contains("Duplicate")) { + code = "error.duplicate_data"; + } else { + code = "error.data_error"; + log.warn(e.getMessage(), e); + } + return LocaleUtils + .resolveMessageReactive(code) + .map(msg -> ResponseMessage.error(400, code, msg)); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java new file mode 100644 index 000000000..8728f13cf --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java @@ -0,0 +1,101 @@ +package org.hswebframework.web.crud.web; + +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; +import org.reactivestreams.Publisher; +import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeType; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; + +@RestControllerAdvice +public class ResponseMessageWrapperAdvice implements ResponseBodyAdvice { + @Setter + @Getter + private Set excludes = new HashSet<>(); + + @Override + public boolean supports(@Nonnull MethodParameter methodParameter, @Nonnull Class> aClass) { + + if (methodParameter.getMethod() == null) { + return true; + } + + RequestMapping mapping = methodParameter.getMethodAnnotation(RequestMapping.class); + if (mapping == null) { + return false; + } + for (String produce : mapping.produces()) { + MimeType mimeType = MimeType.valueOf(produce); + if (MediaType.TEXT_EVENT_STREAM.includes(mimeType) || + MediaType.APPLICATION_STREAM_JSON.includes(mimeType)) { + return false; + } + } + + if (!CollectionUtils.isEmpty(excludes) && methodParameter.getMethod() != null) { + + String typeName = methodParameter.getMethod().getDeclaringClass().getName() + "." + methodParameter + .getMethod() + .getName(); + for (String exclude : excludes) { + if (typeName.startsWith(exclude)) { + return false; + } + } + } + + Class returnType = methodParameter.getMethod().getReturnType(); + + boolean isStream = Publisher.class.isAssignableFrom(returnType); + if (isStream) { + ResolvableType type = ResolvableType.forMethodParameter(methodParameter); + returnType = type.resolveGeneric(0); + } + boolean isAlreadyResponse = returnType == ResponseMessage.class || returnType == ResponseEntity.class; + + return !isAlreadyResponse; + } + + @Override + public Object beforeBodyWrite(Object body, + @Nonnull MethodParameter returnType, + @Nonnull MediaType selectedContentType, + @Nonnull Class> selectedConverterType, + @Nonnull ServerHttpRequest request, + @Nonnull ServerHttpResponse response) { + if (body instanceof Mono) { + return ((Mono) body) + .map(ResponseMessage::ok) + .switchIfEmpty(Mono.just(ResponseMessage.ok())); + } + if (body instanceof Flux) { + return ((Flux) body) + .collectList() + .map(ResponseMessage::ok) + .switchIfEmpty(Mono.just(ResponseMessage.ok())); + } + if (body instanceof String) { + return JSON.toJSONString(ResponseMessage.ok(body)); + } + return ResponseMessage.ok(body); + } + + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/SaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/SaveController.java new file mode 100644 index 000000000..5d818d8b5 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/SaveController.java @@ -0,0 +1,109 @@ +package org.hswebframework.web.crud.web; + +import io.swagger.v3.oas.annotations.Operation; +import org.hswebframework.ezorm.rdb.mapping.SyncRepository; +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.api.crud.entity.RecordCreationEntity; +import org.hswebframework.web.api.crud.entity.RecordModifierEntity; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.SaveAction; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +public interface SaveController { + + @Authorize(ignore = true) + SyncRepository getRepository(); + + @Authorize(ignore = true) + default E applyCreationEntity(Authentication authentication, E entity) { + RecordCreationEntity creationEntity = ((RecordCreationEntity) entity); + creationEntity.setCreateTimeNow(); + creationEntity.setCreatorId(authentication.getUser().getId()); + creationEntity.setCreatorName(authentication.getUser().getName()); + return entity; + } + + @Authorize(ignore = true) + default E applyModifierEntity(Authentication authentication, E entity) { + RecordModifierEntity modifierEntity = ((RecordModifierEntity) entity); + modifierEntity.setModifyTimeNow(); + modifierEntity.setModifierId(authentication.getUser().getId()); + modifierEntity.setModifierName(authentication.getUser().getName()); + return entity; + } + + @Authorize(ignore = true) + default E applyAuthentication(E entity, Authentication authentication) { + if (entity instanceof RecordCreationEntity) { + entity = applyCreationEntity(authentication, entity); + } + if (entity instanceof RecordModifierEntity) { + entity = applyModifierEntity(authentication, entity); + } + return entity; + } + + @PatchMapping + @SaveAction + @Operation(summary = "保存数据", description = "如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增.") + default SaveResult save(@RequestBody List payload) { + return getRepository() + .save(Authentication + .current() + .map(auth -> { + for (E e : payload) { + applyAuthentication(e, auth); + } + return payload; + }) + .orElse(payload) + ); + } + + @PostMapping("/_batch") + @SaveAction + @Operation(summary = "批量新增数据") + default int add(@RequestBody List payload) { + return getRepository() + .insertBatch(Authentication + .current() + .map(auth -> { + for (E e : payload) { + applyAuthentication(e, auth); + } + return payload; + }) + .orElse(payload) + ); + } + + @PostMapping + @SaveAction + @Operation(summary = "新增单个数据,并返回新增后的数据.") + default E add(@RequestBody E payload) { + this.getRepository() + .insert(Authentication + .current() + .map(auth -> applyAuthentication(payload, auth)) + .orElse(payload)); + return payload; + } + + + @PutMapping("/{id}") + @SaveAction + @Operation(summary = "根据ID修改数据") + default boolean update(@PathVariable K id, @RequestBody E payload) { + + return getRepository() + .updateById(id, Authentication + .current() + .map(auth -> applyAuthentication(payload, auth)) + .orElse(payload)) + > 0; + + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceCrudController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceCrudController.java new file mode 100644 index 000000000..feb22bc20 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceCrudController.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.crud.web; + +public interface ServiceCrudController extends + ServiceSaveController, + ServiceQueryController, + ServiceDeleteController { +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceDeleteController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceDeleteController.java new file mode 100644 index 000000000..41290a5f3 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceDeleteController.java @@ -0,0 +1,26 @@ +package org.hswebframework.web.crud.web; + +import io.swagger.v3.oas.annotations.Operation; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.DeleteAction; +import org.hswebframework.web.crud.service.CrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; + +public interface ServiceDeleteController { + @Authorize(ignore = true) + CrudService getService(); + + @DeleteMapping("/{id:.+}") + @DeleteAction + @Operation(summary = "根据ID删除") + default E delete(@PathVariable K id) { + E data = getService() + .findById(id) + .orElseThrow(NotFoundException::new); + getService() + .deleteById(id); + return data; + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java new file mode 100644 index 000000000..c4a95631c --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java @@ -0,0 +1,171 @@ +package org.hswebframework.web.crud.web; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.QueryNoPagingOperation; +import org.hswebframework.web.api.crud.entity.QueryOperation; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.crud.service.CrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.Collections; +import java.util.List; + +/** + * 基于{@link CrudService}的查询控制器. + * + * @param 实体类 + * @param 主键类型 + * @see CrudService + */ +public interface ServiceQueryController { + + @Authorize(ignore = true) + CrudService getService(); + + /** + * 查询,但是不返回分页结果. + * + *
+     *     GET /_query/no-paging?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
+     * 
+ * + * @param query 动态查询条件 + * @return 结果流 + * @see QueryParamEntity + */ + @GetMapping("/_query/no-paging") + @QueryAction + @QueryOperation(summary = "使用GET方式分页动态查询(不返回总数)", + description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") + default List query(@Parameter(hidden = true) QueryParamEntity query) { + return getService() + .createQuery() + .setParam(query) + .fetch(); + } + + /** + * POST方式查询.不返回分页结果 + * + *
+     *     POST /_query/no-paging
+     *
+     *     {
+     *         "pageIndex":0,
+     *         "pageSize":20,
+     *         "where":"name like 张%", //放心使用,没有SQL注入
+     *         "orderBy":"id desc",
+     *         "terms":[ //高级条件
+     *             {
+     *                 "column":"name",
+     *                 "termType":"like",
+     *                 "value":"张%"
+     *             }
+     *         ]
+     *     }
+     * 
+ * + * @param query 查询条件 + * @return 结果流 + * @see QueryParamEntity + */ + @PostMapping("/_query/no-paging") + @QueryAction + @Operation(summary = "使用POST方式分页动态查询(不返回总数)", + description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") + default List postQuery(@RequestBody QueryParamEntity query) { + return this.query(query); + } + + + /** + * GET方式分页查询 + * + *
+     *    GET /_query/no-paging?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
+     * 
+ * + * @param query 查询条件 + * @return 分页查询结果 + * @see PagerResult + */ + @GetMapping("/_query") + @QueryAction + @QueryOperation(summary = "使用GET方式分页动态查询") + default PagerResult queryPager(@Parameter(hidden = true) QueryParamEntity query) { + if (query.getTotal() != null) { + return PagerResult + .of(query.getTotal(), + getService() + .createQuery() + .setParam(query.rePaging(query.getTotal())) + .fetch(), query) + ; + } + int total = getService().createQuery().setParam(query).count(); + if (total == 0) { + return PagerResult.of(0, Collections.emptyList(), query); + } + return PagerResult + .of(total, + getService() + .createQuery() + .setParam(query.rePaging(total)) + .fetch(), query); + } + + + @PostMapping("/_query") + @QueryAction + @SuppressWarnings("all") + @Operation(summary = "使用POST方式分页动态查询") + default PagerResult postQueryPager(@RequestBody QueryParamEntity query) { + return queryPager(query); + } + + @PostMapping("/_count") + @QueryAction + @Operation(summary = "使用POST方式查询总数") + default int postCount(@RequestBody QueryParamEntity query) { + return this.count(query); + } + + /** + * 统计查询 + * + *
+     *     GET /_count
+     * 
+ * + * @param query 查询条件 + * @return 统计结果 + */ + @GetMapping("/_count") + @QueryAction + @QueryNoPagingOperation(summary = "使用GET方式查询总数") + default int count(@Parameter(hidden = true) QueryParamEntity query) { + return getService() + .createQuery() + .setParam(query) + .count(); + } + + @GetMapping("/{id:.+}") + @QueryAction + @Operation(summary = "根据ID查询") + default E getById(@PathVariable K id) { + return getService() + .findById(id) + .orElseThrow(NotFoundException::new); + } + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceSaveController.java new file mode 100644 index 000000000..df3be1af5 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceSaveController.java @@ -0,0 +1,109 @@ +package org.hswebframework.web.crud.web; + +import io.swagger.v3.oas.annotations.Operation; +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.api.crud.entity.RecordCreationEntity; +import org.hswebframework.web.api.crud.entity.RecordModifierEntity; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.SaveAction; +import org.hswebframework.web.crud.service.CrudService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +public interface ServiceSaveController { + + @Authorize(ignore = true) + CrudService getService(); + + @Authorize(ignore = true) + default E applyCreationEntity(Authentication authentication, E entity) { + RecordCreationEntity creationEntity = ((RecordCreationEntity) entity); + creationEntity.setCreateTimeNow(); + creationEntity.setCreatorId(authentication.getUser().getId()); + creationEntity.setCreatorName(authentication.getUser().getName()); + return entity; + } + + @Authorize(ignore = true) + default E applyModifierEntity(Authentication authentication, E entity) { + RecordModifierEntity modifierEntity = ((RecordModifierEntity) entity); + modifierEntity.setModifyTimeNow(); + modifierEntity.setModifierId(authentication.getUser().getId()); + modifierEntity.setModifierName(authentication.getUser().getName()); + return entity; + } + + @Authorize(ignore = true) + default E applyAuthentication(E entity, Authentication authentication) { + if (entity instanceof RecordCreationEntity) { + entity = applyCreationEntity(authentication, entity); + } + if (entity instanceof RecordModifierEntity) { + entity = applyModifierEntity(authentication, entity); + } + return entity; + } + + @PatchMapping + @SaveAction + @Operation(summary = "保存数据", description = "如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增.") + default SaveResult save(@RequestBody List payload) { + return getService() + .save(Authentication + .current() + .map(auth -> { + for (E e : payload) { + applyAuthentication(e, auth); + } + return payload; + }) + .orElse(payload) + ); + } + + @PostMapping("/_batch") + @SaveAction + @Operation(summary = "批量新增数据") + default int add(@RequestBody List payload) { + return getService() + .insert(Authentication + .current() + .map(auth -> { + for (E e : payload) { + applyAuthentication(e, auth); + } + return payload; + }) + .orElse(payload) + ); + } + + @PostMapping + @SaveAction + @Operation(summary = "新增单个数据,并返回新增后的数据.") + default E add(@RequestBody E payload) { + this.getService() + .insert(Authentication + .current() + .map(auth -> applyAuthentication(payload, auth)) + .orElse(payload)); + return payload; + } + + + @PutMapping("/{id}") + @SaveAction + @Operation(summary = "根据ID修改数据") + default boolean update(@PathVariable K id, @RequestBody E payload) { + + return getService() + .updateById(id, Authentication + .current() + .map(auth -> applyAuthentication(payload, auth)) + .orElse(payload)) + > 0; + + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java index ec01cca9e..37cd9a805 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java @@ -78,9 +78,9 @@ default Flux query(@Parameter(hidden = true) QueryParamEntity query) { */ @PostMapping("/_query/no-paging") @QueryAction - @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)", + @Operation(summary = "使用POST方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") - default Flux query(@Parameter(hidden = true) @RequestBody Mono query) { + default Flux query(@RequestBody Mono query) { return query.flatMapMany(this::query); } @@ -121,8 +121,8 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti @PostMapping("/_query") @QueryAction @SuppressWarnings("all") - @QueryOperation(summary = "使用POST方式分页动态查询") - default Mono> queryPager(@Parameter(hidden = true) @RequestBody Mono query) { + @Operation(summary = "使用POST方式分页动态查询") + default Mono> queryPager(@RequestBody Mono query) { return query.flatMap(q -> queryPager(q)); } @@ -145,8 +145,8 @@ default Mono count(@Parameter(hidden = true) @RequestBody Mono count(@Parameter(hidden = true) QueryParamEntity query) { + @Operation(summary = "使用GET方式查询总数") + default Mono count(QueryParamEntity query) { return getRepository() .createQuery() .setParam(query) 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 3a51d2ae5..0fe7a61e4 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 @@ -3,4 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.hswebframework.web.crud.configuration.EasyormConfiguration,\ org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration,\ -org.hswebframework.web.crud.web.CommonWebFluxConfiguration \ No newline at end of file +org.hswebframework.web.crud.web.CommonWebFluxConfiguration,\ +org.hswebframework.web.crud.web.CommonWebMvcConfiguration \ No newline at end of file diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index ac94d6cec..004110ad0 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -45,6 +45,7 @@ org.springframework spring-jdbc + true @@ -55,6 +56,7 @@ io.r2dbc r2dbc-spi + true diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index bec7c5ff3..80475ba59 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -33,9 +33,11 @@ hsweb-commons-crud ${project.version} + org.springframework spring-webflux + true diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java index b6605d30f..6fcdb1adc 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -1,10 +1,8 @@ package org.hswebframework.web.starter.jackson; import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.deser.std.EnumDeserializer; import com.fasterxml.jackson.databind.module.SimpleDeserializers; import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.type.ClassKey; import org.hswebframework.web.api.crud.entity.EntityFactory; import org.hswebframework.web.dict.EnumDict; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -55,6 +53,11 @@ public JsonDeserializer findEnumDeserializer(Class type, }; } + @Bean + CustomMappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(EntityFactory entityFactory,ObjectMapper objectMapper) { + return new CustomMappingJackson2HttpMessageConverter(objectMapper, entityFactory); + } + } diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomMappingJackson2HttpMessageConverter.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomMappingJackson2HttpMessageConverter.java new file mode 100644 index 000000000..351dee180 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomMappingJackson2HttpMessageConverter.java @@ -0,0 +1,72 @@ +package org.hswebframework.web.starter.jackson; + +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.reactivestreams.Publisher; +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.ResolvableType; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.annotation.Nonnull; + +public class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter { + + + private final EntityFactory entityFactory; + + public CustomMappingJackson2HttpMessageConverter(ObjectMapper objectMapper, + EntityFactory entityFactory) { + super(objectMapper); + this.entityFactory = entityFactory; + } + + public Object doRead(Type type, Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + if (type instanceof Class) { + Type newType = entityFactory.getInstanceType(((Class) type), false); + if (null != newType) { + type = newType; + } + } + return super.read(type, contextClass, inputMessage); + } + + @Override + @Nonnull + public Object read(@Nonnull Type type, Class contextClass,@Nonnull HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + + if (type instanceof ParameterizedType) { + ResolvableType resolvableType = ResolvableType.forType(GenericTypeResolver.resolveType(type, contextClass)); + Class clazz = resolvableType.toClass(); + //适配响应式的参数 + if (Publisher.class.isAssignableFrom(clazz)) { + Type _gen = resolvableType.getGeneric(0).getType(); + if (Flux.class.isAssignableFrom(clazz)) { + //Flux则转为List + Object rel = doRead(ResolvableType.forClassWithGenerics(List.class,resolvableType.getGeneric(0)).getType(), contextClass, inputMessage); + if (rel instanceof Iterable) { + return Flux.fromIterable(((Iterable) rel)); + } else { + return Flux.just(rel); + } + } + return Mono.just(doRead(_gen, contextClass, inputMessage)); + } + } + + return doRead(type, contextClass, inputMessage); + } + +} 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 index 43bfe03d8..ae061a4ab 100644 --- 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 @@ -17,7 +17,6 @@ import org.hswebframework.web.system.authorization.api.event.UserDeletedEvent; 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; @@ -55,7 +54,7 @@ public Mono newUserInstance() { } @Override - @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono saveUser(Mono request) { return request .flatMap(userEntity -> { @@ -118,13 +117,13 @@ protected Mono doUpdate(UserEntity userEntity) { } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono findById(String id) { return getRepository().findById(Mono.just(id)); } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono findByUsername(String username) { return Mono.justOrEmpty(username) .flatMap(_name -> repository @@ -134,7 +133,7 @@ public Mono findByUsername(String username) { } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono findByUsernameAndPassword(String username, String plainPassword) { return Mono.justOrEmpty(username) .flatMap(_name -> repository @@ -147,7 +146,7 @@ public Mono findByUsernameAndPassword(String username, String plainP } @Override - @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono changeState(Publisher userId, byte state) { return Flux.from(userId) .collectList() @@ -162,7 +161,7 @@ public Mono changeState(Publisher userId, byte state) { } @Override - @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(rollbackFor = Exception.class, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono changePassword(String userId, String oldPassword, String newPassword) { passwordValidator.validate(newPassword); return findById(userId) @@ -178,7 +177,7 @@ public Mono changePassword(String userId, String oldPassword, String ne } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Flux findUser(QueryParam queryParam) { return repository .createQuery() @@ -187,7 +186,7 @@ public Flux findUser(QueryParam queryParam) { } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono countUser(QueryParam queryParam) { return repository .createQuery() @@ -196,7 +195,7 @@ public Mono countUser(QueryParam queryParam) { } @Override - @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) + @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) public Mono deleteUser(String userId) { return this .findById(userId) From 1a456899e2e2439af2a100bb4f1ebeb241c8825b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 29 Jul 2021 13:41:54 +0800 Subject: [PATCH 092/542] easyorm 4.0.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f84ea3f2..730a22028 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.11-SNAPSHOT + 4.0.11 3.0.2 3.0.2 2.7.0 From ed5e3b0751b43be438db875ebbe67bbc5c6ed4e9 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 29 Jul 2021 16:39:48 +0800 Subject: [PATCH 093/542] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../events/AuthorizationExitEvent.java | 6 +- .../ReactiveTokenAuthenticationSupplier.java | 16 +++-- .../authorization/token/UserTokenManager.java | 2 +- ...erTokenReactiveAuthenticationSupplier.java | 26 ++++---- .../AuthorizingHandlerAutoConfiguration.java | 11 +++- .../basic/web/AuthorizedToken.java | 2 +- .../basic/web/ServletUserTokenGenPar.java | 66 +++++++++++++++++++ .../basic/web/UserOnSignOut.java | 9 +-- .../basic/web/UserTokenWebFilter.java | 45 +++++++++---- .../basic/web/WebUserTokenInterceptor.java | 21 +++--- .../web/oauth2/server/AccessTokenManager.java | 27 ++++++++ .../auth/ReactiveOAuth2AccessTokenParser.java | 19 +++--- .../web/context/ContextUtils.java | 5 +- .../web/logger/ReactiveLogger.java | 22 ++++++- .../web/logger/ReactiveLoggerTest.java | 7 +- 15 files changed, 213 insertions(+), 71 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java index d4515b227..f96287802 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java @@ -19,6 +19,7 @@ package org.hswebframework.web.authorization.events; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.springframework.context.ApplicationEvent; /** @@ -26,14 +27,13 @@ * * @author zhouhao */ -public class AuthorizationExitEvent extends ApplicationEvent implements AuthorizationEvent { +public class AuthorizationExitEvent extends DefaultAsyncEvent implements AuthorizationEvent { private static final long serialVersionUID = -4590245933665047280L; - private Authentication authentication; + private final Authentication authentication; public AuthorizationExitEvent(Authentication authentication) { - super(authentication); this.authentication = authentication; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java index bd7b59516..97efdb45a 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java @@ -20,13 +20,15 @@ public Mono get(String userId) { @Override public Mono get() { - return ContextUtils.reactiveContext() - .flatMap(context -> - context.get(ContextKey.of(ParsedToken.class)) - .map(t -> tokenManager.getByToken(t.getToken())) - .orElseGet(Mono::empty)) - .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId()) - .then(ReactiveLogger.mdc("username", auth.getUser().getName())) + return ContextUtils + .reactiveContext() + .flatMap(context -> context + .get(ContextKey.of(ParsedToken.class)) + .map(t -> tokenManager.getByToken(t.getToken())) + .orElseGet(Mono::empty)) + .flatMap(auth -> ReactiveLogger + .mdc("userId", auth.getUser().getId(), + "username", auth.getUser().getName()) .thenReturn(auth)); } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java index 897bc3d43..7781683f8 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java @@ -97,7 +97,7 @@ public interface UserTokenManager { * @param userId userId * @param state 状态 * @see org.hswebframework.web.authorization.token.event.UserTokenChangedEvent - * @see this#changeTokenState + * @see UserTokenManager#changeTokenState */ Mono changeUserState(String userId, TokenState state); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java index f43423ad1..ae8b3d853 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java @@ -68,20 +68,18 @@ protected Mono get(ReactiveAuthenticationManager authenticationM @Override public Mono get() { - return ContextUtils.reactiveContext() - .flatMap(context -> - context.get(ContextKey.of(ParsedToken.class)) - .map(t -> userTokenManager - .getByToken(t.getToken()) - .filter(UserToken::validate)) - .map(tokenMono -> tokenMono - .flatMap(token -> userTokenManager - .touch(token.getToken()) - .thenReturn(token)) - .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId()))) - .orElseGet(Mono::empty)) - .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId()) - .then(ReactiveLogger.mdc("username", auth.getUser().getName())) + return ContextUtils + .reactiveContext() + .flatMap(context -> context + .get(ContextKey.of(ParsedToken.class)) + .map(t -> userTokenManager.getByToken(t.getToken()).filter(UserToken::validate)) + .map(tokenMono -> tokenMono + .flatMap(token -> userTokenManager.touch(token.getToken()).thenReturn(token)) + .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId()))) + .orElseGet(Mono::empty)) + .flatMap(auth -> ReactiveLogger + .mdc("userId", auth.getUser().getId(), + "username", auth.getUser().getName()) .thenReturn(auth)) ; diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java index 9f909b20c..50e4510a9 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import javax.annotation.Nonnull; import java.util.List; /** @@ -85,6 +86,11 @@ public UserOnSignOut userOnSignOut(UserTokenManager userTokenManager) { return new UserOnSignOut(userTokenManager); } + @SuppressWarnings("all") + @ConfigurationProperties(prefix = "hsweb.authorize.token.default") + public ServletUserTokenGenPar servletUserTokenGenPar(){ + return new ServletUserTokenGenPar(); + } @Bean @ConditionalOnMissingBean(UserTokenParser.class) @@ -101,11 +107,10 @@ public SessionIdUserTokenGenerator sessionIdUserTokenGenerator() { @ConditionalOnProperty(prefix = "hsweb.authorize.two-factor", name = "enable", havingValue = "true") @Order(100) public WebMvcConfigurer twoFactorHandlerConfigurer(TwoFactorValidatorManager manager) { - return new WebMvcConfigurerAdapter() { + return new WebMvcConfigurer() { @Override - public void addInterceptors(InterceptorRegistry registry) { + public void addInterceptors(@Nonnull InterceptorRegistry registry) { registry.addInterceptor(new TwoFactorHandlerInterceptorAdapter(manager)); - super.addInterceptors(registry); } }; } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java index e4502a610..f53a74868 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java @@ -3,7 +3,7 @@ import org.hswebframework.web.authorization.token.ParsedToken; /** - * 已完成认证的令牌,如果返回此令牌,将直接使用{@link this#getUserId()}来绑定用户信息 + * 已完成认证的令牌,如果返回此令牌,将直接使用{@link AuthorizedToken#getUserId()}来绑定用户信息 * * @author zhouhao */ diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java new file mode 100644 index 000000000..597c359ca --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java @@ -0,0 +1,66 @@ +package org.hswebframework.web.authorization.basic.web; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.token.ParsedToken; +import org.hswebframework.web.id.IDGenerator; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +@Getter +@Setter +public class ServletUserTokenGenPar implements UserTokenParser, UserTokenGenerator { + private long timeout = TimeUnit.MINUTES.toMillis(30); + + private String headerName = "X-Access-Token"; + + @Override + public String getSupportTokenType() { + return "default"; + } + + + @Override + public GeneratedToken generate(Authentication authentication) { + String token = IDGenerator.MD5.generate(); + + return new GeneratedToken() { + @Override + public Map getResponse() { + return Collections.singletonMap("expires", timeout); + } + + @Override + public String getToken() { + return token; + } + + @Override + public String getType() { + return getSupportTokenType(); + } + + @Override + public long getTimeout() { + return timeout; + } + }; + } + + @Override + public ParsedToken parseToken(HttpServletRequest request) { + String token = Optional + .ofNullable(request.getHeader(headerName)) + .orElseGet(() -> request.getParameter(":X_Access_Token")); + if (StringUtils.hasText(token)) { + return ParsedToken.of(getSupportTokenType(), token); + } + return null; + } +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java index 5f186f827..51eaed077 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java @@ -5,12 +5,13 @@ import org.hswebframework.web.authorization.token.UserTokenHolder; import org.hswebframework.web.authorization.token.UserTokenManager; import org.springframework.context.ApplicationListener; +import org.springframework.context.event.EventListener; /** * @author zhouhao */ -public class UserOnSignOut implements ApplicationListener { - private UserTokenManager userTokenManager; +public class UserOnSignOut { + private final UserTokenManager userTokenManager; public UserOnSignOut(UserTokenManager userTokenManager) { this.userTokenManager = userTokenManager; @@ -21,8 +22,8 @@ private String geToken() { return null != token ? token.getToken() : ""; } - @Override + @EventListener public void onApplicationEvent(AuthorizationExitEvent event) { - userTokenManager.signOutByToken(geToken()); + event.async(userTokenManager.signOutByToken(geToken())); } } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java index d0eae7df2..d8b24a621 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; @Component @Slf4j @@ -40,13 +41,28 @@ public class UserTokenWebFilter implements WebFilter, BeanPostProcessor { @NonNull public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { - return chain.filter(exchange) - .subscriberContext(ContextUtils.acceptContext(ctx -> - Flux.fromIterable(parsers) - .flatMap(parser -> parser.parseToken(exchange)) - .subscribe(token -> ctx.put(ParsedToken.class, token)))) - .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId())) - ; + return Flux + .fromIterable(parsers) + .flatMap(parser -> parser.parseToken(exchange)) + .next() + .map(token -> chain + .filter(exchange) + .subscriberContext( + ContextUtils.acceptContext( + context -> context.put(ParsedToken.class, token) + ) + )) + .defaultIfEmpty(chain.filter(exchange)) + .flatMap(Function.identity()) + .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId())); + +// return chain.filter(exchange) +// .subscriberContext(ContextUtils.acceptContext(ctx -> +// Flux.fromIterable(parsers) +// .flatMap(parser -> parser.parseToken(exchange)) +// .subscribe(token -> ctx.put(ParsedToken.class, token))) +// ) +// .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId())) } @EventListener @@ -60,14 +76,17 @@ public void handleUserSign(AuthorizationSuccessEvent event) { if (StringUtils.hasText(token.getToken())) { event.getResult().put("token", token.getToken()); long expires = event.getParameter("expires") - .map(String::valueOf) - .map(Long::parseLong) - .orElse(token.getTimeout()); + .map(String::valueOf) + .map(Long::parseLong) + .orElse(token.getTimeout()); event.getResult().put("expires", expires); event.async(userTokenManager - .signIn(token.getToken(), token.getType(), event.getAuthentication().getUser().getId(), expires) - .doOnNext(t -> log.debug("user [{}] sign in", t.getUserId())) - .then()); + .signIn(token.getToken(), token.getType(), event + .getAuthentication() + .getUser() + .getId(), expires) + .doOnNext(t -> log.debug("user [{}] sign in", t.getUserId())) + .then()); } } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java index 1ccb862a1..dc882e7e1 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java @@ -22,27 +22,31 @@ */ public class WebUserTokenInterceptor extends HandlerInterceptorAdapter { - private UserTokenManager userTokenManager; + private final UserTokenManager userTokenManager; - private List userTokenParser; + private final List userTokenParser; - private AopMethodAuthorizeDefinitionParser parser; + private final AopMethodAuthorizeDefinitionParser parser; - private boolean enableBasicAuthorization = false; + private final boolean enableBasicAuthorization; - public WebUserTokenInterceptor(UserTokenManager userTokenManager, List userTokenParser, AopMethodAuthorizeDefinitionParser definitionParser) { + public WebUserTokenInterceptor(UserTokenManager userTokenManager, + List userTokenParser, + AopMethodAuthorizeDefinitionParser definitionParser) { this.userTokenManager = userTokenManager; this.userTokenParser = userTokenParser; this.parser = definitionParser; - enableBasicAuthorization = userTokenParser.stream() + enableBasicAuthorization = userTokenParser + .stream() .filter(UserTokenForTypeParser.class::isInstance) .anyMatch(parser -> "basic".equalsIgnoreCase(((UserTokenForTypeParser) parser).getTokenType())); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - List tokens = userTokenParser.stream() + List tokens = userTokenParser + .stream() .map(parser -> parser.parseToken(request)) .filter(Objects::nonNull) .collect(Collectors.toList()); @@ -68,7 +72,8 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons userTokenManager.signOutByToken(token).subscribe(); userToken = userTokenManager - .signIn(parsedToken.getToken(), parsedToken.getType(), ((AuthorizedToken) parsedToken).getUserId(), ((AuthorizedToken) parsedToken).getMaxInactiveInterval()) + .signIn(parsedToken.getToken(), parsedToken.getType(), ((AuthorizedToken) parsedToken).getUserId(), ((AuthorizedToken) parsedToken) + .getMaxInactiveInterval()) .block(); } if (null != userToken) { diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java index 1645357d3..e90793c6c 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java @@ -3,14 +3,41 @@ import org.hswebframework.web.authorization.Authentication; import reactor.core.publisher.Mono; +/** + * OAuth2 AccessToken管理器,用于创建,刷新token以及根据token获取权限信息 + * + * @author zhouhao + * @since 4.0.7 + */ public interface AccessTokenManager { + /** + * 根据token获取权限信息 + * + * @param accessToken accessToken + * @return 权限信息 + */ Mono getAuthenticationByToken(String accessToken); + /** + * 根据ClientId以及权限信息创建token + * + * @param clientId clientId {@link OAuth2Client#getClientId()} + * @param authentication 权限信息 + * @param singleton 是否单例,如果为true,重复创建token将返回首次创建的token + * @return + */ Mono createAccessToken(String clientId, Authentication authentication, boolean singleton); + /** + * 刷新token + * + * @param clientId clientId {@link OAuth2Client#getClientId()} + * @param refreshToken refreshToken + * @return 新的token + */ Mono refreshAccessToken(String clientId, String refreshToken); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java index 7f1ab25a8..dedcfe752 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java @@ -47,15 +47,16 @@ public Mono get(String userId) { @Override public Mono get() { - return ContextUtils.reactiveContext() - .flatMap(context -> - context.get(ContextKey.of(ParsedToken.class)) - .filter(token -> "oauth2".equals(token.getType())) - .map(t -> accessTokenManager - .getAuthenticationByToken(t.getToken())) - .orElse(Mono.empty())) - .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId()) - .then(ReactiveLogger.mdc("username", auth.getUser().getName())) + return ContextUtils + .reactiveContext() + .flatMap(context -> context + .get(ContextKey.of(ParsedToken.class)) + .filter(token -> "oauth2".equals(token.getType())) + .map(t -> accessTokenManager.getAuthenticationByToken(t.getToken())) + .orElse(Mono.empty())) + .flatMap(auth -> ReactiveLogger + .mdc("userId", auth.getUser().getId(), + "username", auth.getUser().getName()) .thenReturn(auth)); } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java index 6640aa5f9..256ee95ee 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java @@ -18,11 +18,12 @@ public static Context currentContext() { } public static Mono reactiveContext() { - return Mono.subscriberContext() + return Mono + .subscriberContext() .handle((context, sink) -> { if (context.hasKey(Context.class)) { sink.next(context.get(Context.class)); - }else { + } else { sink.complete(); } }) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java b/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java index 64361ae80..572adc5e8 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java @@ -13,17 +13,32 @@ @Slf4j public class ReactiveLogger { - private static String CONTEXT_KEY = ReactiveLogger.class.getName(); + private static final String CONTEXT_KEY = ReactiveLogger.class.getName(); public static Function start(String key, String value) { return start(Collections.singletonMap(key, value)); } + public static Function start(String... keyAndValue) { + Map map = new HashMap<>(); + for (int i = 0, len = keyAndValue.length / 2; i < len; i++) { + map.put(keyAndValue[i * 2], keyAndValue[i * 2 + 1]); + } + return start(map); + } + public static Mono mdc(String key, String value) { - return Mono.empty() + return Mono + .empty() .subscriberContext(start(key, value)); } + public static Mono mdc(String... keyAndValue) { + return Mono + .empty() + .subscriberContext(start(keyAndValue)); + } + public static Function start(Map context) { return ctx -> { Optional> maybeContextMap = ctx.getOrEmpty(CONTEXT_KEY); @@ -74,7 +89,8 @@ public static Consumer> on(SignalType type, BiConsumer mdc(Consumer> consumer) { - return Mono.subscriberContext() + return Mono + .subscriberContext() .doOnNext(ctx -> { Optional> maybeContextMap = ctx.getOrEmpty(CONTEXT_KEY); if (maybeContextMap.isPresent()) { diff --git a/hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java b/hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java index 8a12e8ee4..135a7ea9b 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; +import org.slf4j.MDC; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -17,12 +18,12 @@ public class ReactiveLoggerTest { public void test() { Flux.range(0, 5) - .delayElements(Duration.ofSeconds(1)) .flatMap(i -> ReactiveLogger.mdc("requestId", "test").thenReturn(i)) .doOnEach(ReactiveLogger.onNext(v -> { - log.info("test:{}", v); + + log.info("test:{} {}", v, MDC.getCopyOfContextMap()); })) - .subscriberContext(ReactiveLogger.start("r", "1")) + .subscriberContext(ReactiveLogger.start("r", "1","t","1")) .as(StepVerifier::create) .expectNextCount(5) .verifyComplete(); From 52bfe0288d9499762bab71d294000d091ac5bd45 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 30 Jul 2021 17:12:11 +0800 Subject: [PATCH 094/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=82=E6=95=B0clo?= =?UTF-8?q?ne?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/crud/entity/QueryParamEntity.java | 2 +- .../web/crud/service/ReactiveCrudService.java | 4 ++-- .../web/crud/web/QueryController.java | 2 +- .../web/crud/web/ServiceQueryController.java | 2 +- .../crud/web/reactive/ReactiveQueryController.java | 13 +++++++------ 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index 716a84f5a..b02fecca2 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -128,7 +128,7 @@ public Query toQuery() { *

* 执行后条件: (name=? or type=?) and userId=? * - * @see this#toNestQuery(Consumer) + * @see QueryParamEntity#toNestQuery(Consumer) * @since 3.0.4 */ public Query toNestQuery() { 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 fc0f5bf6e..67680a295 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 @@ -207,14 +207,14 @@ default Mono> queryPager(QueryParamEntity query, Function PagerResult.of(total, data, query) ); } return getRepository() .createQuery() - .setParam(query) + .setParam(query.clone()) .count() .flatMap(total -> { if (total == 0) { 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 index c796dc6f8..98ec2cc13 100644 --- 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 @@ -113,7 +113,7 @@ default PagerResult queryPager(@Parameter(hidden = true) QueryParamEntity que .fetch(), query) ; } - int total = getRepository().createQuery().setParam(query).count(); + int total = getRepository().createQuery().setParam(query.clone()).count(); if (total == 0) { return PagerResult.of(0, Collections.emptyList(), query); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java index c4a95631c..369364486 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ServiceQueryController.java @@ -111,7 +111,7 @@ default PagerResult queryPager(@Parameter(hidden = true) QueryParamEntity que .fetch(), query) ; } - int total = getService().createQuery().setParam(query).count(); + int total = getService().createQuery().setParam(query.clone()).count(); if (total == 0) { return PagerResult.of(0, Collections.emptyList(), query); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java index 37cd9a805..b568cad64 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java @@ -44,7 +44,7 @@ public interface ReactiveQueryController { @QueryAction @QueryOperation(summary = "使用GET方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") - default Flux query(@Parameter(hidden = true) QueryParamEntity query) { + default Flux query(@Parameter(hidden = true) QueryParamEntity query) { return getRepository() .createQuery() .setParam(query) @@ -109,11 +109,12 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti .map(list -> PagerResult.of(query.getTotal(), list, query)); } - return Mono.zip( - getRepository().createQuery().setParam(query).count(), - query(query.clone()).collectList(), - (total, data) -> PagerResult.of(total, data, query) - ); + return Mono + .zip( + getRepository().createQuery().setParam(query.clone()).count(), + query(query.clone()).collectList(), + (total, data) -> PagerResult.of(total, data, query) + ); } From 1748cc933cfae56e89346cb48b0313e2a9202275 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 2 Aug 2021 09:42:47 +0800 Subject: [PATCH 095/542] 4.0.11 --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 29b604d2c..eed7ed198 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index c84ed38d3..76936ee3c 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index bd6a19dad..03bbde304 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index 648940783..f89af6a09 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 58d710013..b92cc07f1 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 48738a4f4..06f2dcbed 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 8bb72abb4..79e07c6b6 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index e61c36d5c..ea10ae1f3 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index e6d347806..4520f833c 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 3e3287c15..fc514ede0 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 004110ad0..fa44d3a8a 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 7e1dfc09d..c553b2db8 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 07cc4dc04..87806c89e 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index f3325bfdc..0bfadf240 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 9f8ee910e..50d2d6a68 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 6032079d3..111fc6db4 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 09a4df8d2..d0e8e069d 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 80475ba59..3961c9648 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index bf2868bf2..564620973 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 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 54a12b8d9..98480392b 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index df8b63484..0cf7cdf24 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 1d69d60ec..cd847567e 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 98b247541..648e03008 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 8e41af9dc..236bc3be7 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index f5e10ce48..8f50b3cc2 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11-SNAPSHOT + 4.0.11 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 730a22028..4877892f0 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.11-SNAPSHOT + 4.0.11 hsweb-starter hsweb-core From 493ecf27ea9c365c3836e0b72899025ede056b9a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 3 Aug 2021 09:26:31 +0800 Subject: [PATCH 096/542] prepare 4.0.12-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index eed7ed198..474c3bf07 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 76936ee3c..9f0520387 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index 03bbde304..ac8384abf 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index f89af6a09..ee5932301 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index b92cc07f1..8ca290de6 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 06f2dcbed..70a5d4d87 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 79e07c6b6..1aa8c684f 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index ea10ae1f3..1e20dc9d8 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 4520f833c..78403e73d 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index fc514ede0..7f8f2d910 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index fa44d3a8a..441f96ea6 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index c553b2db8..568b37f01 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 87806c89e..1aa0e2ee7 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 0bfadf240..66a48e7a8 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 50d2d6a68..556da7658 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 111fc6db4..e7b01fc7e 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index d0e8e069d..63578e39f 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 3961c9648..c37e11d05 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 564620973..e6052a036 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 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 98480392b..0e9365faa 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 0cf7cdf24..dfc0507ad 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index cd847567e..68192e546 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 648e03008..e28a65878 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 236bc3be7..24f3d9977 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index 8f50b3cc2..17f87c9a6 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.11 + 4.0.12-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 4877892f0..85abff372 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.11 + 4.0.12-SNAPSHOT hsweb-starter hsweb-core From 988e9851ef83b852917d43f9fbe0c2fbb7182e6d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 3 Aug 2021 09:26:54 +0800 Subject: [PATCH 097/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/aop/MethodInterceptorHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java index 07079dc6d..4bfa511c4 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java @@ -114,7 +114,7 @@ public boolean handleReactiveArguments(Function, Publisher> hand for (int i = 0; i < args.length; i++) { Object arg = args[i]; if (arg instanceof Publisher) { - args[i] = handler.apply(((Mono) arg)); + args[i] = handler.apply(((Publisher) arg)); handled = true; } } From 19ede4c864153254b405015c7e6799b9d8d0c8f9 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 9 Aug 2021 15:21:33 +0800 Subject: [PATCH 098/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E5=8F=82=E6=95=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/exception/ValidationException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index e37dc7742..fc62966ed 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -29,7 +29,7 @@ public ValidationException(String property, String message, Object... args) { } public ValidationException(String message, List details, Object... args) { - super(message, 400, args); + super(message, args); this.details = details; for (Detail detail : this.details) { detail.translateI18n(args); From 87699e5b0c5c9829d02ef2a367656c1050faa6db Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 23 Aug 2021 15:01:13 +0800 Subject: [PATCH 099/542] add CollectionUtils --- hsweb-core/pom.xml | 5 ++++ .../web/aop/MethodInterceptorContext.java | 4 +-- .../web/logger/ReactiveLogger.java | 7 ++---- .../web/utils/CollectionUtils.java | 25 +++++++++++++++++++ .../web/utils/CollectionUtilsTest.java | 18 +++++++++++++ 5 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/utils/CollectionUtils.java create mode 100644 hsweb-core/src/test/java/org/hswebframework/web/utils/CollectionUtilsTest.java diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 7f8f2d910..6a0ad3521 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -101,5 +101,10 @@ hibernate-validator + + io.projectreactor.addons + reactor-extra + + \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorContext.java b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorContext.java index 79223cc0e..2f4496aa2 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorContext.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorContext.java @@ -31,7 +31,7 @@ * AOP拦截到方法的参数上下文,用于获取当前进行操作的方法的各种参数信息,如:当前所在类实例,参数集合,注解 * * @author zhouhao - * @see 3.0 + * @since 3.0 */ public interface MethodInterceptorContext extends Serializable { @@ -73,7 +73,7 @@ public interface MethodInterceptorContext extends Serializable { * 获取全部参数 * * @return 参数集合 - * @see this#getArgument(String) + * @see MethodInterceptorContext#getArgument(String) */ Map getNamedArguments(); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java b/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java index 572adc5e8..cccc9aced 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java @@ -1,6 +1,7 @@ package org.hswebframework.web.logger; import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.utils.CollectionUtils; import org.slf4j.MDC; import reactor.core.publisher.*; import reactor.util.context.Context; @@ -20,11 +21,7 @@ public static Function start(String key, String value) { } public static Function start(String... keyAndValue) { - Map map = new HashMap<>(); - for (int i = 0, len = keyAndValue.length / 2; i < len; i++) { - map.put(keyAndValue[i * 2], keyAndValue[i * 2 + 1]); - } - return start(map); + return start(CollectionUtils.pairingArrayMap(keyAndValue)); } public static Mono mdc(String key, String value) { diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/CollectionUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/CollectionUtils.java new file mode 100644 index 000000000..dae958e08 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/CollectionUtils.java @@ -0,0 +1,25 @@ +package org.hswebframework.web.utils; + +import reactor.function.Consumer3; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class CollectionUtils { + + @SafeVarargs + public static Map pairingArrayMap(A... array) { + return pairingArray(array, LinkedHashMap::new, Map::put); + } + + public static T pairingArray(A[] array, + Supplier supplier, + Consumer3 mapping) { + T container = supplier.get(); + for (int i = 0, len = array.length / 2; i < len; i++) { + mapping.accept(container, array[i * 2], array[i * 2 + 1]); + } + return container; + } +} diff --git a/hsweb-core/src/test/java/org/hswebframework/web/utils/CollectionUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/utils/CollectionUtilsTest.java new file mode 100644 index 000000000..ae0e56704 --- /dev/null +++ b/hsweb-core/src/test/java/org/hswebframework/web/utils/CollectionUtilsTest.java @@ -0,0 +1,18 @@ +package org.hswebframework.web.utils; + +import org.junit.Test; + +import java.util.Map; + +import static org.junit.Assert.*; + +public class CollectionUtilsTest { + + @Test + public void test() { + Map maps = CollectionUtils.pairingArrayMap(1, 2, 3, 4, 5); + assertEquals(2, maps.size()); + assertEquals(Integer.valueOf(2), maps.get(1)); + assertEquals(Integer.valueOf(4), maps.get(3)); + } +} \ No newline at end of file From 2c8f12dffa56e1ac8edc1ac6e68adb112bc757e0 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 24 Aug 2021 13:54:50 +0800 Subject: [PATCH 100/542] =?UTF-8?q?=E4=BC=98=E5=8C=96clientId=E5=92=8Csecu?= =?UTF-8?q?re=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/web/OAuth2AuthorizeController.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java index 2629686f4..b71ee6468 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.exception.UnAuthorizedException; @@ -19,14 +20,18 @@ import org.hswebframework.web.oauth2.server.code.AuthorizationCodeTokenRequest; import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; import org.hswebframework.web.oauth2.server.refresh.RefreshTokenRequest; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import java.net.URLEncoder; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -84,10 +89,10 @@ public Mono> requestTokenByCode( @RequestParam("grant_type") GrantType grantType, ServerWebExchange exchange) { Map params = exchange.getRequest().getQueryParams().toSingleValueMap(); - + Tuple2 clientIdAndSecret = getClientIdAndClientSecret(params,exchange); return this - .getOAuth2Client(params.get("client_id")) - .doOnNext(client -> client.validateSecret(params.get("client_secret"))) + .getOAuth2Client(clientIdAndSecret.getT1()) + .doOnNext(client -> client.validateSecret(clientIdAndSecret.getT2())) .flatMap(client -> grantType.requestToken(oAuth2GrantService, client, new HashMap<>(params))) .map(ResponseEntity::ok); } @@ -106,15 +111,28 @@ public Mono> requestTokenByCode(ServerWebExchange ex .getFormData() .map(MultiValueMap::toSingleValueMap) .flatMap(params -> { + Tuple2 clientIdAndSecret = getClientIdAndClientSecret(params,exchange); GrantType grantType = GrantType.of(params.get("grant_type")); return this - .getOAuth2Client(params.get("client_id")) - .doOnNext(client -> client.validateSecret(params.get("client_secret"))) + .getOAuth2Client(clientIdAndSecret.getT1()) + .doOnNext(client -> client.validateSecret(clientIdAndSecret.getT2())) .flatMap(client -> grantType.requestToken(oAuth2GrantService, client, new HashMap<>(params))) .map(ResponseEntity::ok); }); } + private Tuple2 getClientIdAndClientSecret(Map params, ServerWebExchange exchange) { + String authorization = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION); + if (authorization != null && authorization.startsWith("Basic ")) { + String[] arr = new String(Base64.decodeBase64(authorization.substring(5))).split(":"); + if (arr.length >= 2) { + return Tuples.of(arr[0], arr[1]); + } + return Tuples.of(arr[0], arr[0]); + } + return Tuples.of(params.getOrDefault("client_id",""),params.getOrDefault("client_secret","")); + } + public enum GrantType { authorization_code { @Override @@ -132,7 +150,7 @@ Mono requestToken(OAuth2GrantService service, OAuth2Client client, .requestToken(new ClientCredentialRequest(client, param)); } }, - refresh_token{ + refresh_token { @Override Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param) { return service @@ -143,10 +161,10 @@ Mono requestToken(OAuth2GrantService service, OAuth2Client client, abstract Mono requestToken(OAuth2GrantService service, OAuth2Client client, Map param); - static GrantType of(String name){ + static GrantType of(String name) { try { return GrantType.valueOf(name); - }catch (Throwable e){ + } catch (Throwable e) { throw new OAuth2Exception(ErrorType.UNSUPPORTED_GRANT_TYPE); } } From 3c8f2544e1650aac6b5f205811d2bc8f1d88b018 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 26 Aug 2021 17:48:02 +0800 Subject: [PATCH 101/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96List=E6=B3=9B=E5=9E=8B=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackson/CustomJackson2JsonDecoder.java | 27 +++++++++++++---- .../CustomJackson2JsonDecoderTest.java | 29 ++++++++++++++++++- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index 576817be3..ab9c16179 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -120,17 +121,33 @@ public Object decode(@NonNull DataBuffer dataBuffer, @NonNull ResolvableType tar } } + private Type getRelType(Type type) { + if (type instanceof Class) { + Class realType = entityFactory.getInstanceType(((Class) type), false); + if (realType != null) { + return realType; + } + } + return type; + } + private ObjectReader getObjectReader(ResolvableType elementType, @Nullable Map hints) { Assert.notNull(elementType, "'elementType' must not be null"); MethodParameter param = getParameter(elementType); Class contextClass = (param != null ? param.getContainingClass() : null); Type type = elementType.resolve() == null ? elementType.getType() : elementType.toClass(); - if (type instanceof Class) { - Class realType = entityFactory.getInstanceType(((Class) type), false); - if (realType != null) { - type = realType; - } + + if (Iterable.class.isAssignableFrom(elementType.toClass())) { + ResolvableType genType = elementType.getGeneric(0); + type = ResolvableType + .forClassWithGenerics( + elementType.toClass(), + ResolvableType.forType(getRelType(genType.getType()))) + .getType(); + } else { + type = getRelType(type); } + JavaType javaType = getJavaType(type, contextClass); Class jsonView = (hints != null ? (Class) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null); return jsonView != null ? diff --git a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java index d70421e16..d2e24edbf 100644 --- a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java +++ b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java @@ -1,6 +1,8 @@ package org.hswebframework.web.starter.jackson; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.Setter; import lombok.SneakyThrows; import org.hswebframework.web.api.crud.entity.EntityFactory; import org.hswebframework.web.api.crud.entity.QueryParamEntity; @@ -17,6 +19,7 @@ import reactor.core.publisher.Mono; import java.util.Collections; +import java.util.List; import static org.junit.Assert.*; @@ -28,7 +31,7 @@ public void testDecodeCustomType() { MapperEntityFactory entityFactory = new MapperEntityFactory(); - entityFactory.addMapping(QueryParamEntity.class,MapperEntityFactory.defaultMapper(CustomQueryParamEntity.class)); + entityFactory.addMapping(QueryParamEntity.class, MapperEntityFactory.defaultMapper(CustomQueryParamEntity.class)); ObjectMapper mapper = new ObjectMapper(); @@ -46,6 +49,30 @@ public void testDecodeCustomType() { } + @Test + @SneakyThrows + public void testDecodeList() { + ObjectMapper mapper = new ObjectMapper(); + CustomJackson2JsonDecoder decoder = new CustomJackson2JsonDecoder(new MapperEntityFactory(), mapper); + + ResolvableType type = ResolvableType.forClassWithGenerics(List.class, MyEntity.class); + DataBuffer buffer = new DefaultDataBufferFactory().wrap("[{\"id\":\"test\"}]".getBytes()); + + Object object = decoder.decode(buffer, type, MediaType.APPLICATION_JSON, Collections.emptyMap()); + + assertTrue(object instanceof List); + assertTrue(((List) object).size() > 0); + assertTrue(((List) object).get(0) instanceof MyEntity); + assertEquals(((MyEntity) ((List) object).get(0)).getId(), "test"); + + } + + @Getter + @Setter + public static class MyEntity { + private String id; + } + public static class CustomQueryParamEntity extends QueryParamEntity { } From 069d801df4ffc19fe42346b1b48eb417f2800930 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 26 Aug 2021 17:48:20 +0800 Subject: [PATCH 102/542] =?UTF-8?q?=E4=BD=BF=E7=94=A8CandidateComponentsIn?= =?UTF-8?q?dex=E4=BC=98=E5=8C=96=E5=90=AF=E5=8A=A8=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EasyormRepositoryRegistrar.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) 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 0947c94c2..9fe25ff59 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 @@ -15,6 +15,8 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.context.index.CandidateComponentsIndex; +import org.springframework.context.index.CandidateComponentsIndexLoader; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.Resource; @@ -25,6 +27,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import javax.persistence.Table; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; @@ -60,18 +63,26 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B boolean nonReactiveEnabled = Boolean.TRUE.equals(attr.get("nonReactive")); String[] arr = (String[]) attr.get("value"); - Set resources = Arrays - .stream(arr) - .flatMap(this::doGetResources) - .collect(Collectors.toSet()); +// Set resources = Arrays +// .stream(arr) +// .flatMap(this::doGetResources) +// .collect(Collectors.toSet()); Class[] anno = (Class[]) attr.get("annotation"); Set entityInfos = new HashSet<>(); - - for (Resource resource : resources) { - MetadataReader reader = metadataReaderFactory.getMetadataReader(resource); - String className = reader.getClassMetadata().getClassName(); + CandidateComponentsIndex index = CandidateComponentsIndexLoader.loadIndex(org.springframework.util.ClassUtils.getDefaultClassLoader()); + Set entities = Stream + .of(arr) + .flatMap(_package -> { + return index + .getCandidateTypes(_package, Table.class.getName()) + .stream(); + }) + .collect(Collectors.toSet()); + for (String className : entities) { +// MetadataReader reader = metadataReaderFactory.getMetadataReader(resource); +// String className = reader.getClassMetadata().getClassName(); Class entityType = org.springframework.util.ClassUtils.forName(className, null); if (Arrays.stream(anno) .noneMatch(ann -> AnnotationUtils.findAnnotation(entityType, ann) != null)) { From 01c5eb9e6c3868a39c8fa87c0e02fd761ef7d9d5 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 27 Aug 2021 18:28:57 +0800 Subject: [PATCH 103/542] =?UTF-8?q?UserTokenManager=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=8F=AF=E6=8C=87=E5=AE=9A=E6=9D=83=E9=99=90=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../token/AuthenticationUserToken.java | 21 +++ .../token/DefaultUserTokenManager.java | 28 +++- .../token/LocalAuthenticationUserToken.java | 22 +++ .../authorization/token/UserTokenManager.java | 23 +++- ...erTokenReactiveAuthenticationSupplier.java | 14 +- .../token/event/UserTokenCreatedEvent.java | 2 +- .../token/redis/RedisUserTokenManager.java | 49 ++++--- .../redis/SimpleAuthenticationUserToken.java | 15 +++ .../token/redis/SimpleUserToken.java | 6 +- .../authorization/AuthenticationTests.java | 8 +- .../authorization/UserTokenManagerTests.java | 60 ++++++--- .../redis/RedisUserTokenManagerTest.java | 125 ++++++++++-------- 12 files changed, 265 insertions(+), 108 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AuthenticationUserToken.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalAuthenticationUserToken.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleAuthenticationUserToken.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AuthenticationUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AuthenticationUserToken.java new file mode 100644 index 000000000..1aef5e7ad --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AuthenticationUserToken.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.authorization.token; + +import org.hswebframework.web.authorization.Authentication; + +/** + * 包含认证信息的token + * + * @author zhouhao + * @since 4.0.12 + */ +public interface AuthenticationUserToken extends UserToken { + + /** + * 获取认证信息 + * + * @return auth + * @see Authentication + */ + Authentication getAuthentication(); + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java index 05e61807f..545589b84 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/DefaultUserTokenManager.java @@ -20,6 +20,7 @@ import lombok.Getter; import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.token.event.UserTokenChangedEvent; import org.hswebframework.web.authorization.token.event.UserTokenCreatedEvent; @@ -33,6 +34,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Supplier; /** * 默认到用户令牌管理器,使用ConcurrentMap来存储令牌信息 @@ -122,9 +124,9 @@ public Flux getByUserId(String userId) { return Flux.empty(); } return Flux.fromStream(tokens - .stream() - .map(tokenStorage::get) - .filter(Objects::nonNull)); + .stream() + .map(tokenStorage::get) + .filter(Objects::nonNull)); } @Override @@ -228,14 +230,23 @@ public Mono changeTokenState(String token, TokenState state) { @Override public Mono changeUserState(String user, TokenState state) { return Mono.from(getByUserId(user) - .flatMap(token -> changeTokenState(token.getToken(), state))); + .flatMap(token -> changeTokenState(token.getToken(), state))); } @Override public Mono signIn(String token, String type, String userId, long maxInactiveInterval) { + return doSignIn(token, type, userId, maxInactiveInterval, LocalUserToken::new) + .cast(UserToken.class); + + } + + private Mono doSignIn(String token, String type, String userId, long maxInactiveInterval, Supplier tokenSupplier) { + return Mono.defer(() -> { - LocalUserToken detail = new LocalUserToken(userId, token); + T detail = tokenSupplier.get(); + detail.setUserId(userId); + detail.setToken(token); detail.setType(type); detail.setMaxInactiveInterval(maxInactiveInterval); detail.setState(TokenState.normal); @@ -272,6 +283,13 @@ public Mono signIn(String token, String type, String userId, long max } + @Override + public Mono signIn(String token, String type, String userId, long maxInactiveInterval, Authentication authentication) { + return this + .doSignIn(token, type, userId, maxInactiveInterval, () -> new LocalAuthenticationUserToken(authentication)) + .cast(AuthenticationUserToken.class); + } + @Override public Mono touch(String token) { LocalUserToken userToken = tokenStorage.get(token); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalAuthenticationUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalAuthenticationUserToken.java new file mode 100644 index 000000000..0dff060c9 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalAuthenticationUserToken.java @@ -0,0 +1,22 @@ +package org.hswebframework.web.authorization.token; + +import lombok.AllArgsConstructor; +import org.hswebframework.web.authorization.Authentication; + + +/** + * 包含认证信息的用户令牌信息 + * + * @author zhouhao + * @since 4.0.12 + */ +@AllArgsConstructor +public class LocalAuthenticationUserToken extends LocalUserToken implements AuthenticationUserToken { + + private final Authentication authentication; + + @Override + public Authentication getAuthentication() { + return authentication; + } +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java index 7781683f8..6ae9fd685 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java @@ -18,6 +18,7 @@ package org.hswebframework.web.authorization.token; +import org.hswebframework.web.authorization.Authentication; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -116,11 +117,29 @@ public interface UserTokenManager { * @param token token * @param type 令牌类型 * @param userId 用户id - * @param maxInactiveInterval 最大不活动时间,超过后令牌状态{@link UserToken#getState()}将变为过期{@link TokenState#expired} + * @param maxInactiveInterval 最大不活动时间(单位毫秒),超过后令牌状态{@link UserToken#getState()}将变为过期{@link TokenState#expired} * @see org.hswebframework.web.authorization.token.event.UserTokenCreatedEvent */ Mono signIn(String token, String type, String userId, long maxInactiveInterval); + /** + * 登记一个包含认证信息的token + * + * @param token token + * @param type 令牌类型 + * @param userId 用户ID + * @param maxInactiveInterval 最大不活动时间(单位毫秒),小于0永不过期,超过后令牌状态{@link UserToken#getState()}将变为过期{@link TokenState#expired} + * @param authentication 认证信息 + * @return token信息 + */ + default Mono signIn(String token, + String type, + String userId, + long maxInactiveInterval, + Authentication authentication) { + throw new UnsupportedOperationException(); + } + /** * 更新token,使其不过期 * @@ -131,7 +150,7 @@ public interface UserTokenManager { /** * 检查已过期的token,并将其remove * - * @see this#signOutByToken(String) + * @see UserTokenManager#signOutByToken(String) */ Mono checkExpiredToken(); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java index ae8b3d853..894a78f8c 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java @@ -72,10 +72,16 @@ public Mono get() { .reactiveContext() .flatMap(context -> context .get(ContextKey.of(ParsedToken.class)) - .map(t -> userTokenManager.getByToken(t.getToken()).filter(UserToken::validate)) - .map(tokenMono -> tokenMono - .flatMap(token -> userTokenManager.touch(token.getToken()).thenReturn(token)) - .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId()))) + .map(t -> userTokenManager + .getByToken(t.getToken()) + .filter(UserToken::validate) + .flatMap(token -> { + Mono before = userTokenManager.touch(token.getToken()); + if (token instanceof AuthenticationUserToken) { + return before.thenReturn(((AuthenticationUserToken) token).getAuthentication()); + } + return before.then(get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())); + })) .orElseGet(Mono::empty)) .flatMap(auth -> ReactiveLogger .mdc("userId", auth.getUser().getId(), diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/event/UserTokenCreatedEvent.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/event/UserTokenCreatedEvent.java index 98dcc0ada..ed7043cee 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/event/UserTokenCreatedEvent.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/event/UserTokenCreatedEvent.java @@ -5,7 +5,7 @@ import org.springframework.context.ApplicationEvent; public class UserTokenCreatedEvent extends ApplicationEvent implements AuthorizationEvent { - private UserToken detail; + private final UserToken detail; public UserTokenCreatedEvent(UserToken detail) { super(detail); diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index d508ee1d1..e890de127 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -2,11 +2,9 @@ import lombok.Getter; import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.exception.AccessDenyException; -import org.hswebframework.web.authorization.token.AllopatricLoginMode; -import org.hswebframework.web.authorization.token.TokenState; -import org.hswebframework.web.authorization.token.UserToken; -import org.hswebframework.web.authorization.token.UserTokenManager; +import org.hswebframework.web.authorization.token.*; import org.hswebframework.web.authorization.token.event.UserTokenChangedEvent; import org.hswebframework.web.authorization.token.event.UserTokenCreatedEvent; import org.hswebframework.web.authorization.token.event.UserTokenRemovedEvent; @@ -26,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -51,14 +50,14 @@ public RedisUserTokenManager(ReactiveRedisOperations operations) .subscribe(msg -> localCache.remove(String.valueOf(msg.getMessage()))); Flux.create(sink -> this.touchSink = sink) - .buffer(Flux.interval(Duration.ofSeconds(10)), HashSet::new) - .flatMap(list -> Flux - .fromIterable(list) - .flatMap(token -> operations - .expire(getTokenRedisKey(token.getToken()), Duration.ofMillis(token.getMaxInactiveInterval())) - .then()) - .onErrorResume(err -> Mono.empty())) - .subscribe(); + .buffer(Flux.interval(Duration.ofSeconds(10)), HashSet::new) + .flatMap(list -> Flux + .fromIterable(list) + .flatMap(token -> operations + .expire(getTokenRedisKey(token.getToken()), Duration.ofMillis(token.getMaxInactiveInterval())) + .then()) + .onErrorResume(err -> Mono.empty())) + .subscribe(); } @@ -212,8 +211,11 @@ public Mono changeTokenState(String token, TokenState state) { }); } - @Override - public Mono signIn(String token, String type, String userId, long maxInactiveInterval) { + private Mono signIn(String token, + String type, + String userId, + long maxInactiveInterval, + Consumer> cacheBuilder) { return Mono .defer(() -> { Mono doSign = Mono.defer(() -> { @@ -225,7 +227,7 @@ public Mono signIn(String token, String type, String userId, long max map.put("state", TokenState.normal.getValue()); map.put("signInTime", System.currentTimeMillis()); map.put("lastRequestTime", System.currentTimeMillis()); - + cacheBuilder.accept(map); String key = getTokenRedisKey(token); return userTokenStore .putAll(key, map) @@ -265,6 +267,23 @@ public Mono signIn(String token, String type, String userId, long max .flatMap(this::onUserTokenCreated); } + @Override + public Mono signIn(String token, String type, String userId, long maxInactiveInterval) { + return signIn(token, type, userId, maxInactiveInterval, ignore -> { + }); + } + + @Override + public Mono signIn(String token, + String type, + String userId, + long maxInactiveInterval, + Authentication authentication) { + return this + .signIn(token, type, userId, maxInactiveInterval, + cache -> cache.put("authentication", authentication)) + .cast(AuthenticationUserToken.class); + } @Override public Mono touch(String token) { diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleAuthenticationUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleAuthenticationUserToken.java new file mode 100644 index 000000000..a5e2826eb --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleAuthenticationUserToken.java @@ -0,0 +1,15 @@ +package org.hswebframework.web.authorization.token.redis; + +import lombok.AllArgsConstructor; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.token.AuthenticationUserToken; + +@AllArgsConstructor +public class SimpleAuthenticationUserToken extends SimpleUserToken implements AuthenticationUserToken { + private final Authentication authentication; + + @Override + public Authentication getAuthentication() { + return authentication; + } +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java index 83742ba3b..d986bda34 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java @@ -4,6 +4,7 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.token.TokenState; import org.hswebframework.web.authorization.token.UserToken; import org.hswebframework.web.bean.FastBeanCopier; @@ -33,7 +34,10 @@ public class SimpleUserToken implements UserToken { private long maxInactiveInterval; public static SimpleUserToken of(Map map) { - + Object authentication = map.get("authentication"); + if(authentication instanceof Authentication){ + return FastBeanCopier.copy(map, new SimpleAuthenticationUserToken(((Authentication) authentication))); + } return FastBeanCopier.copy(map, new SimpleUserToken()); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java index 96559854f..9e4df5c31 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java @@ -106,16 +106,16 @@ public Mono authenticate(Mono request) { @Override public Mono getByUserId(String userId) { - if (userId.equals("admin")) { - return Mono.just(authentication); - } +// if (userId.equals("admin")) { +// return Mono.just(authentication); +// } return Mono.empty(); } }; //绑定用户token UserTokenManager userTokenManager = new DefaultUserTokenManager(); - UserToken token = userTokenManager.signIn("test", "token-test", "admin", -1).block(); + UserToken token = userTokenManager.signIn("test", "token-test", "admin", -1,authentication).block(); ReactiveAuthenticationHolder.addSupplier(new UserTokenReactiveAuthenticationSupplier(userTokenManager, authenticationManager)); ParsedToken parsedToken=new ParsedToken() { diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java index 5287dd5e7..9331086cd 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java @@ -1,6 +1,7 @@ package org.hswebframework.web.authorization; import org.hswebframework.web.authorization.exception.AccessDenyException; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; import org.hswebframework.web.authorization.token.*; import org.junit.Assert; import org.junit.Test; @@ -11,7 +12,8 @@ public class UserTokenManagerTests { /** * 基本功能测试 - * @throws InterruptedException Thread.sleep error + * + * @throws InterruptedException Thread.sleep error */ @Test public void testDefaultSetting() throws InterruptedException { @@ -26,15 +28,15 @@ public void testDefaultSetting() throws InterruptedException { //2个token userTokenManager.totalToken() - .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); //1个用户 userTokenManager.totalUser() - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); //改变token状态 userTokenManager.changeUserState("admin", TokenState.deny).subscribe(); @@ -48,28 +50,28 @@ public void testDefaultSetting() throws InterruptedException { Thread.sleep(1200); userTokenManager.getByToken(userToken.getToken()) - .map(UserToken::isExpired) - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .map(UserToken::isExpired) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); userTokenManager.checkExpiredToken().subscribe(); userTokenManager.getByToken(userToken.getToken()) - .as(StepVerifier::create) - .expectNextCount(0) - .verifyComplete(); + .as(StepVerifier::create) + .expectNextCount(0) + .verifyComplete(); userTokenManager.totalToken() - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); userTokenManager.totalUser() - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); } @@ -99,7 +101,7 @@ public void testDeny() throws InterruptedException { * 测试异地登录模式之踢下线 */ @Test - public void testOffline() { + public void testOffline() { DefaultUserTokenManager userTokenManager = new DefaultUserTokenManager(); userTokenManager.setAllopatricLoginMode(AllopatricLoginMode.offlineOther); //将其他地方登录的用户踢下线 @@ -113,5 +115,21 @@ public void testOffline() { } + @Test + public void testAuth() { + UserTokenManager userTokenManager = new DefaultUserTokenManager(); + Authentication authentication = new SimpleAuthentication(); + + userTokenManager.signIn("test", "test", "test", 1000, authentication) + .as(StepVerifier::create) + .expectNextMatches(token -> token.getAuthentication() == authentication) + .verifyComplete(); + + userTokenManager.getByToken("test") + .cast(AuthenticationUserToken.class) + .as(StepVerifier::create) + .expectNextMatches(token -> token.getAuthentication() == authentication) + .verifyComplete(); + } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManagerTest.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManagerTest.java index 27480d006..53fbcdeaf 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManagerTest.java +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManagerTest.java @@ -1,12 +1,11 @@ package org.hswebframework.web.authorization.token.redis; import lombok.SneakyThrows; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.exception.UnAuthorizedException; -import org.hswebframework.web.authorization.token.AllopatricLoginMode; -import org.hswebframework.web.authorization.token.TokenState; -import org.hswebframework.web.authorization.token.UserToken; -import org.hswebframework.web.authorization.token.UserTokenManager; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; +import org.hswebframework.web.authorization.token.*; import org.junit.Before; import org.junit.Test; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; @@ -48,30 +47,30 @@ public void init() { public void testSign() { tokenManager.signIn("test-token", "test", "test", 10000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectNext("test-token") - .verifyComplete(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectNext("test-token") + .verifyComplete(); tokenManager.userIsLoggedIn("test") - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); tokenManager.tokenIsLoggedIn("test-token") - .as(StepVerifier::create) - .expectNext(true) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); tokenManager.getByToken("test-token") - .map(UserToken::getState) - .as(StepVerifier::create) - .expectNext(TokenState.normal) - .verifyComplete(); + .map(UserToken::getState) + .as(StepVerifier::create) + .expectNext(TokenState.normal) + .verifyComplete(); tokenManager.signOutByToken("test-token") - .as(StepVerifier::create) - .verifyComplete(); + .as(StepVerifier::create) + .verifyComplete(); } @@ -80,65 +79,81 @@ public void testSign() { @SneakyThrows public void testOfflineOther() { tokenManager.signIn("test-token_offline1", "offline", "user1", 1000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectNext("test-token_offline1") - .verifyComplete(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectNext("test-token_offline1") + .verifyComplete(); tokenManager.signIn("test-token_offline2", "offline", "user1", 1000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectNext("test-token_offline2") - .verifyComplete(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectNext("test-token_offline2") + .verifyComplete(); tokenManager.getByToken("test-token_offline1") - .map(UserToken::getState) - .as(StepVerifier::create) - .expectNext(TokenState.offline) - .verifyComplete(); + .map(UserToken::getState) + .as(StepVerifier::create) + .expectNext(TokenState.offline) + .verifyComplete(); } @Test @SneakyThrows public void testDeny() { tokenManager.signIn("test-token_offline3", "deny", "user2", 1000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectNext("test-token_offline3") - .verifyComplete(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectNext("test-token_offline3") + .verifyComplete(); tokenManager.signIn("test-token_offline4", "deny", "user2", 1000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectError(AccessDenyException.class) - .verify(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectError(AccessDenyException.class) + .verify(); } @Test @SneakyThrows public void testSignTimeout() { tokenManager.signIn("test-token_2", "test", "test2", 1000) - .map(UserToken::getToken) - .as(StepVerifier::create) - .expectNext("test-token_2") - .verifyComplete(); + .map(UserToken::getToken) + .as(StepVerifier::create) + .expectNext("test-token_2") + .verifyComplete(); tokenManager.touch("test-token_2") - .as(StepVerifier::create) - .expectComplete() - .verify(); + .as(StepVerifier::create) + .expectComplete() + .verify(); Thread.sleep(2000); tokenManager.getByToken("test-token_2") - .switchIfEmpty(Mono.error(new UnAuthorizedException())) - .as(StepVerifier::create) - .expectError(UnAuthorizedException.class) - .verify(); + .switchIfEmpty(Mono.error(new UnAuthorizedException())) + .as(StepVerifier::create) + .expectError(UnAuthorizedException.class) + .verify(); tokenManager.getByUserId("test2") - .count() - .as(StepVerifier::create) - .expectNext(0L) - .verifyComplete(); + .count() + .as(StepVerifier::create) + .expectNext(0L) + .verifyComplete(); + } + + @Test + public void testAuth() { + Authentication authentication = new SimpleAuthentication(); + + tokenManager.signIn("testAuth", "test", "test", 1000, authentication) + .as(StepVerifier::create) + .expectNextMatches(token -> token.getAuthentication() == authentication) + .verifyComplete(); + + tokenManager.getByToken("testAuth") + .cast(AuthenticationUserToken.class) + .as(StepVerifier::create) + .expectNextMatches(token -> token.getAuthentication() != null) + .verifyComplete(); } } \ No newline at end of file From e70a72d13b892840b92991375880f17b43779853 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 3 Sep 2021 18:18:04 +0800 Subject: [PATCH 104/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0before=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/annotation/EnableEntityEvent.java | 5 + .../crud/configuration/AutoDDLProcessor.java | 23 +- .../crud/events/EntityBeforeCreateEvent.java | 21 ++ .../crud/events/EntityBeforeDeleteEvent.java | 24 ++ .../crud/events/EntityBeforeModifyEvent.java | 26 ++ .../crud/events/EntityBeforeQueryEvent.java | 24 ++ .../crud/events/EntityBeforeSaveEvent.java | 21 ++ .../web/crud/events/EntityDDLEvent.java | 13 + .../web/crud/events/EntityEventListener.java | 335 +++++++++++------- .../crud/events/EntityEventListenerTest.java | 19 +- .../web/crud/events/TestEntityListener.java | 45 +++ pom.xml | 6 +- 12 files changed, 425 insertions(+), 137 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeCreateEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeDeleteEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeModifyEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeQueryEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeSaveEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java index 55b731085..99153e203 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java @@ -19,6 +19,11 @@ * @see org.hswebframework.web.crud.events.EntityDeletedEvent * @see org.hswebframework.web.crud.events.EntityCreatedEvent * @see org.hswebframework.web.crud.events.EntitySavedEvent + * @see org.hswebframework.web.crud.events.EntityBeforeSaveEvent + * @see org.hswebframework.web.crud.events.EntityBeforeModifyEvent + * @see org.hswebframework.web.crud.events.EntityBeforeDeleteEvent + * @see org.hswebframework.web.crud.events.EntityBeforeCreateEvent + * @see org.hswebframework.web.crud.events.EntityBeforeQueryEvent */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) 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 1a96e4b61..8cdc3a765 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 @@ -8,8 +8,12 @@ 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.hswebframework.web.crud.events.EntityBeforeQueryEvent; +import org.hswebframework.web.crud.events.EntityDDLEvent; +import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -43,6 +47,9 @@ public class AutoDDLProcessor implements InitializingBean { @Autowired private EntityFactory entityFactory; + @Autowired + private ApplicationEventPublisher eventPublisher; + private boolean reactive; @Override @@ -60,7 +67,12 @@ public void afterPropertiesSet() { if (reactive) { Flux.fromIterable(entities) .doOnNext(type -> log.trace("auto ddl for {}", type)) - .map(resolver::resolve) + .map(type -> { + RDBTableMetadata metadata = resolver.resolve(type); + EntityDDLEvent event = new EntityDDLEvent(type,metadata); + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); + return metadata; + }) .flatMap(meta -> operator .ddl() .createOrAlter(meta) @@ -73,11 +85,14 @@ public void afterPropertiesSet() { .then() .block(Duration.ofMinutes(5)); } else { - for (Class entity : entities) { - log.trace("auto ddl for {}", entity); + for (Class type : entities) { + log.trace("auto ddl for {}", type); try { + RDBTableMetadata metadata = resolver.resolve(type); + EntityDDLEvent event = new EntityDDLEvent(type,metadata); + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); operator.ddl() - .createOrAlter(resolver.resolve(entity)) + .createOrAlter(metadata) .autoLoad(false) .commit() .sync(); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeCreateEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeCreateEvent.java new file mode 100644 index 000000000..73491fa2c --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeCreateEvent.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityBeforeCreateEvent extends DefaultAsyncEvent implements Serializable { + + private final List entity; + + private final Class entityType; +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeDeleteEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeDeleteEvent.java new file mode 100644 index 000000000..83bb172d1 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeDeleteEvent.java @@ -0,0 +1,24 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @param + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + */ +@AllArgsConstructor +@Getter +public class EntityBeforeDeleteEvent extends DefaultAsyncEvent implements Serializable { + + private static final long serialVersionUID = -7158901204884303777L; + + private final List entity; + + private final Class entityType; + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeModifyEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeModifyEvent.java new file mode 100644 index 000000000..30bbc15da --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeModifyEvent.java @@ -0,0 +1,26 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityBeforeModifyEvent extends DefaultAsyncEvent implements Serializable{ + + private static final long serialVersionUID = -7158901204884303777L; + + private final List before; + + private final List after; + + private final Class entityType; + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeQueryEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeQueryEvent.java new file mode 100644 index 000000000..7c46f3cbd --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeQueryEvent.java @@ -0,0 +1,24 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityBeforeQueryEvent extends DefaultAsyncEvent implements Serializable { + + private final QueryParam param; + + private final Class entityType; + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeSaveEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeSaveEvent.java new file mode 100644 index 000000000..0df1b5d58 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeSaveEvent.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityBeforeSaveEvent extends DefaultAsyncEvent implements Serializable { + + private final List entity; + + private final Class entityType; +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java new file mode 100644 index 000000000..25dcfefcc --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java @@ -0,0 +1,13 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; + +@AllArgsConstructor +@Getter +public class EntityDDLEvent { + private Class type; + + private RDBTableMetadata table; +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 587cec06d..a50eca7c7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -17,7 +17,11 @@ import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Async; import reactor.core.publisher.Mono; +import reactor.function.Function3; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import java.util.ArrayList; import java.util.Collections; @@ -54,21 +58,23 @@ public void onEvent(EventType type, EventContext context) { mapping.getEntityType().getAnnotation(EnableEntityEvent.class) == null) { return; } - + if (type == MappingEventTypes.select_before) { + handleQueryBefore(mapping, context); + } if (type == MappingEventTypes.insert_before) { boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false); if (single) { - handleSingleOperation(mapping.getEntityType(), context, EntityCreatedEvent::new); + handleSingleOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new); } else { - handleBatchOperation(mapping.getEntityType(), context, EntityCreatedEvent::new); + handleBatchOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new); } } if (type == MappingEventTypes.save_before) { boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false); if (single) { - handleSingleOperation(mapping.getEntityType(), context, EntitySavedEvent::new); + handleSingleOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new); } else { - handleBatchOperation(mapping.getEntityType(), context, EntitySavedEvent::new); + handleBatchOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new); } } if (type == MappingEventTypes.update_before) { @@ -80,178 +86,249 @@ public void onEvent(EventType type, EventContext context) { } } - protected Mono sendUpdateEvent(List olds, EventContext context) { + protected void handleQueryBefore(EntityColumnMapping mapping, EventContext context) { + context.get(MappingContextKeys.reactiveResultHolder) + .ifPresent(holder -> { + context.get(MappingContextKeys.queryOaram) + .ifPresent(queryParam -> { + EntityBeforeQueryEvent event = new EntityBeforeQueryEvent<>(queryParam, mapping.getEntityType()); + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, mapping.getEntityType())); + holder + .before( + event.getAsync() + ); + }); + }); + } + + protected List createAfterData(List olds, + EventContext context) { List newValues = new ArrayList<>(olds.size()); - EntityColumnMapping mapping = context.get(MappingContextKeys.columnMapping).orElseThrow(UnsupportedOperationException::new); + EntityColumnMapping mapping = context + .get(MappingContextKeys.columnMapping) + .orElseThrow(UnsupportedOperationException::new); TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new); - RDBColumnMetadata idColumn = table.getColumns().stream().filter(RDBColumnMetadata::isPrimaryKey).findFirst().orElse(null); + RDBColumnMetadata idColumn = table + .getColumns() + .stream() + .filter(RDBColumnMetadata::isPrimaryKey) + .findFirst() + .orElse(null); if (idColumn == null) { - return Mono.empty(); + return Collections.emptyList(); } for (Object old : olds) { - Object newValue = context.get(MappingContextKeys.instance) + Object newValue = context + .get(MappingContextKeys.instance) .filter(Entity.class::isInstance) .map(Entity.class::cast) .orElseGet(() -> { return context.get(MappingContextKeys.updateColumnInstance) - .map(map -> { - return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); - }) - .map(Entity.class::cast) - .orElse(null); + .map(map -> { + return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); + }) + .map(Entity.class::cast) + .orElse(null); }); if (newValue != null) { FastBeanCopier.copy(old, newValue, FastBeanCopier.include(idColumn.getAlias())); } newValues.add(newValue); } - EntityModifyEvent event = new EntityModifyEvent(olds, newValues, mapping.getEntityType()); - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, mapping.getEntityType())); - return event.getAsync(); + return newValues; } - protected Mono sendDeleteEvent(List olds, EventContext context) { + protected Mono sendUpdateEvent(List before, + List after, + Class type, + Function3, List, Class, AsyncEvent> mapper) { - EntityColumnMapping mapping = context.get(MappingContextKeys.columnMapping).orElseThrow(UnsupportedOperationException::new); - TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new); + AsyncEvent event = mapper.apply(before, after, type); + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); + return event.getAsync(); + } + + protected Mono sendDeleteEvent(List olds, + Class type, + BiFunction, Class, AsyncEvent> eventBuilder) { - EntityDeletedEvent deletedEvent = new EntityDeletedEvent(olds, mapping.getEntityType()); - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, deletedEvent, mapping.getEntityType())); + AsyncEvent deletedEvent = eventBuilder.apply(olds, type); + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, deletedEvent, type)); return deletedEvent.getAsync(); } protected void handleUpdateBefore(DSLUpdate update, EventContext context) { Object repo = context.get(MappingContextKeys.repository).orElse(null); + EntityColumnMapping mapping = context + .get(MappingContextKeys.columnMapping) + .orElseThrow(UnsupportedOperationException::new); + if (repo instanceof ReactiveRepository) { + context.get(MappingContextKeys.reactiveResultHolder) - .ifPresent(holder -> { - AtomicReference> updated = new AtomicReference<>(); - holder.after(v -> { - return Mono.defer(() -> { - List _tmp = updated.getAndSet(null); + .ifPresent(holder -> { + AtomicReference, List>> updated = new AtomicReference<>(); - if (CollectionUtils.isNotEmpty(_tmp)) { - return sendUpdateEvent(_tmp, context); - } - return Mono.empty(); - }); - }); - holder.before( - ((ReactiveRepository) repo).createQuery() - .setParam(update.toQueryParam()) - .fetch() - .collectList() - .doOnSuccess(updated::set) - .then() - ); - }); - }else if (repo instanceof SyncRepository) { + holder.after(v -> { + return Mono.defer(() -> { + Tuple2, List> _tmp = updated.getAndSet(null); + if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), _tmp.getT2(), (Class) mapping.getEntityType(), EntityModifyEvent::new); + } + return Mono.empty(); + }); + }); + + holder.before( + ((ReactiveRepository) repo) + .createQuery() + .setParam(update.toQueryParam()) + .fetch() + .collectList() + .flatMap((list) -> { + List after = createAfterData(list, context); + updated.set(Tuples.of(list, after)); + return sendUpdateEvent(list, + after, + (Class) mapping.getEntityType(), + EntityBeforeModifyEvent::new); + + }) + .then() + ); + }); + } else if (repo instanceof SyncRepository) { QueryParam param = update.toQueryParam(); - SyncRepository syncRepository = ((SyncRepository) repo); - List list = syncRepository.createQuery() - .setParam(param) - .fetch(); - sendUpdateEvent(list,context).block(); + SyncRepository syncRepository = ((SyncRepository) repo); + List list = syncRepository.createQuery() + .setParam(param) + .fetch(); + sendUpdateEvent(list, + createAfterData(list, context), + (Class) mapping.getEntityType(), + EntityBeforeModifyEvent::new).block(); } } protected void handleUpdateBefore(EventContext context) { context.>get(ContextKeys.source()) - .ifPresent(dslUpdate -> { - handleUpdateBefore(dslUpdate, context); - }); + .ifPresent(dslUpdate -> { + handleUpdateBefore(dslUpdate, context); + }); } protected void handleDeleteBefore(EventContext context) { + EntityColumnMapping mapping = context + .get(MappingContextKeys.columnMapping) + .orElseThrow(UnsupportedOperationException::new); context.get(ContextKeys.source()) - .ifPresent(dslUpdate -> { - Object repo = context.get(MappingContextKeys.repository).orElse(null); - if (repo instanceof ReactiveRepository) { - context.get(MappingContextKeys.reactiveResultHolder) - .ifPresent(holder -> { - AtomicReference> deleted = new AtomicReference<>(); - holder.after(v -> { - return Mono.defer(() -> { - List _tmp = deleted.getAndSet(null); - if (CollectionUtils.isNotEmpty(_tmp)) { - return sendDeleteEvent(_tmp, context); - } - return Mono.empty(); - }); - }); - holder.before( - ((ReactiveRepository) repo).createQuery() - .setParam(dslUpdate.toQueryParam()) - .fetch() - .collectList() - .doOnSuccess(deleted::set) - .then() - ); - }); - } else if (repo instanceof SyncRepository) { - QueryParam param = dslUpdate.toQueryParam(); - SyncRepository syncRepository = ((SyncRepository) repo); - List list = syncRepository.createQuery() - .setParam(param) - .fetch(); - sendDeleteEvent(list,context).block(); - } - }); + .ifPresent(dslUpdate -> { + Object repo = context.get(MappingContextKeys.repository).orElse(null); + if (repo instanceof ReactiveRepository) { + context.get(MappingContextKeys.reactiveResultHolder) + .ifPresent(holder -> { + AtomicReference> deleted = new AtomicReference<>(); + holder.after(v -> { + return Mono + .defer(() -> { + List _tmp = deleted.getAndSet(null); + if (CollectionUtils.isNotEmpty(_tmp)) { + return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new); + } + return Mono.empty(); + }); + }); + holder.before(((ReactiveRepository) repo) + .createQuery() + .setParam(dslUpdate.toQueryParam()) + .fetch() + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> { + deleted.set(list); + return this + .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); + }) + ); + }); + } else if (repo instanceof SyncRepository) { + QueryParam param = dslUpdate.toQueryParam(); + SyncRepository syncRepository = ((SyncRepository) repo); + List list = syncRepository.createQuery() + .setParam(param) + .fetch(); + this.sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new) + .block(); + } + }); } protected void handleUpdateAfter(EventContext context) { } - protected void handleBatchOperation(Class clazz, EventContext context, BiFunction, Class, AsyncEvent> mapper) { + protected void handleBatchOperation(Class clazz, EventContext context, + BiFunction, Class, AsyncEvent> before, + BiFunction, Class, AsyncEvent> after) { context.get(MappingContextKeys.instance) - .filter(List.class::isInstance) - .map(List.class::cast) - .ifPresent(lst -> { - AsyncEvent event = mapper.apply(lst, clazz); - Object repo = context.get(MappingContextKeys.repository).orElse(null); - if (repo instanceof ReactiveRepository) { - Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); - if (resultHolder.isPresent()) { - resultHolder - .get() - .after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz)); - return event.getAsync(); - }); - return; - } - } - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz)); - //block非响应式的支持 - event.getAsync().block(); - }); + .filter(List.class::isInstance) + .map(List.class::cast) + .ifPresent(lst -> { + AsyncEvent afterEvent = after.apply(lst, clazz); + AsyncEvent beforeEvent = before.apply(lst, clazz); + Object repo = context.get(MappingContextKeys.repository).orElse(null); + if (repo instanceof ReactiveRepository) { + Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); + if (resultHolder.isPresent()) { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + ReactiveResultHolder holder = resultHolder.get(); + if (null != beforeEvent) { + holder.before(beforeEvent.publish(eventPublisher)); + } + holder.after(v -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); + return; + } + } + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + //block非响应式的支持 + afterEvent.getAsync().block(); + }); } - protected void handleSingleOperation(Class clazz, EventContext context, BiFunction, Class, AsyncEvent> mapper) { + protected void handleSingleOperation(Class clazz, + EventContext context, + BiFunction, Class, AsyncEvent> before, + BiFunction, Class, AsyncEvent> after) { context.get(MappingContextKeys.instance) - .filter(Entity.class::isInstance) - .map(Entity.class::cast) - .ifPresent(entity -> { - AsyncEvent event = mapper.apply(Collections.singletonList(entity), clazz); - Object repo = context.get(MappingContextKeys.repository).orElse(null); - if (repo instanceof ReactiveRepository) { - Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); - if (resultHolder.isPresent()) { - resultHolder - .get() - .after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz)); - return event.getAsync(); - }); - return; - } - } - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz)); - //block非响应式的支持 - event.getAsync().block(); - }); + .filter(Entity.class::isInstance) + .map(Entity.class::cast) + .ifPresent(entity -> { + AsyncEvent afterEvent = after.apply(Collections.singletonList(entity), clazz); + AsyncEvent beforeEvent = before.apply(Collections.singletonList(entity), clazz); + Object repo = context.get(MappingContextKeys.repository).orElse(null); + if (repo instanceof ReactiveRepository) { + Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); + if (resultHolder.isPresent()) { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + ReactiveResultHolder holder = resultHolder.get(); + if (null != beforeEvent) { + holder.before(beforeEvent.publish(eventPublisher)); + } + holder.after(v -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); + return; + } + } + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + //block非响应式的支持 + afterEvent.getAsync().block(); + }); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java index 1dd916aae..6a636ec64 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java @@ -50,19 +50,32 @@ public void test() { @Test public void testInsertBatch() { + reactiveRepository.createQuery() + .where(EventTestEntity::getId,"test") + .fetch() + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + Assert.assertEquals(listener.beforeQuery.getAndSet(0), 1); + + Flux.just(EventTestEntity.of("test2", 1), EventTestEntity.of("test3", 2)) .as(reactiveRepository::insert) .as(StepVerifier::create) .expectNext(2) .verifyComplete(); Assert.assertEquals(listener.created.getAndSet(0), 2); + Assert.assertEquals(listener.beforeCreate.getAndSet(0), 2); - reactiveRepository.createUpdate().set("age",3).where().in("name","test2","test3").execute() + reactiveRepository + .createUpdate().set("age",3).where().in("name","test2","test3").execute() .as(StepVerifier::create) .expectNext(2) .verifyComplete(); Assert.assertEquals(listener.modified.getAndSet(0), 2); + Assert.assertEquals(listener.beforeModify.getAndSet(0), 2); reactiveRepository.createDelete().where().in("name","test2","test3").execute() .as(StepVerifier::create) @@ -70,6 +83,7 @@ public void testInsertBatch() { .verifyComplete(); Assert.assertEquals(listener.deleted.getAndSet(0), 2); + Assert.assertEquals(listener.beforeDelete.getAndSet(0), 2); reactiveRepository.save(EventTestEntity.of("test2", 1)) .then() @@ -78,6 +92,9 @@ public void testInsertBatch() { .verify(); Assert.assertEquals(listener.saved.getAndSet(0), 1); + Assert.assertEquals(listener.beforeSave.getAndSet(0), 1); + + } diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/TestEntityListener.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/TestEntityListener.java index 05e3be01f..d141667d7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/TestEntityListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/TestEntityListener.java @@ -11,12 +11,57 @@ @Component public class TestEntityListener { + AtomicInteger beforeCreate = new AtomicInteger(); + AtomicInteger beforeDelete = new AtomicInteger(); AtomicInteger created = new AtomicInteger(); AtomicInteger deleted = new AtomicInteger(); AtomicInteger modified = new AtomicInteger(); + AtomicInteger beforeModify = new AtomicInteger(); AtomicInteger saved = new AtomicInteger(); + AtomicInteger beforeSave = new AtomicInteger(); + AtomicInteger beforeQuery = new AtomicInteger(); + + @EventListener + public void handleBeforeQuery(EntityBeforeQueryEvent event){ + event.async(Mono.fromRunnable(() -> { + System.out.println(event); + beforeQuery.addAndGet(1); + })); + } + + @EventListener + public void handleBeforeSave(EntityBeforeSaveEvent event) { + event.async(Mono.fromRunnable(() -> { + System.out.println(event); + beforeSave.addAndGet(event.getEntity().size()); + })); + } + + @EventListener + public void handleBeforeDelete(EntityBeforeModifyEvent event) { + event.async(Mono.fromRunnable(() -> { + System.out.println(event); + beforeModify.addAndGet(event.getBefore().size()); + })); + } + + @EventListener + public void handleBeforeDelete(EntityBeforeDeleteEvent event) { + event.async(Mono.fromRunnable(() -> { + System.out.println(event); + beforeDelete.addAndGet(event.getEntity().size()); + })); + } + + @EventListener + public void handleBeforeCreated(EntityBeforeCreateEvent event) { + event.async(Mono.fromRunnable(() -> { + System.out.println(event); + beforeCreate.addAndGet(event.getEntity().size()); + })); + } @EventListener public void handleCreated(EntityCreatedEvent event) { diff --git a/pom.xml b/pom.xml index 85abff372..4f07bd296 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ pom hsweb framework - http://www.hswebframework.org + https://github.com/hs-web 2016 hsweb (haʊs wɛb) 是一个用于快速搭建企业后台管理系统的基础项目,集成一揽子便捷功能如:通用增删改查,在线代码生成,权限管理(可控制到列和行),动态多数据源分布式事务,动态脚本,动态定时任务,在线数据库维护等等 @@ -48,7 +48,7 @@ The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt + https://www.apache.org/licenses/LICENSE-2.0.txt @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.11 + 4.0.12-SNAPSHOT 3.0.2 3.0.2 2.7.0 From 0658d64f18023767cb8625218d9cb13a083ff447 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 3 Sep 2021 18:18:19 +0800 Subject: [PATCH 105/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0hasListener=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/event/DefaultAsyncEvent.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index 045c54c02..36f30afb9 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -10,7 +10,10 @@ public class DefaultAsyncEvent implements AsyncEvent { @Getter private Mono async = Mono.empty(); + private boolean hasListener; + public synchronized void async(Publisher publisher) { + hasListener = true; this.async = async.then(Mono.from(publisher).then()); } @@ -21,4 +24,8 @@ public Mono publish(ApplicationEventPublisher eventPublisher) { return this.async; } + + public boolean hasListener() { + return hasListener; + } } From 470c1a0722cf4f668d7154ce0f5ac9a28e338735 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 7 Sep 2021 11:21:06 +0800 Subject: [PATCH 106/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0DimensionManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/DimensionProvider.java | 45 ++++++- .../dimension/DimensionManager.java | 25 ++++ .../dimension/DimensionUserBind.java | 19 +++ .../dimension/DimensionUserBindProvider.java | 11 ++ .../dimension/DimensionUserDetail.java | 33 +++++ ...DefaultAuthorizationAutoConfiguration.java | 14 +++ .../simple/DefaultDimensionManager.java | 90 ++++++++++++++ .../service/DefaultDimensionService.java | 114 +++++++++++------- 8 files changed, 305 insertions(+), 46 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionManager.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBind.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBindProvider.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserDetail.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultDimensionManager.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java index ac8cecf7b..41b6ea01f 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java @@ -3,14 +3,57 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Collection; + +/** + * 维度提供商,用户管理维度信息 + * + * @author zhouhao + * @since 4.0 + */ public interface DimensionProvider { + /** + * 获取全部支持的维度 + * + * @return 全部支持的维度 + */ Flux getAllType(); + /** + * 获取用户获取维度信息 + * + * @param userId 用户ID + * @return 维度列表 + */ Flux getDimensionByUserId(String userId); + /** + * 根据维度类型和ID获取维度信息 + * + * @param type 类型 + * @param id ID + * @return 维度信息 + */ Mono getDimensionById(DimensionType type, String id); - Flux getUserIdByDimensionId(String dimensionId); + /** + * 根据维度类型和Id获取多个维度 + * @param type 类型 + * @param idList ID + * @return 维度信息 + */ + default Flux getDimensionsById(DimensionType type, Collection idList){ + return Flux + .fromIterable(idList) + .flatMap(id->this.getDimensionById(type,id)); + } + /** + * 根据维度ID获取用户ID + * + * @param dimensionId 维度ID + * @return 用户ID + */ + Flux getUserIdByDimensionId(String dimensionId); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionManager.java new file mode 100644 index 000000000..5837635db --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionManager.java @@ -0,0 +1,25 @@ +package org.hswebframework.web.authorization.dimension; + +import reactor.core.publisher.Flux; + +import java.util.Collection; + +/** + * 维度管理器 + * + * @author zhouhao + * @since 4.0.12 + */ +public interface DimensionManager { + + /** + * 获取用户维度 + * + * @param type 维度类型 + * @param userId 用户ID + * @return 用户维度信息 + */ + Flux getUserDimension(Collection userId); + + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBind.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBind.java new file mode 100644 index 000000000..f1f81bdd9 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBind.java @@ -0,0 +1,19 @@ +package org.hswebframework.web.authorization.dimension; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor(staticName = "of") +@NoArgsConstructor +public class DimensionUserBind { + private String userId; + + private String dimensionType; + + private String dimensionId; + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBindProvider.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBindProvider.java new file mode 100644 index 000000000..eb0602673 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBindProvider.java @@ -0,0 +1,11 @@ +package org.hswebframework.web.authorization.dimension; + +import reactor.core.publisher.Flux; + +import java.util.Collection; + +public interface DimensionUserBindProvider { + + Flux getDimensionBindInfo(Collection userIdList); + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserDetail.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserDetail.java new file mode 100644 index 000000000..02fe2fe9e --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserDetail.java @@ -0,0 +1,33 @@ +package org.hswebframework.web.authorization.dimension; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hswebframework.web.authorization.Dimension; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor(staticName = "of") +@NoArgsConstructor +public class DimensionUserDetail { + private String userId; + + private List dimensions; + + public DimensionUserDetail merge(DimensionUserDetail detail) { + DimensionUserDetail newDetail = new DimensionUserDetail(); + newDetail.setUserId(userId); + newDetail.setDimensions(new ArrayList<>()); + if (null != dimensions) { + newDetail.dimensions.addAll(dimensions); + } + if (null != detail.getDimensions()) { + newDetail.dimensions.addAll(detail.getDimensions()); + } + return newDetail; + } +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java index 229ef8c50..66fadf24e 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java @@ -3,6 +3,8 @@ import org.hswebframework.web.authorization.*; import org.hswebframework.web.authorization.builder.AuthenticationBuilderFactory; import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; +import org.hswebframework.web.authorization.dimension.DimensionManager; +import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider; import org.hswebframework.web.authorization.simple.builder.DataAccessConfigConverter; import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilderFactory; import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory; @@ -10,6 +12,7 @@ import org.hswebframework.web.authorization.twofactor.TwoFactorValidatorManager; import org.hswebframework.web.authorization.twofactor.defaults.DefaultTwoFactorValidatorManager; import org.hswebframework.web.convert.CustomMessageConverter; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -100,4 +103,15 @@ public Object convert(Class clazz, byte[] message) { } }; } + + @Bean + @ConditionalOnMissingBean(DimensionManager.class) + public DimensionManager defaultDimensionManager(ObjectProviderbindProviders, + ObjectProvider providers){ + DefaultDimensionManager manager = new DefaultDimensionManager(); + bindProviders.forEach(manager::addBindProvider); + providers.forEach(manager::addProvider); + + return manager; + } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultDimensionManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultDimensionManager.java new file mode 100644 index 000000000..25f842c19 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultDimensionManager.java @@ -0,0 +1,90 @@ +package org.hswebframework.web.authorization.simple; + +import org.hswebframework.web.authorization.Dimension; +import org.hswebframework.web.authorization.DimensionProvider; +import org.hswebframework.web.authorization.dimension.DimensionManager; +import org.hswebframework.web.authorization.dimension.DimensionUserBind; +import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider; +import org.hswebframework.web.authorization.dimension.DimensionUserDetail; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; + +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class DefaultDimensionManager implements DimensionManager { + + private final List dimensionProviders = new CopyOnWriteArrayList<>(); + private final List bindProviders = new CopyOnWriteArrayList<>(); + + private final Mono> providerMapping = Flux + .defer(() -> Flux.fromIterable(dimensionProviders)) + .flatMap(provider -> provider + .getAllType() + .map(type -> Tuples.of(type.getId(), provider))) + .collectMap(Tuple2::getT1, Tuple2::getT2); + + public DefaultDimensionManager() { + + } + + public void addProvider(DimensionProvider provider) { + dimensionProviders.add(provider); + } + + public void addBindProvider(DimensionUserBindProvider bindProvider) { + bindProviders.add(bindProvider); + } + + private Mono> providerMapping() { + return providerMapping; + } + + @Override + public Flux getUserDimension(Collection userId) { + return this + .providerMapping() + .flatMapMany(providerMapping -> Flux + .fromIterable(bindProviders) + //获取绑定信息 + .flatMap(provider -> provider.getDimensionBindInfo(userId)) + .groupBy(DimensionUserBind::getDimensionType) + .flatMap(group -> { + String type = String.valueOf(group.key()); + Flux binds = group.cache(); + DimensionProvider provider = providerMapping.get(type); + if (null == provider) { + return Mono.empty(); + } + //获取维度信息 + return binds + .map(DimensionUserBind::getDimensionId) + .collect(Collectors.toSet()) + .flatMapMany(idList -> provider.getDimensionsById(SimpleDimensionType.of(type), idList)) + .collectMap(Dimension::getId, Function.identity()) + .flatMapMany(mapping -> binds + .groupBy(DimensionUserBind::getUserId) + .flatMap(userGroup -> Mono + .zip( + Mono.just(String.valueOf(userGroup.key())), + userGroup + .handle((bind, sink) -> { + Dimension dimension = mapping.get(bind.getDimensionId()); + if (dimension != null) { + sink.next(dimension); + } + }) + .collectList(), + DimensionUserDetail::of + )) + ); + }) + ) + .groupBy(DimensionUserDetail::getUserId) + .flatMap(group->group.reduce(DimensionUserDetail::merge)); + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java index 0487cd38f..bd702d177 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java @@ -1,6 +1,10 @@ package org.hswebframework.web.system.authorization.defaults.service; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; +import org.apache.commons.collections4.multimap.HashSetValuedHashMap; import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate; @@ -8,6 +12,8 @@ import org.hswebframework.web.authorization.Dimension; import org.hswebframework.web.authorization.DimensionProvider; import org.hswebframework.web.authorization.DimensionType; +import org.hswebframework.web.authorization.dimension.DimensionUserBind; +import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider; import org.hswebframework.web.crud.service.GenericReactiveCrudService; import org.hswebframework.web.crud.service.GenericReactiveTreeSupportCrudService; import org.hswebframework.web.crud.service.ReactiveCrudService; @@ -24,14 +30,14 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.List; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; public class DefaultDimensionService extends GenericReactiveTreeSupportCrudService implements - DimensionProvider { + DimensionProvider, DimensionUserBindProvider { @Autowired private ReactiveRepository dimensionUserRepository; @@ -64,39 +70,56 @@ public Flux getAllType() { @Override public Mono getDimensionById(DimensionType type, String id) { - return createQuery() - .where(DimensionEntity::getId,id) + .where(DimensionEntity::getId, id) .fetch() .singleOrEmpty() - .map(entity-> DynamicDimension.of(entity, type)); + .map(entity -> DynamicDimension.of(entity, type)); + } + + @Override + public Flux getDimensionsById(DimensionType type, Collection idList) { + return this.createQuery() + .where(DimensionEntity::getTypeId, type.getId()) + .in(DimensionEntity::getId, idList) + .fetch() + .map(entity -> DynamicDimension.of(entity, type)); } @Override public Flux getDimensionByUserId(String userId) { return getAllType() .collect(Collectors.toMap(DimensionType::getId, Function.identity())) - .flatMapMany(typeGrouping -> - dimensionUserRepository - .createQuery() - .where(DimensionUserEntity::getUserId, userId) - .fetch() - .collectList() - .filter(CollectionUtils::isNotEmpty) - .flatMapMany(list -> { - //查询所有的维度 - return this.queryIncludeChildren(list.stream() - .map(DimensionUserEntity::getDimensionId) - .collect(Collectors.toSet())) - .filter(dimension -> typeGrouping.containsKey(dimension.getTypeId())) - .map(dimension -> - DynamicDimension.of(dimension, typeGrouping.get(dimension.getTypeId())) - ); - - }) + .flatMapMany(typeGrouping -> dimensionUserRepository + .createQuery() + .where(DimensionUserEntity::getUserId, userId) + .fetch() + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMapMany(list -> { + //查询所有的维度 + return this + .queryIncludeChildren(list.stream() + .map(DimensionUserEntity::getDimensionId) + .collect(Collectors.toSet())) + .filter(dimension -> typeGrouping.containsKey(dimension.getTypeId())) + .map(dimension -> + DynamicDimension.of(dimension, typeGrouping.get(dimension.getTypeId())) + ); + + }) ); } + @Override + public Flux getDimensionBindInfo(Collection userIdList) { + return dimensionUserRepository + .createQuery() + .in(DimensionUserEntity::getUserId, userIdList) + .fetch() + .map(entity -> DimensionUserBind.of(entity.getUserId(), entity.getDimensionTypeId(), entity.getDimensionId())); + } + @Override @SuppressWarnings("all") public Flux getUserIdByDimensionId(String dimensionId) { @@ -111,49 +134,50 @@ public Flux getUserIdByDimensionId(String dimensionId) { @Override public Mono save(Publisher entityPublisher) { return super.save(entityPublisher) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); + .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); } @Override public Mono updateById(String id, Mono entityPublisher) { return super.updateById(id, entityPublisher) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); + .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); } @Override public ReactiveUpdate createUpdate() { return super.createUpdate() - .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); + .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); } @Override public ReactiveDelete createDelete() { return super.createDelete() - .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); + .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); } @Override public Mono deleteById(Publisher idPublisher) { return Flux.from(idPublisher) - .collectList() - .flatMap(list -> super.queryIncludeChildren(list) - .flatMap(dimension -> dimensionUserRepository.createDelete() //删除维度用户关联 - .where() - .is(DimensionUserEntity::getDimensionId, dimension.getId()) - .execute() - .then(getRepository().deleteById(Mono.just(dimension.getId()))) - .thenReturn(dimension) - ) - .groupBy(DimensionEntity::getTypeId, DimensionEntity::getId)//按维度类型分组 - .flatMap(grouping -> grouping.collectList() - .flatMap(dimensionId -> settingRepository //删除权限设置 - .createDelete() - .where(AuthorizationSettingEntity::getDimensionType, grouping.key()) - .in(AuthorizationSettingEntity::getDimensionTarget, dimensionId).execute())) - .collect(Collectors.summarizingInt(Integer::intValue)) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())) - .thenReturn(list.size())); + .collectList() + .flatMap(list -> super.queryIncludeChildren(list) + .flatMap(dimension -> dimensionUserRepository.createDelete() //删除维度用户关联 + .where() + .is(DimensionUserEntity::getDimensionId, dimension.getId()) + .execute() + .then(getRepository().deleteById(Mono.just(dimension.getId()))) + .thenReturn(dimension) + ) + .groupBy(DimensionEntity::getTypeId, DimensionEntity::getId)//按维度类型分组 + .flatMap(grouping -> grouping.collectList() + .flatMap(dimensionId -> settingRepository //删除权限设置 + .createDelete() + .where(AuthorizationSettingEntity::getDimensionType, grouping.key()) + .in(AuthorizationSettingEntity::getDimensionTarget, dimensionId) + .execute())) + .collect(Collectors.summarizingInt(Integer::intValue)) + .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())) + .thenReturn(list.size())); } } From 7395e6fb1f911fe4e16d835bb2d57e16919949e8 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 8 Sep 2021 18:32:55 +0800 Subject: [PATCH 107/542] =?UTF-8?q?=E4=BC=98=E5=8C=96jsr303=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/configuration/AutoDDLProcessor.java | 16 +++++----------- .../web/crud/events/EntityDDLEvent.java | 15 ++++++++++----- .../web/crud/events/ValidateEventListener.java | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) 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 8cdc3a765..ce99ab329 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 @@ -8,24 +8,18 @@ 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.hswebframework.web.crud.events.EntityBeforeQueryEvent; import org.hswebframework.web.crud.events.EntityDDLEvent; import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.transaction.ReactiveTransactionManager; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; import java.time.Duration; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @Getter @@ -69,7 +63,7 @@ public void afterPropertiesSet() { .doOnNext(type -> log.trace("auto ddl for {}", type)) .map(type -> { RDBTableMetadata metadata = resolver.resolve(type); - EntityDDLEvent event = new EntityDDLEvent(type,metadata); + EntityDDLEvent event = new EntityDDLEvent(this,type,metadata); eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); return metadata; }) @@ -89,7 +83,7 @@ public void afterPropertiesSet() { log.trace("auto ddl for {}", type); try { RDBTableMetadata metadata = resolver.resolve(type); - EntityDDLEvent event = new EntityDDLEvent(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/events/EntityDDLEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java index 25dcfefcc..3711a620c 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java @@ -1,13 +1,18 @@ package org.hswebframework.web.crud.events; -import lombok.AllArgsConstructor; import lombok.Getter; import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.springframework.context.ApplicationEvent; -@AllArgsConstructor @Getter -public class EntityDDLEvent { - private Class type; +public class EntityDDLEvent extends ApplicationEvent { + private final Class type; - private RDBTableMetadata table; + private final RDBTableMetadata table; + + public EntityDDLEvent(Object source,Class type,RDBTableMetadata table) { + super(source); + this.type=type; + this.table=table; + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 96b292136..be7e1fb00 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -34,7 +34,7 @@ public void onEvent(EventType type, EventContext context) { if (resultHolder.isPresent()) { resultHolder .ifPresent(holder -> holder - .before(LocaleUtils + .invoke(LocaleUtils .currentReactive() .doOnNext(locale -> LocaleUtils.doWith(locale, (l) -> tryValidate(type, context))) .then() From da89ab202f04b3f5e7536947291a5955313d0c1a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 9 Sep 2021 16:21:19 +0800 Subject: [PATCH 108/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=8F=AF=E9=85=8D=E7=BD=AE=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/annotation/EnableEntityEvent.java | 11 + .../configuration/EasyormConfiguration.java | 14 +- .../DefaultEntityEventListenerConfigure.java | 105 +++++++ .../web/crud/events/EntityEventListener.java | 274 ++++++++++++------ .../events/EntityEventListenerConfigure.java | 73 +++++ .../events/EntityEventListenerCustomizer.java | 18 ++ .../web/crud/events/EntityEventPhase.java | 9 + .../web/crud/events/EntityEventType.java | 8 + .../crud/events/EntityPrepareCreateEvent.java | 21 ++ .../crud/events/EntityPrepareModifyEvent.java | 26 ++ .../crud/events/EntityPrepareSaveEvent.java | 21 ++ ...faultEntityEventListenerConfigureTest.java | 23 ++ 12 files changed, 508 insertions(+), 95 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigure.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerConfigure.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerCustomizer.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventPhase.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventType.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareCreateEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareModifyEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareSaveEvent.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigureTest.java diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java index 99153e203..e153b10ab 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java @@ -1,7 +1,11 @@ package org.hswebframework.web.crud.annotation; +import org.hswebframework.web.crud.events.EntityEventType; + import java.lang.annotation.*; +//import static org.hswebframework.web.crud.annotation.EnableEntityEvent.Feature.*; + /** * 在实体类上添加此注解,表示开启实体操作事件,当实体类发生类修改,更新,删除等操作时,会触发事件。 * 可以通过spring event监听事件: @@ -31,4 +35,11 @@ @Documented public @interface EnableEntityEvent { + EntityEventType[] value() default { + EntityEventType.create, + EntityEventType.delete, + EntityEventType.modify, + EntityEventType.save + }; + } 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 5287f17d2..107f16be7 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 @@ -19,9 +19,7 @@ import org.hswebframework.web.crud.annotation.EnableEasyormRepository; import org.hswebframework.web.crud.entity.factory.EntityMappingCustomizer; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; -import org.hswebframework.web.crud.events.CompositeEventListener; -import org.hswebframework.web.crud.events.EntityEventListener; -import org.hswebframework.web.crud.events.ValidateEventListener; +import org.hswebframework.web.crud.events.*; import org.hswebframework.web.crud.generator.CurrentTimeGenerator; import org.hswebframework.web.crud.generator.DefaultIdGenerator; import org.hswebframework.web.crud.generator.MD5Generator; @@ -33,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -55,7 +54,7 @@ public class EasyormConfiguration { @Bean @ConditionalOnMissingBean public EntityFactory entityFactory(ObjectProvider customizers) { - MapperEntityFactory factory= new MapperEntityFactory(); + MapperEntityFactory factory = new MapperEntityFactory(); for (EntityMappingCustomizer customizer : customizers) { customizer.custom(factory); } @@ -149,8 +148,11 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw } @Bean - public EntityEventListener entityEventListener() { - return new EntityEventListener(); + public EntityEventListener entityEventListener(ApplicationEventPublisher eventPublisher, + ObjectProvider customizers) { + DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); + customizers.forEach(customizer -> customizer.customize(configure)); + return new EntityEventListener(eventPublisher, configure); } @Bean diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigure.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigure.java new file mode 100644 index 000000000..04a6460b6 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigure.java @@ -0,0 +1,105 @@ +package org.hswebframework.web.crud.events; + +import org.apache.commons.collections4.MapUtils; +import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; +import org.springframework.core.annotation.AnnotatedElementUtils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class DefaultEntityEventListenerConfigure implements EntityEventListenerConfigure { + + private final Map, Map>> enabledFeatures = new ConcurrentHashMap<>(); + private final Map, Map>> disabledFeatures = new ConcurrentHashMap<>(); + + @Override + public void enable(Class entityType) { + initByEntity(entityType, getOrCreateTypeMap(entityType, enabledFeatures), true); + } + + @Override + public void disable(Class entityType) { + enabledFeatures.remove(entityType); + initByEntity(entityType, getOrCreateTypeMap(entityType, disabledFeatures), true); + } + + @Override + public void enable(Class entityType, EntityEventType type, EntityEventPhase... feature) { + if (feature.length == 0) { + feature = EntityEventPhase.all; + } + getOrCreatePhaseSet(type, getOrCreateTypeMap(entityType, enabledFeatures)) + .addAll(Arrays.asList(feature)); + + //删除disabled + Arrays.asList(feature) + .forEach(getOrCreatePhaseSet(type, getOrCreateTypeMap(entityType, disabledFeatures))::remove); + } + + @Override + public void disable(Class entityType, EntityEventType type, EntityEventPhase... feature) { + if (feature.length == 0) { + feature = EntityEventPhase.all; + } + getOrCreatePhaseSet(type, getOrCreateTypeMap(entityType, disabledFeatures)) + .addAll(Arrays.asList(feature)); + //删除enabled + Arrays.asList(feature) + .forEach(getOrCreatePhaseSet(type, getOrCreateTypeMap(entityType, enabledFeatures))::remove); + } + + protected Map> getOrCreateTypeMap(Class type, + Map, Map>> map) { + return map.computeIfAbsent(type, ignore -> new EnumMap<>(EntityEventType.class)); + } + + protected Set getOrCreatePhaseSet(EntityEventType type, + Map> map) { + return map.computeIfAbsent(type, ignore -> EnumSet.noneOf(EntityEventPhase.class)); + } + + protected void initByEntity(Class type, + Map> typeSetMap, + boolean all) { + EnableEntityEvent annotation = AnnotatedElementUtils.findMergedAnnotation(type, EnableEntityEvent.class); + EntityEventType[] types = annotation != null ? annotation.value() : all ? EntityEventType.values() : new EntityEventType[0]; + + for (EntityEventType entityEventType : types) { + Set phases = getOrCreatePhaseSet(entityEventType, typeSetMap); + phases.addAll(Arrays.asList(EntityEventPhase.values())); + } + } + + @Override + public boolean isEnabled(Class entityType) { + if (!enabledFeatures.containsKey(entityType)) { + initByEntity(entityType, getOrCreateTypeMap(entityType, enabledFeatures), false); + } + return MapUtils.isNotEmpty(enabledFeatures.get(entityType)); + } + + @Override + public boolean isEnabled(Class entityType, + EntityEventType type, + EntityEventPhase phase) { + if (!enabledFeatures.containsKey(entityType)) { + initByEntity(entityType, getOrCreateTypeMap(entityType, enabledFeatures), false); + } + Map> enabled = enabledFeatures.get(entityType); + if (MapUtils.isEmpty(enabled)) { + return false; + } + Map> disabled = disabledFeatures.get(entityType); + Set phases = enabled.get(type); + if (phases != null && phases.contains(phase)) { + if (disabled != null) { + Set disabledPhases = disabled.get(type); + return disabledPhases == null || !disabledPhases.contains(phase); + } + return true; + } + + return false; + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index a50eca7c7..825b09ac7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -1,9 +1,11 @@ package org.hswebframework.web.crud.events; +import lombok.AllArgsConstructor; import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.core.param.QueryParam; import org.hswebframework.ezorm.rdb.events.*; +import org.hswebframework.ezorm.rdb.events.EventType; import org.hswebframework.ezorm.rdb.mapping.*; import org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys; import org.hswebframework.ezorm.rdb.mapping.events.MappingEventTypes; @@ -31,10 +33,12 @@ import java.util.function.BiFunction; @SuppressWarnings("all") +@AllArgsConstructor public class EntityEventListener implements EventListener { - @Autowired - ApplicationEventPublisher eventPublisher; + private final ApplicationEventPublisher eventPublisher; + + private final EntityEventListenerConfigure listenerConfigure; @Override public String getId() { @@ -53,36 +57,59 @@ public void onEvent(EventType type, EventContext context) { return; } EntityColumnMapping mapping = context.get(MappingContextKeys.columnMapping).orElse(null); + Class entityType; + if (mapping == null || - !Entity.class.isAssignableFrom(mapping.getEntityType()) || - mapping.getEntityType().getAnnotation(EnableEntityEvent.class) == null) { + !Entity.class.isAssignableFrom(entityType = (Class) mapping.getEntityType()) || + !listenerConfigure.isEnabled(entityType)) { return; } + if (type == MappingEventTypes.select_before) { handleQueryBefore(mapping, context); } if (type == MappingEventTypes.insert_before) { boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false); if (single) { - handleSingleOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new); + handleSingleOperation(mapping.getEntityType(), + EntityEventType.create, + context, + EntityPrepareCreateEvent::new, + EntityBeforeCreateEvent::new, + EntityCreatedEvent::new); } else { - handleBatchOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new); + handleBatchOperation(mapping.getEntityType(), + EntityEventType.save, + context, + EntityPrepareSaveEvent::new, + EntityBeforeCreateEvent::new, + EntityCreatedEvent::new); } } if (type == MappingEventTypes.save_before) { boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false); if (single) { - handleSingleOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new); + handleSingleOperation(mapping.getEntityType(), + EntityEventType.save, + context, + + EntityPrepareSaveEvent::new, + EntityBeforeSaveEvent::new, + EntitySavedEvent::new); } else { - handleBatchOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new); + handleBatchOperation(mapping.getEntityType(), + EntityEventType.save, + context, + EntityPrepareSaveEvent::new, + EntityBeforeSaveEvent::new, + EntitySavedEvent::new); } } if (type == MappingEventTypes.update_before) { handleUpdateBefore(context); } - if (type == MappingEventTypes.delete_before) { - handleDeleteBefore(context); + handleDeleteBefore(entityType, context); } } @@ -123,12 +150,13 @@ protected List createAfterData(List olds, .filter(Entity.class::isInstance) .map(Entity.class::cast) .orElseGet(() -> { - return context.get(MappingContextKeys.updateColumnInstance) - .map(map -> { - return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); - }) - .map(Entity.class::cast) - .orElse(null); + return context + .get(MappingContextKeys.updateColumnInstance) + .map(map -> { + return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); + }) + .map(Entity.class::cast) + .orElse(null); }); if (newValue != null) { FastBeanCopier.copy(old, newValue, FastBeanCopier.include(idColumn.getAlias())); @@ -162,51 +190,81 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) EntityColumnMapping mapping = context .get(MappingContextKeys.columnMapping) .orElseThrow(UnsupportedOperationException::new); - + Class entityType = (Class) mapping.getEntityType(); if (repo instanceof ReactiveRepository) { context.get(MappingContextKeys.reactiveResultHolder) .ifPresent(holder -> { AtomicReference, List>> updated = new AtomicReference<>(); + //prepare + if (isEnabled(entityType, + EntityEventType.modify, + EntityEventPhase.prepare, + EntityEventPhase.before, + EntityEventPhase.after)) { + holder.before( + ((ReactiveRepository) repo) + .createQuery() + .setParam(update.toQueryParam()) + .fetch() + .collectList() + .flatMap((list) -> { + List after = createAfterData(list, context); + updated.set(Tuples.of(list, after)); + return sendUpdateEvent(list, + after, + entityType, + EntityPrepareModifyEvent::new); - holder.after(v -> { - return Mono.defer(() -> { - Tuple2, List> _tmp = updated.getAndSet(null); + }) + .then() + ); + } + //before + if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.before)) { + holder.invoke(Mono.defer(() -> { + Tuple2, List> _tmp = updated.get(); if (_tmp != null) { - return sendUpdateEvent(_tmp.getT1(), _tmp.getT2(), (Class) mapping.getEntityType(), EntityModifyEvent::new); + return sendUpdateEvent(_tmp.getT1(), + _tmp.getT2(), + entityType, + EntityBeforeModifyEvent::new); } return Mono.empty(); + })); + } + + //after + if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.after)) { + holder.after(v -> { + return Mono + .defer(() -> { + Tuple2, List> _tmp = updated.getAndSet(null); + if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), + _tmp.getT2(), + entityType, + EntityModifyEvent::new); + } + return Mono.empty(); + }); }); - }); - - holder.before( - ((ReactiveRepository) repo) - .createQuery() - .setParam(update.toQueryParam()) - .fetch() - .collectList() - .flatMap((list) -> { - List after = createAfterData(list, context); - updated.set(Tuples.of(list, after)); - return sendUpdateEvent(list, - after, - (Class) mapping.getEntityType(), - EntityBeforeModifyEvent::new); - - }) - .then() - ); + } + }); } else if (repo instanceof SyncRepository) { - QueryParam param = update.toQueryParam(); - SyncRepository syncRepository = ((SyncRepository) repo); - List list = syncRepository.createQuery() - .setParam(param) - .fetch(); - sendUpdateEvent(list, - createAfterData(list, context), - (Class) mapping.getEntityType(), - EntityBeforeModifyEvent::new).block(); + if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.before)) { + QueryParam param = update.toQueryParam(); + SyncRepository syncRepository = ((SyncRepository) repo); + List list = syncRepository.createQuery() + .setParam(param) + .fetch(); + sendUpdateEvent(list, + createAfterData(list, context), + (Class) mapping.getEntityType(), + EntityBeforeModifyEvent::new) + .block(); + } } } @@ -218,7 +276,7 @@ protected void handleUpdateBefore(EventContext context) { } - protected void handleDeleteBefore(EventContext context) { + protected void handleDeleteBefore(Class entityType, EventContext context) { EntityColumnMapping mapping = context .get(MappingContextKeys.columnMapping) .orElseThrow(UnsupportedOperationException::new); @@ -229,28 +287,33 @@ protected void handleDeleteBefore(EventContext context) { context.get(MappingContextKeys.reactiveResultHolder) .ifPresent(holder -> { AtomicReference> deleted = new AtomicReference<>(); - holder.after(v -> { - return Mono - .defer(() -> { - List _tmp = deleted.getAndSet(null); - if (CollectionUtils.isNotEmpty(_tmp)) { - return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new); - } - return Mono.empty(); - }); - }); - holder.before(((ReactiveRepository) repo) - .createQuery() - .setParam(dslUpdate.toQueryParam()) - .fetch() - .collectList() - .filter(CollectionUtils::isNotEmpty) - .flatMap(list -> { - deleted.set(list); - return this - .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); - }) - ); + if (isEnabled(entityType, EntityEventType.delete, EntityEventPhase.before, EntityEventPhase.after)) { + holder.before(((ReactiveRepository) repo) + .createQuery() + .setParam(dslUpdate.toQueryParam()) + .fetch() + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> { + deleted.set(list); + return this + .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); + }) + ); + } + if (isEnabled(entityType, EntityEventType.delete, EntityEventPhase.after)) { + holder.after(v -> { + return Mono + .defer(() -> { + List _tmp = deleted.getAndSet(null); + if (CollectionUtils.isNotEmpty(_tmp)) { + return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new); + } + return Mono.empty(); + }); + }); + } + }); } else if (repo instanceof SyncRepository) { QueryParam param = dslUpdate.toQueryParam(); @@ -268,29 +331,41 @@ protected void handleUpdateAfter(EventContext context) { } - protected void handleBatchOperation(Class clazz, EventContext context, + protected void handleBatchOperation(Class clazz, + EntityEventType entityEventType, + EventContext context, BiFunction, Class, AsyncEvent> before, + BiFunction, Class, AsyncEvent> execute, BiFunction, Class, AsyncEvent> after) { context.get(MappingContextKeys.instance) .filter(List.class::isInstance) .map(List.class::cast) .ifPresent(lst -> { + AsyncEvent prepareEvent = before.apply(lst, clazz); AsyncEvent afterEvent = after.apply(lst, clazz); - AsyncEvent beforeEvent = before.apply(lst, clazz); + AsyncEvent beforeEvent = execute.apply(lst, clazz); Object repo = context.get(MappingContextKeys.repository).orElse(null); if (repo instanceof ReactiveRepository) { Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); if (resultHolder.isPresent()) { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); ReactiveResultHolder holder = resultHolder.get(); - if (null != beforeEvent) { - holder.before(beforeEvent.publish(eventPublisher)); + if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); + holder.before(prepareEvent.getAsync()); + } + if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { + holder.invoke(Mono.defer(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + return beforeEvent.getAsync(); + })); + } + if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { + holder.after(v -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); } - holder.after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); - }); return; } } @@ -300,29 +375,50 @@ protected void handleBatchOperation(Class clazz, EventContext context, }); } + boolean isEnabled(Class clazz, EntityEventType entityEventType, EntityEventPhase... phase) { + for (EntityEventPhase entityEventPhase : phase) { + if (listenerConfigure.isEnabled(clazz, entityEventType, entityEventPhase)) { + return true; + } + } + return false; + } + protected void handleSingleOperation(Class clazz, + EntityEventType entityEventType, EventContext context, BiFunction, Class, AsyncEvent> before, + BiFunction, Class, AsyncEvent> execute, BiFunction, Class, AsyncEvent> after) { context.get(MappingContextKeys.instance) .filter(Entity.class::isInstance) .map(Entity.class::cast) .ifPresent(entity -> { + AsyncEvent prepareEvent = before.apply(Collections.singletonList(entity), clazz); + AsyncEvent beforeEvent = execute.apply(Collections.singletonList(entity), clazz); AsyncEvent afterEvent = after.apply(Collections.singletonList(entity), clazz); - AsyncEvent beforeEvent = before.apply(Collections.singletonList(entity), clazz); + Object repo = context.get(MappingContextKeys.repository).orElse(null); if (repo instanceof ReactiveRepository) { Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); if (resultHolder.isPresent()) { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); ReactiveResultHolder holder = resultHolder.get(); - if (null != beforeEvent) { - holder.before(beforeEvent.publish(eventPublisher)); + if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); + holder.before(prepareEvent.getAsync()); + } + if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { + holder.invoke(Mono.defer(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + return beforeEvent.getAsync(); + })); + } + if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { + holder.after(v -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); } - holder.after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); - }); return; } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerConfigure.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerConfigure.java new file mode 100644 index 000000000..3bf69830e --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerConfigure.java @@ -0,0 +1,73 @@ +package org.hswebframework.web.crud.events; + +import org.hswebframework.web.api.crud.entity.Entity; + +/** + * 实体事件监听器配置 + *
+ *     configure.enable(MyEntity.class)//启用事件
+ *              //禁用某一类事件
+ *              .disable(MyEntity.class,EntityEventType.modify,EntityEventPhase.all)
+ * 
+ * + * @author zhouhao + * @since 4.0.12 + */ +public interface EntityEventListenerConfigure { + + /** + * 启用实体类的事件 + * + * @param entityType 实体类 + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + */ + void enable(Class entityType); + + /** + * 禁用实体类事件 + * + * @param entityType 实体类 + */ + void disable(Class entityType); + + /** + * 启用指定类型的事件 + * + * @param entityType 实体类型 + * @param type 事件类型 + * @param phases 事件阶段,如果不传则启用全部 + */ + void enable(Class entityType, + EntityEventType type, + EntityEventPhase... phases); + + /** + * 禁用指定类型的事件 + * + * @param entityType 实体类型 + * @param type 事件类型 + * @param phases 事件阶段,如果不传则禁用全部 + */ + void disable(Class entityType, + EntityEventType type, + EntityEventPhase... phases); + + /** + * 判断实体类是否启用了事件 + * + * @param entityType 实体类 + * @return 是否启用 + */ + boolean isEnabled(Class entityType); + + /** + * 判断实体类是否启用了指定类型的事件 + * + * @param entityType 实体类 + * @param type 事件类型 + * @param phase 事件阶段 + * @return 是否启用 + */ + boolean isEnabled(Class entityType, EntityEventType type, EntityEventPhase phase); + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerCustomizer.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerCustomizer.java new file mode 100644 index 000000000..b5fd2dedf --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListenerCustomizer.java @@ -0,0 +1,18 @@ +package org.hswebframework.web.crud.events; + +/** + * 实体事件监听器自定义接口,用于自定义实体事件 + * + * @author zhouhao + * @see EntityEventListenerConfigure + * @since 4.0.12 + */ +public interface EntityEventListenerCustomizer { + + /** + * 执行自定义 + * @param configure configure + */ + void customize(EntityEventListenerConfigure configure); + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventPhase.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventPhase.java new file mode 100644 index 000000000..7b157d5c2 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventPhase.java @@ -0,0 +1,9 @@ +package org.hswebframework.web.crud.events; + +public enum EntityEventPhase { + prepare, + before, + after; + + public static EntityEventPhase[] all = EntityEventPhase.values(); +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventType.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventType.java new file mode 100644 index 000000000..48689e753 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventType.java @@ -0,0 +1,8 @@ +package org.hswebframework.web.crud.events; + +public enum EntityEventType { + create, + delete, + modify, + save +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareCreateEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareCreateEvent.java new file mode 100644 index 000000000..c83d14a52 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareCreateEvent.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityPrepareCreateEvent extends DefaultAsyncEvent implements Serializable { + + private final List entity; + + private final Class entityType; +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareModifyEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareModifyEvent.java new file mode 100644 index 000000000..d59430d48 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareModifyEvent.java @@ -0,0 +1,26 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityPrepareModifyEvent extends DefaultAsyncEvent implements Serializable{ + + private static final long serialVersionUID = -7158901204884303777L; + + private final List before; + + private final List after; + + private final Class entityType; + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareSaveEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareSaveEvent.java new file mode 100644 index 000000000..030379006 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityPrepareSaveEvent.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.crud.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.io.Serializable; +import java.util.List; + +/** + * @see org.hswebframework.web.crud.annotation.EnableEntityEvent + * @param + */ +@AllArgsConstructor +@Getter +public class EntityPrepareSaveEvent extends DefaultAsyncEvent implements Serializable { + + private final List entity; + + private final Class entityType; +} diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigureTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigureTest.java new file mode 100644 index 000000000..55281eca3 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/DefaultEntityEventListenerConfigureTest.java @@ -0,0 +1,23 @@ +package org.hswebframework.web.crud.events; + +import org.hswebframework.web.crud.entity.EventTestEntity; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DefaultEntityEventListenerConfigureTest { + + @Test + public void test() { + DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); + configure.enable(EventTestEntity.class); + configure.disable(EventTestEntity.class, EntityEventType.create, EntityEventPhase.after); + + + assertTrue(configure.isEnabled(EventTestEntity.class)); + assertTrue(configure.isEnabled(EventTestEntity.class, EntityEventType.create, EntityEventPhase.before)); + + assertFalse(configure.isEnabled(EventTestEntity.class, EntityEventType.create, EntityEventPhase.after)); + + } +} \ No newline at end of file From 8989197124e64a090198b0030facc1178fde454e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 9 Sep 2021 18:51:26 +0800 Subject: [PATCH 109/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 825b09ac7..2e16f7998 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -2,10 +2,13 @@ import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.core.param.QueryParam; import org.hswebframework.ezorm.rdb.events.*; +import org.hswebframework.ezorm.rdb.events.EventListener; import org.hswebframework.ezorm.rdb.events.EventType; +import org.hswebframework.ezorm.rdb.executor.NullValue; import org.hswebframework.ezorm.rdb.mapping.*; import org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys; import org.hswebframework.ezorm.rdb.mapping.events.MappingEventTypes; @@ -25,10 +28,7 @@ import reactor.util.function.Tuple2; import reactor.util.function.Tuples; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; @@ -153,7 +153,18 @@ protected List createAfterData(List olds, return context .get(MappingContextKeys.updateColumnInstance) .map(map -> { - return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); + Object data = FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); + //set null + for (Map.Entry stringObjectEntry : map.entrySet()) { + if (stringObjectEntry.getValue() == null || stringObjectEntry.getValue() instanceof NullValue) { + try { + BeanUtilsBean + .getInstance() + .setProperty(data, stringObjectEntry.getKey(), null); + }catch (Throwable ignore){} + } + } + return data; }) .map(Entity.class::cast) .orElse(null); From 2a508dd3307e6d667286dda76966ca09bafba20a Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 14 Sep 2021 08:46:03 +0800 Subject: [PATCH 110/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=91=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BF=9D=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveTreeSortEntityService.java | 165 +++++++++++++++++- .../ReactiveTreeSortEntityServiceTest.java | 111 ++++++++++-- 2 files changed, 254 insertions(+), 22 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index 2cf5f6c8c..9b49472c1 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -1,17 +1,23 @@ package org.hswebframework.web.crud.service; +import org.apache.commons.collections4.CollectionUtils; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.ezorm.rdb.operator.dml.Terms; import org.hswebframework.utils.RandomUtil; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.api.crud.entity.TreeSortSupportEntity; import org.hswebframework.web.api.crud.entity.TreeSupportEntity; import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.validator.CreateGroup; import org.reactivestreams.Publisher; import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.function.Tuple3; import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -52,6 +58,16 @@ default Flux queryIncludeChildren(Collection idList) { .fetch()); } + default Flux queryIncludeParent(Collection idList) { + return findById(idList) + .flatMap(e -> createQuery() + .where() + .accept(Terms.Like.reversal("path", e.getPath(), false, true)) + .notEmpty("path") + .notNull("path") + .fetch()); + } + default Flux queryIncludeChildren(QueryParamEntity queryParam) { return query(queryParam) .flatMap(e -> createQuery() @@ -102,14 +118,151 @@ default Mono checkCyclicDependency(K id, E ele) { .then(Mono.just(ele)); } + default Mono refactorChildPath(K id, String path, Consumer pathAccepter) { + return this + .createQuery() + .where("parentId", id) + .fetch() + .flatMap(e -> { + if (StringUtils.isEmpty(path)) { + e.setPath(RandomUtil.randomChar(4)); + } else { + e.setPath(path + "-" + RandomUtil.randomChar(4)); + } + pathAccepter.accept(e); + if (e.getParentId() != null) { + return this + .refactorChildPath(e.getId(), e.getPath(), pathAccepter) + .thenReturn(e); + } + return Mono.just(e); + }) + .as(getRepository()::save) + .then(); + } + @Override default Mono save(Publisher entityPublisher) { - return this.getRepository() - .save(Flux.from(entityPublisher) - .flatMap(this::applyTreeProperty) - //把树结构平铺 - .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) - ); + return Flux + .from(entityPublisher) + .flatMapIterable(e -> TreeSupportEntity.expandTree2List(e, getIDGenerator())) + .collectList() + .flatMapIterable(list -> { + Map map = list + .stream() + .filter(e -> e.getId() != null) + .collect(Collectors.toMap(TreeSupportEntity::getId, Function.identity())); + + return TreeSupportEntity.list2tree(list, + this::setChildren, + (Predicate) e -> this.isRootNode(e) || map.get(e.getParentId()) == null); + + }) + .doOnNext(e -> e.tryValidate(CreateGroup.class)) + .flatMapIterable(e -> TreeSupportEntity.expandTree2List(e, getIDGenerator())) + .as(this::tryRefactorPath) + .as(this.getRepository()::save); + + } + + default Flux tryRefactorPath(Flux stream) { + Flux cache = stream.cache(); + Mono> mapping = cache + .filter(e -> null != e.getId()) + .collectMap(TreeSupportEntity::getId, Function.identity()) + .defaultIfEmpty(Collections.emptyMap()); + + //查询出旧数据 + Mono> olds = cache + .filter(e -> null != e.getId()) + .map(TreeSupportEntity::getId) + .as(this::findById) + .collectMap(TreeSupportEntity::getId, Function.identity()) + .defaultIfEmpty(Collections.emptyMap()); + + + return Mono + .zip(mapping, olds) + .flatMapMany(tp2 -> { + Map map = tp2.getT1(); + Map oldMap = tp2.getT2(); + + return cache + .flatMap(data -> { + E old = data.getId() == null ? null : oldMap.get(data.getId()); + K parentId = old != null ? old.getParentId() : data.getParentId(); + E oldParent = parentId == null ? null : oldMap.get(parentId); + if (old != null) { + K newParentId= data.getParentId(); + //父节点发生变化,更新所有子节点path + if (!Objects.equals(parentId,newParentId)) { + List> jobs = new ArrayList<>(); + Consumer childConsumer = child -> { + //更新了父节点,但是同时也传入的对应的子节点 + E readyToUpdate = map.get(child.getId()); + if (null != readyToUpdate) { + readyToUpdate.setPath(child.getPath()); + } + }; + + //变更到了顶级节点 + if (isRootNode(data)) { + data.setPath(RandomUtil.randomChar(4)); + jobs.add(this.refactorChildPath(old.getId(), data.getPath(), childConsumer)); + } else { + if (null != oldParent) { + data.setPath(oldParent.getPath() + "-" + RandomUtil.randomChar(4)); + jobs.add(this.refactorChildPath(old.getId(), data.getPath(), childConsumer)); + } else { + jobs.add(this.findById(newParentId) + .flatMap(parent -> { + data.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4)); + return this.refactorChildPath(data.getId(), data.getPath(), childConsumer); + }) + ); + } + } + return Flux.merge(jobs) + .then(Mono.just(data)); + } else { + //父节点未变化则使用原始的path + Consumer pathRefactor = (parent) -> { + if (old.getPath().startsWith(parent.getPath())) { + data.setPath(old.getPath()); + } else { + data.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4)); + } + }; + if (oldParent != null) { + pathRefactor.accept(oldParent); + } else if (parentId != null) { + return findById(parentId) + .switchIfEmpty(Mono.fromRunnable(() ->{ + data.setParentId(null); + data.setLevel(1); + data.setPath(old.getPath()); + })) + .doOnNext(pathRefactor) + .thenReturn(data); + }else { + data.setPath(old.getPath()); + } + + } + } + return Mono.just(data); + }); + }); + } + + @Override + default Mono save(Collection collection) { + return save(Flux.fromIterable(collection)); + } + + @Override + default Mono save(E data) { + return save(Flux.just(data)); } @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java index dd7c20481..ca3d3404d 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java @@ -26,38 +26,117 @@ public class ReactiveTreeSortEntityServiceTest { @Test - public void testCrud(){ - TestTreeSortEntity entity=new TestTreeSortEntity(); + public void testCrud() { + TestTreeSortEntity entity = new TestTreeSortEntity(); entity.setId("test"); entity.setName("test"); - TestTreeSortEntity entity2=new TestTreeSortEntity(); + TestTreeSortEntity entity2 = new TestTreeSortEntity(); entity2.setName("test2"); entity.setChildren(Arrays.asList(entity2)); sortEntityService.insert(Mono.just(entity)) - .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); sortEntityService.save(Mono.just(entity)) - .map(SaveResult::getTotal) - .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + .map(SaveResult::getTotal) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); sortEntityService.queryResultToTree(QueryParamEntity.of()) - .map(List::size) - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .map(List::size) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); + + sortEntityService.queryIncludeParent(Arrays.asList(entity2.getId())) + .as(StepVerifier::create) + .expectNextCount(2) + .verifyComplete(); sortEntityService.deleteById(Mono.just("test")) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); + } + + @Test + public void testChangeParent() { + TestTreeSortEntity entity = new TestTreeSortEntity(); + entity.setId("test_p1"); + entity.setName("test1"); + + TestTreeSortEntity entity_0 = new TestTreeSortEntity(); + entity_0.setId("test_p0"); + entity_0.setName("test0"); + + TestTreeSortEntity entity2 = new TestTreeSortEntity(); + entity2.setId("test_p2"); + entity2.setName("test2"); + entity2.setParentId(entity.getId()); + + TestTreeSortEntity entity3 = new TestTreeSortEntity(); + entity3.setId("test_p3"); + entity3.setName("test3"); + entity3.setParentId(entity2.getId()); + + sortEntityService + .save(Arrays.asList(entity, entity_0, entity2, entity3)) + .then() .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + .expectComplete() + .verify(); + + entity2.setChildren(null); + entity2.setParentId(entity_0.getId()); + + sortEntityService + .save(Arrays.asList(entity2)) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + sortEntityService.queryIncludeChildren(Arrays.asList(entity_0.getId())) + .as(StepVerifier::create) + .expectNextCount(3) + .verifyComplete(); + } + @Test + public void testSave() { + TestTreeSortEntity entity = new TestTreeSortEntity(); + entity.setId("test_path"); + entity.setName("test-path"); + + sortEntityService + .save(entity) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + String firstPath = entity.getPath(); + assertNotNull(firstPath); + entity.setPath(null); + + sortEntityService + .save(entity) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + sortEntityService + .findById(entity.getId()) + .map(TestTreeSortEntity::getPath) + .as(StepVerifier::create) + .expectNext(firstPath) + .verifyComplete(); + } } \ No newline at end of file From 97292b23ed8586a8308b4f0432af9f7b0c866864 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 14 Sep 2021 08:46:11 +0800 Subject: [PATCH 111/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/DefaultDimensionManagerTest.java | 59 +++++++++++++++++++ .../crud/annotation/EnableEntityEvent.java | 6 ++ 2 files changed, 65 insertions(+) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/simple/DefaultDimensionManagerTest.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/simple/DefaultDimensionManagerTest.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/simple/DefaultDimensionManagerTest.java new file mode 100644 index 000000000..b780c30e2 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/simple/DefaultDimensionManagerTest.java @@ -0,0 +1,59 @@ +package org.hswebframework.web.authorization.simple; + +import org.hswebframework.web.authorization.Dimension; +import org.hswebframework.web.authorization.DimensionProvider; +import org.hswebframework.web.authorization.DimensionType; +import org.hswebframework.web.authorization.dimension.DimensionUserBind; +import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider; +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Collection; +import java.util.Collections; + +import static org.junit.Assert.*; + +public class DefaultDimensionManagerTest { + + @Test + public void test() { + DefaultDimensionManager manager = new DefaultDimensionManager(); + manager.addBindProvider(userIdList -> Flux.just( + DimensionUserBind.of("testUser", "testType", "testId") + , DimensionUserBind.of("testUser", "testType", "testId2"))); + manager.addProvider(new DimensionProvider() { + @Override + public Flux getAllType() { + return Flux.just(SimpleDimensionType.of("testType")); + } + + @Override + public Flux getDimensionsById(DimensionType type, + Collection idList) { + return Flux.just(SimpleDimension.of("testId", "testName", SimpleDimensionType.of("testType"), null)); + } + + @Override + public Flux getDimensionByUserId(String userId) { + return Flux.empty(); + } + + @Override + public Mono getDimensionById(DimensionType type, String id) { + return Mono.empty(); + } + + @Override + public Flux getUserIdByDimensionId(String dimensionId) { + return Flux.empty(); + } + }); + + manager.getUserDimension(Collections.singleton("testUser")) + .as(StepVerifier::create) + .expectNextMatches(detail -> detail.getDimensions().size() == 1) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java index e153b10ab..da724df40 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java @@ -28,6 +28,7 @@ * @see org.hswebframework.web.crud.events.EntityBeforeDeleteEvent * @see org.hswebframework.web.crud.events.EntityBeforeCreateEvent * @see org.hswebframework.web.crud.events.EntityBeforeQueryEvent + * @see org.hswebframework.web.crud.events.EntityEventListenerCustomizer */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @@ -35,6 +36,11 @@ @Documented public @interface EnableEntityEvent { + /** + * 指定开启的事件类型,也可以通过{@link org.hswebframework.web.crud.events.EntityEventListenerCustomizer}进行自定义 + * @return 事件类型 + * @see org.hswebframework.web.crud.events.EntityEventListenerCustomizer + */ EntityEventType[] value() default { EntityEventType.create, EntityEventType.delete, From d6b67a93ac2d391bee078e35952388301eccac21 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 15 Sep 2021 14:17:32 +0800 Subject: [PATCH 112/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../i18n/authentication-default/messages_zh.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties index 16da067f5..2ace1f08f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/resources/i18n/authentication-default/messages_zh.properties @@ -1,2 +1,2 @@ -error.duplicate_key=重复的请求 +error.duplicate_key=已存在重复的数据 error.user_already_exists=用户已存在 \ No newline at end of file From 58615232638caa118a42fc19b4bcdaf78669ca17 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 17 Sep 2021 12:41:37 +0800 Subject: [PATCH 113/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/hswebframework/web/i18n/LocaleUtils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 4ae721cfc..d3c66ade3 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -207,6 +207,10 @@ public static Mono resolveThrowable(MessageSource me S source, BiFunction mapper, Object... args) { + if (source instanceof I18nSupportException && args.length == 0) { + I18nSupportException ex = ((I18nSupportException) source); + return resolveThrowable(ex, (err, msg) -> mapper.apply(source, msg)); + } return doWithReactive(messageSource, source, Throwable::getMessage, mapper, args); } From 20b25b3e948e1d0662bb1d7c21f3c88d86c9e415 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 17 Sep 2021 19:07:44 +0800 Subject: [PATCH 114/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackson/CustomJackson2JsonDecoder.java | 23 +++++++--- .../CustomJackson2JsonDecoderTest.java | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index ab9c16179..cbf0100b8 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -31,6 +31,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.List; @@ -128,6 +129,19 @@ private Type getRelType(Type type) { return realType; } } + if (type instanceof ParameterizedType) { + ResolvableType elementType = ResolvableType.forType(type); + ResolvableType[] generics = elementType.getGenerics(); + for (int i = 0; i < generics.length; i++) { + generics[i] = ResolvableType.forType(getRelType(generics[i].getType())); + } + + type = ResolvableType + .forClassWithGenerics( + elementType.toClass(), + generics) + .getType(); + } return type; } @@ -137,13 +151,8 @@ private ObjectReader getObjectReader(ResolvableType elementType, @Nullable Map contextClass = (param != null ? param.getContainingClass() : null); Type type = elementType.resolve() == null ? elementType.getType() : elementType.toClass(); - if (Iterable.class.isAssignableFrom(elementType.toClass())) { - ResolvableType genType = elementType.getGeneric(0); - type = ResolvableType - .forClassWithGenerics( - elementType.toClass(), - ResolvableType.forType(getRelType(genType.getType()))) - .getType(); + if (elementType.getType() instanceof ParameterizedType) { + type = getRelType(elementType.getType()); } else { type = getRelType(type); } diff --git a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java index d2e24edbf..c7984b2ce 100644 --- a/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java +++ b/hsweb-starter/src/test/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoderTest.java @@ -5,6 +5,7 @@ import lombok.Setter; import lombok.SneakyThrows; import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.hswebframework.web.api.crud.entity.PagerResult; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.crud.entity.factory.MapperEntityFactory; import org.hswebframework.web.crud.web.reactive.ReactiveQueryController; @@ -16,10 +17,15 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.MediaType; import org.springframework.util.MimeType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; +import java.lang.reflect.Method; import java.util.Collections; import java.util.List; +import java.util.Map; import static org.junit.Assert.*; @@ -67,6 +73,45 @@ public void testDecodeList() { } + @Test + @SneakyThrows + public void testGeneric() { + ObjectMapper mapper = new ObjectMapper(); + CustomJackson2JsonDecoder decoder = new CustomJackson2JsonDecoder(new MapperEntityFactory(), mapper); + + ResolvableType type = ResolvableType.forClassWithGenerics(PagerResult.class, MyEntity.class); + DataBuffer buffer = new DefaultDataBufferFactory().wrap("{\"pageSize\":1,\"data\":[{\"id\":\"test\"}]}".getBytes()); + + Object object = decoder.decode(buffer, type, MediaType.APPLICATION_JSON, Collections.emptyMap()); + + assertTrue(object instanceof PagerResult); + PagerResult result= ((PagerResult) object); + + assertTrue(result.getData().size()>0); + assertEquals(result.getData().get(0).getId(), "test"); + + } + + @Test + @SneakyThrows + public void testComplexGeneric() { + ObjectMapper mapper = new ObjectMapper(); + CustomJackson2JsonDecoder decoder = new CustomJackson2JsonDecoder(new MapperEntityFactory(), mapper); + ResolvableType type = ResolvableType.forClassWithGenerics(PagerResult.class, ResolvableType.forClassWithGenerics( + Map.class,String.class,MyEntity.class + )); + DataBuffer buffer = new DefaultDataBufferFactory().wrap("{\"pageSize\":1,\"data\":[{\"test\":{\"id\":\"test\"}}]}".getBytes()); + + Object object = decoder.decode(buffer, type, MediaType.APPLICATION_JSON, Collections.emptyMap()); + + assertTrue(object instanceof PagerResult); + PagerResult> result= ((PagerResult>) object); + + assertTrue(result.getData().size()>0); + assertEquals(result.getData().get(0).get("test").getId(), "test"); + } + + @Getter @Setter public static class MyEntity { From 78ac856e5935fd382ab98b87a3bf769248c2edcf Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 22 Sep 2021 09:47:29 +0800 Subject: [PATCH 115/542] =?UTF-8?q?=E4=BC=98=E5=8C=96null=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/crud/sql/DefaultR2dbcExecutor.java | 4 ++++ 1 file changed, 4 insertions(+) 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 7c6c8d300..6e8ab1444 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 @@ -19,6 +19,7 @@ import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; +import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Date; import java.util.Map; @@ -48,6 +49,9 @@ protected SqlRequest convertRequest(SqlRequest sqlRequest) { } protected void bindNull(Statement statement, int index, Class type) { + if (type == Date.class) { + type = LocalDateTime.class; + } if (bindCustomSymbol) { statement.bindNull(getBindSymbol() + (index + getBindFirstIndex()), type); return; From 4e8a0f99ec27e1efd0b0490e1713d5acbb2599fd Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 24 Sep 2021 19:37:14 +0800 Subject: [PATCH 116/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/utils/TemplateParser.java | 5 ++++- .../web/utils/ExpressionUtilsTest.java | 6 ++++-- .../web/utils/TemplateParserTest.java | 21 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/TemplateParser.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/TemplateParser.java index a052c0fde..275d8d8f3 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/TemplateParser.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/TemplateParser.java @@ -103,11 +103,14 @@ public String parse(Function propertyMapping) { while (next()) { if (isPrepare()) { inPrepare = true; - } else if (inPrepare&&isPrepareEnd()) { + } else if (inPrepare && isPrepareEnd()) { inPrepare = false; setParsed(propertyMapping.apply(new String(expression, 0, expressionPos)).toCharArray()); expressionPos = 0; } else if (inPrepare) { + if (expression.length <= expressionPos) { + expression = Arrays.copyOf(expression, (int)(expression.length * 1.5)); + } expression[expressionPos++] = symbol; } else if (!isPreparing()) { setParsed(symbol); diff --git a/hsweb-core/src/test/java/org/hswebframework/web/utils/ExpressionUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/utils/ExpressionUtilsTest.java index 5f3b0cf11..ebe483af1 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/utils/ExpressionUtilsTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/utils/ExpressionUtilsTest.java @@ -53,7 +53,7 @@ public void testJson2(){ " \"msgtype\": \"markdown\",\n" + " \"markdown\": {\n" + " \"title\":\"消息类型:${messageType}\",\n" + - " \"text\": \" - 设备ID: `${deviceId}` \\n - 设备型号: `${headers.productId}`\\n - 设备名称: `${headers.deviceName}`\"" + + " \"text\": \" - 设备ID: `${deviceId}` 值:`${properties.a-r-str}` \\n - 设备型号: `${headers.productId}`\\n - 设备名称: `${headers.deviceName}`\"" + " \n},\n" + " \"at\": {\n" + " \"isAtAll\": false\n" + @@ -63,7 +63,9 @@ public void testJson2(){ " \"headers\": {\n" + " \"productId\": \"VIS-Mandrake\",\n" + " \"deviceName\": \"能见度仪-曼德克-01\"\n" + - " },\n" + + " }, \"properties\": {\n" + + " \"a-r-str\": \"a2\"\n" + + " },\n" + " \"messageType\": \"OFFLINE\",\n" + " \"timestamp\": 1592098397277\n" + "}"), "spel"); diff --git a/hsweb-core/src/test/java/org/hswebframework/web/utils/TemplateParserTest.java b/hsweb-core/src/test/java/org/hswebframework/web/utils/TemplateParserTest.java index 48ef26364..a5923a7cf 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/utils/TemplateParserTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/utils/TemplateParserTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import java.util.Collections; +import java.util.function.Function; import static org.junit.Assert.*; @@ -18,6 +19,17 @@ public void test() { Assert.assertEquals(result, "test-test-test"); } + @Test + public void testLargeExpr() { + String expr = ""; + for (int i = 0; i < 1000; i++) { + expr += "expr_" + i; + } + String result = TemplateParser.parse("${"+expr+"}", Function.identity()); + + assertEquals(expr,result); + + } @Test public void testLarge() { String str = ""; @@ -30,4 +42,13 @@ public void testLarge() { } + @Test + public void testNest() { + + + String result = TemplateParser.parse("test-${properties.a-r-str}", Collections.singletonMap("properties", Collections.singletonMap("a-r-str","123"))); + + Assert.assertEquals(result, "test-123"); + } + } \ No newline at end of file From 1c26669430bf26f150a7f79c399fca7d6ffdf873 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 24 Sep 2021 22:23:08 +0800 Subject: [PATCH 117/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9url=20encode?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-commons/hsweb-commons-api/pom.xml | 4 +++ .../api/crud/entity/TermExpressionParser.java | 25 ++++++++++++------- .../crud/entity/TermExpressionParserTest.java | 13 ++++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 8ca290de6..2dfc46220 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -44,6 +44,10 @@ 3.0.2 compile + + commons-codec + commons-codec + diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java index e7a8ca65a..af76310f1 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java @@ -1,5 +1,7 @@ package org.hswebframework.web.api.crud.entity; +import lombok.SneakyThrows; +import org.apache.commons.codec.net.URLCodec; import org.hswebframework.ezorm.core.NestConditional; import org.hswebframework.ezorm.core.dsl.Query; import org.hswebframework.ezorm.core.param.Sort; @@ -22,7 +24,12 @@ */ public class TermExpressionParser { + static final URLCodec urlCodec = new URLCodec(); + + @SneakyThrows public static List parse(String expression) { + expression = urlCodec.decode(expression); + Query conditional = QueryParamEntity.newQuery(); NestConditional nest = null; @@ -181,15 +188,15 @@ public static List parse(String expression) { */ public static List parseOrder(String expression) { return Stream.of(expression.split("[,]")) - .map(str -> str.split("[ ]")) - .map(arr -> { - Sort sort = new Sort(); - sort.setName(arr[0]); - if (arr.length > 1 && "desc".equalsIgnoreCase(arr[1])) { - sort.desc(); - } - return sort; - }).collect(Collectors.toList()); + .map(str -> str.split("[ ]")) + .map(arr -> { + Sort sort = new Sort(); + sort.setName(arr[0]); + if (arr.length > 1 && "desc".equalsIgnoreCase(arr[1])) { + sort.desc(); + } + return sort; + }).collect(Collectors.toList()); } private static String convertTermType(String termType) { diff --git a/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java index b91588483..a04ea1cd0 100644 --- a/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java +++ b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java @@ -10,6 +10,19 @@ public class TermExpressionParserTest { + @Test + public void testUrl(){ + List terms = TermExpressionParser.parse("type=email%20and%20provider=test"); + + assertEquals(terms.get(0).getTermType(), TermType.eq); + assertEquals(terms.get(0).getColumn(), "type"); + assertEquals(terms.get(0).getValue(), "email"); + + assertEquals(terms.get(1).getTermType(), TermType.eq); + assertEquals(terms.get(1).getColumn(), "provider"); + assertEquals(terms.get(1).getValue(), "test"); + + } @Test public void test() { { From 5174482a11c28758092d9589854a76c79308a2e3 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 24 Sep 2021 22:23:37 +0800 Subject: [PATCH 118/542] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=97=B6=E6=B8=85=E9=99=A4=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/DefaultReactiveUserService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 index ae061a4ab..f3580edc5 100644 --- 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 @@ -13,6 +13,7 @@ import org.hswebframework.web.system.authorization.api.PasswordValidator; import org.hswebframework.web.system.authorization.api.UsernameValidator; import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; import org.hswebframework.web.system.authorization.api.event.UserCreatedEvent; import org.hswebframework.web.system.authorization.api.event.UserDeletedEvent; import org.hswebframework.web.system.authorization.api.event.UserModifiedEvent; @@ -111,7 +112,10 @@ protected Mono doUpdate(UserEntity userEntity) { .where(userEntity::getId) .execute() .flatMap(__ -> new UserModifiedEvent(userEntity, passwordChanged).publish(eventPublisher)) - .thenReturn(userEntity); + .thenReturn(userEntity) + .doOnNext(e->{ + eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(e.getId())); + }); }); } From 10888a311d00e3e446d45ad7f944d77ee9d1246d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 11:39:33 +0800 Subject: [PATCH 119/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0EntityEventHelper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventHelper.java | 60 ++++++++ .../web/crud/events/EntityEventListener.java | 143 +++++++++++------- .../crud/events/EntityEventListenerTest.java | 60 +++++--- 3 files changed, 181 insertions(+), 82 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java new file mode 100644 index 000000000..328374793 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java @@ -0,0 +1,60 @@ +package org.hswebframework.web.crud.events; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.context.Context; + +/** + * 实体事件帮助器 + * + * @author zhouhao + * @since 4.0.12 + */ +public class EntityEventHelper { + + private static final String doEventContextKey = EntityEventHelper.class.getName() + "_doEvent"; + + /** + * 判断当前是否设置了事件 + * + * @param defaultIfEmpty 如果未设置时的默认值 + * @return 是否设置了事件 + */ + public static Mono isDoFireEvent(boolean defaultIfEmpty) { + return Mono + .subscriberContext() + .flatMap(ctx -> Mono.justOrEmpty(ctx.getOrEmpty(doEventContextKey))) + .defaultIfEmpty(defaultIfEmpty); + } + + /** + * 设置Mono不触发实体类事件 + * + *
+     *     save(...)
+     *     .as(EntityEventHelper::setDoNotFireEvent)
+     * 
+ * + * @param stream 流 + * @param 泛型 + * @return 流 + */ + public static Mono setDoNotFireEvent(Mono stream) { + return stream.subscriberContext(Context.of(doEventContextKey, false)); + } + + /** + * 设置Flux不触发实体类事件 + *
+     *     fetch()
+     *     .as(EntityEventHelper::setDoNotFireEvent)
+     * 
+ * + * @param stream 流 + * @param 泛型 + * @return 流 + */ + public static Flux setDoNotFireEvent(Flux stream) { + return stream.subscriberContext(Context.of(doEventContextKey, false)); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 2e16f7998..95987081b 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -17,12 +17,9 @@ import org.hswebframework.ezorm.rdb.metadata.TableOrViewMetadata; import org.hswebframework.web.api.crud.entity.Entity; import org.hswebframework.web.bean.FastBeanCopier; -import org.hswebframework.web.crud.annotation.EnableEntityEvent; import org.hswebframework.web.event.AsyncEvent; import org.hswebframework.web.event.GenericsPayloadApplicationEvent; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.scheduling.annotation.Async; import reactor.core.publisher.Mono; import reactor.function.Function3; import reactor.util.function.Tuple2; @@ -31,6 +28,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; +import java.util.function.Supplier; @SuppressWarnings("all") @AllArgsConstructor @@ -161,7 +159,8 @@ protected List createAfterData(List olds, BeanUtilsBean .getInstance() .setProperty(data, stringObjectEntry.getKey(), null); - }catch (Throwable ignore){} + } catch (Throwable ignore) { + } } } return data; @@ -214,7 +213,7 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) EntityEventPhase.before, EntityEventPhase.after)) { holder.before( - ((ReactiveRepository) repo) + this.doAsyncEvent(() -> ((ReactiveRepository) repo) .createQuery() .setParam(update.toQueryParam()) .fetch() @@ -227,13 +226,13 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) entityType, EntityPrepareModifyEvent::new); - }) - .then() + }).then() + ) ); } //before if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.before)) { - holder.invoke(Mono.defer(() -> { + holder.invoke(this.doAsyncEvent(() -> { Tuple2, List> _tmp = updated.get(); if (_tmp != null) { return sendUpdateEvent(_tmp.getT1(), @@ -247,19 +246,20 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) //after if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.after)) { - holder.after(v -> { - return Mono - .defer(() -> { - Tuple2, List> _tmp = updated.getAndSet(null); - if (_tmp != null) { - return sendUpdateEvent(_tmp.getT1(), - _tmp.getT2(), - entityType, - EntityModifyEvent::new); - } - return Mono.empty(); - }); - }); + holder.after(v -> this + .doAsyncEvent(() -> { + return Mono + .defer(() -> { + Tuple2, List> _tmp = updated.getAndSet(null); + if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), + _tmp.getT2(), + entityType, + EntityModifyEvent::new); + } + return Mono.empty(); + }); + })); } }); @@ -299,30 +299,30 @@ protected void handleDeleteBefore(Class entityType, EventContext context .ifPresent(holder -> { AtomicReference> deleted = new AtomicReference<>(); if (isEnabled(entityType, EntityEventType.delete, EntityEventPhase.before, EntityEventPhase.after)) { - holder.before(((ReactiveRepository) repo) - .createQuery() - .setParam(dslUpdate.toQueryParam()) - .fetch() - .collectList() - .filter(CollectionUtils::isNotEmpty) - .flatMap(list -> { - deleted.set(list); - return this - .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); - }) + holder.before( + this.doAsyncEvent(() -> ((ReactiveRepository) repo) + .createQuery() + .setParam(dslUpdate.toQueryParam()) + .fetch() + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> { + deleted.set(list); + return this + .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); + }) + ) ); } if (isEnabled(entityType, EntityEventType.delete, EntityEventPhase.after)) { - holder.after(v -> { - return Mono - .defer(() -> { - List _tmp = deleted.getAndSet(null); - if (CollectionUtils.isNotEmpty(_tmp)) { - return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new); - } - return Mono.empty(); - }); - }); + holder.after(v -> this + .doAsyncEvent(() -> { + List _tmp = deleted.getAndSet(null); + if (CollectionUtils.isNotEmpty(_tmp)) { + return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new); + } + return Mono.empty(); + })); } }); @@ -362,19 +362,28 @@ protected void handleBatchOperation(Class clazz, if (resultHolder.isPresent()) { ReactiveResultHolder holder = resultHolder.get(); if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); - holder.before(prepareEvent.getAsync()); + holder.before( + this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); + return prepareEvent.getAsync(); + }) + ); } + if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { - holder.invoke(Mono.defer(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); - return beforeEvent.getAsync(); - })); + holder.invoke( + this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + return beforeEvent.getAsync(); + }) + ); } if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { holder.after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); + return this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); }); } return; @@ -415,19 +424,28 @@ protected void handleSingleOperation(Class clazz, if (resultHolder.isPresent()) { ReactiveResultHolder holder = resultHolder.get(); if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); - holder.before(prepareEvent.getAsync()); + holder.before( + this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); + return prepareEvent.getAsync(); + }) + ); } + if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { - holder.invoke(Mono.defer(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); - return beforeEvent.getAsync(); - })); + holder.invoke( + this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); + return beforeEvent.getAsync(); + }) + ); } if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { holder.after(v -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); + return this.doAsyncEvent(() -> { + eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); + return afterEvent.getAsync(); + }); }); } return; @@ -438,4 +456,13 @@ protected void handleSingleOperation(Class clazz, afterEvent.getAsync().block(); }); } + + protected Mono doAsyncEvent(Supplier> eventSupplier) { + return EntityEventHelper + .isDoFireEvent(true) + .filter(Boolean::booleanValue) + .flatMap(ignore -> { + return eventSupplier.get(); + }); + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java index 6a636ec64..85e9167b2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java @@ -39,10 +39,10 @@ public class EntityEventListenerTest { @Test public void test() { Mono.just(EventTestEntity.of("test", 1)) - .as(reactiveRepository::insert) - .as(StepVerifier::create) - .expectNext(1) - .verifyComplete(); + .as(reactiveRepository::insert) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); Assert.assertEquals(listener.created.getAndSet(0), 1); @@ -51,7 +51,7 @@ public void test() { @Test public void testInsertBatch() { reactiveRepository.createQuery() - .where(EventTestEntity::getId,"test") + .where(EventTestEntity::getId, "test") .fetch() .then() .as(StepVerifier::create) @@ -61,15 +61,15 @@ public void testInsertBatch() { Flux.just(EventTestEntity.of("test2", 1), EventTestEntity.of("test3", 2)) - .as(reactiveRepository::insert) - .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + .as(reactiveRepository::insert) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); Assert.assertEquals(listener.created.getAndSet(0), 2); Assert.assertEquals(listener.beforeCreate.getAndSet(0), 2); reactiveRepository - .createUpdate().set("age",3).where().in("name","test2","test3").execute() + .createUpdate().set("age", 3).where().in("name", "test2", "test3").execute() .as(StepVerifier::create) .expectNext(2) .verifyComplete(); @@ -77,39 +77,51 @@ public void testInsertBatch() { Assert.assertEquals(listener.modified.getAndSet(0), 2); Assert.assertEquals(listener.beforeModify.getAndSet(0), 2); - reactiveRepository.createDelete().where().in("name","test2","test3").execute() - .as(StepVerifier::create) - .expectNext(2) - .verifyComplete(); + reactiveRepository.createDelete().where().in("name", "test2", "test3").execute() + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); Assert.assertEquals(listener.deleted.getAndSet(0), 2); Assert.assertEquals(listener.beforeDelete.getAndSet(0), 2); reactiveRepository.save(EventTestEntity.of("test2", 1)) - .then() - .as(StepVerifier::create) - .expectComplete() - .verify(); + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); Assert.assertEquals(listener.saved.getAndSet(0), 1); Assert.assertEquals(listener.beforeSave.getAndSet(0), 1); - } @Test @Ignore public void testInsertError() { Flux.just(EventTestEntity.of("test2", 1), EventTestEntity.of("test3", 2)) - .as(reactiveRepository::insert) - .flatMap(i -> Mono.error(new RuntimeException())) - .as(transactionalOperator::transactional) - .as(StepVerifier::create) - .verifyError(); + .as(reactiveRepository::insert) + .flatMap(i -> Mono.error(new RuntimeException())) + .as(transactionalOperator::transactional) + .as(StepVerifier::create) + .verifyError(); Assert.assertEquals(listener.created.getAndSet(0), 0); } + @Test + public void testDoNotFire() { + Mono.just(EventTestEntity.of("test", 1)) + .as(reactiveRepository::insert) + .as(EntityEventHelper::setDoNotFireEvent) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); + Assert.assertEquals(listener.created.getAndSet(0), 0); + + + } + } \ No newline at end of file From 4d374489dda455e939d9b855829d097ed0b12603 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 13:45:15 +0800 Subject: [PATCH 120/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventHelper.java | 67 +++++++++++++++ .../web/crud/events/EntityEventListener.java | 85 ++++++++++--------- 2 files changed, 114 insertions(+), 38 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java index 328374793..3a6ffd8d9 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventHelper.java @@ -1,9 +1,18 @@ package org.hswebframework.web.crud.events; +import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.event.AsyncEvent; +import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.context.Context; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + /** * 实体事件帮助器 * @@ -57,4 +66,62 @@ public static Mono setDoNotFireEvent(Mono stream) { public static Flux setDoNotFireEvent(Flux stream) { return stream.subscriberContext(Context.of(doEventContextKey, false)); } + + public static Mono publishSavedEvent(Object source, + Class entityType, + List entities, + Consumer>> publisher) { + return publishEvent(source, entityType, () -> new EntitySavedEvent<>(entities, entityType), publisher); + } + + public static Mono publishModifyEvent(Object source, + Class entityType, + List before, + Consumer afterTransfer, + Consumer>> publisher) { + return publishEvent(source, + entityType, + () -> new EntityModifyEvent<>(before, + before + .stream() + .map(t -> t.copyTo(entityType)) + .peek(afterTransfer) + .collect(Collectors.toList()), + entityType), + publisher); + } + + public static Mono publishModifyEvent(Object source, + Class entityType, + List before, + List after, + Consumer>> publisher) { + return publishEvent(source, entityType, () -> new EntityModifyEvent<>(before, after, entityType), publisher); + } + + public static Mono publishDeletedEvent(Object source, + Class entityType, + List entities, + Consumer>> publisher) { + return publishEvent(source, entityType, () -> new EntityDeletedEvent<>(entities, entityType), publisher); + } + + public static Mono publishCreatedEvent(Object source, + Class entityType, + List entities, + Consumer>> publisher) { + return publishEvent(source, entityType, () -> new EntityCreatedEvent<>(entities, entityType), publisher); + } + + public static Mono publishEvent(Object source, + Class entityType, + Supplier eventSupplier, + Consumer> publisher) { + E event = eventSupplier.get(); + if (event == null) { + return Mono.empty(); + } + publisher.accept(new GenericsPayloadApplicationEvent<>(source, event, entityType)); + return event.getAsync(); + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 95987081b..9595da9cc 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.collections.CollectionUtils; +import org.hswebframework.ezorm.core.GlobalConfig; import org.hswebframework.ezorm.core.param.QueryParam; import org.hswebframework.ezorm.rdb.events.*; import org.hswebframework.ezorm.rdb.events.EventListener; @@ -30,6 +31,8 @@ import java.util.function.BiFunction; import java.util.function.Supplier; +import static org.hswebframework.web.crud.events.EntityEventHelper.*; + @SuppressWarnings("all") @AllArgsConstructor public class EntityEventListener implements EventListener { @@ -155,12 +158,9 @@ protected List createAfterData(List olds, //set null for (Map.Entry stringObjectEntry : map.entrySet()) { if (stringObjectEntry.getValue() == null || stringObjectEntry.getValue() instanceof NullValue) { - try { - BeanUtilsBean - .getInstance() - .setProperty(data, stringObjectEntry.getKey(), null); - } catch (Throwable ignore) { - } + GlobalConfig + .getPropertyOperator() + .setProperty(data, stringObjectEntry.getKey(), null); } } return data; @@ -181,18 +181,19 @@ protected Mono sendUpdateEvent(List before, Class type, Function3, List, Class, AsyncEvent> mapper) { - AsyncEvent event = mapper.apply(before, after, type); - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type)); - return event.getAsync(); + return publishEvent(this, + type, + () -> mapper.apply(before, after, type), + eventPublisher::publishEvent); } protected Mono sendDeleteEvent(List olds, Class type, BiFunction, Class, AsyncEvent> eventBuilder) { - - AsyncEvent deletedEvent = eventBuilder.apply(olds, type); - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, deletedEvent, type)); - return deletedEvent.getAsync(); + return publishEvent(this, + type, + () -> eventBuilder.apply(olds, type), + eventPublisher::publishEvent); } protected void handleUpdateBefore(DSLUpdate update, EventContext context) { @@ -248,17 +249,14 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) if (isEnabled(entityType, EntityEventType.modify, EntityEventPhase.after)) { holder.after(v -> this .doAsyncEvent(() -> { - return Mono - .defer(() -> { - Tuple2, List> _tmp = updated.getAndSet(null); - if (_tmp != null) { - return sendUpdateEvent(_tmp.getT1(), - _tmp.getT2(), - entityType, - EntityModifyEvent::new); - } - return Mono.empty(); - }); + Tuple2, List> _tmp = updated.getAndSet(null); + if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), + _tmp.getT2(), + entityType, + EntityModifyEvent::new); + } + return Mono.empty(); })); } @@ -364,8 +362,10 @@ protected void handleBatchOperation(Class clazz, if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { holder.before( this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); - return prepareEvent.getAsync(); + return publishEvent(this, + clazz, + () -> prepareEvent, + eventPublisher::publishEvent); }) ); } @@ -373,16 +373,20 @@ protected void handleBatchOperation(Class clazz, if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { holder.invoke( this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); - return beforeEvent.getAsync(); + return publishEvent(this, + clazz, + () -> beforeEvent, + eventPublisher::publishEvent); }) ); } if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { holder.after(v -> { return this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); + return publishEvent(this, + clazz, + () -> afterEvent, + eventPublisher::publishEvent); }); }); } @@ -426,8 +430,10 @@ protected void handleSingleOperation(Class clazz, if (null != prepareEvent && isEnabled(clazz, entityEventType, EntityEventPhase.prepare)) { holder.before( this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, prepareEvent, clazz)); - return prepareEvent.getAsync(); + return publishEvent(this, + clazz, + () -> prepareEvent, + eventPublisher::publishEvent); }) ); } @@ -435,16 +441,20 @@ protected void handleSingleOperation(Class clazz, if (null != beforeEvent && isEnabled(clazz, entityEventType, EntityEventPhase.before)) { holder.invoke( this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz)); - return beforeEvent.getAsync(); + return publishEvent(this, + clazz, + () -> beforeEvent, + eventPublisher::publishEvent); }) ); } if (null != afterEvent && isEnabled(clazz, entityEventType, EntityEventPhase.after)) { holder.after(v -> { return this.doAsyncEvent(() -> { - eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz)); - return afterEvent.getAsync(); + return publishEvent(this, + clazz, + () -> afterEvent, + eventPublisher::publishEvent); }); }); } @@ -458,8 +468,7 @@ protected void handleSingleOperation(Class clazz, } protected Mono doAsyncEvent(Supplier> eventSupplier) { - return EntityEventHelper - .isDoFireEvent(true) + return isDoFireEvent(true) .filter(Boolean::booleanValue) .flatMap(ignore -> { return eventSupplier.get(); From fb46f045c1a044f588689785bd63b15c5038125d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 15:24:13 +0800 Subject: [PATCH 121/542] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/event/AsyncEvent.java | 6 ++++++ .../hswebframework/web/event/DefaultAsyncEvent.java | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java index 77c575d2a..100748047 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java @@ -21,6 +21,12 @@ public interface AsyncEvent { */ void async(Publisher publisher); + /** + * 注册一个优先级高的任务 + * @param publisher 任务 + */ + void first(Publisher publisher); + /** * 推送事件到 ApplicationEventPublisher * diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index 36f30afb9..d58eae333 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -9,6 +9,8 @@ public class DefaultAsyncEvent implements AsyncEvent { @Getter private Mono async = Mono.empty(); + @Getter + private Mono first = Mono.empty(); private boolean hasListener; @@ -17,12 +19,18 @@ public synchronized void async(Publisher publisher) { this.async = async.then(Mono.from(publisher).then()); } + @Override + public synchronized void first(Publisher publisher) { + hasListener = true; + this.first = Mono.from(publisher).then(first); + } + @Override public Mono publish(ApplicationEventPublisher eventPublisher) { eventPublisher.publishEvent(this); - return this.async; + return this.first.then(this.async); } public boolean hasListener() { From c56652a9b8ef467579a096cb25112eff292d0e8c Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 17:17:37 +0800 Subject: [PATCH 122/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dfirst=E4=B8=8D?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/event/DefaultAsyncEvent.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index d58eae333..0cc0d64a6 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -7,9 +7,7 @@ public class DefaultAsyncEvent implements AsyncEvent { - @Getter private Mono async = Mono.empty(); - @Getter private Mono first = Mono.empty(); private boolean hasListener; @@ -25,12 +23,17 @@ public synchronized void first(Publisher publisher) { this.first = Mono.from(publisher).then(first); } + @Override + public Mono getAsync() { + return this.first.then(this.async); + } + @Override public Mono publish(ApplicationEventPublisher eventPublisher) { eventPublisher.publishEvent(this); - return this.first.then(this.async); + return getAsync(); } public boolean hasListener() { From c96f94357c0a9953d6850b73341fd3ba57b4f336 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 17:18:35 +0800 Subject: [PATCH 123/542] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8E=E7=BC=80?= =?UTF-8?q?=E8=BD=AC=E4=B8=BA=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/file/FileUploadProperties.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java index 7c1287738..c1ccb742b 100644 --- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java +++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java @@ -10,6 +10,7 @@ import java.io.File; import java.util.Date; +import java.util.Locale; import java.util.Set; @Getter @@ -30,7 +31,7 @@ public class FileUploadProperties { private Set denyMediaType; public boolean denied(String name, MediaType mediaType) { - String suffix = name.contains(".") ? name.substring(name.lastIndexOf(".") + 1) : ""; + String suffix = (name.contains(".") ? name.substring(name.lastIndexOf(".") + 1) : "").toLowerCase(Locale.ROOT); boolean defaultDeny = false; if (CollectionUtils.isNotEmpty(denyFiles)) { if (denyFiles.contains(suffix)) { From 6bf78a945f8981ee6640089232c3c847109699f0 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Sun, 26 Sep 2021 17:20:10 +0800 Subject: [PATCH 124/542] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8E=E7=BC=80?= =?UTF-8?q?=E8=BD=AC=E4=B8=BA=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/file/FileUploadPropertiesTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/FileUploadPropertiesTest.java b/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/FileUploadPropertiesTest.java index 0476bdc28..d72161081 100644 --- a/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/FileUploadPropertiesTest.java +++ b/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/FileUploadPropertiesTest.java @@ -25,6 +25,7 @@ public void testDenyWithAllow(){ uploadProperties.setAllowFiles(new HashSet<>(Arrays.asList("xls","json"))); assertFalse(uploadProperties.denied("test.xls", MediaType.ALL)); + assertFalse(uploadProperties.denied("test.XLS", MediaType.ALL)); assertTrue(uploadProperties.denied("test.exe", MediaType.ALL)); } From c51f5a502bab35b9a9d87273455a0cb676225305 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 28 Sep 2021 10:12:25 +0800 Subject: [PATCH 125/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 9f4ad00dd..17b6140a9 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -56,7 +56,8 @@ public Mono> handleException(UnsupportedOperationExcepti @ResponseStatus(HttpStatus.UNAUTHORIZED) public Mono> handleException(UnAuthorizedException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> (ResponseMessage.error(401, CodeConstants.Error.unauthorized, msg) + .resolveThrowable(e, (err, msg) -> (ResponseMessage + .error(401, CodeConstants.Error.unauthorized, msg) .result(e.getState()))); } @@ -175,7 +176,6 @@ public Mono> handleException(IllegalArgumentException e) public Mono> handleException(AuthenticationException e) { return LocaleUtils .resolveThrowable(e, (err, msg) -> ResponseMessage.error(400, err.getCode(), msg)) - .doOnEach(ReactiveLogger.onNext(r -> log.error(e.getLocalizedMessage(), e))) ; } From 5db1e87200fbc794b7e5247c28c5b3900ade246d Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 13 Oct 2021 14:13:24 +0800 Subject: [PATCH 126/542] 4.0.12 --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 6 +++--- 26 files changed, 28 insertions(+), 28 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 474c3bf07..c934b6e02 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 9f0520387..35782663a 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index ac8384abf..5d1eb4026 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index ee5932301..fffdb47e8 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 2dfc46220..1f70cecc1 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 70a5d4d87..b37cd8fae 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 1aa8c684f..ee97725d6 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 1e20dc9d8..47836eab9 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 78403e73d..73284a906 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 6a0ad3521..582e86bbe 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 441f96ea6..7c6708f52 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 568b37f01..094eb1d63 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 1aa0e2ee7..9ae233df8 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 66a48e7a8..4ff665b7b 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 556da7658..d7350b1e1 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index e7b01fc7e..d3cad29a6 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 63578e39f..045cde927 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index c37e11d05..76bde2742 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index e6052a036..132061de4 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 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 0e9365faa..db9216b92 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index dfc0507ad..70349ffef 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 68192e546..8cf3b2d53 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index e28a65878..6bc56f838 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 24f3d9977..cf4381e7e 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index 17f87c9a6..fa4e74ef1 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12-SNAPSHOT + 4.0.12 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 4f07bd296..fc884dabc 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.12-SNAPSHOT + 4.0.12 hsweb-starter hsweb-core @@ -90,12 +90,12 @@ 3.2.2 1.6.12 - 4.0.12-SNAPSHOT + 4.0.12 3.0.2 3.0.2 2.7.0 - Arabba-RELEASE + Arabba-SR10 From f6938e6f65c7a8591c84cdf831af363fd17ed391 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Oct 2021 08:58:57 +0800 Subject: [PATCH 127/542] 4.0.13-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index c934b6e02..260044351 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 35782663a..4cee3010c 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index 5d1eb4026..b1ed31100 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index fffdb47e8..ca288ae27 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 1f70cecc1..f273b989f 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index b37cd8fae..2f03314e7 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index ee97725d6..49956e019 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 47836eab9..b48abe970 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 73284a906..256a58bd1 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 582e86bbe..8e7394a11 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 7c6708f52..7add8016e 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 094eb1d63..6291e1e5b 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 9ae233df8..fa7a74e6e 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 4ff665b7b..f10f0f041 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index d7350b1e1..b264011c3 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index d3cad29a6..a1417bb87 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 045cde927..607ebd984 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 76bde2742..1b75183c0 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 132061de4..459e8e1ed 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 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 db9216b92..db9703dc3 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 70349ffef..fe06e8d32 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 8cf3b2d53..5d42aacb4 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 6bc56f838..9b98e9b81 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index cf4381e7e..041afbbf9 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index fa4e74ef1..d28ee529b 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.12 + 4.0.13-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index fc884dabc..870043527 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.12 + 4.0.13-SNAPSHOT hsweb-starter hsweb-core From c9af0310dbdca0066c7a6c47f185581dd20b1b28 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Oct 2021 09:02:51 +0800 Subject: [PATCH 128/542] =?UTF-8?q?=E4=BC=98=E5=8C=96id=20generator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/id/IDGenerator.java | 15 ++--- .../hswebframework/web/utils/DigestUtils.java | 60 +++++++++++++++++++ 2 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/id/IDGenerator.java b/hsweb-core/src/main/java/org/hswebframework/web/id/IDGenerator.java index bbb88dd8e..0b8dca66c 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/id/IDGenerator.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/id/IDGenerator.java @@ -19,6 +19,7 @@ package org.hswebframework.web.id; import org.hswebframework.utils.RandomUtil; +import org.hswebframework.web.utils.DigestUtils; import java.math.BigInteger; import java.security.MessageDigest; @@ -41,7 +42,7 @@ public interface IDGenerator { @SuppressWarnings("unchecked") static IDGenerator getNullGenerator() { - return (IDGenerator) NULL; + return (IDGenerator) NULL; } /** @@ -55,17 +56,9 @@ static IDGenerator getNullGenerator() { IDGenerator RANDOM = RandomUtil::randomChar; /** - * md5(uuid()+random()) + * md5(uuid()) */ - IDGenerator MD5 = () -> { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(UUID.generate().concat(RandomUtil.randomChar()).getBytes()); - return new BigInteger(1, md.digest()).toString(16); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - }; + IDGenerator MD5 = () -> DigestUtils.md5Hex(UUID.generate()); /** * 雪花算法 diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java new file mode 100644 index 000000000..214443292 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java @@ -0,0 +1,60 @@ +package org.hswebframework.web.utils; + +import org.apache.commons.codec.binary.Hex; + +import java.security.MessageDigest; + +public class DigestUtils { + + public static final MessageDigest md5 = org.apache.commons.codec.digest.DigestUtils.getMd5Digest(); + public static final MessageDigest sha256 = org.apache.commons.codec.digest.DigestUtils.getSha256Digest(); + public static final MessageDigest sha1 = org.apache.commons.codec.digest.DigestUtils.getSha1Digest(); + + public static byte[] md5(byte[] data) { + return org.apache.commons.codec.digest.DigestUtils.digest(md5, data); + } + + public static byte[] md5(String str) { + return md5(str.getBytes()); + } + + public static String md5Hex(String str) { + return Hex.encodeHexString(md5(str.getBytes())); + } + + public static byte[] sha256(byte[] data) { + return org.apache.commons.codec.digest.DigestUtils.digest(sha256, data); + } + + public static byte[] sha256(String str) { + return sha256(str.getBytes()); + } + + public static String sha256Hex(String str) { + return Hex.encodeHexString(sha256(str.getBytes())); + } + + public static byte[] sha1(byte[] data) { + return org.apache.commons.codec.digest.DigestUtils.digest(sha1, data); + } + + public static byte[] sha1(String str) { + return sha1(str.getBytes()); + } + + public static String sha1Hex(String str) { + return Hex.encodeHexString(sha1(str.getBytes())); + } + + public static byte[] digest(MessageDigest digest, byte[] data) { + return org.apache.commons.codec.digest.DigestUtils.digest(digest, data); + } + + public static byte[] digest(MessageDigest digest, String str) { + return digest(digest, str.getBytes()); + } + + public static String digestHex(MessageDigest digest, String str) { + return Hex.encodeHexString(digest(digest, str)); + } +} From 08bdc14973546374e62ca653ffad229148aa7ac2 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Oct 2021 09:09:51 +0800 Subject: [PATCH 129/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0UserStateChangedEvent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/event/UserStateChangedEvent.java | 20 +++++++++++++++++++ .../service/DefaultReactiveUserService.java | 15 ++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserStateChangedEvent.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserStateChangedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserStateChangedEvent.java new file mode 100644 index 000000000..35c08bd31 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserStateChangedEvent.java @@ -0,0 +1,20 @@ +package org.hswebframework.web.system.authorization.api.event; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor(staticName = "of") +public class UserStateChangedEvent extends DefaultAsyncEvent { + + private List userIdList; + + private byte state; + +} 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 index f3580edc5..2f771c7a3 100644 --- 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 @@ -13,10 +13,7 @@ import org.hswebframework.web.system.authorization.api.PasswordValidator; import org.hswebframework.web.system.authorization.api.UsernameValidator; import org.hswebframework.web.system.authorization.api.entity.UserEntity; -import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; -import org.hswebframework.web.system.authorization.api.event.UserCreatedEvent; -import org.hswebframework.web.system.authorization.api.event.UserDeletedEvent; -import org.hswebframework.web.system.authorization.api.event.UserModifiedEvent; +import org.hswebframework.web.system.authorization.api.event.*; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; @@ -113,7 +110,7 @@ protected Mono doUpdate(UserEntity userEntity) { .execute() .flatMap(__ -> new UserModifiedEvent(userEntity, passwordChanged).publish(eventPublisher)) .thenReturn(userEntity) - .doOnNext(e->{ + .doOnNext(e -> { eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(e.getId())); }); }); @@ -160,7 +157,13 @@ public Mono changeState(Publisher userId, byte state) { .set(UserEntity::getStatus, state) .where() .in(UserEntity::getId, list) - .execute()) + .execute() + .flatMap(i -> UserStateChangedEvent + .of(list, state) + .publish(eventPublisher) + .thenReturn(i) + ) + ) .defaultIfEmpty(0); } From cb6df631d538bca03170b3dfeede77d5d1c57e51 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Thu, 28 Oct 2021 10:20:44 +0800 Subject: [PATCH 130/542] =?UTF-8?q?=E7=A6=81=E7=94=A8=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=B8=A2=E5=87=BA=E7=94=A8=E6=88=B7=E7=99=BB?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...AuthorizationServiceAutoConfiguration.java | 6 +++ .../RemoveUserTokenWhenUserDisabled.java | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/RemoveUserTokenWhenUserDisabled.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java index 92c3ad910..a8f5e2f95 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java @@ -4,6 +4,7 @@ import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService; import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider; import org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration; +import org.hswebframework.web.authorization.token.UserTokenManager; import org.hswebframework.web.system.authorization.api.UserDimensionProvider; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.hswebframework.web.system.authorization.defaults.service.*; @@ -69,6 +70,11 @@ public DefaultPermissionService defaultPermissionService() { return new DefaultPermissionService(); } + @Bean + @ConditionalOnBean(UserTokenManager.class) + public RemoveUserTokenWhenUserDisabled removeUserTokenWhenUserDisabled(UserTokenManager tokenManager){ + return new RemoveUserTokenWhenUserDisabled(tokenManager); + } } @Bean diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/RemoveUserTokenWhenUserDisabled.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/RemoveUserTokenWhenUserDisabled.java new file mode 100644 index 000000000..80780d087 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/RemoveUserTokenWhenUserDisabled.java @@ -0,0 +1,38 @@ +package org.hswebframework.web.system.authorization.defaults.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.authorization.token.UserTokenManager; +import org.hswebframework.web.system.authorization.api.event.UserModifiedEvent; +import org.hswebframework.web.system.authorization.api.event.UserStateChangedEvent; +import org.springframework.context.event.EventListener; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@AllArgsConstructor +@Slf4j +public class RemoveUserTokenWhenUserDisabled { + + private final UserTokenManager userTokenManager; + + @EventListener + public void handleStateChangeEvent(UserModifiedEvent event) { + if (event.getUserEntity().getStatus() != null && event.getUserEntity().getStatus() != 1) { + event.async( + Mono.just(event.getUserEntity().getId()) + .flatMap(userTokenManager::signOutByUserId) + ); + } + } + + @EventListener + public void handleStateChangeEvent(UserStateChangedEvent event) { + if (event.getState() != 1) { + event.async( + Flux.fromIterable(event.getUserIdList()) + .flatMap(userTokenManager::signOutByUserId) + ); + } + } + +} From 79e85859b78bd8dd34e28bbf46a1b9c7ecfd327e Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 2 Nov 2021 15:22:01 +0800 Subject: [PATCH 131/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dpath=E4=B8=BAnull?= =?UTF-8?q?=E6=97=B6=E4=BC=9A=E6=9F=A5=E8=AF=A2=E5=87=BA=E6=89=80=E6=9C=89?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveTreeSortEntityService.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index 9b49472c1..84839cacc 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.service; -import org.apache.commons.collections4.CollectionUtils; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; import org.hswebframework.ezorm.rdb.operator.dml.Terms; import org.hswebframework.utils.RandomUtil; @@ -13,10 +12,8 @@ import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.util.function.Tuple3; import java.util.*; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -52,7 +49,10 @@ default Mono> queryIncludeChildrenTree(QueryParamEntity paramEntity) { default Flux queryIncludeChildren(Collection idList) { return findById(idList) - .flatMap(e -> createQuery() + .flatMap(e -> StringUtils + .isEmpty(e.getPath()) + ? Mono.just(e) + : createQuery() .where() .like$("path", e.getPath()) .fetch()); @@ -60,7 +60,10 @@ default Flux queryIncludeChildren(Collection idList) { default Flux queryIncludeParent(Collection idList) { return findById(idList) - .flatMap(e -> createQuery() + .flatMap(e -> StringUtils + .isEmpty(e.getPath()) + ? Mono.just(e) + : createQuery() .where() .accept(Terms.Like.reversal("path", e.getPath(), false, true)) .notEmpty("path") @@ -70,7 +73,10 @@ default Flux queryIncludeParent(Collection idList) { default Flux queryIncludeChildren(QueryParamEntity queryParam) { return query(queryParam) - .flatMap(e -> createQuery() + .flatMap(e -> StringUtils + .isEmpty(e.getPath()) + ? Mono.just(e) + : createQuery() .where() .like$("path", e.getPath()) .fetch()); @@ -193,9 +199,9 @@ default Flux tryRefactorPath(Flux stream) { K parentId = old != null ? old.getParentId() : data.getParentId(); E oldParent = parentId == null ? null : oldMap.get(parentId); if (old != null) { - K newParentId= data.getParentId(); + K newParentId = data.getParentId(); //父节点发生变化,更新所有子节点path - if (!Objects.equals(parentId,newParentId)) { + if (!Objects.equals(parentId, newParentId)) { List> jobs = new ArrayList<>(); Consumer childConsumer = child -> { //更新了父节点,但是同时也传入的对应的子节点 @@ -237,14 +243,14 @@ default Flux tryRefactorPath(Flux stream) { pathRefactor.accept(oldParent); } else if (parentId != null) { return findById(parentId) - .switchIfEmpty(Mono.fromRunnable(() ->{ + .switchIfEmpty(Mono.fromRunnable(() -> { data.setParentId(null); data.setLevel(1); data.setPath(old.getPath()); })) .doOnNext(pathRefactor) .thenReturn(data); - }else { + } else { data.setPath(old.getPath()); } From e867cca1a6d10a589fc578691479d57b467865bf Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 9 Nov 2021 12:17:05 +0800 Subject: [PATCH 132/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=B8=AD=E6=96=87=E6=9D=A1=E4=BB=B6=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/crud/entity/TermExpressionParser.java | 9 ++++++--- .../crud/entity/TermExpressionParserTest.java | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java index af76310f1..7000e3c46 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TermExpressionParser.java @@ -9,6 +9,8 @@ import org.hswebframework.ezorm.core.param.TermType; import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -24,12 +26,13 @@ */ public class TermExpressionParser { - static final URLCodec urlCodec = new URLCodec(); - @SneakyThrows public static List parse(String expression) { - expression = urlCodec.decode(expression); + try { + expression = URLDecoder.decode(expression, "utf-8"); + }catch (Throwable ignore){ + } Query conditional = QueryParamEntity.newQuery(); NestConditional nest = null; diff --git a/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java index a04ea1cd0..1d0b883b2 100644 --- a/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java +++ b/hsweb-commons/hsweb-commons-api/src/test/java/org/hswebframework/web/api/crud/entity/TermExpressionParserTest.java @@ -23,6 +23,25 @@ public void testUrl(){ assertEquals(terms.get(1).getValue(), "test"); } + + @Test + public void testChinese() { + { + List terms = TermExpressionParser.parse("name = 我"); + + assertEquals(terms.get(0).getTermType(), TermType.eq); + assertEquals(terms.get(0).getValue(),"我"); + + } + + { + List terms = TermExpressionParser.parse("name like %我%"); + + assertEquals(terms.get(0).getTermType(), TermType.like); + assertEquals(terms.get(0).getValue(),"%我%"); + + } + } @Test public void test() { { From 88d4fcf8dc6bc8b9d63e5f199f6968355ee4e7ee Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Tue, 9 Nov 2021 12:17:31 +0800 Subject: [PATCH 133/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=8E=B7=E5=8F=96map=E4=B8=AD=E5=8C=85?= =?UTF-8?q?=E5=90=AB.=E7=9A=84=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/utils/ExpressionUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/ExpressionUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/ExpressionUtils.java index de2af2fb1..5e247667d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/ExpressionUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/ExpressionUtils.java @@ -3,7 +3,6 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.beanutils.BeanUtilsBean2; -import org.apache.commons.codec.digest.DigestUtils; import org.hswebframework.expands.script.engine.DynamicScriptEngine; import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory; import org.hswebframework.expands.script.engine.ExecuteResult; @@ -91,7 +90,10 @@ public static String analytical(String expression, Map vars, Str if (StringUtils.isEmpty(var)) { return ""; } - + Object val = vars.get(var); + if (val != null) { + return String.valueOf(val); + } if ("spel".equalsIgnoreCase(language) && !var.contains("#")) { try { Object fast = BeanUtilsBean2.getInstance().getPropertyUtils().getProperty(vars, var); From e831c1d227b3eb0a214f7db2dea3e072f6016313 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Wed, 17 Nov 2021 11:58:22 +0800 Subject: [PATCH 134/542] #104 upgrade javassist 3.28.0-GA --- hsweb-core/pom.xml | 2 +- .../src/main/java/org/hswebframework/web/proxy/Proxy.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 8e7394a11..1e26bc252 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -18,7 +18,7 @@ org.javassist javassist - 3.22.0-GA + 3.28.0-GA com.fasterxml.jackson.core diff --git a/hsweb-core/src/main/java/org/hswebframework/web/proxy/Proxy.java b/hsweb-core/src/main/java/org/hswebframework/web/proxy/Proxy.java index cf6c1b3d0..f6a453e0c 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/proxy/Proxy.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/proxy/Proxy.java @@ -153,7 +153,7 @@ public I newInstance() { @SneakyThrows public Class getTargetClass() { if (targetClass == null) { - targetClass = ctClass.toClass(ClassUtils.getDefaultClassLoader(), null); + targetClass = (Class)ctClass.toClass(ClassUtils.getDefaultClassLoader(), null); } return targetClass; } From fdc16aeef3708c3f77f24bd94f2073a6bedaec4f Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 26 Nov 2021 11:49:44 +0800 Subject: [PATCH 135/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/web/CommonErrorControllerAdvice.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 17b6140a9..c1556f9c7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -16,7 +16,9 @@ import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -95,39 +97,44 @@ public Mono>> handleException(C @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) + @SuppressWarnings("all") public Mono>> handleException(BindException e) { - return handleException(new ValidationException(e.getMessage(), e - .getBindingResult().getAllErrors() - .stream() - .filter(FieldError.class::isInstance) - .map(FieldError.class::cast) - .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) - .collect(Collectors.toList()))); + return handleBindingResult(e.getBindingResult()); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) + @SuppressWarnings("all") public Mono>> handleException(WebExchangeBindException e) { - return handleException(new ValidationException(e.getMessage(), e - .getBindingResult().getAllErrors() - .stream() - .filter(FieldError.class::isInstance) - .map(FieldError.class::cast) - .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) - .collect(Collectors.toList()))); + return handleBindingResult(e.getBindingResult()); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) + @SuppressWarnings("all") public Mono>> handleException(MethodArgumentNotValidException e) { - return handleException(new ValidationException(e.getMessage(), e - .getBindingResult().getAllErrors() + return handleBindingResult(e.getBindingResult()); + } + + private Mono>> handleBindingResult(BindingResult result) { + String message; + FieldError fieldError = result.getFieldError(); + ObjectError globalError = result.getGlobalError(); + + if (null != fieldError) { + message = fieldError.getDefaultMessage(); + } else if (null != globalError) { + message = globalError.getDefaultMessage(); + } else { + message = CodeConstants.Error.illegal_argument; + } + List details = result + .getFieldErrors() .stream() - .filter(FieldError.class::isInstance) - .map(FieldError.class::cast) .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) - .collect(Collectors.toList()))); + .collect(Collectors.toList()); + return handleException(new ValidationException(message, details)); } @ExceptionHandler From f7ab9f922616b0deadefa3d04773fb67048f5563 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 6 Dec 2021 17:54:15 +0800 Subject: [PATCH 136/542] =?UTF-8?q?=E4=BC=98=E5=8C=96FastBeanCopier?= =?UTF-8?q?=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-core/pom.xml | 11 ++ .../web/bean/ClassDescription.java | 27 ++++ .../web/bean/ClassDescriptions.java | 16 +++ .../web/bean/FastBeanCopier.java | 119 +++++++++++------- 4 files changed, 125 insertions(+), 48 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 1e26bc252..4dfe92bb4 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -106,5 +106,16 @@ reactor-extra + + com.google.guava + guava + + + + jctools-core + org.jctools + 2.1.2 + + \ No newline at end of file diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java new file mode 100644 index 000000000..9de02b6b0 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java @@ -0,0 +1,27 @@ +package org.hswebframework.web.bean; + +import lombok.Getter; +import org.hswebframework.web.dict.EnumDict; + +import java.util.Collection; + +@Getter +public class ClassDescription { + private final Class type; + + private final boolean collectionType; + private final boolean arrayType; + private final boolean enumType; + private final boolean enumDict; + private final int fieldSize; + + public ClassDescription(Class type) { + this.type = type; + collectionType = Collection.class.isAssignableFrom(type); + enumDict = EnumDict.class.isAssignableFrom(type); + arrayType = type.isArray(); + enumType = type.isEnum(); + fieldSize = type.getDeclaredFields().length; + } + +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java new file mode 100644 index 000000000..c5af73b58 --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java @@ -0,0 +1,16 @@ +package org.hswebframework.web.bean; + +import org.jctools.maps.NonBlockingHashMap; + +import java.util.Map; + +public class ClassDescriptions { + + private static final Map, ClassDescription> CACHE = new NonBlockingHashMap<>(); + + public static ClassDescription getDescription(Class type) { + return CACHE.computeIfAbsent(type, ClassDescription::new); + } + + +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index e00ba28d4..066da714a 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -1,14 +1,17 @@ package org.hswebframework.web.bean; +import com.google.common.collect.Maps; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.beanutils.ConvertUtilsBean; import org.apache.commons.beanutils.PropertyUtilsBean; import org.hswebframework.utils.time.DateFormatter; import org.hswebframework.web.dict.EnumDict; import org.hswebframework.web.proxy.Proxy; +import org.jctools.maps.NonBlockingHashMap; import org.springframework.core.ResolvableType; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -30,10 +33,12 @@ */ @Slf4j public final class FastBeanCopier { - private static final Map CACHE = new ConcurrentHashMap<>(); + private static final Map CACHE = new NonBlockingHashMap<>(); private static final PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils(); + private static final ConvertUtilsBean convertUtils = BeanUtilsBean.getInstance().getConvertUtils(); + private static final Map, Class> wrapperClassMapping = new HashMap<>(); @SuppressWarnings("all") @@ -123,7 +128,7 @@ static Class getUserClass(Object object) { Class type = ClassUtils.getUserClass(object); if (java.lang.reflect.Proxy.isProxyClass(type)) { - Class[] interfaces= type.getInterfaces(); + Class[] interfaces = type.getInterfaces(); return interfaces[0]; } @@ -167,8 +172,8 @@ public static Copier createCopier(Class source, Class target) { "\n}"; try { return Proxy.create(Copier.class) - .addMethod(method) - .newInstance(); + .addMethod(method) + .newInstance(); } catch (Exception e) { log.error("创建bean copy 代理对象失败:\n{}", method, e); throw new UnsupportedOperationException(e.getMessage(), e); @@ -178,20 +183,22 @@ public static Copier createCopier(Class source, Class target) { private static Map createProperty(Class type) { List fieldNames = Arrays.stream(type.getDeclaredFields()) - .map(Field::getName).collect(Collectors.toList()); + .map(Field::getName).collect(Collectors.toList()); return Stream.of(propertyUtils.getPropertyDescriptors(type)) - .filter(property -> !property.getName().equals("class") && property.getReadMethod() != null && property.getWriteMethod() != null) - .map(BeanClassProperty::new) - //让字段有序 - .sorted(Comparator.comparing(property -> fieldNames.indexOf(property.name))) - .collect(Collectors.toMap(ClassProperty::getName, Function.identity(), (k, k2) -> k, LinkedHashMap::new)); + .filter(property -> !property + .getName() + .equals("class") && property.getReadMethod() != null && property.getWriteMethod() != null) + .map(BeanClassProperty::new) + //让字段有序 + .sorted(Comparator.comparing(property -> fieldNames.indexOf(property.name))) + .collect(Collectors.toMap(ClassProperty::getName, Function.identity(), (k, k2) -> k, LinkedHashMap::new)); } private static Map createMapProperty(Map template) { return template.values().stream().map(classProperty -> new MapClassProperty(classProperty.name)) - .collect(Collectors.toMap(ClassProperty::getName, Function.identity(), (k, k2) -> k, LinkedHashMap::new)); + .collect(Collectors.toMap(ClassProperty::getName, Function.identity(), (k, k2) -> k, LinkedHashMap::new)); } private static String createCopierCode(Class source, Class target) { @@ -231,13 +238,16 @@ private static String createCopierCode(Class source, Class target) { code.append("if($$__source.").append(sourceProperty.getReadMethod()).append("!=null){\n"); } code.append(targetProperty.generateVar(targetProperty.getName())).append("=") - .append(sourceProperty.generateGetter(target, targetProperty.getType())) - .append(";\n"); + .append(sourceProperty.generateGetter(target, targetProperty.getType())) + .append(";\n"); if (!targetProperty.isPrimitive()) { code.append("\tif(").append(sourceProperty.getName()).append("!=null){\n"); } - code.append("\t$$__target.").append(targetProperty.generateSetter(targetProperty.getType(), sourceProperty.getName())).append(";\n"); + code + .append("\t$$__target.") + .append(targetProperty.generateSetter(targetProperty.getType(), sourceProperty.getName())) + .append(";\n"); if (!targetProperty.isPrimitive()) { code.append("\t}\n"); } @@ -310,10 +320,10 @@ public boolean isWrapper(Class type) { protected Class getPrimitiveType(Class type) { return wrapperClassMapping.entrySet().stream() - .filter(entry -> entry.getValue() == type) - .map(Map.Entry::getKey) - .findFirst() - .orElse(null); + .filter(entry -> entry.getValue() == type) + .map(Map.Entry::getKey) + .findFirst() + .orElse(null); } protected Class getWrapperType() { @@ -334,11 +344,11 @@ public BiFunction, Class, String> createGetterFunction() { boolean hasGeneric = false; if (field != null) { String[] arr = Arrays.stream(ResolvableType.forField(field) - .getGenerics()) - .map(ResolvableType::getRawClass) - .filter(Objects::nonNull) - .map(t -> t.getName().concat(".class")) - .toArray(String[]::new); + .getGenerics()) + .map(ResolvableType::getRawClass) + .filter(Objects::nonNull) + .map(t -> t.getName().concat(".class")) + .toArray(String[]::new); if (arr.length > 0) { generic = "new Class[]{" + String.join(",", arr) + "}"; hasGeneric = true; @@ -365,11 +375,11 @@ public BiFunction, Class, String> createGetterFunction() { } else { //类型不一致,调用convert转换 convertCode.append("((").append(targetWrapperClass.getName()) - .append(")") - .append(convert) - .append(").") - .append(targetType.getName()) - .append("Value()"); + .append(")") + .append(convert) + .append(").") + .append(targetType.getName()) + .append("Value()"); } } else if (isPrimitive()) { @@ -377,25 +387,30 @@ public BiFunction, Class, String> createGetterFunction() { //源字段类型为基本数据类型,目标字段为包装器类型 if (targetIsWrapper) { convertCode.append(targetType.getName()) - .append(".valueOf(") - .append(getterCode) - .append(")"); + .append(".valueOf(") + .append(getterCode) + .append(")"); } else { convertCode.append("(").append(targetType.getName()) - .append(")(") - .append(convert) - .append(")"); + .append(")(") + .append(convert) + .append(")"); } } else { convertCode.append("(").append(getTypeName(targetType)) - .append(")(") - .append(convert) - .append(")"); + .append(")(") + .append(convert) + .append(")"); } } else { if (Cloneable.class.isAssignableFrom(targetType)) { try { - convertCode.append("(").append(getTypeName()).append(")").append(getterCode).append(".clone()"); + convertCode + .append("(") + .append(getTypeName()) + .append(")") + .append(getterCode) + .append(".clone()"); } catch (Exception e) { convertCode.append(getterCode); } @@ -499,7 +514,9 @@ public T convert(Object source, Class targetClass, Class[] genericType) { if (source == null) { return null; } - if (source.getClass().isEnum()) { + ClassDescription target = ClassDescriptions.getDescription(targetClass); + + if (target.isEnumType()) { if (source instanceof EnumDict) { Object val = (T) ((EnumDict) source).getValue(); if (targetClass.isInstance(val)) { @@ -555,8 +572,8 @@ public T convert(Object source, Class targetClass, Class[] genericType) { return (T) collection; } - if (targetClass.isEnum()) { - if (EnumDict.class.isAssignableFrom(targetClass)) { + if (target.isEnumType()){ + if (target.isEnumDict()) { String strVal = String.valueOf(source); Object val = EnumDict.find((Class) targetClass, e -> { @@ -567,10 +584,10 @@ public T convert(Object source, Class targetClass, Class[] genericType) { } return convert(val, targetClass, genericType); } - String strSource=String.valueOf(source); + String strSource = String.valueOf(source); for (T t : targetClass.getEnumConstants()) { if (((Enum) t).name().equalsIgnoreCase(strSource) - ||Objects.equals(String.valueOf(((Enum) t).ordinal()),strSource)) { + || Objects.equals(String.valueOf(((Enum) t).ordinal()), strSource)) { return t; } } @@ -579,21 +596,27 @@ public T convert(Object source, Class targetClass, Class[] genericType) { return null; } //转换为数组 - if (targetClass.isArray()) { + if (target.isArrayType()) { Class componentType = targetClass.getComponentType(); List val = convert(source, List.class, new Class[]{componentType}); return (T) val.toArray((Object[]) Array.newInstance(componentType, val.size())); } try { - org.apache.commons.beanutils.Converter converter = BeanUtilsBean - .getInstance() - .getConvertUtils() - .lookup(targetClass); + org.apache.commons.beanutils.Converter converter = convertUtils.lookup(targetClass); if (null != converter) { return converter.convert(targetClass, source); } + //快速复制map + if (targetClass == Map.class) { + if(source instanceof Map) { + return (T) new HashMap(((Map) source)); + } + ClassDescription sourType = ClassDescriptions.getDescription(source.getClass()); + return (T)copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize())); + } + return copy(source, beanFactory.newInstance(targetClass), this); } catch (Exception e) { log.warn("复制类型{}->{}失败", source, targetClass, e); From e199b29925c8789ab2ad8d4bc3b857d732cea790 Mon Sep 17 00:00:00 2001 From: zeje Date: Thu, 9 Dec 2021 18:59:12 +0800 Subject: [PATCH 137/542] Update RedisUserTokenManager.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 处理redis中Hash:user-token只增不减的bug --- .../web/authorization/token/redis/RedisUserTokenManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index e890de127..a33b5fa3f 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -184,7 +184,7 @@ public Mono signOutByToken(String token) { return getByToken(token) .flatMap(t -> operations .delete(getTokenRedisKey(t.getToken())) - .then(userTokenMapping.remove(getUserRedisKey(t.getToken()), token)) + .then(userTokenMapping.remove(getUserRedisKey(t.getUserId()), token)) .then(onTokenRemoved(t)) ) .then(); From b881e4bbefb473840c9c5751151b67614b842548 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 10 Dec 2021 09:40:56 +0800 Subject: [PATCH 138/542] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=88=97=E9=95=BF?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/authorization/api/entity/DimensionUserEntity.java | 4 ++-- .../web/dictionary/entity/DictionaryEntity.java | 2 +- .../web/dictionary/entity/DictionaryItemEntity.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index b4cb0256f..752361a18 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -34,7 +34,7 @@ public class DimensionUserEntity extends GenericEntity { private String dimensionTypeId; @Comment("维度ID") - @Column(name = "dimension_id", nullable = false, length = 32) + @Column(name = "dimension_id", nullable = false, length = 64) @Schema(description = "维度ID") private String dimensionId; @@ -45,7 +45,7 @@ public class DimensionUserEntity extends GenericEntity { private String dimensionName; @Comment("用户ID") - @Column(name = "user_id", nullable = false, length = 32) + @Column(name = "user_id", nullable = false, length = 64) @Schema(description = "用户ID") private String userId; diff --git a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java index 4dd1a001a..6b95b7e37 100644 --- a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java +++ b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java @@ -46,7 +46,7 @@ public class DictionaryEntity extends GenericEntity implements RecordCre @Schema(description = "字典名称") private String name; //分类 - @Column(length = 32, name = "classified") + @Column(length = 64, name = "classified") @Schema(description = "分类标识") private String classified; //说明 diff --git a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java index 09d417b23..ef74f9f2e 100644 --- a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java +++ b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java @@ -41,7 +41,7 @@ }) public class DictionaryItemEntity extends GenericTreeSortSupportEntity implements EnumDict { //字典id - @Column(name = "dict_id", length = 32, updatable = false, nullable = false) + @Column(name = "dict_id", length = 64, updatable = false, nullable = false) @Schema(description = "数据字典ID") private String dictId; //名称 From 25040ef2f898a5ab5d1072c5ee20b647127e8c60 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Fri, 10 Dec 2021 09:41:15 +0800 Subject: [PATCH 139/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=91=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/GenericTreeSortSupportEntity.java | 2 +- .../ReactiveTreeSortEntityService.java | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java index 6a37ebf61..8a79dbc5a 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/GenericTreeSortSupportEntity.java @@ -37,7 +37,7 @@ public abstract class GenericTreeSortSupportEntity extends GenericEntity /** * 父级类别 */ - @Column(name = "parent_id", length = 32) + @Column(name = "parent_id", length = 64) @Comment("父级ID") @Schema(description = "父节点ID") private PK parentId; diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index 84839cacc..d0759d640 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -48,38 +48,48 @@ default Mono> queryIncludeChildrenTree(QueryParamEntity paramEntity) { } default Flux queryIncludeChildren(Collection idList) { + Set duplicateCheck = new HashSet<>(); + return findById(idList) - .flatMap(e -> StringUtils - .isEmpty(e.getPath()) + .concatMap(e -> StringUtils + .isEmpty(e.getPath())|| !duplicateCheck.add(e.getPath()) ? Mono.just(e) : createQuery() .where() .like$("path", e.getPath()) - .fetch()); + .fetch()) + .distinct(TreeSupportEntity::getId); } default Flux queryIncludeParent(Collection idList) { + Set duplicateCheck = new HashSet<>(); + return findById(idList) - .flatMap(e -> StringUtils - .isEmpty(e.getPath()) + .concatMap(e -> StringUtils + .isEmpty(e.getPath())|| !duplicateCheck.add(e.getPath()) ? Mono.just(e) : createQuery() .where() .accept(Terms.Like.reversal("path", e.getPath(), false, true)) .notEmpty("path") .notNull("path") - .fetch()); + .fetch()) + .distinct(TreeSupportEntity::getId); } default Flux queryIncludeChildren(QueryParamEntity queryParam) { + Set duplicateCheck = new HashSet<>(); + return query(queryParam) - .flatMap(e -> StringUtils - .isEmpty(e.getPath()) + .concatMap(e -> StringUtils + .isEmpty(e.getPath()) || !duplicateCheck.add(e.getPath()) ? Mono.just(e) : createQuery() .where() .like$("path", e.getPath()) - .fetch()); + .fetch() + ) + .distinct(TreeSupportEntity::getId); } @Override From 26dc740560e3b29f33a3ed2c0719d715aed934f5 Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 13 Dec 2021 19:12:29 +0800 Subject: [PATCH 140/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8DDigestUtils=E5=9C=A8?= =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E4=B8=8B=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/utils/DigestUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java index 214443292..246a6dbd2 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java @@ -6,12 +6,12 @@ public class DigestUtils { - public static final MessageDigest md5 = org.apache.commons.codec.digest.DigestUtils.getMd5Digest(); - public static final MessageDigest sha256 = org.apache.commons.codec.digest.DigestUtils.getSha256Digest(); - public static final MessageDigest sha1 = org.apache.commons.codec.digest.DigestUtils.getSha1Digest(); + public static final ThreadLocal md5 = ThreadLocal.withInitial(org.apache.commons.codec.digest.DigestUtils::getMd5Digest); + public static final ThreadLocal sha256 = ThreadLocal.withInitial(org.apache.commons.codec.digest.DigestUtils::getSha256Digest); + public static final ThreadLocal sha1 = ThreadLocal.withInitial(org.apache.commons.codec.digest.DigestUtils::getSha1Digest); public static byte[] md5(byte[] data) { - return org.apache.commons.codec.digest.DigestUtils.digest(md5, data); + return org.apache.commons.codec.digest.DigestUtils.digest(md5.get(), data); } public static byte[] md5(String str) { @@ -23,7 +23,7 @@ public static String md5Hex(String str) { } public static byte[] sha256(byte[] data) { - return org.apache.commons.codec.digest.DigestUtils.digest(sha256, data); + return org.apache.commons.codec.digest.DigestUtils.digest(sha256.get(), data); } public static byte[] sha256(String str) { @@ -35,7 +35,7 @@ public static String sha256Hex(String str) { } public static byte[] sha1(byte[] data) { - return org.apache.commons.codec.digest.DigestUtils.digest(sha1, data); + return org.apache.commons.codec.digest.DigestUtils.digest(sha1.get(), data); } public static byte[] sha1(String str) { From e5df1e819919061a27b5e04b3d9673f3eb3a629b Mon Sep 17 00:00:00 2001 From: zhou-hao Date: Mon, 13 Dec 2021 19:15:46 +0800 Subject: [PATCH 141/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8DDigestUtils=E5=9C=A8?= =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E4=B8=8B=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/utils/DigestUtilsTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 hsweb-core/src/test/java/org/hswebframework/web/utils/DigestUtilsTest.java diff --git a/hsweb-core/src/test/java/org/hswebframework/web/utils/DigestUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/utils/DigestUtilsTest.java new file mode 100644 index 000000000..f052ef09e --- /dev/null +++ b/hsweb-core/src/test/java/org/hswebframework/web/utils/DigestUtilsTest.java @@ -0,0 +1,28 @@ +package org.hswebframework.web.utils; + +import lombok.SneakyThrows; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static org.junit.Assert.*; + +public class DigestUtilsTest { + + + @Test + @SneakyThrows + public void test() { + Set check = ConcurrentHashMap.newKeySet(); + + for (int i = 0; i < 1000; i++) { + new Thread(() -> check.add(DigestUtils.md5Hex("test"))) + .start(); + } + Thread.sleep(1000); + System.out.println(check); + assertEquals(1, check.size()); + } +} \ No newline at end of file From 4de4861d15dca6095e1d8c21c5ce9a56ff77b0d9 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 21 Dec 2021 10:10:41 +0800 Subject: [PATCH 142/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/FieldDataAccess.java | 4 + .../authorization/annotation/Resource.java | 73 ++++++++++++ .../annotation/ResourceAction.java | 43 +++++++- .../authorization/annotation/SaveAction.java | 9 +- .../authorization/annotation/UserOwnData.java | 3 + .../events/AuthorizingHandleBeforeEvent.java | 32 +++++- .../web/api/crud/entity/Entity.java | 30 +++++ .../web/api/crud/entity/PagerResult.java | 36 ++++++ .../crud/entity/QueryNoPagingOperation.java | 18 +++ .../web/api/crud/entity/QueryOperation.java | 18 ++- .../web/api/crud/entity/QueryParamEntity.java | 16 ++- .../api/crud/entity/RecordCreationEntity.java | 32 ++++++ .../api/crud/entity/RecordModifierEntity.java | 30 +++++ .../api/crud/entity/SortSupportEntity.java | 22 +++- .../api/crud/entity/TreeSupportEntity.java | 57 ++++++++++ .../annotation/EnableEasyormRepository.java | 16 +++ .../web/crud/annotation/Reactive.java | 4 + .../web/crud/service/ReactiveCrudService.java | 23 ++-- .../ReactiveTreeSortEntityService.java | 51 ++++++++- .../crud/web/CommonErrorControllerAdvice.java | 9 +- .../web/reactive/ReactiveCrudController.java | 9 ++ .../web/reactive/ReactiveSaveController.java | 104 +++++++++++++++++- .../ReactiveServiceQueryController.java | 73 +++++++++++- .../ReactiveServiceSaveController.java | 100 +++++++++++++++-- 24 files changed, 767 insertions(+), 45 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/FieldDataAccess.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/FieldDataAccess.java index 5c945f3fc..70b129ebf 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/FieldDataAccess.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/FieldDataAccess.java @@ -4,10 +4,14 @@ import java.lang.annotation.*; +/** + * @deprecated 已弃用 + */ @DataAccessType(id = "FIELD_DENY", name = "字段权限") @Retention(RetentionPolicy.RUNTIME) @Documented @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Deprecated public @interface FieldDataAccess { @AliasFor(annotation = DataAccessType.class) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java index 543704dbc..6b0efbe24 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java @@ -1,28 +1,101 @@ package org.hswebframework.web.authorization.annotation; +import org.hswebframework.web.authorization.Permission; import org.hswebframework.web.authorization.define.Phased; import java.lang.annotation.*; +/** + * 接口资源声明注解,声明Controller的资源相关信息,用于进行权限控制。 + *
+ * 在Controller进行注解,表示此接口需要有对应的权限{@link Permission#getId()}才能进行访问. + * 具体的操作权限控制,需要在方法上注解{@link ResourceAction}. + *
+ * + * + *
{@code
+ * @RestController
+ * //声明资源
+ * @Resource(id = "test", name = "测试功能")
+ * public class TestController implements ReactiveCrudController {
+ *
+ *     //声明操作,需要有 test:query 权限才能访问此接口
+ *     @QueryAction
+ *     public Mono getUser() {
+ *         return Authentication.currentReactive()
+ *                 .switchIfEmpty(Mono.error(new UnAuthorizedException()))
+ *                 .map(Authentication::getUser);
+ *     }
+ *
+ * }
+ * }
+ * 
+ * 如果接口不需要进行权限控制,可注解{@link Authorize#ignore()}来标识此接口不需要权限控制. + * 或者通过监听 {@link org.hswebframework.web.authorization.events.AuthorizingHandleBeforeEvent}来进行自定义处理 + *
{@code
+ *   @EventListener
+ *   public void handleAuthEvent(AuthorizingHandleBeforeEvent e) {
+ *      //admin用户可以访问全部操作
+ *      if ("admin".equals(e.getContext().getAuthentication().getUser().getUsername())) {
+ *         e.setAllow(true);
+ *       }
+ *    }
+ * }
+ * + * @author zhouhao + * @see ResourceAction + * @see Authorize + * @see org.hswebframework.web.authorization.events.AuthorizingHandleBeforeEvent + * @since 4.0 + */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Resource { + + /** + * 资源ID + * + * @return 资源ID + */ String id(); + /** + * @return 资源名称 + */ String name(); + /** + * @return 资源操作定义 + */ ResourceAction[] actions() default {}; + /** + * @return 多个操作控制逻辑 + */ Logical logical() default Logical.DEFAULT; + /** + * @return 权限控制阶段 + */ Phased phased() default Phased.before; + /** + * @return 资源描述 + */ String[] description() default {}; + /** + * @return 资源分组 + */ String[] group() default {}; + /** + * 如果在方法上设置此属性,表示是否合并类上注解的属性 + * + * @return 是否合并 + */ boolean merge() default true; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java index 335ef878d..e8993be5d 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java @@ -1,24 +1,65 @@ package org.hswebframework.web.authorization.annotation; -import org.hswebframework.web.authorization.define.Phased; + +import org.hswebframework.web.authorization.Permission; import java.lang.annotation.*; /** + * 对资源操作的描述,通常用来进行权限控制. + *

+ * 在Controller方法上添加此注解,来声明根据权限操作{@link Permission#getActions()}进行权限控制. + *

+ * 可以使用注解继承的方式来统一定义操作: + *

{@code
+ * @Target(ElementType.METHOD)
+ * @Retention(RetentionPolicy.RUNTIME)
+ * @Inherited
+ * @Documented
+ * @ResourceAction(id = "create", name = "新增")
+ * public @interface CreateAction {
+ *
+ * }
+ * }
+ * 
+ * * @see CreateAction + * @see DeleteAction + * @see SaveAction + * @see org.hswebframework.web.authorization.Authentication + * @see Permission#getActions() */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface ResourceAction { + /** + * 操作标识 + * + * @return 操作标识 + * @see Permission#getActions() + */ String id(); + /** + * @return 操作名称 + */ String name(); + /** + * @return 操作说明 + */ String[] description() default {}; + /** + * @return 多个操作时的判断逻辑 + */ Logical logical() default Logical.DEFAULT; + /** + * @deprecated 已弃用, 4.1中移除 + */ + @Deprecated DataAccess[] dataAccess() default @DataAccess(ignore = true); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/SaveAction.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/SaveAction.java index cf7b7b339..d878c52ae 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/SaveAction.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/SaveAction.java @@ -5,6 +5,12 @@ import java.lang.annotation.*; +/** + * 继承{@link ResourceAction},提供统一的id定义 + * + * @author zhouhao + * @since 4.0 + */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited @@ -12,6 +18,7 @@ @ResourceAction(id = Permission.ACTION_SAVE, name = "保存") public @interface SaveAction { - @AliasFor(annotation = ResourceAction.class,attribute = "dataAccess") + @Deprecated + @AliasFor(annotation = ResourceAction.class, attribute = "dataAccess") DataAccess dataAccess() default @DataAccess(ignore = true); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/UserOwnData.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/UserOwnData.java index 7f4caa9f8..74dbb12f7 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/UserOwnData.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/UserOwnData.java @@ -4,12 +4,15 @@ /** * 声明某个操作支持用户查看自己的数据 + * + * @deprecated 已弃用 */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @DataAccessType(id = "user_own_data", name = "用户自己的数据") +@Deprecated public @interface UserOwnData { } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizingHandleBeforeEvent.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizingHandleBeforeEvent.java index 3eb6d2876..d2d189f26 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizingHandleBeforeEvent.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizingHandleBeforeEvent.java @@ -4,6 +4,22 @@ import org.hswebframework.web.authorization.define.HandleType; import org.springframework.context.ApplicationEvent; +/** + * 权限控制事件,在进行权限控制之前会推送此事件,用于自定义权限控制结果: + *
{@code
+ *   @EventListener
+ *   public void handleAuthEvent(AuthorizingHandleBeforeEvent e) {
+ *      //admin用户可以访问全部操作
+ *      if ("admin".equals(e.getContext().getAuthentication().getUser().getUsername())) {
+ *         e.setAllow(true);
+ *       }
+ *    }
+ * }
+ * + * @author zhouhao + * @since 4.0 + */ +// TODO: 2021/12/21 Reactive支持 public class AuthorizingHandleBeforeEvent extends ApplicationEvent implements AuthorizationEvent { private static final long serialVersionUID = -1095765748533721998L; @@ -14,7 +30,7 @@ public class AuthorizingHandleBeforeEvent extends ApplicationEvent implements Au private String message; - private HandleType handleType; + private final HandleType handleType; public AuthorizingHandleBeforeEvent(AuthorizingContext context, HandleType handleType) { super(context); @@ -33,6 +49,11 @@ public boolean isAllow() { return allow; } + /** + * 设置通过当前请求 + * + * @param allow allow + */ public void setAllow(boolean allow) { execute = false; this.allow = allow; @@ -42,11 +63,18 @@ public String getMessage() { return message; } + /** + * 设置错误提示消息 + * + * @param message 消息 + */ public void setMessage(String message) { this.message = message; } - + /** + * @return 权限控制类型 + */ public HandleType getHandleType() { return handleType; } 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 52d100b81..9d69f33e6 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 @@ -32,18 +32,48 @@ */ public interface Entity extends Serializable { + /** + * 使用jsr303对当前实体类进行验证,如果未通过验证则会抛出{@link org.hswebframework.web.exception.ValidationException}异常 + * + * @param groups 分组 + * @see org.hswebframework.web.exception.ValidationException + */ default void tryValidate(Class... groups) { ValidatorUtils.tryValidate(this, groups); } + /** + * 将当前实体类复制到指定其他类型中,类型将会被自动实例化,在类型明确时,建议使用{@link Entity#copyFrom(Object, String...)}. + * + * @param target 目标类型 + * @param ignoreProperties 忽略复制的属性 + * @param 类型 + * @return 复制结果 + */ default T copyTo(Class target, String... ignoreProperties) { return FastBeanCopier.copy(this, target, ignoreProperties); } + /** + * 将当前实体类复制到其他对象中 + * + * @param target 目标实体 + * @param ignoreProperties 忽略复制的属性 + * @param 类型 + * @return 复制结果 + */ default T copyTo(T target, String... ignoreProperties) { return FastBeanCopier.copy(this, target, ignoreProperties); } + /** + * 从其他对象复制属性到当前对象 + * + * @param target 其他对象 + * @param ignoreProperties 忽略复制的属性 + * @param 类型 + * @return 当前对象 + */ @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/PagerResult.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java index 77d473772..9ff27518b 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/PagerResult.java @@ -28,15 +28,42 @@ import java.util.List; import java.util.Map; +/** + * 分页查询结果,用于在分页查询时,定义查询结果.如果需要拓展此类,例如自定义json序列化,请使用spi方式定义拓展实现类型: + *
+ * ---resources
+ * -----|--META-INF
+ * -----|----services
+ * -----|------org.hswebframework.web.api.crud.entity.PagerResult
+ * 
+ * + * @param 结果类型 + * @author zhouhao + * @since 4.0.0 + */ @Getter @Setter public class PagerResult { private static final long serialVersionUID = -6171751136953308027L; + /** + * 创建一个空结果 + * + * @param 结果类型 + * @return PagerResult + */ public static PagerResult empty() { return of(0, new ArrayList<>()); } + /** + * 创建一个分页结果 + * + * @param total 总数据量 + * @param list 当前页数据列表 + * @param 结果类型 + * @return PagerResult + */ @SuppressWarnings("all") public static PagerResult of(int total, List list) { PagerResult result; @@ -46,6 +73,15 @@ public static PagerResult of(int total, List list) { return result; } + /** + * 创建一个分页结果,并将查询参数中的分页索引等信息填充到分页结果中 + * + * @param total 总数据量 + * @param list 当前页数据列表 + * @param entity 查询参数 + * @param 结果类型 + * @return PagerResult + */ public static PagerResult of(int total, List list, QueryParam entity) { PagerResult pagerResult = of(total, list); pagerResult.setPageIndex(entity.getThinkPageIndex()); diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryNoPagingOperation.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryNoPagingOperation.java index cdf1ac6b7..f24aafb69 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryNoPagingOperation.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryNoPagingOperation.java @@ -22,6 +22,24 @@ import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.METHOD; +/** + * 使用注解继承来对swagger接口文档注解的拓展,用来标识接口不支持分页查询参数. + * + * + *
{@code
+ * @GetMapping
+ * @QueryNoPagingOperation(summary="接口说明")
+ * public Flux handleRequest(@Parameter(hidden = true) QueryParamEntity query){
+ *  return service.query(query);
+ * }
+ *
+ * }
+ * + * 注意在参数上注解 {@code @Parameter(hidden=true)} + * @author zhouhao + * @since 4.0.5 + * @see QueryNoPagingOperation#parameters() + */ @Target({METHOD, ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryOperation.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryOperation.java index 9552e72f5..3dd75ab47 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryOperation.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryOperation.java @@ -22,6 +22,22 @@ import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.METHOD; +/** + * 使用注解继承来对swagger接口文档注解的拓展,用来标识接口支持分页查询参数. + * + *
{@code
+ * @GetMapping
+ * @QueryOperation(summary="接口说明")
+ * public Flux handleRequest(@Parameter(hidden = true) QueryParamEntity query){
+ *  return service.query(query);
+ * }
+ *
+ * }
+ * + * @author zhouhao + * @see QueryOperation#parameters() + * @since 4.0.5 + */ @Target({METHOD, ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @@ -97,7 +113,7 @@ Parameter[] parameters() default { @Parameter(name = "where", description = "条件表达式,和terms参数冲突", example = "id = 1", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), @Parameter(name = "orderBy", description = "排序表达式,和sorts参数冲突", example = "id desc", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), @Parameter(name = "includes", description = "指定要查询的列,多列使用逗号分隔", example = "id", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), - @Parameter(name = "excludes", description = "指定不查询的列,多列使用逗号分隔", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), + @Parameter(name = "excludes", description = "指定不查询的列,多列使用逗号分隔", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), @Parameter(name = "terms[0].column", description = "指定条件字段", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY), @Parameter(name = "terms[0].termType", description = "条件类型", schema = @Schema(implementation = String.class), example = "like", in = ParameterIn.QUERY), @Parameter(name = "terms[0].type", description = "多个条件组合方式", schema = @Schema(implementation = Term.Type.class), in = ParameterIn.QUERY), diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index b02fecca2..680d51589 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -25,9 +25,19 @@ * 查询参数实体,使用easyorm进行动态查询参数构建
* 可通过静态方法创建:
* 如: - * - * QueryParamEntity.of("id",id); - * + *
+ *{@code
+ *      QueryParamEntity.of("id",id);
+ *}
+ * 
+ * + * 或者使用DSL方式来构造: + *
{@code
+ *  QueryParamEntity
+ *  .newQuery()
+ *  .where("id",1)
+ *  .execute(service::query)
+ * }
* * @author zhouhao * @see QueryParam diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordCreationEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordCreationEntity.java index 930e841f6..69c9d7272 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordCreationEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordCreationEntity.java @@ -12,23 +12,55 @@ */ public interface RecordCreationEntity extends Entity { + /** + * @return 创建者ID + */ String getCreatorId(); + /** + * 设置创建者ID + * + * @param creatorId 创建者ID + */ void setCreatorId(String creatorId); + /** + * 创建时间,UTC时间戳 + * + * @return 创建时间 + * @see System#currentTimeMillis() + */ Long getCreateTime(); + /** + * 设置创建时间 ,UTC时间戳 + * + * @param createTime 创建时间 + * @see System#currentTimeMillis() + */ void setCreateTime(Long createTime); + /** + * 设置创建者名字,为了兼容,默认不支持记录创建者名字,由具体的实现类进行实现 + * + * @param name 创建者名字 + */ default void setCreatorName(String name) { } + /** + * 设置创建时间为当前时间 + */ default void setCreateTimeNow() { setCreateTime(System.currentTimeMillis()); } + /** + * @deprecated 已弃用, 在4.1版本中移除 + */ @JsonIgnore + @Deprecated default String getCreatorIdProperty() { return "creatorId"; } diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordModifierEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordModifierEntity.java index e43c41801..4811967a5 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordModifierEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/RecordModifierEntity.java @@ -13,22 +13,52 @@ public interface RecordModifierEntity extends Entity { String modifierId = "modifierId"; String modifyTime = "modifyTime"; + /** + * 修改人ID + * + * @return 修改人ID + */ String getModifierId(); + /** + * 设置修改人ID + * + * @param modifierId 修改人ID + */ void setModifierId(String modifierId); + /** + * 设置修改人名字,为了兼容,默认不支持记录修改人名字,由具体的实现类进行实现 + * + * @param modifierName 修改人名字 + */ default void setModifierName(String modifierName) { } + /** + * @return 修改时间 + */ Long getModifyTime(); + /** + * 设置修改时间,UTC时间戳 + * + * @param modifyTime 修改时间 + * @see System#currentTimeMillis() + */ void setModifyTime(Long modifyTime); + /** + * 设置修改时间为当前时间 + */ default void setModifyTimeNow() { setModifyTime(System.currentTimeMillis()); } + /** + * @deprecated 已弃用, 4.1版本中移除 + */ @JsonIgnore default String getModifierIdProperty() { return modifierId; diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java index 64dd3862e..657946c8e 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java @@ -18,18 +18,30 @@ package org.hswebframework.web.api.crud.entity; +import javax.annotation.Nonnull; + +/** + * 支持排序的实体 + * + * @author zhouhao + * @since 4.0.0 + */ public interface SortSupportEntity extends Comparable, Entity { + /** + * @return 排序序号 + */ Long getSortIndex(); + /** + * 设置排序序号 + * + * @param sortIndex 排序序号 + */ void setSortIndex(Long sortIndex); @Override - default int compareTo(SortSupportEntity support) { - if (support == null) { - return -1; - } - + default int compareTo(@Nonnull SortSupportEntity support) { return Long.compare(getSortIndex() == null ? 0 : getSortIndex(), support.getSortIndex() == null ? 0 : support.getSortIndex()); } } diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index 3f35ddb6c..fd3e4e4f9 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -29,25 +29,82 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +/** + * 支持树结构的实体类 + * + * @param 主键类型 + * @author zhouhao + * @since 4.0 + */ @SuppressWarnings("all") public interface TreeSupportEntity extends Entity { + /** + * 获取主键 + * + * @return ID + */ PK getId(); + /** + * 设置主键 + * + * @param id ID + */ void setId(PK id); + /** + * 获取树路径,树路径表示当前节点所在位置 + * 格式通常为: aBcD-EfgH-iJkl,以-分割,一个分割表示一级. + * 比如: aBcD-EfgH-iJkl表示 当前节点在第三级,上一个节点为EfgH. + * + * @return 树路径 + */ String getPath(); + /** + * 设置路径,此值通常不需要手动设置,在进行保存时,由service自动进行分配. + * + * @param path 路径 + * @see TreeSupportEntity#expandTree2List(TreeSupportEntity, IDGenerator) + */ void setPath(String path); + /** + * 获取上级ID + * + * @return 上级ID + */ PK getParentId(); + /** + * 设置上级节点ID + * + * @param parentId + */ void setParentId(PK parentId); + /** + * 获取节点层级 + * + * @return 节点层级 + */ Integer getLevel(); + /** + * 设置节点层级 + * + * @return 节点层级 + */ void setLevel(Integer level); + /** + * 获取所有子节点,默认情况下此字段只会返回null.可以使用{@link TreeSupportEntity#list2tree(Collection, BiConsumer)}将 + * 列表结构转为树形结构 + * + * @param 当前实体类型 + * @return 自己节点 + */ > List getChildren(); @Override diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java index c7c9a60f8..5e2e820e8 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEasyormRepository.java @@ -7,6 +7,13 @@ import java.lang.annotation.*; /** + * 在启动类上注解,标识开启自动注册实体通用增删改查接口到spring上下文中. + * 在spring中,可直接进行泛型注入使用: + *
{@code
+ *   @Autowire
+ *   ReactiveRepository repository;
+ * }
+ * * @see org.hswebframework.ezorm.rdb.mapping.ReactiveRepository * @see org.hswebframework.ezorm.rdb.mapping.SyncRepository * @since 4.0.0 @@ -30,8 +37,17 @@ */ Class[] annotation() default Table.class; + /** + * @return 是否开启响应式, 默认开启 + */ boolean reactive() default true; + /** + * 是否开启非响应式操作,在使用WebFlux时,不建议开启 + * + * @return 开启非响应式 + * @see org.hswebframework.ezorm.rdb.mapping.SyncRepository + */ boolean nonReactive() default false; } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/Reactive.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/Reactive.java index b535fe517..aa7982b48 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/Reactive.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/Reactive.java @@ -3,7 +3,11 @@ import java.lang.annotation.*; /** + * 在实体类上注解,标记是否开启响应式仓库 + * + * @author zhouhao * @see org.hswebframework.ezorm.rdb.mapping.ReactiveRepository + * @since 4.0.0 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) 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 67680a295..6179b186a 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 @@ -37,13 +37,13 @@ public interface ReactiveCrudService { /** * 创建一个DSL的动态查询接口,可使用DSL方式进行链式调用来构造动态查询条件.例如: - *
-     * Flux<MyEntity> flux=
-     *     service
+     * 
{@code
+     * Flux flux = service
      *     .createQuery()
      *     .where(MyEntity::getName,name)
      *     .in(MyEntity::getState,state1,state2)
      *     .fetch()
+     * }
      * 
* * @return 动态查询接口 @@ -54,14 +54,14 @@ default ReactiveQuery createQuery() { /** * 创建一个DSL动态更新接口,可使用DSL方式进行链式调用来构造动态更新条件.例如: - *
-     * Mono<Integer> flux=
-     *     service
+     * 
{@code
+     * Mono result = service
      *     .createUpdate()
      *     .set(entity::getState)
      *     .where(MyEntity::getName,name)
      *     .in(MyEntity::getState,state1,state2)
      *     .execute()
+     *     }
      * 
* * @return 动态更新接口 @@ -72,13 +72,13 @@ default ReactiveUpdate createUpdate() { /** * 创建一个DSL动态删除接口,可使用DSL方式进行链式调用来构造动态删除条件.例如: - *
-     * Mono<Integer> flux=
-     *     service
+     * 
{@code
+     * Mono result = service
      *     .createDelete()
      *     .where(MyEntity::getName,name)
      *     .in(MyEntity::getState,state1,state2)
      *     .execute()
+     * }
      * 
* * @return 动态更新接口 @@ -194,6 +194,8 @@ default Mono> queryPager(QueryParamEntity queryParamMono) { @Transactional(readOnly = true, transactionManager = TransactionManagers.reactiveTransactionManager) default Mono> queryPager(QueryParamEntity query, Function mapper) { + //如果查询参数指定了总数,表示不需要再进行count操作. + //建议前端在使用分页查询时,切换下一页时,将第一次查询到total结果传入查询参数,可以提升查询性能. if (query.getTotal() != null) { return getRepository() .createQuery() @@ -203,7 +205,7 @@ default Mono> queryPager(QueryParamEntity query, Function PagerResult.of(query.getTotal(), list, query)); } - //并行分页 + //并行分页,更快,所在页码无数据时,会返回空list. if (query.isParallelPager()) { return Mono .zip( @@ -220,6 +222,7 @@ default Mono> queryPager(QueryParamEntity query, Function(), query)); } + //查询前根据数据总数进行重新分页:要跳转的页码没有数据则跳转到最后一页 return query(query.clone().rePaging(total)) .map(mapper) .collectList() diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index d0759d640..64f14a28c 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -20,6 +20,8 @@ import java.util.stream.Collectors; /** + * 树形结构的通用增删改查服务 + * * @param TreeSortSupportEntity * @param ID * @see GenericReactiveTreeSupportCrudService @@ -27,10 +29,22 @@ public interface ReactiveTreeSortEntityService, K> extends ReactiveCrudService { + /** + * 动态查询并将查询结构转为树形结构 + * + * @param paramEntity 查询参数 + * @return 树形结构 + */ default Mono> queryResultToTree(Mono paramEntity) { return paramEntity.flatMap(this::queryResultToTree); } + /** + * 动态查询并将查询结构转为树形结构 + * + * @param paramEntity 查询参数 + * @return 树形结构 + */ default Mono> queryResultToTree(QueryParamEntity paramEntity) { return query(paramEntity) .collectList() @@ -39,6 +53,12 @@ default Mono> queryResultToTree(QueryParamEntity paramEntity) { this::createRootNodePredicate)); } + /** + * 动态查询并将查询结构转为树形结构,包含所有子节点 + * + * @param paramEntity 查询参数 + * @return 树形结构 + */ default Mono> queryIncludeChildrenTree(QueryParamEntity paramEntity) { return queryIncludeChildren(paramEntity) .collectList() @@ -47,29 +67,43 @@ default Mono> queryIncludeChildrenTree(QueryParamEntity paramEntity) { this::createRootNodePredicate)); } + /** + * 查询指定ID的实体以及对应的全部子节点 + * + * @param idList ID集合 + * @return 树形结构 + */ default Flux queryIncludeChildren(Collection idList) { Set duplicateCheck = new HashSet<>(); return findById(idList) .concatMap(e -> StringUtils - .isEmpty(e.getPath())|| !duplicateCheck.add(e.getPath()) + .isEmpty(e.getPath()) || !duplicateCheck.add(e.getPath()) ? Mono.just(e) : createQuery() .where() + //使用path快速查询 .like$("path", e.getPath()) .fetch()) .distinct(TreeSupportEntity::getId); } + /** + * 查询指定ID的实体以及对应的全部父节点 + * + * @param idList ID集合 + * @return 树形结构 + */ default Flux queryIncludeParent(Collection idList) { Set duplicateCheck = new HashSet<>(); return findById(idList) .concatMap(e -> StringUtils - .isEmpty(e.getPath())|| !duplicateCheck.add(e.getPath()) + .isEmpty(e.getPath()) || !duplicateCheck.add(e.getPath()) ? Mono.just(e) : createQuery() .where() + //where ? like path and path !='' and path not null .accept(Terms.Like.reversal("path", e.getPath(), false, true)) .notEmpty("path") .notNull("path") @@ -77,6 +111,12 @@ default Flux queryIncludeParent(Collection idList) { .distinct(TreeSupportEntity::getId); } + /** + * 动态查询并将查询结构转为树形结构 + * + * @param queryParam 查询参数 + * @return 树形结构 + */ default Flux queryIncludeChildren(QueryParamEntity queryParam) { Set duplicateCheck = new HashSet<>(); @@ -134,6 +174,7 @@ default Mono checkCyclicDependency(K id, E ele) { .then(Mono.just(ele)); } + //重构子节点的path default Mono refactorChildPath(K id, String path, Consumer pathAccepter) { return this .createQuery() @@ -161,6 +202,7 @@ default Mono refactorChildPath(K id, String path, Consumer pathAccepter default Mono save(Publisher entityPublisher) { return Flux .from(entityPublisher) + //1.先平铺 .flatMapIterable(e -> TreeSupportEntity.expandTree2List(e, getIDGenerator())) .collectList() .flatMapIterable(list -> { @@ -168,14 +210,17 @@ default Mono save(Publisher entityPublisher) { .stream() .filter(e -> e.getId() != null) .collect(Collectors.toMap(TreeSupportEntity::getId, Function.identity())); - + //2. 重新组装树结构 return TreeSupportEntity.list2tree(list, this::setChildren, (Predicate) e -> this.isRootNode(e) || map.get(e.getParentId()) == null); }) + //执行验证 .doOnNext(e -> e.tryValidate(CreateGroup.class)) + //再次平铺为 .flatMapIterable(e -> TreeSupportEntity.expandTree2List(e, getIDGenerator())) + //重构path .as(this::tryRefactorPath) .as(this.getRepository()::save); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index c1556f9c7..0d4b0b77e 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -32,8 +32,13 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; +/** + * 统一错误处理 + * + * @author zhouhao + * @since 4.0 + */ @RestControllerAdvice -//@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @Slf4j @Order public class CommonErrorControllerAdvice { @@ -134,7 +139,7 @@ private Mono>> handleBindingRes .stream() .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(), null)) .collect(Collectors.toList()); - return handleException(new ValidationException(message, details)); + return handleException(new ValidationException(message, details)); } @ExceptionHandler diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveCrudController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveCrudController.java index 3437a0eab..16c31e46f 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveCrudController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveCrudController.java @@ -1,5 +1,14 @@ package org.hswebframework.web.crud.web.reactive; +/** + * 通用响应式增删该查Controller,实现本接口来默认支持增删改查相关操作. + * + * @param 实体类型 + * @param 主键类型 + * @see ReactiveSaveController + * @see ReactiveQueryController + * @see ReactiveDeleteController + */ public interface ReactiveCrudController extends ReactiveSaveController, ReactiveQueryController, diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java index c373a6323..cad2f6dcc 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java @@ -15,6 +15,12 @@ import javax.validation.Valid; +/** + * 响应式保存接口,基于{@link ReactiveRepository}提供默认的新增,保存,修改接口. + * + * @param 实体类型 + * @param 主键类型 + */ public interface ReactiveSaveController { @Authorize(ignore = true) @@ -38,6 +44,14 @@ default E applyModifierEntity(Authentication authentication, E entity) { return entity; } + /** + * 尝试设置登陆用户信息到实体中 + * + * @param entity 实体 + * @param authentication 权限信息 + * @see RecordCreationEntity + * @see RecordModifierEntity + */ @Authorize(ignore = true) default E applyAuthentication(E entity, Authentication authentication) { if (entity instanceof RecordCreationEntity) { @@ -49,45 +63,123 @@ default E applyAuthentication(E entity, Authentication authentication) { return entity; } + /** + * 保存数据,如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增. + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * PATCH /api/test
+     * Content-Type: application/json
+     *
+     * [
+     *  {
+     *   "name":"value"
+     *  }
+     * ]
+     * }
+     * 
+ * + * @param payload payload + * @return 保存结果 + */ @PatchMapping @SaveAction @Operation(summary = "保存数据", description = "如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增.") default Mono save(@RequestBody Flux payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMapMany(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .as(getRepository()::save); } + /** + * 批量新增 + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * POST /api/test/_batch
+     * Content-Type: application/json
+     *
+     * [
+     *  {
+     *   "name":"value"
+     *  }
+     * ]
+     * }
+     * 
+ * + * @param payload payload + * @return 保存结果 + */ @PostMapping("/_batch") @SaveAction @Operation(summary = "批量新增数据") default Mono add(@RequestBody Flux payload) { - - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMapMany(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .collectList() .as(getRepository()::insertBatch); } + /** + * 新增单个数据,并返回新增后的数据. + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * POST /api/test
+     * Content-Type: application/json
+     *
+     *  {
+     *   "name":"value"
+     *  }
+     * }
+     * 
+ * + * @param payload payload + * @return 新增后的数据 + */ @PostMapping @SaveAction @Operation(summary = "新增单个数据,并返回新增后的数据.") default Mono add(@RequestBody Mono payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMap(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .flatMap(entity -> getRepository().insert(Mono.just(entity)).thenReturn(entity)); } + /** + * 根据ID修改数据 + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * PUT /api/test/{id}
+     * Content-Type: application/json
+     *
+     *  {
+     *   "name":"value"
+     *  }
+     * }
+     * 
+ * + * @param payload payload + * @return 是否成功 + */ @PutMapping("/{id}") @SaveAction @Operation(summary = "根据ID修改数据") default Mono update(@PathVariable K id, @RequestBody Mono payload) { - - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMap(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .flatMap(entity -> getRepository().updateById(id, Mono.just(entity))) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java index d1dd307e4..ef0f074a1 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java @@ -74,7 +74,7 @@ default Flux query(@Parameter(hidden = true) QueryParamEntity query) { @QueryAction @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)", description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false") - default Flux query(@Parameter(hidden = true)@RequestBody Mono query) { + default Flux query(@Parameter(hidden = true) @RequestBody Mono query) { return query.flatMapMany(this::query); } @@ -105,6 +105,31 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti } + /** + * POST方式动态查询. + * + *
+     *     POST /_query
+     *
+     *     {
+     *         "pageIndex":0,
+     *         "pageSize":20,
+     *         "where":"name like 张%", //放心使用,没有SQL注入
+     *         "orderBy":"id desc",
+     *         "terms":[ //高级条件
+     *             {
+     *                 "column":"name",
+     *                 "termType":"like",
+     *                 "value":"张%"
+     *             }
+     *         ]
+     *     }
+     * 
+ * + * @param query 查询条件 + * @return 结果流 + * @see QueryParamEntity + */ @PostMapping("/_query") @QueryAction @SuppressWarnings("all") @@ -113,6 +138,31 @@ default Mono> queryPager(@Parameter(hidden = true) @RequestBody M return query.flatMap(q -> queryPager(q)); } + /** + * POST方式动态查询数量. + * + *
+     *     POST /_count
+     *
+     *     {
+     *         "pageIndex":0,
+     *         "pageSize":20,
+     *         "where":"name like 张%", //放心使用,没有SQL注入
+     *         "orderBy":"id desc",
+     *         "terms":[ //高级条件
+     *             {
+     *                 "column":"name",
+     *                 "termType":"like",
+     *                 "value":"张%"
+     *             }
+     *         ]
+     *     }
+     * 
+ * + * @param query 查询条件 + * @return 查询结果 + * @see QueryParamEntity + */ @PostMapping("/_count") @QueryAction @QueryNoPagingOperation(summary = "使用POST方式查询总数") @@ -121,14 +171,17 @@ default Mono count(@Parameter(hidden = true) @RequestBody Mono - * GET /_count + * + * GET /_query/_count?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc + * *
* * @param query 查询条件 - * @return 统计结果 + * @return 查询结果 + * @see QueryParamEntity */ @GetMapping("/_count") @QueryAction @@ -140,6 +193,18 @@ default Mono count(@Parameter(hidden = true) QueryParamEntity query) { .count(); } + /** + * 根据ID查询. + *
+     * {@code
+     *     GET /{id}
+     * }
+     * 
+ * + * @param id ID + * @return 结果流 + * @see QueryParamEntity + */ @GetMapping("/{id:.+}") @QueryAction @Operation(summary = "根据ID查询") diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java index 581adfb7f..cf82b783b 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java @@ -1,6 +1,7 @@ package org.hswebframework.web.crud.web.reactive; import io.swagger.v3.oas.annotations.Operation; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; import org.hswebframework.web.api.crud.entity.RecordCreationEntity; import org.hswebframework.web.api.crud.entity.RecordModifierEntity; @@ -12,10 +13,16 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -public interface ReactiveServiceSaveController { +/** + * 响应式保存接口,基于{@link ReactiveCrudService}提供默认的新增,保存,修改接口. + * + * @param 实体类型 + * @param 主键类型 + */ +public interface ReactiveServiceSaveController { @Authorize(ignore = true) - ReactiveCrudService getService(); + ReactiveCrudService getService(); @Authorize(ignore = true) default E applyCreationEntity(Authentication authentication, E entity) { @@ -46,45 +53,124 @@ default E applyAuthentication(E entity, Authentication authentication) { return entity; } + /** + * 保存数据,如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增. + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * PATCH /api/test
+     * Content-Type: application/json
+     *
+     * [
+     *  {
+     *   "name":"value"
+     *  }
+     * ]
+     * }
+     * 
+ * + * @param payload payload + * @return 保存结果 + */ @PatchMapping @SaveAction @Operation(summary = "保存数据", description = "如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增.") default Mono save(@RequestBody Flux payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMapMany(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .as(getService()::save); } + /** + * 批量新增 + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * POST /api/test/_batch
+     * Content-Type: application/json
+     *
+     * [
+     *  {
+     *   "name":"value"
+     *  }
+     * ]
+     * }
+     * 
+ * + * @param payload payload + * @return 保存结果 + */ @PostMapping("/_batch") @SaveAction @Operation(summary = "批量新增数据") default Mono add(@RequestBody Flux payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMapMany(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .collectList() .as(getService()::insertBatch); } + /** + * 新增单个数据,并返回新增后的数据. + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * POST /api/test
+     * Content-Type: application/json
+     *
+     *  {
+     *   "name":"value"
+     *  }
+     * }
+     * 
+ * + * @param payload payload + * @return 新增后的数据 + */ @PostMapping @SaveAction @Operation(summary = "新增单个数据,并返回新增后的数据.") default Mono add(@RequestBody Mono payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMap(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .flatMap(entity -> getService().insert(Mono.just(entity)).thenReturn(entity)); } - + /** + * 根据ID修改数据 + *

+ * 以类注解{@code @RequestMapping("/api/test")}为例: + *
{@code
+     *
+     * PUT /api/test/{id}
+     * Content-Type: application/json
+     *
+     *  {
+     *   "name":"value"
+     *  }
+     * }
+     * 
+ * + * @param payload payload + * @return 是否成功 + */ @PutMapping("/{id}") @SaveAction @Operation(summary = "根据ID修改数据") default Mono update(@PathVariable K id, @RequestBody Mono payload) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .flatMap(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .flatMap(entity -> getService().updateById(id, Mono.just(entity))) From 43d3b908c4a8f0f8083fbb11b90334b71282069b Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 23 Dec 2021 15:05:40 +0800 Subject: [PATCH 143/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9ca7dcc37..deff62247 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # hsweb4 基于spring-boot2,全响应式的后台管理框架 + [![Codecov](https://codecov.io/gh/hs-web/hsweb-framework/branch/4.0.x/graph/badge.svg)](https://codecov.io/gh/hs-web/hsweb-framework/branch/master) [![Build Status](https://api.travis-ci.com/hs-web/hsweb-framework.svg?branch=4.0.x)](https://travis-ci.com/hs-web/hsweb-framework) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg?style=flat-square)](https://www.apache.org/licenses/LICENSE-2.0.html) # 功能,特性 + - [x] 基于[r2dbc](https://github.com/r2dbc) ,[easy-orm](https://github.com/hs-web/hsweb-easy-orm/tree/4.0.x) 的通用响应式CRUD - [x] H2,Mysql,SqlServer,PostgreSQL - [x] 响应式r2dbc事务控制 @@ -12,7 +14,7 @@ - [x] 数据权限控制 - [ ] 双因子验证 - [x] 多维度权限管理功能 -- [x] 响应式缓存 +- [x] 响应式缓存 - [ ] 非响应式支持(mvc,jdbc) - [ ] 内置业务功能 - [x] 权限管理 @@ -24,10 +26,108 @@ - [ ] 文件秒传 - [x] 数据字典 -# 文档 +# 示例 + +https://github.com/zhou-hao/hsweb4-examples + +## 应用场景 + +1. 完全开源的后台管理系统. +2. 模块化的后台管理系统. +3. 功能可拓展的后台管理系统. +4. 集成各种常用功能的后台管理系统. +5. 前后分离的后台管理系统. + +注意: +项目主要基于`spring-boot`,`spring-webflux`. 在使用`hsweb`之前,你应该对 [project-reactor](https://projectreactor.io/) , +[spring-boot](https://github.com/spring-projects/spring-boot) 有一定的了解. + +项目模块太多?不要被吓到.我们不推荐将本项目直接`clone`后修改,运行.而是使用maven依赖的方式使用`hsweb`. 选择自己需要的模块进行依赖,正式版发布后,所有模块都将发布到maven中央仓库. + +## 文档 + +各个模块的使用方式查看对应模块下的 `README.md`,在使用之前, 你可以先粗略浏览一下各个模块,对每个模块的作用有大致的了解. + +## 核心技术选型 + +1. Java 8 +2. Maven3 +3. Spring Boot 2.x +4. Project Reactor 响应式编程框架 +5. hsweb easy orm 对r2dbc的orm封装 + +## 模块简介 + +| 模块 | 说明 | +| ------------- |:----------:| +|[hsweb-authorization](hsweb-authorization)| 权限控制 | +|[hsweb-commons](hsweb-commons) | 基础通用功能 | +|[hsweb-concurrent](hsweb-concurrent)| 并发包,缓存,等 | +|[hsweb-core](hsweb-core)| 框架核心,基础工具类 | +|[hsweb-datasource](hsweb-datasource)| 数据源 | +|[hsweb-logging](hsweb-logging)| 日志 | +|[hsweb-starter](hsweb-starter)| 模块启动器 | +|[hsweb-system](hsweb-system)| **系统常用功能** | + +## 核心特性 + +1. 响应式,首个基于spring-webflux,r2dbc,从头到位的响应式. +2. DSL风格,可拓展的通用curd,支持前端直接传参数,无需担心任何sql注入. + +```java + //where name = #{name} + createQuery() + .where("name",name) + .fetch(); + + //update s_user set name = #{user.name} where id = #{user.id} + createUpdate() + .set(user::getName) + .where(user::getId) + .execute(); + +``` + +3. 类JPA增删改 + +```java + +@Table(name = "s_entity") +public class MyEntity { + + @Id + private String id; + + @Column + private String name; + + @Column + private Long createTime; +} + +``` + +直接注入即可实现增删改查 + +```java + +@Autowire +private ReactiveRepository repository; + +``` + +2. 灵活的权限控制 + +```java + +@PostMapping("/account") +@SaveAction +public Mono addAccount(@RequestBody Mono account){ + return accountService.doSave(account); +} -直接看代码: https://github.com/zhou-hao/hsweb4-examples +``` -# 实践 +## License -[JetLinks开源物联网平台](https://github.com/jetlinks) +[Apache 2.0](https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt) \ No newline at end of file From 5f752c81c3b7fc18c7b1126008e41b550456b15a Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 27 Dec 2021 13:44:29 +0800 Subject: [PATCH 144/542] =?UTF-8?q?=E5=87=8F=E5=B0=91=E4=B8=8D=E5=BF=85?= =?UTF-8?q?=E8=A6=81=E7=9A=84=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/aop/MethodInterceptorHolder.java | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java index 4bfa511c4..57b1b0304 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/aop/MethodInterceptorHolder.java @@ -18,14 +18,16 @@ package org.hswebframework.web.aop; +import com.google.common.collect.Maps; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; import org.aopalliance.intercept.MethodInvocation; import org.hswebframework.web.utils.AnnotationUtils; +import org.hswebframework.web.utils.DigestUtils; import org.reactivestreams.Publisher; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.util.DigestUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -48,25 +50,28 @@ public class MethodInterceptorHolder { public static final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); public static MethodInterceptorHolder create(MethodInvocation invocation) { - String id = DigestUtils.md5DigestAsHex(String.valueOf(invocation.getMethod().hashCode()).getBytes()); String[] argNames = nameDiscoverer.getParameterNames(invocation.getMethod()); Object[] args = invocation.getArguments(); - Map argMap = new LinkedHashMap<>(); - String[] names = new String[args.length]; - for (int i = 0, len = args.length; i < len; i++) { - names[i] = (argNames == null || argNames.length <= i || argNames[i] == null) ? "arg" + i : argNames[i]; - argMap.put(names[i], args[i]); - } - return new MethodInterceptorHolder(id, - invocation.getMethod(), - invocation.getThis(), - args, - names, - argMap); + String[] names; + //参数名与参数长度不一致,则填充argx来作为参数名 + if (argNames == null || argNames.length != args.length) { + names = new String[args.length]; + for (int i = 0, len = args.length; i < len; i++) { + names[i] = (argNames == null || argNames.length <= i || argNames[i] == null) ? "arg" + i : argNames[i]; + } + } else { + names = argNames; + } + return new MethodInterceptorHolder(null, + invocation.getMethod(), + invocation.getThis(), + args, + names, + null); } - private final String id; + private String id; private final Method method; @@ -76,8 +81,27 @@ public static MethodInterceptorHolder create(MethodInvocation invocation) { private final String[] argumentsNames; - private final Map namedArguments; + private Map namedArguments; + + public String getId() { + if (id == null) { + id = DigestUtils.md5Hex(method.toString()); + } + return id; + } + protected Map createNamedArguments() { + Map namedArguments = Maps.newLinkedHashMapWithExpectedSize(arguments.length); + for (int i = 0, len = arguments.length; i < len; i++) { + namedArguments.put(argumentsNames[i], arguments[i]); + } + return namedArguments; + + } + + public Map getNamedArguments() { + return namedArguments == null ? namedArguments = createNamedArguments() : namedArguments; + } public T findMethodAnnotation(Class annClass) { return AnnotationUtils.findMethodAnnotation(annClass, method, annClass); From 7846812266602c596ac74a3897e908a6b0f2e493 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 27 Dec 2021 13:45:04 +0800 Subject: [PATCH 145/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/logging/aop/AccessLoggerParser.java | 2 +- .../aop/DefaultAccessLoggerParser.java | 2 +- .../aop/ReactiveAopAccessLoggerSupport.java | 59 +++++++++++++------ .../aop/ResourceAccessLoggerParser.java | 2 +- .../aop/Swagger3AccessLoggerParser.java | 2 +- .../aop/SwaggerAccessLoggerParser.java | 2 +- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/AccessLoggerParser.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/AccessLoggerParser.java index e51573e94..584ba6f85 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/AccessLoggerParser.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/AccessLoggerParser.java @@ -7,7 +7,7 @@ import java.lang.reflect.Method; public interface AccessLoggerParser { - boolean support(Class clazz, Method method); + boolean support(Class clazz, Method method); LoggerDefine parse(MethodInterceptorHolder holder); } diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/DefaultAccessLoggerParser.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/DefaultAccessLoggerParser.java index 3c9f742ba..a0fc433fc 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/DefaultAccessLoggerParser.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/DefaultAccessLoggerParser.java @@ -13,7 +13,7 @@ public class DefaultAccessLoggerParser implements AccessLoggerParser { @Override - public boolean support(Class clazz, Method method) { + public boolean support(Class clazz, Method method) { AccessLogger ann = AnnotationUtils.findAnnotation(method, AccessLogger.class); //注解了并且未取消 return null != ann && !ann.ignore(); diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 9dd11cf35..7afb1a897 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -16,6 +16,7 @@ import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -41,6 +42,11 @@ public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutA @Autowired private ApplicationEventPublisher eventPublisher; + private final Map defineCache = new ConcurrentReferenceHashMap<>(); + + private static final LoggerDefine UNSUPPORTED = new LoggerDefine(); + + @SuppressWarnings("all") public ReactiveAopAccessLoggerSupport() { setAdvice((MethodInterceptor) methodInvocation -> { MethodInterceptorHolder methodInterceptorHolder = MethodInterceptorHolder.create(methodInvocation); @@ -55,23 +61,34 @@ public ReactiveAopAccessLoggerSupport() { }); } + private Mono currentRequestInfo() { + return Mono + .subscriberContext() + .handle((context, sink) -> { + if (context.hasKey(RequestInfo.class)) { + RequestInfo info = context.get(RequestInfo.class); + ReactiveLogger.log(context, info::setContext); + sink.next(info); + } + }); + } + protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { - return Mono.subscriberContext() - .flatMap(ctx -> Mono.justOrEmpty(ctx.getOrEmpty(RequestInfo.class)) - .doOnNext(info -> ReactiveLogger.log(ctx, info::setContext))) + return this + .currentRequestInfo() .doOnNext(loggerInfo::putAccessInfo) .thenMany(flux) .doOnError(loggerInfo::setException) .doFinally(f -> { loggerInfo.setResponseTime(System.currentTimeMillis()); eventPublisher.publishEvent(new AccessLoggerAfterEvent(loggerInfo)); - }).subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + }) + .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); } protected Mono wrapMonoResponse(Mono mono, AccessLoggerInfo loggerInfo) { - return Mono.subscriberContext() - .flatMap(ctx -> Mono.justOrEmpty(ctx.getOrEmpty(RequestInfo.class)) - .doOnNext(info -> ReactiveLogger.log(ctx, info::setContext))) + return this + .currentRequestInfo() .doOnNext(loggerInfo::putAccessInfo) .then(mono) .doOnError(loggerInfo::setException) @@ -79,20 +96,26 @@ protected Mono wrapMonoResponse(Mono mono, AccessLoggerInfo loggerInfo) { .doFinally(f -> { loggerInfo.setResponseTime(System.currentTimeMillis()); eventPublisher.publishEvent(new AccessLoggerAfterEvent(loggerInfo)); - }).subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + }) + .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + } + + private LoggerDefine createDefine(MethodInterceptorHolder holder) { + return loggerParsers + .stream() + .filter(parser -> parser.support(ClassUtils.getUserClass(holder.getTarget()), holder.getMethod())) + .findAny() + .map(parser -> parser.parse(holder)) + .orElse(UNSUPPORTED); } @SuppressWarnings("all") protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { AccessLoggerInfo info = new AccessLoggerInfo(); info.setId(IDGenerator.MD5.generate()); - info.setRequestTime(System.currentTimeMillis()); - LoggerDefine define = loggerParsers.stream() - .filter(parser -> parser.support(ClassUtils.getUserClass(holder.getTarget()), holder.getMethod())) - .findAny() - .map(parser -> parser.parse(holder)) - .orElse(null); + + LoggerDefine define = defineCache.computeIfAbsent(holder.getMethod(), method -> createDefine(holder)); if (define != null) { info.setAction(define.getAction()); @@ -113,14 +136,14 @@ protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { continue; } if (val instanceof Mono) { - args[i] = ((Mono) val) + args[i] = ((Mono) val) .doOnNext(param -> { value.put(name, param); }); } else if (val instanceof Flux) { List arr = new ArrayList<>(); value.put(name, arr); - args[i] = ((Flux) val) + args[i] = ((Flux) val) .doOnNext(param -> { arr.add(param); }); @@ -143,7 +166,9 @@ public int getOrder() { @Override public boolean matches(Method method, Class aClass) { - return loggerParsers.stream().anyMatch(parser -> parser.support(aClass, method)); + return loggerParsers + .stream() + .anyMatch(parser -> parser.support(aClass, method)); } @Override diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ResourceAccessLoggerParser.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ResourceAccessLoggerParser.java index acf42e5b3..faf351128 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ResourceAccessLoggerParser.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ResourceAccessLoggerParser.java @@ -22,7 +22,7 @@ public class ResourceAccessLoggerParser implements AccessLoggerParser { )); @Override - public boolean support(Class clazz, Method method) { + public boolean support(Class clazz, Method method) { Set a1 = AnnotatedElementUtils.findAllMergedAnnotations(method, annotations); Set a2 = AnnotatedElementUtils.findAllMergedAnnotations(clazz, annotations); diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/Swagger3AccessLoggerParser.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/Swagger3AccessLoggerParser.java index c0b91a8c7..12de9191b 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/Swagger3AccessLoggerParser.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/Swagger3AccessLoggerParser.java @@ -12,7 +12,7 @@ public class Swagger3AccessLoggerParser implements AccessLoggerParser { @Override - public boolean support(Class clazz, Method method) { + public boolean support(Class clazz, Method method) { Tag api = AnnotationUtils.findAnnotation(clazz, Tag.class); Operation operation = AnnotationUtils.findAnnotation(method, Operation.class); diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/SwaggerAccessLoggerParser.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/SwaggerAccessLoggerParser.java index 408ab7d33..2ac75180b 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/SwaggerAccessLoggerParser.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/SwaggerAccessLoggerParser.java @@ -11,7 +11,7 @@ public class SwaggerAccessLoggerParser implements AccessLoggerParser { @Override - public boolean support(Class clazz, Method method) { + public boolean support(Class clazz, Method method) { Api api = AnnotationUtils.findAnnotation(clazz, Api.class); ApiOperation operation = AnnotationUtils.findAnnotation(method, ApiOperation.class); From 4131aa3653efc77622128b4444a2bd0d1063bb53 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 4 Jan 2022 15:00:39 +0800 Subject: [PATCH 146/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonWebMvcConfiguration.java | 2 ++ .../web/crud/web/ResponseMessageWrapperAdvice.java | 1 - hsweb-core/pom.xml | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java index b310160e8..cb72e93e4 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebMvcConfiguration.java @@ -1,5 +1,6 @@ package org.hswebframework.web.crud.web; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; @@ -9,6 +10,7 @@ @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +@ConditionalOnClass(org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice.class) public class CommonWebMvcConfiguration { @Bean diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java index 8728f13cf..b57bcc504 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java @@ -13,7 +13,6 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; -import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 4dfe92bb4..a45bbb244 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -20,18 +20,22 @@ javassist 3.28.0-GA + com.fasterxml.jackson.core jackson-databind + org.hswebframework hsweb-utils + org.springframework spring-context + org.springframework spring-web From a9c625648d10d811670be94d5b0b54ee0c526a5e Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 6 Jan 2022 09:27:26 +0800 Subject: [PATCH 147/542] 4.0.13 --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 260044351..3e0b543e6 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 4cee3010c..7feeaf2e0 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index b1ed31100..ae2b152e5 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index ca288ae27..bbd184af8 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index f273b989f..f3ad81381 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 2f03314e7..ba1fd7f3e 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 49956e019..33fae8613 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index b48abe970..b0f9524fa 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 256a58bd1..92e5f1712 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index a45bbb244..46dd45ddd 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 7add8016e..0de58de02 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 6291e1e5b..50111f82a 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index fa7a74e6e..d6fb038b6 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index f10f0f041..6bf9f6f4b 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index b264011c3..a3e501d1d 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index a1417bb87..28404502a 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 607ebd984..647087ca1 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 1b75183c0..f5734c051 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 459e8e1ed..00049fb01 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 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 db9703dc3..86cdc693f 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index fe06e8d32..e09542425 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 5d42aacb4..944c194fc 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 9b98e9b81..0c4d96f2a 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 041afbbf9..1a0ed1765 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index d28ee529b..7bb080bc9 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13-SNAPSHOT + 4.0.13 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 870043527..61561dc00 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.13-SNAPSHOT + 4.0.13 hsweb-starter hsweb-core From 6515aa31582f760d587743df71d443ea74cb7d30 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 19 Jan 2022 17:25:28 +0800 Subject: [PATCH 148/542] 4.0.14-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 8 +++++++- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 32 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 3e0b543e6..b78ebb166 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 7feeaf2e0..1d9548f1c 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index ae2b152e5..cfd6f7ffa 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index bbd184af8..eae29abb9 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index f3ad81381..e8b562365 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index ba1fd7f3e..3d80c02ed 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 33fae8613..a95048ed0 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index b0f9524fa..27e913412 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 92e5f1712..678172be7 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 46dd45ddd..9e83cf5aa 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 0de58de02..017bd92ca 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 50111f82a..494446890 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index d6fb038b6..6d4b217fb 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 6bf9f6f4b..c9449114e 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index a3e501d1d..51d34eb87 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 28404502a..323d43ddb 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 647087ca1..c0b0adaa1 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index f5734c051..5970be36b 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 00049fb01..0958d3092 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 @@ -34,6 +34,12 @@ commons-codec commons-codec + + org.hswebframework.web + hsweb-commons-crud + ${project.version} + compile + \ No newline at end of file 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 86cdc693f..c5269c3f5 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index e09542425..9a2488316 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 944c194fc..081cf8074 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 0c4d96f2a..00ee64ca2 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 1a0ed1765..c0f869ecc 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index 7bb080bc9..eb48a52e7 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.13 + 4.0.14-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 61561dc00..7747c72c5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.13 + 4.0.14-SNAPSHOT hsweb-starter hsweb-core From 554fdc2ed48ccb8e1c7e5798b0bad70357762f13 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 19 Jan 2022 17:26:12 +0800 Subject: [PATCH 149/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0DimensionDeletedEvent?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6,=E5=9C=A8=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BB=B4=E5=BA=A6=E6=95=B0=E6=8D=AE=E8=A2=AB=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=B6,=E9=9C=80=E8=A6=81=E6=8E=A8=E9=80=81=E6=AD=A4?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/event/DimensionDeletedEvent.java | 12 ++++++++++++ .../api/event/UserDeletedEvent.java | 16 +++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionDeletedEvent.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionDeletedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionDeletedEvent.java new file mode 100644 index 000000000..833031d82 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/DimensionDeletedEvent.java @@ -0,0 +1,12 @@ +package org.hswebframework.web.system.authorization.api.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; + +@Getter +@AllArgsConstructor +public class DimensionDeletedEvent extends DefaultAsyncEvent { + private final String dimensionType; + private final String dimensionId; +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java index 8bb299139..219b7530b 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/event/UserDeletedEvent.java @@ -1,18 +1,16 @@ package org.hswebframework.web.system.authorization.api.event; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.hswebframework.web.event.DefaultAsyncEvent; +import org.hswebframework.web.authorization.DefaultDimensionType; import org.hswebframework.web.system.authorization.api.entity.UserEntity; @Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class UserDeletedEvent extends DefaultAsyncEvent { +public class UserDeletedEvent extends DimensionDeletedEvent { - private UserEntity user; + private final UserEntity user; + public UserDeletedEvent(UserEntity user) { + super(DefaultDimensionType.user.getId(), user.getId()); + this.user = user; + } } From 54194e8cbbfa4f51019da932f5ed426ed5dd1566 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 19 Jan 2022 17:26:54 +0800 Subject: [PATCH 150/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/AuthorizationSettingEntity.java | 2 + .../DefaultAuthorizationSettingService.java | 144 +++++++++--------- ...aultReactiveAuthenticationManagerTest.java | 9 ++ 3 files changed, 82 insertions(+), 73 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index f22009d01..9ef0a8470 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -9,6 +9,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.Entity; import org.hswebframework.web.bean.FastBeanCopier; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; import org.hswebframework.web.validator.CreateGroup; import org.springframework.util.CollectionUtils; @@ -27,6 +28,7 @@ }) @Getter @Setter +@EnableEntityEvent public class AuthorizationSettingEntity implements Entity { @Id @Column(length = 32) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index ad5350040..9988da900 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -6,13 +6,19 @@ import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; import org.hswebframework.web.authorization.DimensionProvider; import org.hswebframework.web.authorization.DimensionType; +import org.hswebframework.web.crud.events.EntityCreatedEvent; +import org.hswebframework.web.crud.events.EntityDeletedEvent; +import org.hswebframework.web.crud.events.EntityModifyEvent; +import org.hswebframework.web.crud.events.EntitySavedEvent; import org.hswebframework.web.crud.service.GenericReactiveCrudService; import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; +import org.hswebframework.web.system.authorization.api.event.DimensionDeletedEvent; import org.hswebframework.web.system.authorization.defaults.configuration.PermissionProperties; import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.event.EventListener; import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -30,7 +36,6 @@ public class DefaultAuthorizationSettingService extends GenericReactiveCrudServi @Autowired private List providers; - protected AuthorizationSettingEntity generateId(AuthorizationSettingEntity entity) { if (StringUtils.isEmpty(entity.getId())) { entity.setId(DigestUtils.md5Hex(entity.getPermission() + entity.getDimensionType() + entity.getDimensionTarget())); @@ -42,28 +47,7 @@ protected AuthorizationSettingEntity generateId(AuthorizationSettingEntity entit public Mono save(Publisher entityPublisher) { return Flux.from(entityPublisher) .map(this::generateId) - .collectList() - .flatMap(autz -> super.save(Flux.fromIterable(autz)).doOnSuccess(r -> clearUserAuthCache(autz))); - } - - @Override - public Mono updateById(String id, Mono entityPublisher) { - return entityPublisher - .flatMap(autz -> super.updateById(id, Mono.just(autz)) - .doOnSuccess((r) -> clearUserAuthCache(Collections.singletonList(autz)))); - } - - @Override - public Mono deleteById(Publisher idPublisher) { - Flux cache = Flux.from(idPublisher); - - return this - .findById(cache) - .collectList() - .flatMap(list -> this - .deleteById(cache) - .doOnSuccess((i) -> clearUserAuthCache(list)) - ); + .as(super::save); } @Override @@ -71,68 +55,82 @@ public Mono insert(Publisher entityPublishe return Flux.from(entityPublisher) .map(this::generateId) - .collectList() - .flatMap(list -> super - .insert(Flux.fromIterable(list)) - .doOnSuccess(i -> clearUserAuthCache(list))); + .as(super::insert); } @Override public Mono insertBatch(Publisher> entityPublisher) { return Flux .from(entityPublisher) + .doOnNext(list -> list.forEach(this::generateId)) + .as(super::insertBatch); + } + + protected Mono clearUserAuthCache(List settings) { + return Flux + .fromIterable(providers) + .flatMap(provider -> + //按维度类型进行映射 + provider.getAllType() + .map(DimensionType::getId) + .map(t -> Tuples.of(t, provider))) + .collect(Collectors.toMap(Tuple2::getT1, Tuple2::getT2)) + .flatMapMany(typeProviderMapping -> Flux + .fromIterable(settings)//根据维度获取所有userId + .flatMap(setting -> Mono + .justOrEmpty(typeProviderMapping.get(setting.getDimensionType())) + .flatMapMany(provider -> provider.getUserIdByDimensionId(setting.getDimensionTarget())))) .collectList() - .flatMap(list -> super - .insertBatch(Flux.fromStream(list.stream() - .map(lst -> lst.stream() - .map(this::generateId) - .collect(Collectors.toList())))) - .doOnSuccess(i -> clearUserAuthCache(list - .stream() - .flatMap(Collection::stream) - .collect(Collectors.toList())))); + .map(ClearUserAuthorizationCacheEvent::of) + .doOnNext(eventPublisher::publishEvent) + .then(); } - @Override - public ReactiveUpdate createUpdate() { - - return super - .createUpdate() - .onExecute((update, r) -> r - .doOnSuccess(i -> this - .createQuery() - .setParam(update.toQueryParam()) - .fetch() - .collectList() - .subscribe(this::clearUserAuthCache))); + @EventListener + public void handleAuthSettingDeleted(EntityDeletedEvent event) { + event.async( + clearUserAuthCache(event.getEntity()) + ); } - @Override - public ReactiveDelete createDelete() { - return super.createDelete() - .onExecute((delete, r) -> r - .doOnSuccess(i -> this - .createQuery() - .setParam(delete.toQueryParam()) - .fetch() - .collectList() - .subscribe(this::clearUserAuthCache))); + @EventListener + public void handleAuthSettingChanged(EntityModifyEvent event) { + event.async( + clearUserAuthCache(event.getAfter()) + ); + } + + @EventListener + public void handleAuthSettingSaved(EntitySavedEvent event) { + event.async( + clearUserAuthCache(event.getEntity()) + ); + } + + @EventListener + public void handleAuthSettingAdded(EntityCreatedEvent event) { + event.async( + clearUserAuthCache(event.getEntity()) + ); + } + + @EventListener + public void handleDimensionAdd(DimensionDeletedEvent event) { + event.async( + createDelete() + .where(AuthorizationSettingEntity::getDimensionType, event.getDimensionType()) + .and(AuthorizationSettingEntity::getDimensionTarget, event.getDimensionId()) + .execute() + ); } - protected void clearUserAuthCache(List settings) { - Flux.fromIterable(providers) - .flatMap(provider -> - //按维度类型进行映射 - provider.getAllType() - .map(DimensionType::getId) - .map(t -> Tuples.of(t, provider))) - .collect(Collectors.toMap(Tuple2::getT1, Tuple2::getT2)) - .flatMapMany(typeProviderMapping -> Flux - .fromIterable(settings)//根据维度获取所有userId - .flatMap(setting -> Mono.justOrEmpty(typeProviderMapping.get(setting.getDimensionType())) - .flatMapMany(provider -> provider.getUserIdByDimensionId(setting.getDimensionTarget())))) - .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .subscribe(eventPublisher::publishEvent); + @EventListener + public void handleDimensionDeletedEvent(DimensionDeletedEvent event) { + event.async( + createDelete() + .where(AuthorizationSettingEntity::getDimensionType, event.getDimensionType()) + .and(AuthorizationSettingEntity::getDimensionTarget, event.getDimensionId()) + .execute() + ); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveAuthenticationManagerTest.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveAuthenticationManagerTest.java index 424d02e9c..07beab561 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveAuthenticationManagerTest.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/DefaultReactiveAuthenticationManagerTest.java @@ -93,11 +93,20 @@ public void test() { .as(StepVerifier::create) .expectNext(true) .verifyComplete(); + userService.deleteUser(entity.getId()) .as(StepVerifier::create) .expectNext(true) .verifyComplete(); + settingRepository.createQuery() + .where(AuthorizationSettingEntity::getDimensionType,"user") + .and(AuthorizationSettingEntity::getDimensionTarget,entity.getId()) + .fetch() + .as(StepVerifier::create) + .expectNextCount(0) + .verifyComplete(); + } } \ No newline at end of file From bc5e68a09bfa2d8fd26e8954f520e321534f227e Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 19 Jan 2022 18:36:41 +0800 Subject: [PATCH 151/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=BB=91=E5=AE=9A=E8=A7=A3=E7=BB=91=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/AuthorizationSettingEntity.java | 1 + .../api/entity/DimensionEntity.java | 2 + .../api/entity/DimensionUserEntity.java | 5 +- .../DefaultAuthorizationSettingService.java | 12 + .../service/DefaultDimensionService.java | 77 ++----- .../service/DefaultDimensionUserService.java | 125 ++++++----- .../DefaultDimensionUserServiceTest.java | 208 ++++++++++++++++++ 7 files changed, 314 insertions(+), 116 deletions(-) create mode 100644 hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserServiceTest.java diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 9ef0a8470..435663f8a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -67,6 +67,7 @@ public class AuthorizationSettingEntity implements Entity { @Comment("状态") @NotNull(message = "状态不能为空",groups = CreateGroup.class) @Schema(description = "状态,0禁用,1启用") + @DefaultValue("1") private Byte state; @Column diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 0056a12ed..d4ec1e83f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -7,6 +7,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; import org.hswebframework.web.validator.CreateGroup; import javax.persistence.Column; @@ -24,6 +25,7 @@ @Table(name = "s_dimension", indexes = { @Index(name = "idx_dims_path", columnList = "path") }) +@EnableEntityEvent public class DimensionEntity extends GenericTreeSortSupportEntity { @Override diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index 752361a18..827d5a744 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 @@ -7,6 +7,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.ezorm.rdb.mapping.annotation.EnumCodec; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; import org.hswebframework.web.dict.EnumDict; import org.hswebframework.web.system.authorization.api.enums.DimensionUserFeature; import org.springframework.util.DigestUtils; @@ -26,6 +27,7 @@ @Index(name = "idx_dimsu_user_id", columnList = "user_id"), }) +@EnableEntityEvent public class DimensionUserEntity extends GenericEntity { @Comment("维度类型ID") @@ -40,13 +42,14 @@ public class DimensionUserEntity extends GenericEntity { @Comment("维度名称") @Column(name = "dimension_name", nullable = false) - @NotBlank(message = "[dimensionName]不能为空") + @NotBlank @Schema(description = "维度名称") private String dimensionName; @Comment("用户ID") @Column(name = "user_id", nullable = false, length = 64) @Schema(description = "用户ID") + @NotBlank private String userId; @Comment("用户名") diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index 9988da900..b71960930 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -43,6 +43,18 @@ protected AuthorizationSettingEntity generateId(AuthorizationSettingEntity entit return entity; } + @Override + public Mono save(AuthorizationSettingEntity data) { + generateId(data); + return super.save(data); + } + + @Override + public Mono save(Collection collection) { + collection.forEach(this::generateId); + return super.save(collection); + } + @Override public Mono save(Publisher entityPublisher) { return Flux.from(entityPublisher) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java index bd702d177..abcbda00d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java @@ -1,36 +1,30 @@ package org.hswebframework.web.system.authorization.defaults.service; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections4.BidiMap; -import org.apache.commons.collections4.MultiValuedMap; -import org.apache.commons.collections4.bidimap.DualHashBidiMap; -import org.apache.commons.collections4.multimap.HashSetValuedHashMap; -import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete; 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.authorization.Dimension; import org.hswebframework.web.authorization.DimensionProvider; import org.hswebframework.web.authorization.DimensionType; import org.hswebframework.web.authorization.dimension.DimensionUserBind; import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider; -import org.hswebframework.web.crud.service.GenericReactiveCrudService; +import org.hswebframework.web.crud.events.EntityDeletedEvent; +import org.hswebframework.web.crud.events.EntityModifyEvent; +import org.hswebframework.web.crud.events.EntitySavedEvent; import org.hswebframework.web.crud.service.GenericReactiveTreeSupportCrudService; -import org.hswebframework.web.crud.service.ReactiveCrudService; -import org.hswebframework.web.crud.service.ReactiveTreeSortEntityService; import org.hswebframework.web.id.IDGenerator; -import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; import org.hswebframework.web.system.authorization.api.entity.DimensionEntity; import org.hswebframework.web.system.authorization.api.entity.DimensionTypeEntity; import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; -import org.reactivestreams.Publisher; +import org.hswebframework.web.system.authorization.api.event.DimensionDeletedEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.event.EventListener; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.*; +import java.util.Collection; +import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -45,9 +39,6 @@ public class DefaultDimensionService @Autowired private ReactiveRepository dimensionTypeRepository; - @Autowired - private ReactiveRepository settingRepository; - @Autowired private ApplicationEventPublisher eventPublisher; @@ -131,53 +122,23 @@ public Flux getUserIdByDimensionId(String dimensionId) { .map(DimensionUserEntity::getUserId); } - @Override - public Mono save(Publisher entityPublisher) { - return super.save(entityPublisher) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); - } - - @Override - public Mono updateById(String id, Mono entityPublisher) { - return super.updateById(id, entityPublisher) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())); + @EventListener + public void handleDimensionChanged(EntitySavedEvent event) { + eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()); } - @Override - public ReactiveUpdate createUpdate() { - return super.createUpdate() - .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); + @EventListener + public void handleDimensionChanged(EntityModifyEvent event) { + eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()); } - @Override - public ReactiveDelete createDelete() { - return super.createDelete() - .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))); - } + @EventListener + public void dispatchDimensionDeleteEvent(EntityDeletedEvent event) { - @Override - public Mono deleteById(Publisher idPublisher) { - - return Flux.from(idPublisher) - .collectList() - .flatMap(list -> super.queryIncludeChildren(list) - .flatMap(dimension -> dimensionUserRepository.createDelete() //删除维度用户关联 - .where() - .is(DimensionUserEntity::getDimensionId, dimension.getId()) - .execute() - .then(getRepository().deleteById(Mono.just(dimension.getId()))) - .thenReturn(dimension) - ) - .groupBy(DimensionEntity::getTypeId, DimensionEntity::getId)//按维度类型分组 - .flatMap(grouping -> grouping.collectList() - .flatMap(dimensionId -> settingRepository //删除权限设置 - .createDelete() - .where(AuthorizationSettingEntity::getDimensionType, grouping.key()) - .in(AuthorizationSettingEntity::getDimensionTarget, dimensionId) - .execute())) - .collect(Collectors.summarizingInt(Integer::intValue)) - .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())) - .thenReturn(list.size())); + event.async( + Flux.fromIterable(event.getEntity()) + .flatMap(e -> new DimensionDeletedEvent(e.getTypeId(), e.getId()).publish(eventPublisher)) + ); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index f3c8d7e7c..2ab396a51 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -5,9 +5,14 @@ import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete; import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate; import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.crud.events.EntityCreatedEvent; +import org.hswebframework.web.crud.events.EntityDeletedEvent; +import org.hswebframework.web.crud.events.EntityModifyEvent; +import org.hswebframework.web.crud.events.EntitySavedEvent; import org.hswebframework.web.crud.service.GenericReactiveCrudService; import org.hswebframework.web.event.AsyncEvent; import org.hswebframework.web.exception.BusinessException; +import org.hswebframework.web.system.authorization.api.entity.DimensionEntity; import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; import org.hswebframework.web.system.authorization.api.event.DimensionBindEvent; @@ -22,8 +27,13 @@ import reactor.function.Function3; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.*; @Slf4j public class DefaultDimensionUserService extends GenericReactiveCrudService { @@ -31,6 +41,7 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService save(Publisher entityPublisher) { - return this - .publishEvent(entityPublisher, DimensionBindEvent::new) - .as(super::save); + //转发保存维度信息到DimensionBindEvent事件,并清空权限缓存 + @EventListener + public void dispatchDimensionBind(EntitySavedEvent event) { + event.async( + this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) + .then( + this.clearUserCache(event.getEntity()) + ) + ); } - @Override - public Mono updateById(String id, Mono entityPublisher) { - return entityPublisher - .doOnNext(entity -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(entity.getUserId()))) - .as(e -> super.updateById(id, e)); + //新增绑定时转发DimensionBindEvent并清空用户权限信息 + @EventListener + public void dispatchDimensionBind(EntityCreatedEvent event) { + event.async( + this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) + .then( + this.clearUserCache(event.getEntity()) + ) + ); } - @Override - public Mono insert(Publisher entityPublisher) { - return this - .publishEvent(entityPublisher, DimensionBindEvent::new) - .as(super::insert) - .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("error.duplicate_key")); + //删除绑定时转发DimensionUnbindEvent并清空用户权限信息 + @EventListener + public void dispatchDimensionUnbind(EntityDeletedEvent event) { + event.async( + this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionUnbindEvent::new) + .then( + this.clearUserCache(event.getEntity()) + ) + ); } - @Override - public Mono insertBatch(Publisher> entityPublisher) { + //修改绑定信息时清空权限 + @EventListener + public void handleModifyEvent(EntityModifyEvent event) { + event.async( + this.clearUserCache(event.getAfter()) + ); + } - Flux> cache = Flux.from(entityPublisher).cache(); + //维度被删除时同时删除绑定信息 + @EventListener + public void handleDimensionDeletedEntity(EntityDeletedEvent event) { + event.async( + Flux.fromIterable(event.getEntity()) + .collect(groupingBy(DimensionEntity::getTypeId, + mapping(DimensionEntity::getId, toSet()))) + .flatMapIterable(Map::entrySet) + .flatMap(entry -> this + .createDelete() + .where(DimensionUserEntity::getDimensionTypeId, entry.getKey()) + .in(DimensionUserEntity::getDimensionId, entry.getValue()) + .execute()) + ); - return this - .publishEvent(cache.flatMapIterable(Function.identity()), DimensionBindEvent::new) - .then(super.insertBatch(cache)); } private Flux publishEvent(Publisher stream, @@ -83,7 +120,6 @@ private Flux publishEvent(Publisher st .groupBy(DimensionUserEntity::getDimensionId) .flatMap(dimensionIdGroup -> { String dimensionId = dimensionIdGroup.key(); - return dimensionIdGroup .map(DimensionUserEntity::getUserId) .collectList() @@ -96,39 +132,14 @@ private Flux publishEvent(Publisher st .thenMany(cache); } - @Override - @SuppressWarnings("all") - public ReactiveUpdate createUpdate() { - return super - .createUpdate() - .onExecute((update, r) -> r - .flatMap(result -> this - .createQuery() - .select(DimensionUserEntity::getUserId) - .setParam(update.toQueryParam()) - .fetch() - .map(DimensionUserEntity::getUserId) - .distinct() - .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .doOnNext(eventPublisher::publishEvent) - .thenReturn(result) - ) - ); + private Mono clearUserCache(List entities) { + return Flux.fromIterable(entities) + .map(DimensionUserEntity::getUserId) + .distinct() + .collectList() + .map(ClearUserAuthorizationCacheEvent::of) + .doOnNext(eventPublisher::publishEvent) + .then(); } - @Override - @SuppressWarnings("all") - public ReactiveDelete createDelete() { - return super - .createDelete() - .onExecute((delete, r) -> this - .publishEvent(this.createQuery() - .select(DimensionUserEntity::getUserId) - .setParam(delete.toQueryParam()) - .fetch(), - DimensionUnbindEvent::new - ).then(r) - ); - } -} +} \ 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/DefaultDimensionUserServiceTest.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserServiceTest.java new file mode 100644 index 000000000..4009026e3 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserServiceTest.java @@ -0,0 +1,208 @@ +package org.hswebframework.web.system.authorization.defaults.service; + +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.web.authorization.AuthenticationManager; +import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.system.authorization.api.entity.*; +import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; +import org.hswebframework.web.system.authorization.defaults.service.reactive.ReactiveTestApplication; +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; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ReactiveTestApplication.class) +public class DefaultDimensionUserServiceTest { + + @Autowired + private ReactiveUserService userService; + + @Autowired + private ReactiveRepository typeRepository; + + @Autowired + private DefaultDimensionService dimensionService; + + @Autowired + private DefaultDimensionUserService dimensionUserService; + + @Autowired + private DefaultAuthorizationSettingService settingService; + + @Autowired + private ReactiveAuthenticationManager authenticationManager; + + @Test + public void testDeleteBind() { + String dimensionType = "role"; + String dimensionId = "testDeleteBind"; + String userId = initData(dimensionType, dimensionId); + + //删除绑定关系 + dimensionUserService + .createDelete() + .where(DimensionUserEntity::getUserId, userId) + .execute() + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + //校验权限 + authenticationManager + .getByUserId(userId) + .map(auth -> !auth.hasDimension(dimensionType, dimensionId)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + //权限设置并没有被删除 + settingService + .createQuery() + .where(AuthorizationSettingEntity::getDimensionType, dimensionType) + .and(AuthorizationSettingEntity::getDimensionTarget, dimensionId) + .count() + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); + + } + + @Test + public void testDeleteDimension() { + String dimensionType = "role"; + String dimensionId = "testDeleteDimension"; + String userId = initData(dimensionType, dimensionId); + + //删除维度 + dimensionService + .deleteById(dimensionId) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + //判断没有维度 + authenticationManager + .getByUserId(userId) + .map(auth -> !auth.hasDimension(dimensionType, dimensionId)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + //权限设置也被删除 + settingService + .createQuery() + .where(AuthorizationSettingEntity::getDimensionType, dimensionType) + .and(AuthorizationSettingEntity::getDimensionTarget, dimensionId) + .count() + .as(StepVerifier::create) + .expectNext(0) + .verifyComplete(); + + + } + + @Test + public void testDeleteUser() { + String dimensionType = "role"; + String dimensionId = "test"; + + String userId = initData(dimensionType, dimensionId); + + userService.deleteUser(userId) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + authenticationManager + .getByUserId(userId) + .as(StepVerifier::create) + .expectNextCount(0) + .verifyComplete(); + + + dimensionUserService + .createQuery() + .where(DimensionUserEntity::getUserId, userId) + .count() + .as(StepVerifier::create) + .expectNext(0) + .verifyComplete(); + + } + + + private String initData(String dimensionType, String dimensionId) { + UserEntity userEntity = userService.newUserInstance().blockOptional().orElseThrow(NullPointerException::new); + userEntity.setName("test"); + userEntity.setUsername("test_" + dimensionId); + userEntity.setPassword("admin"); + userService.saveUser(Mono.just(userEntity)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + DimensionTypeEntity type = new DimensionTypeEntity(); + type.setId(dimensionType); + type.setName(dimensionType); + typeRepository.save(type) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + DimensionEntity dimension = new DimensionEntity(); + dimension.setId(dimensionId); + dimension.setTypeId(dimensionType); + dimension.setName(dimensionId); + + dimensionService + .save(dimension) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + DimensionUserEntity bind = new DimensionUserEntity(); + bind.setDimensionId(dimension.getId()); + bind.setDimensionTypeId(dimension.getTypeId()); + bind.setDimensionName(dimension.getName()); + bind.setUserId(userEntity.getId()); + bind.setUserName(userEntity.getName()); + dimensionUserService + .save(bind) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + AuthorizationSettingEntity setting = new AuthorizationSettingEntity(); + setting.setDimensionType(dimension.getTypeId()); + setting.setDimensionTarget(dimension.getId()); + setting.setPermission("test"); + + settingService + .insert(setting) + .then() + .as(StepVerifier::create) + .expectComplete() + .verify(); + + authenticationManager + .getByUserId(userEntity.getId()) + .map(auth -> auth.hasDimension(dimensionType, dimensionId)) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + return userEntity.getId(); + } + +} \ No newline at end of file From abf7f91c923f3f81b319560fa262367e1ad37469 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 19 Jan 2022 18:36:59 +0800 Subject: [PATCH 152/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E8=81=9A=E5=90=88=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/service/ReactiveTreeSortEntityService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java index 64f14a28c..66de7ca0e 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -12,6 +12,7 @@ import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.math.MathFlux; import java.util.*; import java.util.function.Consumer; @@ -335,12 +336,12 @@ default Mono updateById(K id, Mono entityPublisher) { @Override default Mono deleteById(Publisher idPublisher) { - return findById(Flux.from(idPublisher)) - .flatMap(e -> createDelete() - .where() - .like$(e::getPath) - .execute()) - .collect(Collectors.summingInt(Integer::intValue)); + return this + .findById(Flux.from(idPublisher)) + .concatMap(e -> StringUtils.hasText(e.getPath()) + ? createDelete().where().like$(e::getPath).execute() + : getRepository().deleteById(e.getId())) + .as(MathFlux::sumInt); } IDGenerator getIDGenerator(); From 8b21574e23b71f023ffb043145660fa1225d9db9 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 25 Jan 2022 09:20:56 +0800 Subject: [PATCH 153/542] =?UTF-8?q?=E4=BC=98=E5=8C=96DigestUtils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/utils/DigestUtils.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java index 246a6dbd2..ac58189f4 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/DigestUtils.java @@ -3,6 +3,8 @@ import org.apache.commons.codec.binary.Hex; import java.security.MessageDigest; +import java.util.function.Consumer; +import java.util.function.Supplier; public class DigestUtils { @@ -10,6 +12,30 @@ public class DigestUtils { public static final ThreadLocal sha256 = ThreadLocal.withInitial(org.apache.commons.codec.digest.DigestUtils::getSha256Digest); public static final ThreadLocal sha1 = ThreadLocal.withInitial(org.apache.commons.codec.digest.DigestUtils::getSha1Digest); + public static byte[] md5(Consumer digestHandler) { + return digest(md5::get, digestHandler); + } + + public static String md5Hex(Consumer digestHandler) { + return digestHex(md5::get, digestHandler); + } + + public static byte[] sha1(Consumer digestHandler) { + return digest(sha1::get, digestHandler); + } + + public static String sha1Hex(Consumer digestHandler) { + return digestHex(sha1::get, digestHandler); + } + + public static byte[] sha256(Consumer digestHandler) { + return digest(sha256::get, digestHandler); + } + + public static String sha256Hex(Consumer digestHandler) { + return digestHex(sha1::get, digestHandler); + } + public static byte[] md5(byte[] data) { return org.apache.commons.codec.digest.DigestUtils.digest(md5.get(), data); } @@ -57,4 +83,16 @@ public static byte[] digest(MessageDigest digest, String str) { public static String digestHex(MessageDigest digest, String str) { return Hex.encodeHexString(digest(digest, str)); } + + private static byte[] digest(Supplier digestSupplier, + Consumer digestHandler) { + MessageDigest digest = digestSupplier.get(); + digestHandler.accept(digest); + return digest.digest(); + } + + private static String digestHex(Supplier digestSupplier, + Consumer digestHandler) { + return Hex.encodeHexString(digest(digestSupplier, digestHandler)); + } } From e5158ed3b27d60f37d538868c4b344e05a8015e4 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 25 Jan 2022 15:39:29 +0800 Subject: [PATCH 154/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../define/AuthorizeDefinitionContext.java | 7 ++++ .../define/AuthorizeDefinitionCustomizer.java | 7 ++++ ...ompositeAuthorizeDefinitionCustomizer.java | 24 +++++++++++ .../define/MergedAuthorizeDefinition.java | 6 +-- ...ultAopMethodAuthorizeDefinitionParser.java | 18 +++++++- .../web/api/crud/entity/QueryParamEntity.java | 24 +++++++++-- .../EnableCacheReactiveCrudService.java | 42 ++++++++++++++----- .../ReactiveServiceQueryController.java | 12 +++--- .../web/cache/ReactiveCache.java | 21 +++++----- .../web/bean/FastBeanCopier.java | 1 - ...AuthorizationServiceAutoConfiguration.java | 9 +++- .../service/PermissionSynchronization.java | 16 +++++-- 12 files changed, 146 insertions(+), 41 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionContext.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionCustomizer.java create mode 100644 hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/CompositeAuthorizeDefinitionCustomizer.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionContext.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionContext.java new file mode 100644 index 000000000..8b69af611 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionContext.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.authorization.define; + +public interface AuthorizeDefinitionContext { + + void addResource(ResourceDefinition def); + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionCustomizer.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionCustomizer.java new file mode 100644 index 000000000..b0fe8d320 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/AuthorizeDefinitionCustomizer.java @@ -0,0 +1,7 @@ +package org.hswebframework.web.authorization.define; + +public interface AuthorizeDefinitionCustomizer { + + void custom(AuthorizeDefinitionContext context); + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/CompositeAuthorizeDefinitionCustomizer.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/CompositeAuthorizeDefinitionCustomizer.java new file mode 100644 index 000000000..54af14835 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/CompositeAuthorizeDefinitionCustomizer.java @@ -0,0 +1,24 @@ +package org.hswebframework.web.authorization.define; + +import lombok.AllArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@AllArgsConstructor +public class CompositeAuthorizeDefinitionCustomizer implements AuthorizeDefinitionCustomizer{ + + private final List customizers; + + public CompositeAuthorizeDefinitionCustomizer(Iterable customizers){ + this(StreamSupport.stream(customizers.spliterator(),false).collect(Collectors.toList())); + } + + @Override + public void custom(AuthorizeDefinitionContext context) { + for (AuthorizeDefinitionCustomizer customizer : customizers) { + customizer.custom(context); + } + } +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/MergedAuthorizeDefinition.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/MergedAuthorizeDefinition.java index 94d32070d..b247c7a0c 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/MergedAuthorizeDefinition.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/MergedAuthorizeDefinition.java @@ -4,11 +4,11 @@ import java.util.Set; -public class MergedAuthorizeDefinition { +public class MergedAuthorizeDefinition implements AuthorizeDefinitionContext { - private ResourcesDefinition resources = new ResourcesDefinition(); + private final ResourcesDefinition resources = new ResourcesDefinition(); - private DimensionsDefinition dimensions = new DimensionsDefinition(); + private final DimensionsDefinition dimensions = new DimensionsDefinition(); public Set getResources() { return resources.getResources(); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/DefaultAopMethodAuthorizeDefinitionParser.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/DefaultAopMethodAuthorizeDefinitionParser.java index 0a5f9efaf..6b3c96afe 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/DefaultAopMethodAuthorizeDefinitionParser.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/DefaultAopMethodAuthorizeDefinitionParser.java @@ -6,6 +6,7 @@ import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.annotation.DataAccess; import org.hswebframework.web.authorization.annotation.Dimension; +import org.hswebframework.web.authorization.annotation.ResourceAction; import org.hswebframework.web.authorization.basic.define.DefaultBasicAuthorizeDefinition; import org.hswebframework.web.authorization.basic.define.EmptyAuthorizeDefinition; import org.hswebframework.web.authorization.define.AuthorizeDefinition; @@ -15,8 +16,10 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.RequestMapping; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -63,7 +66,8 @@ public AuthorizeDefinition parse(Class target, Method method, MethodIntercept } //使用自定义 if (!CollectionUtils.isEmpty(parserCustomizers)) { - definition = parserCustomizers.stream() + definition = parserCustomizers + .stream() .map(customizer -> customizer.parse(target, method, context)) .filter(Objects::nonNull) .findAny().orElse(null); @@ -77,7 +81,7 @@ public AuthorizeDefinition parse(Class target, Method method, MethodIntercept Authorize annotation = AnnotationUtils.findAnnotation(target, method, Authorize.class); - if (annotation != null && annotation.ignore()) { + if (isIgnoreMethod(method) || (annotation != null && annotation.ignore())) { cache.put(key, EmptyAuthorizeDefinition.instance); return null; } @@ -107,4 +111,14 @@ public void destroy() { cache.clear(); } + static boolean isIgnoreMethod(Method method) { + //不是public的方法 + if(!Modifier.isPublic(method.getModifiers())){ + return true; + } + //没有以下注解 + return null == AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class) + && null == AnnotatedElementUtils.findMergedAnnotation(method, ResourceAction.class); + } + } diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java index 680d51589..fadebf1d1 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java @@ -10,9 +10,11 @@ import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.core.NestConditional; import org.hswebframework.ezorm.core.dsl.Query; +import org.hswebframework.ezorm.core.param.Param; import org.hswebframework.ezorm.core.param.QueryParam; import org.hswebframework.ezorm.core.param.Term; import org.hswebframework.ezorm.core.param.TermType; +import org.hswebframework.web.bean.FastBeanCopier; import org.springframework.util.StringUtils; @@ -26,11 +28,11 @@ * 可通过静态方法创建:
* 如: *
- *{@code
+ * {@code
  *      QueryParamEntity.of("id",id);
- *}
+ * }
  * 
- * + *

* 或者使用DSL方式来构造: *

{@code
  *  QueryParamEntity
@@ -97,6 +99,20 @@ public Set getExcludes() {
         return super.getExcludes();
     }
 
+    /**
+     * 基于另外一个条件参数来创建查询条件实体
+     *
+     * @param param 参数
+     * @return 新的查询条件
+     * @since 4.0.14
+     */
+    public static QueryParamEntity of(Param param) {
+        if (param instanceof QueryParamEntity) {
+            return ((QueryParamEntity) param).clone();
+        }
+        return FastBeanCopier.copy(param, new QueryParamEntity());
+    }
+
     /**
      * 创建一个空的查询参数实体,该实体无任何参数.
      *
@@ -217,7 +233,7 @@ public QueryParamEntity noPaging() {
         return this;
     }
 
-    public QueryParamEntity doNotSort(){
+    public QueryParamEntity doNotSort() {
         this.setSorts(new ArrayList<>());
         return this;
     }
diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/EnableCacheReactiveCrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/EnableCacheReactiveCrudService.java
index d152b5e36..272ecd4e5 100644
--- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/EnableCacheReactiveCrudService.java
+++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/EnableCacheReactiveCrudService.java
@@ -9,6 +9,7 @@
 import reactor.core.publisher.Mono;
 
 import java.util.Collection;
+import java.util.function.Function;
 
 public interface EnableCacheReactiveCrudService extends ReactiveCrudService {
 
@@ -16,8 +17,8 @@ public interface EnableCacheReactiveCrudService extends ReactiveCrudServic
 
     default Mono findById(K id) {
         return this.getCache()
-                .mono("id:" + id)
-                .onCacheMissResume(ReactiveCrudService.super.findById(Mono.just(id)));
+                   .mono("id:" + id)
+                   .onCacheMissResume(ReactiveCrudService.super.findById(Mono.just(id)));
     }
 
     @Override
@@ -27,44 +28,65 @@ default Mono findById(Mono publisher) {
 
     @Override
     default Mono updateById(K id, Mono entityPublisher) {
-        return ReactiveCrudService.super.updateById(id, entityPublisher)
+        return ReactiveCrudService.super
+                .updateById(id, entityPublisher)
                 .doFinally(i -> getCache().evict("id:" + id).subscribe());
     }
 
+    @Override
+    default Mono save(E data) {
+        return ReactiveCrudService.super
+                .save(data)
+                .doFinally(i -> getCache().clear().subscribe());
+    }
+
     @Override
     default Mono save(Publisher entityPublisher) {
-        return ReactiveCrudService.super.save(entityPublisher)
+        return ReactiveCrudService.super
+                .save(entityPublisher)
+                .doFinally(i -> getCache().clear().subscribe());
+    }
+
+    @Override
+    default Mono insert(E data) {
+        return ReactiveCrudService.super
+                .insert(data)
                 .doFinally(i -> getCache().clear().subscribe());
     }
 
     @Override
     default Mono insert(Publisher entityPublisher) {
-        return ReactiveCrudService.super.insert(entityPublisher)
+        return ReactiveCrudService.super
+                .insert(entityPublisher)
                 .doFinally(i -> getCache().clear().subscribe());
     }
 
     @Override
     default Mono insertBatch(Publisher> entityPublisher) {
-        return ReactiveCrudService.super.insertBatch(entityPublisher)
+        return ReactiveCrudService.super
+                .insertBatch(entityPublisher)
                 .doFinally(i -> getCache().clear().subscribe());
     }
 
     @Override
     default Mono deleteById(Publisher idPublisher) {
-        return Flux.from(idPublisher)
-                .doOnNext(id -> this.getCache().evict("id:" + id).subscribe())
+        return Flux
+                .from(idPublisher)
+                .flatMap(id -> this.getCache().evict("id:" + id).thenReturn(id))
                 .as(ReactiveCrudService.super::deleteById);
     }
 
     @Override
     default ReactiveUpdate createUpdate() {
-        return ReactiveCrudService.super.createUpdate()
+        return ReactiveCrudService.super
+                .createUpdate()
                 .onExecute((update, s) -> s.doFinally((__) -> getCache().clear().subscribe()));
     }
 
     @Override
     default ReactiveDelete createDelete() {
-        return ReactiveCrudService.super.createDelete()
+        return ReactiveCrudService.super
+                .createDelete()
                 .onExecute((update, s) -> s.doFinally((__) -> getCache().clear().subscribe()));
     }
 }
diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java
index ef0f074a1..51eed4f7f 100644
--- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java
+++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java
@@ -72,9 +72,9 @@ default Flux query(@Parameter(hidden = true) QueryParamEntity query) {
      */
     @PostMapping("/_query/no-paging")
     @QueryAction
-    @QueryNoPagingOperation(summary = "使用POST方式分页动态查询(不返回总数)",
+    @Operation(summary = "使用POST方式分页动态查询(不返回总数)",
             description = "此操作不返回分页总数,如果需要获取全部数据,请设置参数paging=false")
-    default Flux query(@Parameter(hidden = true) @RequestBody Mono query) {
+    default Flux query(@RequestBody Mono query) {
         return query.flatMapMany(this::query);
     }
 
@@ -133,8 +133,8 @@ default Mono> queryPager(@Parameter(hidden = true) QueryParamEnti
     @PostMapping("/_query")
     @QueryAction
     @SuppressWarnings("all")
-    @QueryOperation(summary = "使用POST方式分页动态查询")
-    default Mono> queryPager(@Parameter(hidden = true) @RequestBody Mono query) {
+    @Operation(summary = "使用POST方式分页动态查询")
+    default Mono> queryPager(@RequestBody Mono query) {
         return query.flatMap(q -> queryPager(q));
     }
 
@@ -165,8 +165,8 @@ default Mono> queryPager(@Parameter(hidden = true) @RequestBody M
      */
     @PostMapping("/_count")
     @QueryAction
-    @QueryNoPagingOperation(summary = "使用POST方式查询总数")
-    default Mono count(@Parameter(hidden = true) @RequestBody Mono query) {
+    @Operation(summary = "使用POST方式查询总数")
+    default Mono count(@RequestBody Mono query) {
         return query.flatMap(this::count);
     }
 
diff --git a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/ReactiveCache.java b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/ReactiveCache.java
index 0411631ae..6b5f0f971 100644
--- a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/ReactiveCache.java
+++ b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/ReactiveCache.java
@@ -26,19 +26,20 @@ public interface ReactiveCache {
     Mono clear();
 
     default CacheFlux.FluxCacheBuilderMapMiss flux(Object key) {
-        return otherSupplier ->
-                Flux.defer(() ->
-                        getFlux(key)
-                                .switchIfEmpty(otherSupplier.get()
-                                        .collectList()
-                                        .flatMapMany(values -> put(key, Flux.fromIterable(values))
-                                                .thenMany(Flux.fromIterable(values)))));
+        return otherSupplier -> Flux
+                .defer(() -> this
+                        .getFlux(key)
+                        .switchIfEmpty(otherSupplier.get()
+                                                    .collectList()
+                                                    .flatMapMany(values -> put(key, Flux.fromIterable(values))
+                                                            .thenMany(Flux.fromIterable(values)))));
     }
 
     default CacheMono.MonoCacheBuilderMapMiss mono(Object key) {
-        return otherSupplier ->
-                Mono.defer(() -> getMono(key)
+        return otherSupplier -> Mono
+                .defer(() -> this
+                        .getMono(key)
                         .switchIfEmpty(otherSupplier.get()
-                                .flatMap(value -> put(key, Mono.just(value)).thenReturn(value))));
+                                                    .flatMap(value -> put(key, Mono.just(value)).thenReturn(value))));
     }
 }
diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
index 066da714a..b80d23bf0 100644
--- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
@@ -20,7 +20,6 @@
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.function.Supplier;
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java
index a8f5e2f95..2d80c4fba 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java
+++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java
@@ -3,13 +3,17 @@
 import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
 import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService;
 import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider;
+import org.hswebframework.web.authorization.define.AuthorizeDefinitionCustomizer;
+import org.hswebframework.web.authorization.define.CompositeAuthorizeDefinitionCustomizer;
 import org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration;
 import org.hswebframework.web.authorization.token.UserTokenManager;
 import org.hswebframework.web.system.authorization.api.UserDimensionProvider;
+import org.hswebframework.web.system.authorization.api.entity.PermissionEntity;
 import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
 import org.hswebframework.web.system.authorization.defaults.service.*;
 import org.hswebframework.web.system.authorization.defaults.service.terms.DimensionTerm;
 import org.hswebframework.web.system.authorization.defaults.service.terms.UserDimensionTerm;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.context.annotation.Bean;
@@ -41,8 +45,9 @@ public ReactiveAuthenticationInitializeService reactiveAuthenticationInitializeS
         }
 
         @Bean
-        public PermissionSynchronization permissionSynchronization() {
-            return new PermissionSynchronization();
+        public PermissionSynchronization permissionSynchronization(ReactiveRepository permissionRepository,
+                                                                   ObjectProvider customizer) {
+            return new PermissionSynchronization(permissionRepository, new CompositeAuthorizeDefinitionCustomizer(customizer));
         }
 
         @Bean
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java
index 7a153619e..bd8baa237 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java
+++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java
@@ -26,13 +26,20 @@
 @Slf4j
 public class PermissionSynchronization implements CommandLineRunner {
 
-    @Autowired
-    private ReactiveRepository permissionRepository;
+    private final ReactiveRepository permissionRepository;
+
+    private final AuthorizeDefinitionCustomizer customizer;
 
     private final MergedAuthorizeDefinition definition = new MergedAuthorizeDefinition();
 
     private final Map> entityFieldsMapping = new HashMap<>();
 
+    public PermissionSynchronization(ReactiveRepository permissionRepository,
+                                     AuthorizeDefinitionCustomizer customizer) {
+        this.permissionRepository = permissionRepository;
+        this.customizer = customizer;
+    }
+
     @EventListener
     public void handleResourceParseEvent(AuthorizeDefinitionInitializedEvent event) {
         definition.merge(event.getAllDefinition());
@@ -115,7 +122,10 @@ public void run(String... args) throws Exception {
         if (definition.getResources().isEmpty()) {
             return;
         }
-        permissionRepository.createQuery()
+        customizer.custom(definition);
+
+        permissionRepository
+                .createQuery()
                 .fetch()
                 .collect(Collectors.toMap(PermissionEntity::getId, Function.identity()))
                 .flatMap(group -> Flux.fromIterable(definition.getResources())

From daaa6b47a6532cdf0926ccd3cb6cf97399f424fd Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Wed, 9 Feb 2022 09:39:27 +0800
Subject: [PATCH 155/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0getProperty?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/bean/FastBeanCopier.java              |  12 +-
 .../web/bean/SingleValueMap.java              | 108 ++++++++++++++++++
 2 files changed, 117 insertions(+), 3 deletions(-)
 create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java

diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
index b80d23bf0..a4930a267 100644
--- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
@@ -87,6 +87,12 @@ public boolean contains(Object o) {
         };
     }
 
+    public static Object getProperty(Object source, String key) {
+        SingleValueMap map = new SingleValueMap<>();
+        copy(source, map, include(key));
+        return map.getValue();
+    }
+
     public static  T copy(S source, T target, String... ignore) {
         return copy(source, target, DEFAULT_CONVERT, ignore);
     }
@@ -571,7 +577,7 @@ public  T convert(Object source, Class targetClass, Class[] genericType) {
                 return (T) collection;
             }
 
-            if (target.isEnumType()){
+            if (target.isEnumType()) {
                 if (target.isEnumDict()) {
                     String strVal = String.valueOf(source);
 
@@ -609,11 +615,11 @@ public  T convert(Object source, Class targetClass, Class[] genericType) {
 
                 //快速复制map
                 if (targetClass == Map.class) {
-                    if(source instanceof Map) {
+                    if (source instanceof Map) {
                         return (T) new HashMap(((Map) source));
                     }
                     ClassDescription sourType = ClassDescriptions.getDescription(source.getClass());
-                    return (T)copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize()));
+                    return (T) copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize()));
                 }
 
                 return copy(source, beanFactory.newInstance(targetClass), this);
diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java
new file mode 100644
index 000000000..08c024c61
--- /dev/null
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java
@@ -0,0 +1,108 @@
+package org.hswebframework.web.bean;
+
+import java.util.*;
+
+public class SingleValueMap implements Map {
+    private K key;
+    private V value;
+
+    @Override
+    public int size() {
+        return value == null ? 0 : 1;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return Objects.equals(this.key, key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return Objects.equals(this.value, value);
+    }
+
+    @Override
+    public V get(Object key) {
+        return null;
+    }
+
+    @Override
+    public V put(K key, V value) {
+        this.key = key;
+        V old = this.value;
+        this.value = value;
+        return old;
+    }
+
+    @Override
+    public V remove(Object key) {
+        if (Objects.equals(key, this.key)) {
+            V old = this.value;
+            this.value = null;
+            return old;
+        }
+        return null;
+    }
+
+    @Override
+    public void putAll(Map m) {
+        if (m.size() > 0) {
+            Map.Entry entry = m.entrySet().iterator().next();
+            this.key = entry.getKey();
+            this.value = entry.getValue();
+        }
+    }
+
+    @Override
+    public void clear() {
+        this.key = null;
+        this.value = null;
+    }
+
+    @Override
+    public Set keySet() {
+        return key == null ? Collections.emptySet() : Collections.singleton(key);
+    }
+
+    @Override
+    public Collection values() {
+        return value == null ? Collections.emptySet() : Collections.singleton(value);
+    }
+
+    @Override
+    public Set> entrySet() {
+        return key == null ? Collections.emptySet() : Collections.singleton(
+                new Entry() {
+                    @Override
+                    public K getKey() {
+                        return key;
+                    }
+
+                    @Override
+                    public V getValue() {
+                        return value;
+                    }
+
+                    @Override
+                    public V setValue(V value) {
+                        V old = SingleValueMap.this.value;
+                        SingleValueMap.this.value = value;
+                        return old;
+                    }
+                }
+        );
+    }
+
+    public V getValue() {
+        return value;
+    }
+
+    public K getKey() {
+        return key;
+    }
+}

From 417a31e6fe0095241c05837dd1b1b8b413028c02 Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Wed, 9 Feb 2022 14:45:43 +0800
Subject: [PATCH 156/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A1=A8=E7=BB=93?=
 =?UTF-8?q?=E6=9E=84=E8=87=AA=E5=AE=9A=E4=B9=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CompositeEntityTableMetadataResolver.java |   6 +-
 .../configuration/EasyormConfiguration.java   | 126 ++++++++++++------
 .../TableMetadataCustomizer.java              |  41 ++++++
 pom.xml                                       |   2 +-
 4 files changed, 127 insertions(+), 48 deletions(-)
 create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/TableMetadataCustomizer.java

diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/CompositeEntityTableMetadataResolver.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/CompositeEntityTableMetadataResolver.java
index 28606bbe7..c19e21585 100644
--- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/CompositeEntityTableMetadataResolver.java
+++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/CompositeEntityTableMetadataResolver.java
@@ -15,7 +15,7 @@ public class CompositeEntityTableMetadataResolver implements EntityTableMetadata
 
     private final List resolvers = new ArrayList<>();
 
-    private final Map> cache = new ConcurrentHashMap<>();
+    private final Map, AtomicReference> cache = new ConcurrentHashMap<>();
 
     public void addParser(EntityTableMetadataParser resolver) {
         resolvers.add(resolver);
@@ -33,9 +33,7 @@ private RDBTableMetadata doResolve(Class entityClass) {
                 .filter(Optional::isPresent)
                 .map(Optional::get)
                 .reduce((t1, t2) -> {
-                    for (RDBColumnMetadata column : t1.getColumns()) {
-                        t2.addColumn(column.clone());
-                    }
+                    t2.merge(t1);
                     return t2;
                 }).orElse(null);
     }
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 107f16be7..15714adf8 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
@@ -10,9 +10,12 @@
 import org.hswebframework.ezorm.rdb.mapping.EntityManager;
 import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType;
 import org.hswebframework.ezorm.rdb.mapping.jpa.JpaEntityTableMetadataParser;
+import org.hswebframework.ezorm.rdb.mapping.jpa.JpaEntityTableMetadataParserProcessor;
 import org.hswebframework.ezorm.rdb.mapping.parser.EntityTableMetadataParser;
+import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
 import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata;
 import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata;
+import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
 import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
 import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator;
 import org.hswebframework.web.api.crud.entity.EntityFactory;
@@ -35,9 +38,13 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
 import java.time.Duration;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 @Configuration
 @EnableConfigurationProperties(EasyormProperties.class)
@@ -61,49 +68,6 @@ public EntityFactory entityFactory(ObjectProvider custo
         return factory;
     }
 
-    @Bean
-    @ConditionalOnMissingBean
-    public EntityManager entityManager(EntityTableMetadataResolver resolver, EntityFactory entityFactory) {
-        return new EntityManager() {
-            @Override
-            @SneakyThrows
-            public  E newInstance(Class type) {
-                return entityFactory.newInstance(type);
-            }
-
-            @Override
-            public EntityColumnMapping getMapping(Class entity) {
-
-                return resolver.resolve(entityFactory.getInstanceType(entity, true))
-                               .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entity))
-                               .map(EntityColumnMapping.class::cast)
-                               .orElse(null);
-            }
-        };
-    }
-
-    @Bean
-    public DefaultEntityResultWrapperFactory defaultEntityResultWrapperFactory(EntityManager entityManager) {
-        return new DefaultEntityResultWrapperFactory(entityManager);
-    }
-
-    @Bean
-    @ConditionalOnMissingBean
-    public EntityTableMetadataResolver entityTableMappingResolver(List parsers) {
-        CompositeEntityTableMetadataResolver resolver = new CompositeEntityTableMetadataResolver();
-        parsers.forEach(resolver::addParser);
-        return resolver;
-    }
-
-    @Bean
-    @ConditionalOnMissingBean
-    public EntityTableMetadataParser jpaEntityTableMetadataParser(RDBDatabaseMetadata metadata) {
-        JpaEntityTableMetadataParser parser = new JpaEntityTableMetadataParser();
-        parser.setDatabaseMetadata(metadata);
-
-        return parser;
-    }
-
     @Bean
     @ConditionalOnMissingBean
     @SuppressWarnings("all")
@@ -182,4 +146,80 @@ public CurrentTimeGenerator currentTimeGenerator() {
         return new CurrentTimeGenerator();
     }
 
+    @Configuration
+    public static class EntityTableMetadataParserConfiguration {
+
+        @Bean
+        public DefaultEntityResultWrapperFactory defaultEntityResultWrapperFactory(EntityManager entityManager) {
+            return new DefaultEntityResultWrapperFactory(entityManager);
+        }
+
+        @Bean
+        @ConditionalOnMissingBean
+        public EntityManager entityManager(EntityTableMetadataResolver resolver, EntityFactory entityFactory) {
+            return new EntityManager() {
+                @Override
+                @SneakyThrows
+                public  E newInstance(Class type) {
+                    return entityFactory.newInstance(type);
+                }
+
+                @Override
+                public EntityColumnMapping getMapping(Class entity) {
+
+                    return resolver.resolve(entityFactory.getInstanceType(entity, true))
+                                   .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entity))
+                                   .map(EntityColumnMapping.class::cast)
+                                   .orElse(null);
+                }
+            };
+        }
+
+        @Bean
+        @ConditionalOnMissingBean
+        public EntityTableMetadataResolver entityTableMappingResolver(ObjectProvider parsers) {
+            CompositeEntityTableMetadataResolver resolver = new CompositeEntityTableMetadataResolver();
+            parsers.forEach(resolver::addParser);
+            return resolver;
+        }
+
+        @Bean
+        @ConditionalOnMissingBean
+        public EntityTableMetadataParser jpaEntityTableMetadataParser(RDBDatabaseMetadata metadata,
+                                                                      ObjectProvider customizers) {
+
+            JpaEntityTableMetadataParser parser = new JpaEntityTableMetadataParser() {
+
+                @Override
+                public Optional parseTableMetadata(Class entityType) {
+                    Optional tableOpt = super.parseTableMetadata(entityType);
+                    tableOpt.ifPresent(table -> {
+                        for (TableMetadataCustomizer customizer : customizers) {
+                            customizer.customTable(entityType, table);
+                        }
+                    });
+                    return tableOpt;
+                }
+
+                @Override
+                protected JpaEntityTableMetadataParserProcessor createProcessor(RDBTableMetadata table, Class type) {
+                    return new JpaEntityTableMetadataParserProcessor(table, type) {
+                        @Override
+                        protected void customColumn(PropertyDescriptor descriptor,
+                                                    Field field,
+                                                    RDBColumnMetadata column,
+                                                    Set annotations) {
+                            super.customColumn(descriptor, field, column, annotations);
+                            for (TableMetadataCustomizer customizer : customizers) {
+                                customizer.customColumn(type, descriptor, field, annotations, column);
+                            }
+                        }
+                    };
+                }
+            };
+            parser.setDatabaseMetadata(metadata);
+
+            return parser;
+        }
+    }
 }
diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/TableMetadataCustomizer.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/TableMetadataCustomizer.java
new file mode 100644
index 000000000..f31786433
--- /dev/null
+++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/TableMetadataCustomizer.java
@@ -0,0 +1,41 @@
+package org.hswebframework.web.crud.configuration;
+
+import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
+import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Set;
+
+/**
+ * 表结构自定义器,实现此接口来自定义表结构.
+ *
+ * @author zhouhao
+ * @since 4.0.14
+ */
+public interface TableMetadataCustomizer {
+
+    /**
+     * 自定义列,在列被解析后调用.
+     *
+     * @param entityType  实体类型
+     * @param descriptor  字段描述
+     * @param field       字段
+     * @param column      列定义
+     * @param annotations 字段上的注解
+     */
+    void customColumn(Class entityType,
+                      PropertyDescriptor descriptor,
+                      Field field,
+                      Set annotations,
+                      RDBColumnMetadata column);
+
+    /**
+     * 自定义表,在实体类被解析完成后调用.
+     *
+     * @param entityType 字段类型
+     * @param table      表结构
+     */
+    void customTable(Class entityType, RDBTableMetadata table);
+}
diff --git a/pom.xml b/pom.xml
index 7747c72c5..a2b0328d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,7 +90,7 @@
         3.2.2
         1.6.12
 
-        4.0.12
+        4.0.14-SNAPSHOT
         3.0.2
         3.0.2
         2.7.0

From e57a9a48e2c7f215b801dcf6560e98d8d8774945 Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Wed, 9 Feb 2022 17:45:26 +0800
Subject: [PATCH 157/542] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?=
 =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BD=BF=E7=94=A8=E5=8E=9F=E5=A7=8B=E6=96=87?=
 =?UTF-8?q?=E4=BB=B6=E5=90=8D=E5=AD=98=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/file/FileUploadProperties.java        | 21 ++++++++++++++-----
 .../file/service/LocalFileStorageService.java |  4 +++-
 .../file/web/ReactiveFileControllerTest.java  |  1 +
 3 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java
index c1ccb742b..7412302de 100644
--- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java
+++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java
@@ -22,6 +22,9 @@ public class FileUploadProperties {
 
     private String staticLocation = "/static";
 
+    //是否使用原始文件名进行存储
+    private boolean useOriginalFileName = false;
+
     private Set allowFiles;
 
     private Set denyFiles;
@@ -51,7 +54,7 @@ public boolean denied(String name, MediaType mediaType) {
             if (denyMediaType.contains(mediaType.toString())) {
                 return true;
             }
-            defaultDeny =  false;
+            defaultDeny = false;
         }
 
         if (CollectionUtils.isNotEmpty(allowMediaType)) {
@@ -67,16 +70,24 @@ public boolean denied(String name, MediaType mediaType) {
     public StaticFileInfo createStaticSavePath(String name) {
         String fileName = IDGenerator.SNOW_FLAKE_STRING.generate();
         String filePath = DateFormatter.toString(new Date(), "yyyyMMdd");
-        String absPath = staticFilePath.concat("/").concat(filePath);
+
         //文件后缀
         String suffix = name.contains(".") ?
                 name.substring(name.lastIndexOf(".")) : "";
 
-        new File(absPath).mkdirs();
         StaticFileInfo info = new StaticFileInfo();
 
-        info.location = staticLocation + "/" + filePath + "/" + fileName + suffix;
-        info.savePath = absPath + "/" + fileName + suffix;
+        if (useOriginalFileName) {
+            filePath = filePath + "/" + fileName;
+            fileName = name;
+        } else {
+            fileName = fileName + suffix;
+        }
+        String absPath = staticFilePath.concat("/").concat(filePath);
+        new File(absPath).mkdirs();
+
+        info.location = staticLocation + "/" + filePath + "/" + fileName;
+        info.savePath = absPath + "/" + fileName;
 
         return info;
     }
diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java
index de16cda82..4d46cd7db 100644
--- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java
+++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java
@@ -5,6 +5,7 @@
 import org.hswebframework.web.file.FileUploadProperties;
 import org.springframework.http.codec.multipart.FilePart;
 import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
 import java.io.File;
 import java.io.InputStream;
@@ -55,6 +56,7 @@ public Mono saveFile(InputStream inputStream, String fileType) {
                         }
                         return info.getLocation();
                     }
-                });
+                })
+                .subscribeOn(Schedulers.boundedElastic());
     }
 }
diff --git a/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/web/ReactiveFileControllerTest.java b/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/web/ReactiveFileControllerTest.java
index 4b2211a5a..67ff2654a 100644
--- a/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/web/ReactiveFileControllerTest.java
+++ b/hsweb-system/hsweb-system-file/src/test/java/org/hswebframework/web/file/web/ReactiveFileControllerTest.java
@@ -29,6 +29,7 @@ public class ReactiveFileControllerTest {
 
     static {
         System.setProperty("hsweb.file.upload.static-file-path","./target/upload");
+//        System.setProperty("hsweb.file.upload.use-original-file-name","true");
     }
 
     @Autowired

From a3543b34f237f15a59cbb7db419258e749778554 Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Mon, 21 Feb 2022 14:27:36 +0800
Subject: [PATCH 158/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E6=9C=9F?=
 =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../hswebframework/web/bean/FastBeanCopier.java  | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
index a4930a267..23c6919c8 100644
--- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
@@ -88,7 +88,7 @@ public boolean contains(Object o) {
     }
 
     public static Object getProperty(Object source, String key) {
-        SingleValueMap map = new SingleValueMap<>();
+        SingleValueMap map = new SingleValueMap<>();
         copy(source, map, include(key));
         return map.getValue();
     }
@@ -542,7 +542,11 @@ public  T convert(Object source, Class targetClass, Class[] genericType) {
             }
             if (targetClass == Date.class) {
                 if (source instanceof String) {
-                    return (T) DateFormatter.fromString((String) source);
+                    T parsed = (T) DateFormatter.fromString((String) source);
+                    if (parsed == null) {
+                        return (T) converterByApache(Date.class, source);
+                    }
+                    return parsed;
                 }
                 if (source instanceof Number) {
                     return (T) new Date(((Number) source).longValue());
@@ -629,6 +633,14 @@ public  T convert(Object source, Class targetClass, Class[] genericType) {
             }
 //            return null;
         }
+
+        private Object converterByApache(Class targetClass, Object source) {
+            org.apache.commons.beanutils.Converter converter = convertUtils.lookup(targetClass);
+            if (null != converter) {
+                return converter.convert(targetClass, source);
+            }
+            return null;
+        }
     }
 
     @AllArgsConstructor

From d952c29e4dfd96e9d2e80a4045bfc6802b65fcda Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Mon, 7 Mar 2022 11:49:10 +0800
Subject: [PATCH 159/542] =?UTF-8?q?=E6=9D=83=E9=99=90=E5=A2=9E=E5=8A=A0?=
 =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=BA=BA=E5=92=8C=E4=BF=AE=E6=94=B9=E4=BA=BA?=
 =?UTF-8?q?=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../api/entity/PermissionEntity.java          | 23 ++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index b3957ddd0..1e62c5554 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -7,7 +7,10 @@
 import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
 import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec;
 import org.hswebframework.web.api.crud.entity.GenericEntity;
+import org.hswebframework.web.api.crud.entity.RecordCreationEntity;
+import org.hswebframework.web.api.crud.entity.RecordModifierEntity;
 import org.hswebframework.web.bean.FastBeanCopier;
+import org.hswebframework.web.crud.generator.Generators;
 import org.hswebframework.web.validator.CreateGroup;
 import org.springframework.util.CollectionUtils;
 
@@ -27,7 +30,7 @@
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class PermissionEntity extends GenericEntity {
+public class PermissionEntity extends GenericEntity implements RecordCreationEntity, RecordModifierEntity {
 
     @Override
     @Pattern(regexp = "^[0-9a-zA-Z_\\-]+$", message = "ID只能由数字,字母,下划线和中划线组成", groups = CreateGroup.class)
@@ -80,6 +83,24 @@ public String getId() {
     @Schema(description = "其他配置")
     private Map properties;
 
+    @Schema(description = "创建时间")
+    @Column(updatable = false)
+    @DefaultValue(generator = Generators.CURRENT_TIME)
+    private Long createTime;
+
+    @Schema(description = "创建人ID")
+    @Column(length = 64, updatable = false)
+    private String creatorId;
+
+    @Schema(description = "修改时间")
+    @Column
+    @DefaultValue(generator = Generators.CURRENT_TIME)
+    private Long modifyTime;
+
+    @Schema(description = "修改人ID")
+    @Column(length = 64, updatable = false)
+    private String modifierId;
+
     public PermissionEntity copy(Predicate actionFilter,
                                  Predicate fieldFilter) {
         PermissionEntity entity = FastBeanCopier.copy(this, new PermissionEntity());

From 82cb6877f5efa947c1e2f547e384ab07c173f2d9 Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Fri, 11 Mar 2022 16:31:17 +0800
Subject: [PATCH 160/542] fixed #197: upgrade spring-framework version

---
 pom.xml | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index a2b0328d3..3b9d30506 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,7 +79,7 @@
         1.8
         ${java.version}
 
-        2.3.11.RELEASE
+        2.3.12.RELEASE
 
         3.20.0-GA
         5.19.0.2
@@ -96,6 +96,7 @@
         2.7.0
 
         Arabba-SR10
+        5.2.19.RELEASE
     
 
     
@@ -399,6 +400,14 @@
                 1.9.4
             
 
+            
+                org.springframework
+                spring-framework-bom
+                ${spring-framework.version}
+                pom
+                import
+            
+
             
                 org.springframework.boot
                 spring-boot-dependencies

From 88f029b503ff0aadd98f22bc61897fe6dbd5a3b6 Mon Sep 17 00:00:00 2001
From: zhangji <125540670@qq.com>
Date: Fri, 11 Mar 2022 16:37:50 +0800
Subject: [PATCH 161/542] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E8=A1=A8=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../authorization/api/entity/AuthorizationSettingEntity.java | 2 ++
 .../web/system/authorization/api/entity/DimensionEntity.java | 1 +
 .../system/authorization/api/entity/DimensionTypeEntity.java | 1 +
 .../system/authorization/api/entity/DimensionUserEntity.java | 1 +
 .../system/authorization/api/entity/PermissionEntity.java    | 1 +
 .../web/system/authorization/api/entity/UserEntity.java      | 5 +++++
 .../hswebframework/web/oauth2/entity/OAuth2ClientEntity.java | 2 ++
 .../web/dictionary/entity/DictionaryEntity.java              | 2 ++
 .../web/dictionary/entity/DictionaryItemEntity.java          | 2 ++
 9 files changed, 17 insertions(+)

diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index 435663f8a..753fec7e1 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -26,6 +26,7 @@
         @Index(name = "idx_sasi_dss", columnList = "dimension_type,dimension_target,state desc"),
         @Index(name = "idx_sasi_pdd", columnList = "permission,dimension_type,dimension_target",unique = true)
 })
+@Comment("授权信息")
 @Getter
 @Setter
 @EnableEntityEvent
@@ -33,6 +34,7 @@ public class AuthorizationSettingEntity implements Entity {
     @Id
     @Column(length = 32)
     @GeneratedValue(generator = "md5")
+    @Schema(description = "ID")
     private String id;
 
     @Column(length = 32, nullable = false, updatable = false)
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index d4ec1e83f..e7b383780 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -25,6 +25,7 @@
 @Table(name = "s_dimension", indexes = {
         @Index(name = "idx_dims_path", columnList = "path")
 })
+@Comment("权限纬度")
 @EnableEntityEvent
 public class DimensionEntity extends GenericTreeSortSupportEntity {
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
index 216c45b6d..eb6274a43 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
+++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
@@ -15,6 +15,7 @@
 @Getter
 @Setter
 @Table(name = "s_dimension_type")
+@Comment("纬度类型")
 public class DimensionTypeEntity extends GenericEntity implements DimensionType {
 
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index 827d5a744..31972c751 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -27,6 +27,7 @@
         @Index(name = "idx_dimsu_user_id", columnList = "user_id"),
 
 })
+@Comment("用户纬度关联表")
 @EnableEntityEvent
 public class DimensionUserEntity extends GenericEntity {
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index b3957ddd0..b170a998a 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -22,6 +22,7 @@
 import java.util.stream.Collectors;
 
 @Table(name = "s_permission")
+@Comment("权限信息")
 @Getter
 @Setter
 @Builder
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index 0b05f6c9d..d903669aa 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -6,6 +6,7 @@
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
 import org.hswebframework.web.api.crud.entity.GenericEntity;
 import org.hswebframework.web.api.crud.entity.RecordCreationEntity;
@@ -32,6 +33,7 @@
 @Table(name = "s_user",
         indexes = @Index(name = "user_username_idx", columnList = "username", unique = true)
 )
+@Comment("用户信息")
 public class UserEntity extends GenericEntity implements RecordCreationEntity {
 
     @Column(length = 128, nullable = false)
@@ -54,6 +56,7 @@ public class UserEntity extends GenericEntity implements RecordCreationE
     @Column(nullable = false)
     @ToString.Ignore(cover = false)
     @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+    @Schema(description = "加密盐值")
     @Hidden
     private String salt;
 
@@ -67,11 +70,13 @@ public class UserEntity extends GenericEntity implements RecordCreationE
     private Byte status;
 
     @Column(name = "creator_id", updatable = false)
+    @Schema(description = "创建者ID")
     @Hidden
     private String creatorId;
 
     @Column(name = "create_time", updatable = false)
     @DefaultValue(generator = "current_time")
+    @Schema(description = "创建时间")
     @Hidden
     private Long createTime;
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/entity/OAuth2ClientEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/entity/OAuth2ClientEntity.java
index 88274fc54..ca8677b09 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/entity/OAuth2ClientEntity.java
+++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/entity/OAuth2ClientEntity.java
@@ -4,6 +4,7 @@
 import lombok.Getter;
 import lombok.Setter;
 import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
+import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
 import org.hswebframework.ezorm.rdb.mapping.annotation.EnumCodec;
 import org.hswebframework.web.api.crud.entity.GenericEntity;
@@ -17,6 +18,7 @@
 import javax.validation.constraints.NotBlank;
 
 @Table(name = "s_oauth2_client")
+@Comment("OAuth2客户端")
 @Getter
 @Setter
 public class OAuth2ClientEntity extends GenericEntity {
diff --git a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java
index 6b95b7e37..7930d759f 100644
--- a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java
+++ b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java
@@ -20,6 +20,7 @@
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
 import org.hswebframework.web.api.crud.entity.GenericEntity;
 import org.hswebframework.web.api.crud.entity.RecordCreationEntity;
@@ -37,6 +38,7 @@
  * @author hsweb-generator-online
  */
 @Table(name = "s_dictionary")
+@Comment("数据字典")
 @Getter
 @Setter
 public class DictionaryEntity extends GenericEntity implements RecordCreationEntity {
diff --git a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java
index ef74f9f2e..cdd4b3e11 100644
--- a/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java
+++ b/hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java
@@ -20,6 +20,7 @@
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
 import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity;
 import org.hswebframework.web.dict.EnumDict;
@@ -39,6 +40,7 @@
         @Index(name = "idx_dic_item_ordinal",columnList = "ordinal"),
         @Index(name = "idx_dic_item_path",columnList = "path")
 })
+@Comment("数据字典选项")
 public class DictionaryItemEntity extends GenericTreeSortSupportEntity implements EnumDict {
     //字典id
     @Column(name = "dict_id", length = 64, updatable = false, nullable = false)

From 0db32e8598da7cd03b743004d262500b5cb6307e Mon Sep 17 00:00:00 2001
From: zhangji <125540670@qq.com>
Date: Fri, 11 Mar 2022 16:57:01 +0800
Subject: [PATCH 162/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E5=AD=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/system/authorization/api/entity/DimensionEntity.java    | 2 +-
 .../system/authorization/api/entity/DimensionTypeEntity.java    | 2 +-
 .../system/authorization/api/entity/DimensionUserEntity.java    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index e7b383780..78ee7f731 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -25,7 +25,7 @@
 @Table(name = "s_dimension", indexes = {
         @Index(name = "idx_dims_path", columnList = "path")
 })
-@Comment("权限纬度")
+@Comment("权限维度")
 @EnableEntityEvent
 public class DimensionEntity extends GenericTreeSortSupportEntity {
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
index eb6274a43..765230147 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
+++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionTypeEntity.java
@@ -15,7 +15,7 @@
 @Getter
 @Setter
 @Table(name = "s_dimension_type")
-@Comment("纬度类型")
+@Comment("维度类型")
 public class DimensionTypeEntity extends GenericEntity implements DimensionType {
 
 
diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
index 31972c751..c4cb157ba 100644
--- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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
@@ -27,7 +27,7 @@
         @Index(name = "idx_dimsu_user_id", columnList = "user_id"),
 
 })
-@Comment("用户纬度关联表")
+@Comment("用户维度关联表")
 @EnableEntityEvent
 public class DimensionUserEntity extends GenericEntity {
 

From 789b5303d0fbe890f9bed67585706b730dbd92f6 Mon Sep 17 00:00:00 2001
From: zhouhao 
Date: Thu, 17 Mar 2022 11:40:46 +0800
Subject: [PATCH 163/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=B4=E6=98=8E?=
 =?UTF-8?q?=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../authorization/ReactiveAuthenticationHolder.java  | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java
index de756e4aa..ce7d204ae 100644
--- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java
+++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java
@@ -29,13 +29,13 @@
 import java.util.stream.Collectors;
 
 /**
- * 权限获取器,用于静态方式获取当前登录用户的权限信息.
+ * 响应式权限保持器,用于响应式方式获取当前登录用户的权限信息.
  * 例如:
- * 
- *     @RequestMapping("/example")
- *     public ResponseMessage example(){
- *         Authorization auth = AuthorizationHolder.get();
- *         return ResponseMessage.ok();
+ * 
{@code
+ *     @RequestMapping("/example")
+ *     public Mono example(){
+ *         return ReactiveAuthenticationHolder.get();
+ *     }
  *     }
  * 
* From ddfe97e64130cf7f059d315218dbc7639533f23c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 17 Mar 2022 19:20:16 +0800 Subject: [PATCH 164/542] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8indexer=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EasyormRepositoryRegistrar.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) 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 9fe25ff59..2beddadfc 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 @@ -23,11 +23,13 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import javax.persistence.Table; +import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; @@ -40,7 +42,16 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - private final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + private final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(); + + private String getResourceClassName(Resource resource) { + try { + return metadataReaderFactory.getMetadataReader(resource) + .getClassMetadata().getClassName(); + } catch (IOException e) { + return null; + } + } @SneakyThrows private Stream doGetResources(String packageStr) { @@ -50,6 +61,22 @@ private Stream doGetResources(String packageStr) { return Arrays.stream(resourcePatternResolver.getResources(path)); } + protected Set scanEntities(String[] packageStr) { + CandidateComponentsIndex index = CandidateComponentsIndexLoader.loadIndex(org.springframework.util.ClassUtils.getDefaultClassLoader()); + if (null == index) { + return Stream + .of(packageStr) + .flatMap(this::doGetResources) + .map(this::getResourceClassName) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + return Stream + .of(packageStr) + .flatMap(pkg -> index.getCandidateTypes(pkg, Table.class.getName()).stream()) + .collect(Collectors.toSet()); + } + @Override @SneakyThrows @SuppressWarnings("all") @@ -63,26 +90,12 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B boolean nonReactiveEnabled = Boolean.TRUE.equals(attr.get("nonReactive")); String[] arr = (String[]) attr.get("value"); -// Set resources = Arrays -// .stream(arr) -// .flatMap(this::doGetResources) -// .collect(Collectors.toSet()); Class[] anno = (Class[]) attr.get("annotation"); Set entityInfos = new HashSet<>(); CandidateComponentsIndex index = CandidateComponentsIndexLoader.loadIndex(org.springframework.util.ClassUtils.getDefaultClassLoader()); - Set entities = Stream - .of(arr) - .flatMap(_package -> { - return index - .getCandidateTypes(_package, Table.class.getName()) - .stream(); - }) - .collect(Collectors.toSet()); - for (String className : entities) { -// MetadataReader reader = metadataReaderFactory.getMetadataReader(resource); -// String className = reader.getClassMetadata().getClassName(); + 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)) { From 33f83a24de00456a6dd8eee9b24de2c03c901711 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 18 Mar 2022 19:52:36 +0800 Subject: [PATCH 165/542] =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=93=8D=E5=BA=94=E5=BC=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aop/ReactiveAopAccessLoggerSupport.java | 37 +++++++++++-------- .../hsweb-access-logging-api/pom.xml | 8 ++++ .../events/AccessLoggerAfterEvent.java | 3 +- .../events/AccessLoggerBeforeEvent.java | 3 +- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 7afb1a897..09ac21852 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -9,6 +9,7 @@ import org.hswebframework.web.logging.AccessLoggerListener; import org.hswebframework.web.logging.LoggerDefine; import org.hswebframework.web.logging.events.AccessLoggerAfterEvent; +import org.hswebframework.web.logging.events.AccessLoggerBeforeEvent; import org.hswebframework.web.utils.ReactiveWebUtils; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; import org.springframework.beans.factory.annotation.Autowired; @@ -67,37 +68,41 @@ private Mono currentRequestInfo() { .handle((context, sink) -> { if (context.hasKey(RequestInfo.class)) { RequestInfo info = context.get(RequestInfo.class); - ReactiveLogger.log(context, info::setContext); + ReactiveLogger.log(context, ctx -> info.setContext(new HashMap<>(ctx))); sink.next(info); } }); } protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { - return this + + Flux cache = this .currentRequestInfo() .doOnNext(loggerInfo::putAccessInfo) + .then(Mono.defer(() -> new AccessLoggerBeforeEvent(loggerInfo).publish(eventPublisher))) .thenMany(flux) - .doOnError(loggerInfo::setException) - .doFinally(f -> { + .cache(); + + return cache + .flatMap(ignore -> Mono.empty()) + .then(Mono.defer(() -> { loggerInfo.setResponseTime(System.currentTimeMillis()); - eventPublisher.publishEvent(new AccessLoggerAfterEvent(loggerInfo)); + return new AccessLoggerAfterEvent(loggerInfo).publish(eventPublisher); + })) + .thenMany(cache) + .onErrorResume(err -> { + loggerInfo.setException(err); + loggerInfo.setResponseTime(System.currentTimeMillis()); + return new AccessLoggerAfterEvent(loggerInfo) + .publish(eventPublisher) + .then(Mono.error(err)); }) .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); } protected Mono wrapMonoResponse(Mono mono, AccessLoggerInfo loggerInfo) { - return this - .currentRequestInfo() - .doOnNext(loggerInfo::putAccessInfo) - .then(mono) - .doOnError(loggerInfo::setException) - .doOnSuccess(loggerInfo::setResponse) - .doFinally(f -> { - loggerInfo.setResponseTime(System.currentTimeMillis()); - eventPublisher.publishEvent(new AccessLoggerAfterEvent(loggerInfo)); - }) - .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + return wrapFluxResponse(mono.flux(), loggerInfo) + .singleOrEmpty(); } private LoggerDefine createDefine(MethodInterceptorHolder holder) { diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 323d43ddb..72dd5b811 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -13,5 +13,13 @@ hsweb-access-logging-api 访问日志API模块 + + + org.hswebframework.web + hsweb-core + ${project.version} + compile + + \ No newline at end of file diff --git a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerAfterEvent.java b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerAfterEvent.java index 1129a2eac..5cd153ef1 100644 --- a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerAfterEvent.java +++ b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerAfterEvent.java @@ -2,11 +2,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.hswebframework.web.logging.AccessLoggerInfo; @AllArgsConstructor @Getter -public class AccessLoggerAfterEvent { +public class AccessLoggerAfterEvent extends DefaultAsyncEvent { private AccessLoggerInfo logger; } diff --git a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerBeforeEvent.java b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerBeforeEvent.java index f927cbc84..bf2c4b77b 100644 --- a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerBeforeEvent.java +++ b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/events/AccessLoggerBeforeEvent.java @@ -2,11 +2,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; import org.hswebframework.web.logging.AccessLoggerInfo; @AllArgsConstructor @Getter -public class AccessLoggerBeforeEvent { +public class AccessLoggerBeforeEvent extends DefaultAsyncEvent { private AccessLoggerInfo logger; } From 0da2441a6924f00049f3899b9e37251eb190c175 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 21 Mar 2022 18:25:12 +0800 Subject: [PATCH 166/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/event/AsyncEvent.java | 6 ++++++ .../web/event/DefaultAsyncEvent.java | 19 +++++++++++++++---- .../aop/ReactiveAopAccessLoggerSupport.java | 14 +++++++------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java index 100748047..774e24ef0 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java @@ -4,6 +4,8 @@ import org.springframework.context.ApplicationEventPublisher; import reactor.core.publisher.Mono; +import java.util.function.Function; + /** * 异步事件,使用响应式编程进行事件监听时,请使用此事件接口 * @@ -27,6 +29,10 @@ public interface AsyncEvent { */ void first(Publisher publisher); + void first(Function,Publisher> mapper); + + void async(Function,Publisher> mapper); + /** * 推送事件到 ApplicationEventPublisher * diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index 0cc0d64a6..a076ee5ce 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -1,14 +1,15 @@ package org.hswebframework.web.event; -import lombok.Getter; import org.reactivestreams.Publisher; import org.springframework.context.ApplicationEventPublisher; import reactor.core.publisher.Mono; +import java.util.function.Function; + public class DefaultAsyncEvent implements AsyncEvent { - private Mono async = Mono.empty(); - private Mono first = Mono.empty(); + private Mono async = Mono.empty(); + private Mono first = Mono.empty(); private boolean hasListener; @@ -23,9 +24,19 @@ public synchronized void first(Publisher publisher) { this.first = Mono.from(publisher).then(first); } + @Override + public void first(Function, Publisher> mapper) { + this.first = Mono.from(mapper.apply(this.first)); + } + + @Override + public void async(Function, Publisher> mapper) { + this.async = Mono.from(mapper.apply(this.async)); + } + @Override public Mono getAsync() { - return this.first.then(this.async); + return this.first.then(this.async).then(); } @Override diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 09ac21852..b033de238 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -76,15 +76,15 @@ private Mono currentRequestInfo() { protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { - Flux cache = this + Flux cache = flux.cache(); + return this .currentRequestInfo() .doOnNext(loggerInfo::putAccessInfo) - .then(Mono.defer(() -> new AccessLoggerBeforeEvent(loggerInfo).publish(eventPublisher))) - .thenMany(flux) - .cache(); - - return cache - .flatMap(ignore -> Mono.empty()) + .then(Mono.defer(() -> { + AccessLoggerBeforeEvent event = new AccessLoggerBeforeEvent(loggerInfo); + event.first(cache); + return event.publish(eventPublisher); + })) .then(Mono.defer(() -> { loggerInfo.setResponseTime(System.currentTimeMillis()); return new AccessLoggerAfterEvent(loggerInfo).publish(eventPublisher); From 7666ea5f099737a298cdcdfe5417dc5c79d3285c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 24 Mar 2022 16:48:53 +0800 Subject: [PATCH 167/542] =?UTF-8?q?=E4=BC=98=E5=8C=96i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 21 +++++++++- .../web/exception/ValidationException.java | 42 ++++++++++++++----- .../web/validator/ValidatorUtilsTest.java | 30 +++++++++---- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index ea77021c3..2218c4972 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -5,6 +5,10 @@ import lombok.Getter; import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; +import reactor.core.publisher.Mono; + +import java.util.Locale; +import java.util.Objects; /** * 支持国际化消息的异常,code为 @@ -45,11 +49,24 @@ public I18nSupportException(String code, Throwable cause, Object... args) { @Override public String getMessage() { + if (Objects.equals(super.getMessage(), this.getI18nCode())) { + return getLocalizedMessage(); + } return super.getMessage() != null ? super.getMessage() : getLocalizedMessage(); } @Override - public String getLocalizedMessage() { - return LocaleUtils.resolveMessage(i18nCode, args); + public final String getLocalizedMessage() { + return getLocalizedMessage(LocaleUtils.current()); + } + + public String getLocalizedMessage(Locale locale) { + return LocaleUtils.resolveMessage(i18nCode, locale, getMessage(), args); + } + + public final Mono getLocalizedMessageReactive() { + return LocaleUtils + .currentReactive() + .map(this::getLocalizedMessage); } } 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 index fc62966ed..2a1b0ba13 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -6,10 +6,13 @@ import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; import org.springframework.http.HttpStatus; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ResponseStatus; import javax.validation.ConstraintViolation; import java.util.*; +import java.util.stream.Collectors; @Getter @Setter @@ -31,9 +34,6 @@ public ValidationException(String property, String message, Object... args) { public ValidationException(String message, List details, Object... args) { super(message, args); this.details = details; - for (Detail detail : this.details) { - detail.translateI18n(args); - } } public ValidationException(Set> violations) { @@ -48,23 +48,44 @@ public ValidationException(Set> violations) { //{0} 属性 ,{1} 验证消息 //property也支持国际化? - String resolveMessage = propertyI18nEnabled ? - LocaleUtils.resolveMessage(first.getRootBeanClass().getName() + "." + property, property) + String propertyI18n = propertyI18nEnabled ? + first.getRootBeanClass().getName() + "." + property : property; - setArgs(new Object[]{resolveMessage, first.getMessage()}); + setArgs(new Object[]{propertyI18n, first.getMessage()}); details = new ArrayList<>(violations.size()); for (ConstraintViolation violation : violations) { - details.add(new Detail(violation.getPropertyPath().toString(), violation.getMessage(), null)); + details.add(new Detail(violation.getPropertyPath().toString(), + violation.getMessage(), + null)); } } + public List getDetails(Locale locale) { + return CollectionUtils.isEmpty(details) + ? Collections.emptyList() + : details + .stream() + .map(detail -> detail.translateI18n(locale)) + .collect(Collectors.toList()); + } + + @Override + public String getLocalizedMessage(Locale locale) { + if (propertyI18nEnabled && "validation.property_validate_failed".equals(getI18nCode()) && getArgs().length > 0) { + Object[] args = getArgs().clone(); + args[0] = LocaleUtils.resolveMessage(String.valueOf(args[0]), locale, String.valueOf(args[0])); + return LocaleUtils.resolveMessage(getI18nCode(), locale, getMessage(), args); + } + return super.getLocalizedMessage(locale); + } @Getter @Setter @AllArgsConstructor public static class Detail { + @Schema(description = "字段") String property; @@ -74,10 +95,11 @@ public static class Detail { @Schema(description = "详情") Object detail; - public void translateI18n(Object... args) { - if (message.contains(".")) { - message = LocaleUtils.resolveMessage(message, message, args); + public Detail translateI18n(Locale locale) { + if (StringUtils.hasText(message) && message.contains(".")) { + return new Detail(property, LocaleUtils.resolveMessage(message, locale, message), detail); } + return this; } } } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java index 07ac1d5b9..ca8975c58 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/validator/ValidatorUtilsTest.java @@ -4,7 +4,9 @@ import lombok.Setter; import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.i18n.LocaleUtils; +import org.hswebframework.web.i18n.MessageSourceInitializer; import org.junit.Test; +import org.springframework.context.support.StaticMessageSource; import javax.validation.constraints.NotBlank; @@ -14,27 +16,39 @@ public class ValidatorUtilsTest { + static { + System.setProperty("i18n.validation.property.enabled", "true"); + } @Test - public void test(){ - test(Locale.CHINA,"不能为空"); - test(Locale.ENGLISH,"must not be blank"); + public void test() { + StaticMessageSource source = new StaticMessageSource(); + source.addMessage("validation.property_validate_failed", Locale.CHINA, "{0} {1}"); + source.addMessage("validation.property_validate_failed", Locale.ENGLISH, "{0} {1}"); + + source.addMessage(TestEntity.class.getName() + ".notBlank", Locale.ENGLISH, "Test"); + source.addMessage(TestEntity.class.getName() + ".notBlank", Locale.CHINA, "测试"); + + MessageSourceInitializer.init(source); + test(Locale.CHINA, "不能为空", "测试 不能为空"); + test(Locale.ENGLISH, "must not be blank", "Test must not be blank"); } - public void test(Locale locale,String msg){ + public void test(Locale locale, String msg, String msg2) { try { - LocaleUtils.doWith(locale,en->{ + LocaleUtils.doWith(locale, en -> { ValidatorUtils.tryValidate(new TestEntity()); }); throw new IllegalStateException(); - }catch (ValidationException e){ - assertEquals(msg,e.getDetails().get(0).getMessage()); + } catch (ValidationException e) { + assertEquals(msg, e.getDetails().get(0).getMessage()); + assertEquals(msg2, e.getLocalizedMessage(locale)); } } @Getter @Setter - public static class TestEntity{ + public static class TestEntity { @NotBlank private String notBlank; From 533d86e52a4395355ef86c1fd007b1d4db7b0028 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 24 Mar 2022 16:49:02 +0800 Subject: [PATCH 168/542] =?UTF-8?q?=E4=BC=98=E5=8C=96i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonErrorControllerAdvice.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 0d4b0b77e..f3b4617ad 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -88,10 +88,12 @@ public Mono> handleException(NotFoundException e) { @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono>> handleException(ValidationException e) { return LocaleUtils - .resolveThrowable(e, (err, msg) -> ResponseMessage - .>error(400, CodeConstants.Error.illegal_argument, msg) - .result(e.getDetails())) - ; + .currentReactive() + .map(locale -> ResponseMessage + .>error(400, + CodeConstants.Error.illegal_argument, + e.getLocalizedMessage(locale)) + .result(e.getDetails(locale))); } @ExceptionHandler @@ -250,9 +252,8 @@ public Mono>> handleException(S @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(I18nSupportException e) { - return LocaleUtils - .resolveThrowable(e, - (err, msg) -> ResponseMessage.error(400, err.getI18nCode(), msg)); + return e.getLocalizedMessageReactive() + .map(msg -> ResponseMessage.error(400, e.getI18nCode(), msg)); } } From 630583a2b7b723fab30d64402a3288622b988f28 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 24 Mar 2022 16:49:12 +0800 Subject: [PATCH 169/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/hswebframework/web/event/AsyncEvent.java | 4 ++-- .../java/org/hswebframework/web/event/DefaultAsyncEvent.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java index 774e24ef0..19f78d79c 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/AsyncEvent.java @@ -29,9 +29,9 @@ public interface AsyncEvent { */ void first(Publisher publisher); - void first(Function,Publisher> mapper); + void transformFirst(Function,Publisher> mapper); - void async(Function,Publisher> mapper); + void transform(Function,Publisher> mapper); /** * 推送事件到 ApplicationEventPublisher diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index a076ee5ce..298c0ff12 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -25,12 +25,12 @@ public synchronized void first(Publisher publisher) { } @Override - public void first(Function, Publisher> mapper) { + public void transformFirst(Function, Publisher> mapper) { this.first = Mono.from(mapper.apply(this.first)); } @Override - public void async(Function, Publisher> mapper) { + public void transform(Function, Publisher> mapper) { this.async = Mono.from(mapper.apply(this.async)); } From e8db04361c1da2615c35eb88e8ec3458178c872c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 29 Mar 2022 16:53:28 +0800 Subject: [PATCH 170/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=8D=95=E4=B8=AA=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/crud/entity/Entity.java | 21 +++++++++++++++++++ .../web/validator/ValidatorUtils.java | 12 +++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) 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 9d69f33e6..6797afaa9 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,7 @@ package org.hswebframework.web.api.crud.entity; +import org.hswebframework.ezorm.core.StaticMethodReferenceColumn; import org.hswebframework.web.bean.FastBeanCopier; import org.hswebframework.web.validator.ValidatorUtils; @@ -42,6 +43,26 @@ default void tryValidate(Class... groups) { ValidatorUtils.tryValidate(this, groups); } + /** + * 使用jsr303对当前实体类的指定属性进行验证,如果未通过验证则会抛出{@link org.hswebframework.web.exception.ValidationException}异常 + * + * @param groups 分组 + * @see org.hswebframework.web.exception.ValidationException + */ + default void tryValidate(String property, Class... groups) { + ValidatorUtils.tryValidate(this, property, groups); + } + + /** + * 使用jsr303对当前实体类的指定属性进行验证,如果未通过验证则会抛出{@link org.hswebframework.web.exception.ValidationException}异常 + * + * @param groups 分组 + * @see org.hswebframework.web.exception.ValidationException + */ + default void tryValidate(StaticMethodReferenceColumn property, Class... groups) { + tryValidate(property.getColumn(), groups); + } + /** * 将当前实体类复制到指定其他类型中,类型将会被自动实例化,在类型明确时,建议使用{@link Entity#copyFrom(Object, String...)}. * 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 index e578f1b4d..7fa113a47 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -32,8 +32,7 @@ public static Validator getValidator() { return validator; } - @SuppressWarnings("all") - public static T tryValidate(T bean, Class... group) { + public static T tryValidate(T bean, Class... group) { Set> violations = getValidator().validate(bean, group); if (!violations.isEmpty()) { throw new ValidationException(violations); @@ -42,4 +41,13 @@ public static T tryValidate(T bean, Class... group) { return bean; } + public static T tryValidate(T bean, String property, Class... group) { + Set> violations = getValidator().validateProperty(bean, property, group); + if (!violations.isEmpty()) { + throw new ValidationException(violations); + } + + return bean; + } + } From 5f515953a5877ee5af772486d7b37946bac71142 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 29 Mar 2022 16:53:46 +0800 Subject: [PATCH 171/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 9 +++++---- .../web/exception/ValidationException.java | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 2218c4972..45e7dcf0d 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -47,11 +47,12 @@ public I18nSupportException(String code, Throwable cause, Object... args) { this.i18nCode = code; } + public String getOriginalMessage() { + return super.getMessage(); + } + @Override public String getMessage() { - if (Objects.equals(super.getMessage(), this.getI18nCode())) { - return getLocalizedMessage(); - } return super.getMessage() != null ? super.getMessage() : getLocalizedMessage(); } @@ -61,7 +62,7 @@ public final String getLocalizedMessage() { } public String getLocalizedMessage(Locale locale) { - return LocaleUtils.resolveMessage(i18nCode, locale, getMessage(), args); + return LocaleUtils.resolveMessage(i18nCode, locale, getOriginalMessage(), args); } public final Mono getLocalizedMessageReactive() { 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 index 2a1b0ba13..97d61f2c7 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/ValidationException.java @@ -76,7 +76,7 @@ public String getLocalizedMessage(Locale locale) { if (propertyI18nEnabled && "validation.property_validate_failed".equals(getI18nCode()) && getArgs().length > 0) { Object[] args = getArgs().clone(); args[0] = LocaleUtils.resolveMessage(String.valueOf(args[0]), locale, String.valueOf(args[0])); - return LocaleUtils.resolveMessage(getI18nCode(), locale, getMessage(), args); + return LocaleUtils.resolveMessage(getI18nCode(), locale, getOriginalMessage(), args); } return super.getLocalizedMessage(locale); } From 90255abc9df0bbc0e62b869af2482bebca290515 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 30 Mar 2022 14:20:26 +0800 Subject: [PATCH 172/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/crud/entity/Entity.java | 2 +- .../api/crud/entity/TreeSupportEntity.java | 36 ++--------- .../web/api/crud/entity/TreeUtils.java | 60 +++++++++++++++++++ .../web/bean/DefaultToStringOperator.java | 19 +++--- .../web/validator/ValidatorUtils.java | 10 ++++ 5 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java 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 6797afaa9..b49ce9df9 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 @@ -59,7 +59,7 @@ default void tryValidate(String property, Class... groups) { * @param groups 分组 * @see org.hswebframework.web.exception.ValidationException */ - default void tryValidate(StaticMethodReferenceColumn property, Class... groups) { + default void tryValidate(StaticMethodReferenceColumn property, Class... groups) { tryValidate(property.getColumn(), groups); } diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index fd3e4e4f9..10dc2f3b9 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -269,37 +269,11 @@ static , PK> List list2tree(Collection dat static , PK> List list2tree(final Collection dataList, final BiConsumer> childConsumer, final Function, Predicate> predicateFunction) { - Objects.requireNonNull(dataList, "source list can not be null"); - Objects.requireNonNull(childConsumer, "child consumer can not be null"); - Objects.requireNonNull(predicateFunction, "root predicate function can not be null"); - - Supplier> streamSupplier = () -> dataList.stream(); - // id,node - Map cache = new HashMap<>(); - // parentId,children - Map> treeCache = streamSupplier.get() - .peek(node -> cache.put(node.getId(), node)) - .filter(e -> e.getParentId() != null) - .collect(Collectors.groupingBy(TreeSupportEntity::getParentId)); - - Predicate rootNodePredicate = predicateFunction.apply(new TreeHelper() { - @Override - public List getChildren(PK parentId) { - return treeCache.get(parentId); - } - - @Override - public N getNode(PK id) { - return cache.get(id); - } - }); - - return streamSupplier.get() - //设置每个节点的子节点 - .peek(node -> childConsumer.accept(node, treeCache.get(node.getId()))) - //获取根节点 - .filter(rootNodePredicate) - .collect(Collectors.toList()); + return TreeUtils.list2tree(dataList, + TreeSupportEntity::getId, + TreeSupportEntity::getParentId, + childConsumer, + (helper, node) -> predicateFunction.apply(helper).test(node)); } /** diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java new file mode 100644 index 000000000..04f8233eb --- /dev/null +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java @@ -0,0 +1,60 @@ +package org.hswebframework.web.api.crud.entity; + +import com.google.common.collect.Maps; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Collectors; + +public class TreeUtils { + + /** + * 列表结构转为树结构,并返回根节点集合 + * + * @param dataList 数据集合 + * @param childConsumer 子节点消费接口,用于设置子节点 + * @param predicateFunction 根节点判断函数,传入helper,获取一个判断是否为跟节点的函数 + * @param 元素类型 + * @param 主键类型 + * @return 根节点集合 + */ + public static List list2tree(Collection dataList, + Function idGetter, + Function parentIdGetter, + BiConsumer> childConsumer, + BiPredicate, N> predicateFunction) { + Objects.requireNonNull(dataList, "source list can not be null"); + Objects.requireNonNull(childConsumer, "child consumer can not be null"); + Objects.requireNonNull(predicateFunction, "root predicate function can not be null"); + + // id,node + Map cache = Maps.newHashMapWithExpectedSize(dataList.size()); + // parentId,children + Map> treeCache = dataList + .stream() + .peek(node -> cache.put(idGetter.apply(node), node)) + .filter(e -> parentIdGetter.apply(e) != null) + .collect(Collectors.groupingBy(parentIdGetter)); + + TreeSupportEntity.TreeHelper helper = new TreeSupportEntity.TreeHelper() { + @Override + public List getChildren(PK parentId) { + return treeCache.get(parentId); + } + + @Override + public N getNode(PK id) { + return cache.get(id); + } + }; + + return dataList + .stream() + //设置每个节点的子节点 + .peek(node -> childConsumer.accept(node, treeCache.get(idGetter.apply(node)))) + //获取根节点 + .filter(node -> predicateFunction.test(helper, node)) + .collect(Collectors.toList()); + } + +} 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 adca3b506..9ee75955a 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 @@ -26,7 +26,7 @@ @Slf4j public class DefaultToStringOperator implements ToStringOperator { - private PropertyDescriptor[] descriptors; + private final PropertyDescriptor[] descriptors; private Set defaultIgnoreProperties; @@ -36,10 +36,9 @@ public class DefaultToStringOperator implements ToStringOperator { private Map> converts; - private Function coverStringConvert = (o) -> coverString(String.valueOf(o), 80); + private final Function coverStringConvert = (o) -> coverString(String.valueOf(o), 80); - - private Function> simpleConvertBuilder = type -> { + private final Function, BiFunction> simpleConvertBuilder = type -> { if (Date.class.isAssignableFrom(type)) { return (value, f) -> DateFormatter.toString(((Date) value), "yyyy-MM-dd HH:mm:ss"); } else { @@ -47,13 +46,14 @@ public class DefaultToStringOperator implements ToStringOperator { } }; - private Predicate simpleTypePredicate = ((Predicate) String.class::isAssignableFrom) + private final Predicate> simpleTypePredicate = ((Predicate>) String.class::isAssignableFrom) .or(Class::isEnum) .or(Class::isPrimitive) .or(Date.class::isAssignableFrom) .or(Number.class::isAssignableFrom) .or(Boolean.class::isAssignableFrom); - private Class targetType; + + private final Class targetType; public DefaultToStringOperator(Class targetType) { this.targetType = targetType; @@ -228,10 +228,9 @@ protected void init() { } } - class ConvertConfig { + static class ConvertConfig { long features; Set ignoreProperty; - } protected Map convertMap(Map obj, long features, Set ignoreProperty) { @@ -255,7 +254,7 @@ protected Map convertMap(Map obj, long features, } continue; } - Class type = value.getClass(); + Class type = value.getClass(); if (simpleTypePredicate.test(type)) { value = simpleConvertBuilder.apply(type).apply(value, null); if (ignoreProperty.contains(entry.getKey())) { @@ -292,7 +291,7 @@ protected Map toMap(T target, long features, Set ignoreP if (ToString.Feature.hasFeature(features, ToString.Feature.nullPropertyToEmpty)) { boolean isSimpleType = false; PropertyDescriptor propertyDescriptor = descriptorMap.get(entry.getKey()); - Class propertyType = null; + Class propertyType = null; if (propertyDescriptor != null) { propertyType = propertyDescriptor.getPropertyType(); isSimpleType = simpleTypePredicate.test(propertyType); 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 index 7fa113a47..3db2fad56 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -17,6 +17,9 @@ private ValidatorUtils() { public static Validator getValidator() { if (validator == null) { synchronized (ValidatorUtils.class) { + if (validator != null) { + return validator; + } Configuration configuration = Validation .byDefaultProvider() .configure(); @@ -50,4 +53,11 @@ public static T tryValidate(T bean, String property, Class... group) { return bean; } + public static void tryValidate(Class bean, String property, Object value, Class... group) { + Set> violations = getValidator().validateValue(bean, property, value, group); + if (!violations.isEmpty()) { + throw new ValidationException(violations); + } + } + } From 2b656b59435f4f14ff006e4a4591d7cca297d6af Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 30 Mar 2022 14:20:51 +0800 Subject: [PATCH 173/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E7=B1=BB=E8=87=AA=E5=AE=9A=E4=B9=89=E6=8B=93=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/configuration/AutoDDLProcessor.java | 16 +++--- .../DetectEntityColumnMapping.java | 56 +++++++++++++++++++ .../configuration/EasyormConfiguration.java | 19 +++++-- .../EasyormRepositoryRegistrar.java | 54 ++++++------------ .../web/crud/configuration/EntityInfo.java | 6 +- .../entity/factory/MapperEntityFactory.java | 5 ++ .../crud/generator/DefaultIdGenerator.java | 15 ++--- .../hswebframework/web/crud/CrudTests.java | 26 ++++++--- .../web/crud/TestApplication.java | 8 ++- .../web/crud/entity/CustomTestEntity.java | 26 +++++++++ .../web/crud/entity/TestEntity.java | 2 + .../web/crud/service/CustomTestCustom.java | 15 +++++ .../web/crud/service/TestEntityService.java | 9 +++ 13 files changed, 184 insertions(+), 73 deletions(-) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DetectEntityColumnMapping.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/CustomTestEntity.java create mode 100644 hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/CustomTestCustom.java 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 void afterPropertiesSet() { .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 void afterPropertiesSet() { 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.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 EntityTableMetadataResolver entityTableMappingResolver(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 Optional parseTableMetadata(Class entityType) { @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 @@ protected void customColumn(PropertyDescriptor descriptor, 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 void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B 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 void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B 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 @@ @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 MapperEntityFactory addMapping(Class target, Mapper m 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.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 String getSortId() { @Override @SneakyThrows public DefaultValue generate(RDBColumnMetadata metadata) { - return Mono.justOrEmpty(mappings.get(metadata.getOwner().getName())) - .switchIfEmpty(Mono.justOrEmpty(defaultId)) - .flatMap(id->Mono.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 @@ @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 @@ 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.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 @@ @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()); + } } From 85ccb75eff98fe04dc099a696cfb1dca7595df7b Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 1 Apr 2022 17:27:55 +0800 Subject: [PATCH 174/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=A1=AB=E5=85=85=E5=88=9B=E5=BB=BA=E4=BA=BA=E5=92=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BA=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/EasyormConfiguration.java | 5 + .../web/crud/events/CreatorEventListener.java | 99 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java 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 bedc725fd..26701527d 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 @@ -125,6 +125,11 @@ public ValidateEventListener validateEventListener() { return new ValidateEventListener(); } + @Bean + public CreatorEventListener creatorEventListener() { + return new CreatorEventListener(); + } + @Bean @ConfigurationProperties(prefix = "easyorm.default-value-generator") public DefaultIdGenerator defaultIdGenerator() { diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java new file mode 100644 index 000000000..2ce37eaa0 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -0,0 +1,99 @@ +package org.hswebframework.web.crud.events; + +import org.hswebframework.ezorm.rdb.events.EventContext; +import org.hswebframework.ezorm.rdb.events.EventListener; +import org.hswebframework.ezorm.rdb.events.EventType; +import org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys; +import org.hswebframework.ezorm.rdb.mapping.events.MappingEventTypes; +import org.hswebframework.ezorm.rdb.mapping.events.ReactiveResultHolder; +import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.api.crud.entity.RecordCreationEntity; +import org.hswebframework.web.api.crud.entity.RecordModifierEntity; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.validator.CreateGroup; +import org.hswebframework.web.validator.UpdateGroup; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Mono; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * 自动填充创建人和修改人信息 + */ +public class CreatorEventListener implements EventListener { + + @Override + public String getId() { + return "creator-listener"; + } + + @Override + public String getName() { + return "创建者监听器"; + } + + @Override + public void onEvent(EventType type, EventContext context) { + Optional resultHolder = context.get(MappingContextKeys.reactiveResultHolder); + if (type == MappingEventTypes.insert_before + || type == MappingEventTypes.save_before + || type == MappingEventTypes.update_before) { + if (resultHolder.isPresent()) { + resultHolder + .ifPresent(holder -> holder + .before( + Authentication + .currentReactive() + .doOnNext(auth -> doApplyCreator(type, context, auth)) + .then() + )); + } else { + Authentication + .current() + .ifPresent(auth -> doApplyCreator(type, context, auth)); + } + } + } + + protected void doApplyCreator(EventType type, EventContext context, Authentication auth) { + context.get(MappingContextKeys.instance) + .ifPresent(obj -> { + if (obj instanceof Collection) { + applyCreator(auth, ((Collection) obj), type != MappingEventTypes.update_before); + } else { + applyCreator(auth, obj, type != MappingEventTypes.update_before); + } + }); + } + + public void applyCreator(Authentication auth, Object entity, boolean updateCreator) { + if (updateCreator && entity instanceof RecordCreationEntity) { + RecordCreationEntity e = (RecordCreationEntity) entity; + if (ObjectUtils.isEmpty(e.getCreatorId())) { + e.setCreatorId(auth.getUser().getId()); + e.setCreatorName(auth.getUser().getName()); + e.setCreateTimeNow(); + } + + } + if (entity instanceof RecordModifierEntity) { + RecordModifierEntity e = (RecordModifierEntity) entity; + if (ObjectUtils.isEmpty(e.getModifierId())) { + e.setModifierId(auth.getUser().getId()); + e.setModifierName(auth.getUser().getName()); + e.setModifyTimeNow(); + } + } + } + + public void applyCreator(Authentication auth, Collection entities, boolean updateCreator) { + for (Object entity : entities) { + applyCreator(auth, entity, updateCreator); + } + + } +} From 377c480e9e681e0439b4ab4f963cd5441ce769f1 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 1 Apr 2022 17:28:04 +0800 Subject: [PATCH 175/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/AuthenticationHolder.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java index 3fc9d1c08..d782b6b52 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java @@ -51,14 +51,17 @@ public final class AuthenticationHolder { private static final ReadWriteLock lock = new ReentrantReadWriteLock(); private static Optional get(Function> function) { - - return Flux.fromStream(suppliers.stream().map(function)) - .filter(Optional::isPresent) - .map(Optional::get) - .reduceWith(SimpleAuthentication::new, SimpleAuthentication::merge) - .filter(auth->auth.getUser()!=null) - .map(Authentication.class::cast) - .blockOptional(); + if (suppliers.size() == 1) { + return suppliers.get(0).get(); + } + SimpleAuthentication merge = new SimpleAuthentication(); + for (AuthenticationSupplier supplier : suppliers) { + supplier.get().ifPresent(merge::merge); + } + if (merge.getUser() == null) { + return Optional.empty(); + } + return Optional.of(merge); } /** From 838e66ef962bfebbb1ef96ba2364f25a34caf09f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 1 Apr 2022 17:29:08 +0800 Subject: [PATCH 176/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/AuthenticationHolder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java index d782b6b52..d9c254eee 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java @@ -51,12 +51,16 @@ public final class AuthenticationHolder { private static final ReadWriteLock lock = new ReentrantReadWriteLock(); private static Optional get(Function> function) { - if (suppliers.size() == 1) { + int size = suppliers.size(); + if (size == 0) { + return Optional.empty(); + } + if (size == 1) { return suppliers.get(0).get(); } SimpleAuthentication merge = new SimpleAuthentication(); for (AuthenticationSupplier supplier : suppliers) { - supplier.get().ifPresent(merge::merge); + function.apply(supplier).ifPresent(merge::merge); } if (merge.getUser() == null) { return Optional.empty(); From e7015f1a16d85a2d667fe329d557177341c5f8f5 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 1 Apr 2022 17:29:28 +0800 Subject: [PATCH 177/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/authorization/AuthenticationHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java index d9c254eee..c917ef15a 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java @@ -56,7 +56,7 @@ private static Optional get(Function Date: Wed, 6 Apr 2022 09:50:58 +0800 Subject: [PATCH 178/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E8=8E=B7?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveTokenAuthenticationSupplier.java | 13 ++++-------- ...erTokenReactiveAuthenticationSupplier.java | 13 ++++-------- .../basic/web/UserTokenWebFilter.java | 7 ++----- .../aop/ReactiveAopAccessLoggerSupport.java | 17 ++++++++++++++-- .../web/logging/AccessLoggerInfo.java | 20 ++++++++++++++++++- 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java index 97efdb45a..6b43c1da5 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java @@ -20,15 +20,10 @@ public Mono get(String userId) { @Override public Mono get() { - return ContextUtils - .reactiveContext() - .flatMap(context -> context - .get(ContextKey.of(ParsedToken.class)) + return Mono + .deferWithContext(context -> context + .getOrEmpty(ParsedToken.class) .map(t -> tokenManager.getByToken(t.getToken())) - .orElseGet(Mono::empty)) - .flatMap(auth -> ReactiveLogger - .mdc("userId", auth.getUser().getId(), - "username", auth.getUser().getName()) - .thenReturn(auth)); + .orElse(Mono.empty())); } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java index 894a78f8c..0b2e9dd59 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java @@ -68,10 +68,9 @@ protected Mono get(ReactiveAuthenticationManager authenticationM @Override public Mono get() { - return ContextUtils - .reactiveContext() - .flatMap(context -> context - .get(ContextKey.of(ParsedToken.class)) + return Mono + .deferWithContext(context -> context + .getOrEmpty(ParsedToken.class) .map(t -> userTokenManager .getByToken(t.getToken()) .filter(UserToken::validate) @@ -82,11 +81,7 @@ public Mono get() { } return before.then(get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())); })) - .orElseGet(Mono::empty)) - .flatMap(auth -> ReactiveLogger - .mdc("userId", auth.getUser().getId(), - "username", auth.getUser().getName()) - .thenReturn(auth)) + .orElse(Mono.empty())) ; } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java index d8b24a621..c98edba8c 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java @@ -19,6 +19,7 @@ import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.context.Context; import java.util.ArrayList; import java.util.HashMap; @@ -47,11 +48,7 @@ public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain cha .next() .map(token -> chain .filter(exchange) - .subscriberContext( - ContextUtils.acceptContext( - context -> context.put(ParsedToken.class, token) - ) - )) + .subscriberContext(Context.of(ParsedToken.class, token))) .defaultIfEmpty(chain.filter(exchange)) .flatMap(Function.identity()) .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId())); diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index b033de238..f982d3ec8 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -2,6 +2,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.hswebframework.web.aop.MethodInterceptorHolder; +import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.id.IDGenerator; import org.hswebframework.web.logger.ReactiveLogger; import org.hswebframework.web.logging.RequestInfo; @@ -83,7 +84,19 @@ protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { .then(Mono.defer(() -> { AccessLoggerBeforeEvent event = new AccessLoggerBeforeEvent(loggerInfo); event.first(cache); - return event.publish(eventPublisher); + return Authentication + .currentReactive() + .flatMap(auth -> { + loggerInfo.putContext("userId", auth.getUser().getId()); + loggerInfo.putContext("username", auth.getUser().getUsername()); + loggerInfo.putContext("userName", auth.getUser().getName()); + return ReactiveLogger + .mdc("userId", auth.getUser().getId(), + "username", auth.getUser().getUsername(), + "userName", auth.getUser().getName()) + .thenReturn(auth); + }) + .then(event.publish(eventPublisher)); })) .then(Mono.defer(() -> { loggerInfo.setResponseTime(System.currentTimeMillis()); @@ -166,7 +179,7 @@ protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { @Override public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; + return Ordered.LOWEST_PRECEDENCE; } @Override diff --git a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/AccessLoggerInfo.java b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/AccessLoggerInfo.java index 696022374..153aa4105 100644 --- a/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/AccessLoggerInfo.java +++ b/hsweb-logging/hsweb-access-logging-api/src/main/java/org/hswebframework/web/logging/AccessLoggerInfo.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.io.StringWriter; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.StringJoiner; @@ -115,7 +116,10 @@ public Map toSimpleMap(Function objectFilt Class[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { - methodAppender.add(parameterTypes[i].getSimpleName().concat(" ").concat(parameterNames.length > i ? parameterNames[i] : ("arg" + i))); + methodAppender.add(parameterTypes[i] + .getSimpleName() + .concat(" ") + .concat(parameterNames.length > i ? parameterNames[i] : ("arg" + i))); } map.put("method", methodAppender.toString()); } @@ -153,4 +157,18 @@ public void putAccessInfo(RequestInfo info) { setUrl(info.getPath()); setContext(info.getContext()); } + + public void putContext(Map context) { + if (this.context == null) { + this.context = new HashMap<>(); + } + this.context.putAll(context); + } + + public void putContext(String key, Object value) { + if (this.context == null) { + this.context = new HashMap<>(); + } + this.context.put(key, String.valueOf(value)); + } } From 6d486b6b3bdf6133c64bec19b250310b87b79667 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 6 Apr 2022 17:51:12 +0800 Subject: [PATCH 179/542] =?UTF-8?q?=E4=BC=98=E5=8C=96TreeUtils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/crud/entity/TreeUtils.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java index 04f8233eb..fc0ca0093 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeUtils.java @@ -1,6 +1,7 @@ package org.hswebframework.web.api.crud.entity; import com.google.common.collect.Maps; +import org.springframework.util.ObjectUtils; import java.util.*; import java.util.function.*; @@ -8,6 +9,33 @@ public class TreeUtils { + + /** + * 列表结构转为树结构,并返回根节点集合. + *

+ * 根节点判断逻辑: parentId为空或者对应的节点数据没有在list中 + * + * @param dataList 数据集合 + * @param childConsumer 子节点消费接口,用于设置子节点 + * @param 元素类型 + * @param 主键类型 + * @return 根节点集合 + */ + public static List list2tree(Collection dataList, + Function idGetter, + Function parentIdGetter, + BiConsumer> childConsumer) { + return list2tree(dataList, + idGetter, + parentIdGetter, + childConsumer, + (helper, node) -> { + PK parentId = parentIdGetter.apply(node); + return ObjectUtils.isEmpty(parentId) + || helper.getNode(parentId) == null; + }); + } + /** * 列表结构转为树结构,并返回根节点集合 * From 7f95784e5beea3ea1e2696b32ded8c751226e94f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 6 Apr 2022 21:15:23 +0800 Subject: [PATCH 180/542] =?UTF-8?q?=E4=BC=98=E5=8C=96token=E8=8E=B7?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/AuthenticationTests.java | 3 ++- .../basic/web/ReactiveUserTokenController.java | 4 ++-- .../auth/ReactiveOAuth2AccessTokenParser.java | 13 ++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java index 9e4df5c31..01c4c4ebf 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java @@ -12,6 +12,7 @@ import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; import reactor.test.StepVerifier; +import reactor.util.context.Context; import java.util.Collections; import java.util.Set; @@ -138,7 +139,7 @@ public String getType() { .doOnEach(ReactiveLogger.on(SignalType.ON_NEXT,(ctx,signal)->{ System.out.println(ctx); })) - .subscriberContext(acceptContext(ctx -> ctx.put(ContextKey.of(ParsedToken.class), parsedToken))) + .subscriberContext(Context.of(ParsedToken.class, parsedToken)) .subscriberContext(ReactiveLogger.start("rid","1")) .as(StepVerifier::create) .expectNext("admin") diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ReactiveUserTokenController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ReactiveUserTokenController.java index 1316853c2..470401ea2 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ReactiveUserTokenController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ReactiveUserTokenController.java @@ -47,8 +47,8 @@ public void setAuthenticationManager(ReactiveAuthenticationManager authenticatio @Authorize(merge = false) @Operation(summary = "重置当前用户的令牌") public Mono resetToken() { - return ContextUtils.reactiveContext() - .map(context -> context.get(ContextKey.of(ParsedToken.class)).orElseThrow(UnAuthorizedException::new)) + return Mono + .deferWithContext(ctx -> Mono.justOrEmpty(ctx.getOrEmpty(ParsedToken.class))) .flatMap(token -> userTokenManager.signOutByToken(token.getToken())) .thenReturn(true); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java index dedcfe752..549d291bc 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java @@ -47,16 +47,11 @@ public Mono get(String userId) { @Override public Mono get() { - return ContextUtils - .reactiveContext() - .flatMap(context -> context - .get(ContextKey.of(ParsedToken.class)) + return Mono + .deferWithContext(context -> context + .getOrEmpty(ParsedToken.class) .filter(token -> "oauth2".equals(token.getType())) .map(t -> accessTokenManager.getAuthenticationByToken(t.getToken())) - .orElse(Mono.empty())) - .flatMap(auth -> ReactiveLogger - .mdc("userId", auth.getUser().getId(), - "username", auth.getUser().getName()) - .thenReturn(auth)); + .orElse(Mono.empty())); } } From 8efd19e65d6ad2c2e1f77259f8748a5b86328ffe Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 8 Apr 2022 22:05:09 +0800 Subject: [PATCH 181/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/DefaultEntityResultWrapperFactory.java | 4 ++-- .../web/crud/configuration/DetectEntityColumnMapping.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DefaultEntityResultWrapperFactory.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DefaultEntityResultWrapperFactory.java index 5f9b42d7b..20fbec0e2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DefaultEntityResultWrapperFactory.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/DefaultEntityResultWrapperFactory.java @@ -5,6 +5,7 @@ import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; import org.hswebframework.ezorm.rdb.mapping.EntityManager; import org.hswebframework.ezorm.rdb.mapping.wrapper.EntityResultWrapper; +import org.hswebframework.ezorm.rdb.mapping.wrapper.NestedEntityResultWrapper; @AllArgsConstructor public class DefaultEntityResultWrapperFactory implements EntityResultWrapperFactory { @@ -14,8 +15,7 @@ public class DefaultEntityResultWrapperFactory implements EntityResultWrapperFac @Override @SneakyThrows public ResultWrapper getWrapper(Class tClass) { - return new EntityResultWrapper<>(() -> entityManager.newInstance(tClass), - entityManager.getMapping(tClass)); + return new NestedEntityResultWrapper<>(entityManager.getMapping(tClass)); } } 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 index dbe2cf036..0638d3726 100644 --- 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 @@ -3,6 +3,7 @@ import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.ezorm.rdb.metadata.TableOrViewMetadata; import java.util.Map; import java.util.Optional; @@ -44,6 +45,11 @@ public Map getColumnPropertyMapping() { return mapping.getColumnPropertyMapping(); } + @Override + public TableOrViewMetadata getTable() { + return mapping.getTable(); + } + @Override public String getId() { return id; From 6b0ba45630ff9c331cd7920f1e0b601687e79989 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 8 Apr 2022 22:21:34 +0800 Subject: [PATCH 182/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/configuration/DetectEntityColumnMapping.java | 11 ++++++++++- .../web/crud/configuration/EasyormConfiguration.java | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) 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 index 0638d3726..d2ddc0bc6 100644 --- 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 @@ -4,6 +4,7 @@ import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; import org.hswebframework.ezorm.rdb.metadata.TableOrViewMetadata; +import org.hswebframework.web.api.crud.entity.EntityFactory; import java.util.Map; import java.util.Optional; @@ -12,12 +13,15 @@ class DetectEntityColumnMapping implements EntityColumnMapping { private final String id; private final Class type; private final EntityColumnMapping mapping; + private final EntityFactory entityFactory; public DetectEntityColumnMapping(Class type, - EntityColumnMapping mapping) { + EntityColumnMapping mapping, + EntityFactory entityFactory) { this.id = MappingFeatureType.columnPropertyMapping.createFeatureId(type); this.type = type; this.mapping = mapping; + this.entityFactory = entityFactory; } @Override @@ -50,6 +54,11 @@ public TableOrViewMetadata getTable() { return mapping.getTable(); } + @Override + public Object newInstance() { + return entityFactory.newInstance(getEntityType()); + } + @Override public String getId() { return id; 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 26701527d..9042b6c9d 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 @@ -173,7 +173,7 @@ public E newInstance(Class type) { @Override public EntityColumnMapping getMapping(Class entity) { - return resolver.resolve(entityFactory.getInstanceType(entity, true)) + return resolver.resolve(entity) .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entity)) .map(EntityColumnMapping.class::cast) .orElse(null); @@ -207,7 +207,7 @@ public Optional parseTableMetadata(Class entityType) { entityType, table.findFeatureNow( MappingFeatureType.columnPropertyMapping.createFeatureId(realType) - ))); + ),factory)); } for (TableMetadataCustomizer customizer : customizers) { customizer.customTable(realType, table); From f361f0c1cb1c4dd183f434ac6e3bb48b90c85097 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 13 Apr 2022 15:56:34 +0800 Subject: [PATCH 183/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/exception/I18nSupportException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 45e7dcf0d..6213a36c8 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -48,7 +48,7 @@ public I18nSupportException(String code, Throwable cause, Object... args) { } public String getOriginalMessage() { - return super.getMessage(); + return super.getMessage() != null ? super.getMessage() : getI18nCode(); } @Override From 69ac98c9859bd747c56db0ee446a7e03d6fb0a2f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 21 Apr 2022 13:45:51 +0800 Subject: [PATCH 184/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=A1=AB=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/crud/events/CreatorEventListener.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java index 2ce37eaa0..9662899d3 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -76,6 +76,8 @@ public void applyCreator(Authentication auth, Object entity, boolean updateCreat if (ObjectUtils.isEmpty(e.getCreatorId())) { e.setCreatorId(auth.getUser().getId()); e.setCreatorName(auth.getUser().getName()); + } + if (e.getCreateTime() == null) { e.setCreateTimeNow(); } @@ -85,6 +87,8 @@ public void applyCreator(Authentication auth, Object entity, boolean updateCreat if (ObjectUtils.isEmpty(e.getModifierId())) { e.setModifierId(auth.getUser().getId()); e.setModifierName(auth.getUser().getName()); + } + if (e.getModifyTime() == null) { e.setModifyTimeNow(); } } From b51c7cae955ebf2bd2a30c3f6fd5f3e0f38b80a8 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 21 Apr 2022 13:46:05 +0800 Subject: [PATCH 185/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/file/web/ReactiveFileController.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/web/ReactiveFileController.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/web/ReactiveFileController.java index b4a54fdab..c55a3ee2f 100644 --- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/web/ReactiveFileController.java +++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/web/ReactiveFileController.java @@ -43,16 +43,19 @@ public ReactiveFileController(FileUploadProperties properties, FileStorageServic @ResourceAction(id = "upload-static", name = "静态文件") @Operation(summary = "上传静态文件") public Mono uploadStatic(@RequestPart("file") - @Parameter(name = "file", description = "文件", style = ParameterStyle.FORM) Part part) { - if (part instanceof FilePart) { - FilePart filePart = ((FilePart) part); - if (properties.denied(filePart.filename(), filePart.headers().getContentType())) { - throw new AccessDenyException(); - } - return fileStorageService.saveFile(filePart); - } else { - return Mono.error(() -> new IllegalArgumentException("[file] part is not a file")); - } + @Parameter(name = "file", description = "文件", style = ParameterStyle.FORM) Mono partMono) { + return partMono + .flatMap(part -> { + if (part instanceof FilePart) { + FilePart filePart = ((FilePart) part); + if (properties.denied(filePart.filename(), filePart.headers().getContentType())) { + return Mono.error( new AccessDenyException()); + } + return fileStorageService.saveFile(filePart); + } else { + return Mono.error(() -> new IllegalArgumentException("[file] part is not a file")); + } + }); } From dd92471f63f5a72e98a693853be32e0fc176f00e Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 27 Apr 2022 16:15:30 +0800 Subject: [PATCH 186/542] =?UTF-8?q?=E4=BD=BF=E7=94=A8share=E4=BB=A3?= =?UTF-8?q?=E6=9B=BFcache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/logging/aop/ReactiveAopAccessLoggerSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index f982d3ec8..c44831e54 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -77,7 +77,7 @@ private Mono currentRequestInfo() { protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { - Flux cache = flux.cache(); + Flux cache = flux.share(); return this .currentRequestInfo() .doOnNext(loggerInfo::putAccessInfo) From 9ba15121831037f928e0cc45a141ffea052fbb1b Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 27 Apr 2022 16:16:13 +0800 Subject: [PATCH 187/542] jakarta.el --- hsweb-core/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 9e83cf5aa..00c463942 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -96,8 +96,7 @@ org.glassfish - javax.el - 3.0.0 + jakarta.el From 16da624c1a08eaf20cf8b506b41824ef193b6249 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 27 Apr 2022 19:45:53 +0800 Subject: [PATCH 188/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=AF=BC=E8=87=B4=E6=97=A0=E6=B3=95=E7=9B=91?= =?UTF-8?q?=E5=90=AC=E6=B5=81onCancel=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/utils/FluxCache.java | 30 ++++++++ .../aop/ReactiveAopAccessLoggerSupport.java | 70 ++++++++++--------- 2 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/utils/FluxCache.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/FluxCache.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/FluxCache.java new file mode 100644 index 000000000..a8c40c33a --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/FluxCache.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.utils; + +import org.reactivestreams.Publisher; +import reactor.core.Disposable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.function.Function; + +public class FluxCache { + + + public static Flux cache(Flux source, Function, Publisher> handler) { + Disposable[] ref = new Disposable[1]; + Flux cache = source + .doFinally((s) -> ref[0] = null) + .replay() + .autoConnect(1, dis -> ref[0] = dis); + return Mono + .from(handler.apply(cache)) + .thenMany(cache) + .doFinally((s) -> { + if (ref[0] != null) { + ref[0].dispose(); + } + }); + + } + +} diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index c44831e54..9ec6fbb60 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -1,5 +1,6 @@ package org.hswebframework.web.logging.aop; +import lombok.SneakyThrows; import org.aopalliance.intercept.MethodInterceptor; import org.hswebframework.web.aop.MethodInterceptorHolder; import org.hswebframework.web.authorization.Authentication; @@ -11,6 +12,7 @@ import org.hswebframework.web.logging.LoggerDefine; import org.hswebframework.web.logging.events.AccessLoggerAfterEvent; import org.hswebframework.web.logging.events.AccessLoggerBeforeEvent; +import org.hswebframework.web.utils.FluxCache; import org.hswebframework.web.utils.ReactiveWebUtils; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; import org.springframework.beans.factory.annotation.Autowired; @@ -22,13 +24,16 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; +import reactor.core.Disposable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.context.Context; import java.lang.reflect.Method; +import java.time.Duration; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; /** * 使用AOP记录访问日志,并触发{@link AccessLoggerListener#onLogger(AccessLoggerInfo)} @@ -76,41 +81,40 @@ private Mono currentRequestInfo() { } protected Flux wrapFluxResponse(Flux flux, AccessLoggerInfo loggerInfo) { + return Flux.deferWithContext(ctx -> this + .currentRequestInfo() + .doOnNext(loggerInfo::putAccessInfo) + .then(beforeRequest(loggerInfo)) + .thenMany(flux) + .doOnError(loggerInfo::setException) + .doFinally(signal -> completeRequest(loggerInfo, ctx))) + .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + } - Flux cache = flux.share(); - return this - .currentRequestInfo() - .doOnNext(loggerInfo::putAccessInfo) - .then(Mono.defer(() -> { - AccessLoggerBeforeEvent event = new AccessLoggerBeforeEvent(loggerInfo); - event.first(cache); - return Authentication - .currentReactive() - .flatMap(auth -> { - loggerInfo.putContext("userId", auth.getUser().getId()); - loggerInfo.putContext("username", auth.getUser().getUsername()); - loggerInfo.putContext("userName", auth.getUser().getName()); - return ReactiveLogger - .mdc("userId", auth.getUser().getId(), - "username", auth.getUser().getUsername(), - "userName", auth.getUser().getName()) - .thenReturn(auth); - }) - .then(event.publish(eventPublisher)); - })) - .then(Mono.defer(() -> { - loggerInfo.setResponseTime(System.currentTimeMillis()); - return new AccessLoggerAfterEvent(loggerInfo).publish(eventPublisher); - })) - .thenMany(cache) - .onErrorResume(err -> { - loggerInfo.setException(err); - loggerInfo.setResponseTime(System.currentTimeMillis()); - return new AccessLoggerAfterEvent(loggerInfo) - .publish(eventPublisher) - .then(Mono.error(err)); + private Mono beforeRequest(AccessLoggerInfo loggerInfo) { + + AccessLoggerBeforeEvent event = new AccessLoggerBeforeEvent(loggerInfo); + return Authentication + .currentReactive() + .flatMap(auth -> { + loggerInfo.putContext("userId", auth.getUser().getId()); + loggerInfo.putContext("username", auth.getUser().getUsername()); + loggerInfo.putContext("userName", auth.getUser().getName()); + return ReactiveLogger + .mdc("userId", auth.getUser().getId(), + "username", auth.getUser().getUsername(), + "userName", auth.getUser().getName()) + .thenReturn(auth); }) - .subscriberContext(ReactiveLogger.start("accessLogId", loggerInfo.getId())); + .then(event.publish(eventPublisher)); + } + + private void completeRequest(AccessLoggerInfo loggerInfo, Context ctx) { + loggerInfo.setResponseTime(System.currentTimeMillis()); + new AccessLoggerAfterEvent(loggerInfo) + .publish(eventPublisher) + .subscriberContext(ctx) + .subscribe(); } protected Mono wrapMonoResponse(Mono mono, AccessLoggerInfo loggerInfo) { From 2e4628eef1c4b8c568cb04445b631d2310c212dc Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 27 Apr 2022 19:48:04 +0800 Subject: [PATCH 189/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8DAccessLogger=E5=A4=B1?= =?UTF-8?q?=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../logging/aop/ReactiveAopAccessLoggerSupport.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 9ec6fbb60..adecd16d8 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -6,10 +6,7 @@ import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.id.IDGenerator; import org.hswebframework.web.logger.ReactiveLogger; -import org.hswebframework.web.logging.RequestInfo; -import org.hswebframework.web.logging.AccessLoggerInfo; -import org.hswebframework.web.logging.AccessLoggerListener; -import org.hswebframework.web.logging.LoggerDefine; +import org.hswebframework.web.logging.*; import org.hswebframework.web.logging.events.AccessLoggerAfterEvent; import org.hswebframework.web.logging.events.AccessLoggerBeforeEvent; import org.hswebframework.web.utils.FluxCache; @@ -18,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; @@ -188,6 +186,10 @@ public int getOrder() { @Override public boolean matches(Method method, Class aClass) { + AccessLogger ann = AnnotationUtils.findAnnotation(method, AccessLogger.class); + if (ann != null && ann.ignore()) { + return false; + } return loggerParsers .stream() .anyMatch(parser -> parser.support(aClass, method)); From ab06d54ee085b4697a4681c4bcc0bcc922463686 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 28 Apr 2022 18:03:19 +0800 Subject: [PATCH 190/542] =?UTF-8?q?=E4=BC=98=E5=8C=96token=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/OAuth2Properties.java | 20 +++++++++++++++++++ .../server/OAuth2ServerAutoConfiguration.java | 10 ++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Properties.java diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Properties.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Properties.java new file mode 100644 index 000000000..8956781c1 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2Properties.java @@ -0,0 +1,20 @@ +package org.hswebframework.web.oauth2.server; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.time.Duration; + +@ConfigurationProperties(prefix = "hsweb.oauth2") +@Getter +@Setter +public class OAuth2Properties { + + //token有效期 + private Duration tokenExpireIn = Duration.ofSeconds(7200); + + //refreshToken有效期 + private Duration refreshTokenIn = Duration.ofDays(30); + +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index 66228cc79..6003a593f 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -18,11 +18,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; @Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(OAuth2Properties.class) public class OAuth2ServerAutoConfiguration { @@ -46,8 +48,12 @@ static class ReactiveOAuth2ServerAutoConfiguration { @Bean @ConditionalOnMissingBean - public AccessTokenManager accessTokenManager(ReactiveRedisConnectionFactory redisConnectionFactory) { - return new RedisAccessTokenManager(redisConnectionFactory); + public AccessTokenManager accessTokenManager(ReactiveRedisConnectionFactory redisConnectionFactory, + OAuth2Properties properties) { + RedisAccessTokenManager manager = new RedisAccessTokenManager(redisConnectionFactory); + manager.setTokenExpireIn((int) properties.getTokenExpireIn().getSeconds()); + manager.setRefreshExpireIn((int) properties.getRefreshTokenIn().getSeconds()); + return manager; } @Bean From a12289af5370eeac8dda5c1e9d9f80ed2e83a5c2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 6 May 2022 10:19:00 +0800 Subject: [PATCH 191/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0exists=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReactiveServiceQueryController.java | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java index 51eed4f7f..d798dacad 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java @@ -167,7 +167,7 @@ default Mono> queryPager(@RequestBody Mono quer @QueryAction @Operation(summary = "使用POST方式查询总数") default Mono count(@RequestBody Mono query) { - return query.flatMap(this::count); + return getService().count(query); } /** @@ -175,7 +175,7 @@ default Mono count(@RequestBody Mono query) { * *

      *
-     *    GET /_query/_count?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
+     *    GET /_count?pageIndex=0&pageSize=20&where=name is 张三&orderBy=id desc
      *
      * 
* @@ -187,10 +187,39 @@ default Mono count(@RequestBody Mono query) { @QueryAction @QueryNoPagingOperation(summary = "使用GET方式查询总数") default Mono count(@Parameter(hidden = true) QueryParamEntity query) { - return getService() - .createQuery() - .setParam(query) - .count(); + return Mono.defer(() -> getService().count(query)); + } + + @PostMapping("/_exists") + @QueryAction + @Operation(summary = "使用POST方式判断数据是否存在") + default Mono exists(@RequestBody Mono query) { + return query + .flatMap(param -> getService() + .createQuery() + .setParam(param) + .fetchOne() + .hasElement()); + } + + /** + * 使用GET方式判断数据是否存在. + * + *
+     *
+     *    GET /_exists?where=name is 张三
+     *
+     * 
+ * + * @param query 查询条件 + * @return 查询结果 + * @see QueryParamEntity + */ + @GetMapping("/_exists") + @QueryAction + @QueryNoPagingOperation(summary = "使用GET方式判断数据是否存在") + default Mono exists(@Parameter(hidden = true) QueryParamEntity query) { + return exists(Mono.just(query)); } /** From d8a890a253b6e70c120a4e7ce92304f48d1948cd Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 17 May 2022 15:41:45 +0800 Subject: [PATCH 192/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-core/pom.xml | 3 ++- pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 00c463942..b38151361 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -18,7 +18,7 @@ org.javassist javassist - 3.28.0-GA + 3.29.0-GA @@ -51,6 +51,7 @@ org.slf4j slf4j-api + commons-beanutils commons-beanutils diff --git a/pom.xml b/pom.xml index 3b9d30506..9f4ceee33 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.20.0-GA 5.19.0.2 - 1.2.74 + 1.2.80 1.4.200 5.1.39 3.2.2 @@ -96,7 +96,7 @@ 2.7.0 Arabba-SR10 - 5.2.19.RELEASE + 5.2.22.RELEASE From 6b99d542b991dcd537f0950a3162caeb899b74d2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 19 May 2022 19:08:22 +0800 Subject: [PATCH 193/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=8F=8F=E8=BF=B0=E5=8F=AF=E8=83=BD=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aop/ReactiveAopAccessLoggerSupport.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index adecd16d8..76b5cf295 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -1,6 +1,6 @@ package org.hswebframework.web.logging.aop; -import lombok.SneakyThrows; +import lombok.*; import org.aopalliance.intercept.MethodInterceptor; import org.hswebframework.web.aop.MethodInterceptorHolder; import org.hswebframework.web.authorization.Authentication; @@ -47,7 +47,7 @@ public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutA @Autowired private ApplicationEventPublisher eventPublisher; - private final Map defineCache = new ConcurrentReferenceHashMap<>(); + private final Map defineCache = new ConcurrentReferenceHashMap<>(); private static final LoggerDefine UNSUPPORTED = new LoggerDefine(); @@ -135,7 +135,9 @@ protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { info.setId(IDGenerator.MD5.generate()); info.setRequestTime(System.currentTimeMillis()); - LoggerDefine define = defineCache.computeIfAbsent(holder.getMethod(), method -> createDefine(holder)); + LoggerDefine define = defineCache.computeIfAbsent(new CacheKey( + ClassUtils.getUserClass(holder.getTarget()), + holder.getMethod()), method -> createDefine(holder)); if (define != null) { info.setAction(define.getAction()); @@ -215,4 +217,10 @@ private RequestInfo createAccessInfo(ServerWebExchange exchange) { return info; } + @AllArgsConstructor + @EqualsAndHashCode + private static class CacheKey{ + private Class type; + private Method method; + } } From 1a6108de2831d0fb0c3cb70ca54f41470a51cc11 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 19 May 2022 19:08:27 +0800 Subject: [PATCH 194/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hswebframework/web/utils/HttpParameterConverter.java | 5 ++--- .../defaults/service/DefaultAuthorizationSettingService.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/utils/HttpParameterConverter.java b/hsweb-core/src/main/java/org/hswebframework/web/utils/HttpParameterConverter.java index 46257aa19..d61c1b0aa 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/utils/HttpParameterConverter.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/utils/HttpParameterConverter.java @@ -2,6 +2,7 @@ import org.apache.commons.beanutils.BeanMap; import org.hswebframework.utils.time.DateFormatter; +import org.hswebframework.web.bean.FastBeanCopier; import java.util.*; import java.util.function.Function; @@ -61,9 +62,7 @@ public HttpParameterConverter(Object bean) { if (bean instanceof Map) { beanMap = ((Map) bean); } else { - beanMap = new HashMap<>((Map) new BeanMap(bean)); - beanMap.remove("class"); - beanMap.remove("declaringClass"); + beanMap = FastBeanCopier.copy(bean,new HashMap<>()); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index b71960930..1a9fe3d43 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -86,7 +86,7 @@ protected Mono clearUserAuthCache(List setting provider.getAllType() .map(DimensionType::getId) .map(t -> Tuples.of(t, provider))) - .collect(Collectors.toMap(Tuple2::getT1, Tuple2::getT2)) + .collectMap(Tuple2::getT1, Tuple2::getT2) .flatMapMany(typeProviderMapping -> Flux .fromIterable(settings)//根据维度获取所有userId .flatMap(setting -> Mono From 23e3da23a30ee65ed7249148e5959c9618fa92ad Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 20 May 2022 09:50:44 +0800 Subject: [PATCH 195/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../token/UserTokenReactiveAuthenticationSupplier.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java index 0b2e9dd59..c796c13fd 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java @@ -73,8 +73,14 @@ public Mono get() { .getOrEmpty(ParsedToken.class) .map(t -> userTokenManager .getByToken(t.getToken()) - .filter(UserToken::validate) .flatMap(token -> { + //已过期则返回空 + if (token.isExpired()) { + return Mono.empty(); + } + if(!token.validate()){ + return Mono.empty(); + } Mono before = userTokenManager.touch(token.getToken()); if (token instanceof AuthenticationUserToken) { return before.thenReturn(((AuthenticationUserToken) token).getAuthentication()); From cf9541a7f3fb9078ea141a9671442939bb76811d Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 23 May 2022 15:36:17 +0800 Subject: [PATCH 196/542] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=8D=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E7=9A=84=E6=95=B0=E6=8D=AE=E8=BF=94=E5=9B=9E404?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/web/reactive/ReactiveServiceSaveController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java index cf82b783b..7d86b4510 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java @@ -9,6 +9,7 @@ import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.annotation.SaveAction; import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.hswebframework.web.exception.NotFoundException; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -174,6 +175,11 @@ default Mono update(@PathVariable K id, @RequestBody Mono payload) { .flatMap(auth -> payload.map(entity -> applyAuthentication(entity, auth))) .switchIfEmpty(payload) .flatMap(entity -> getService().updateById(id, Mono.just(entity))) + .doOnNext(i -> { + if (i == 0) { + throw new NotFoundException(); + } + }) .thenReturn(true); } From ebe5a2e8d16c78e01ee5c90e4a03396296b40ba0 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 24 May 2022 14:39:49 +0800 Subject: [PATCH 197/542] fastjson 1.2.83 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9f4ceee33..ca388f1e6 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.20.0-GA 5.19.0.2 - 1.2.80 + 1.2.83 1.4.200 5.1.39 3.2.2 From 03b72a585be5944d6253decfb6c0f051fb0801c2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 24 May 2022 15:52:29 +0800 Subject: [PATCH 198/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-starter/pom.xml | 13 ++++++++++++- pom.xml | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index e8b562365..13481ca8d 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -41,9 +41,9 @@ com.google.code.findbugs jsr305 - 3.0.2 compile + commons-codec commons-codec diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 5970be36b..4ee82b842 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -21,6 +21,12 @@ org.hswebframework hsweb-expands-script ${hsweb.expands.version} + + + junit + junit + + @@ -45,35 +51,40 @@ spring-test test + org.springframework.boot spring-boot-test-autoconfigure test + org.springframework.boot spring-boot-starter-test test + org.springframework.boot spring-boot-test test + org.springframework.boot spring-boot-starter-data-r2dbc test + io.r2dbc r2dbc-h2 test + com.google.code.findbugs jsr305 - 3.0.2 compile diff --git a/pom.xml b/pom.xml index ca388f1e6..cd1496d88 100644 --- a/pom.xml +++ b/pom.xml @@ -325,6 +325,13 @@ + + + com.google.code.findbugs + jsr305 + 3.0.2 + + io.r2dbc r2dbc-bom From a7c68770748357e390eef9c00eee254dcf4a757c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 7 Jun 2022 17:02:48 +0800 Subject: [PATCH 199/542] ignore EntityFactory aware error --- .../crud/entity/EntityFactoryHolderConfiguration.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java index 8dc3d6ceb..84074bfcc 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactoryHolderConfiguration.java @@ -1,5 +1,6 @@ package org.hswebframework.web.api.crud.entity; +import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,7 +11,13 @@ public class EntityFactoryHolderConfiguration { @Bean public ApplicationContextAware entityFactoryHolder() { - return context -> EntityFactoryHolder.FACTORY = context.getBean(EntityFactory.class); + return context -> { + try { + EntityFactoryHolder.FACTORY = context.getBean(EntityFactory.class); + } catch (BeansException ignore) { + + } + }; } } From d134cda07b735c65302d2f22cd8ca07972a09a92 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 7 Jun 2022 17:06:22 +0800 Subject: [PATCH 200/542] jacoco 0.8.8 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cd1496d88..592e7028c 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ org.jacoco jacoco-maven-plugin - 0.8.0 + 0.8.8 @@ -221,7 +221,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.10.1 ${project.build.jdk} ${project.build.jdk} From c5a380f222bbb5d0bc3cbcb075e8ef923cea9cf0 Mon Sep 17 00:00:00 2001 From: Winston Date: Tue, 14 Jun 2022 20:07:14 +0800 Subject: [PATCH 201/542] AsyncEvent must not cancel the source past the first element --- .../web/event/DefaultAsyncEvent.java | 8 +++--- .../hswebframework/web/event/EventTest.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 hsweb-core/src/test/java/org/hswebframework/web/event/EventTest.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java index 298c0ff12..5ee7d9020 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/event/DefaultAsyncEvent.java @@ -15,23 +15,23 @@ public class DefaultAsyncEvent implements AsyncEvent { public synchronized void async(Publisher publisher) { hasListener = true; - this.async = async.then(Mono.from(publisher).then()); + this.async = async.then(Mono.fromDirect(publisher).then()); } @Override public synchronized void first(Publisher publisher) { hasListener = true; - this.first = Mono.from(publisher).then(first); + this.first = Mono.fromDirect(publisher).then(first); } @Override public void transformFirst(Function, Publisher> mapper) { - this.first = Mono.from(mapper.apply(this.first)); + this.first = Mono.fromDirect(mapper.apply(this.first)); } @Override public void transform(Function, Publisher> mapper) { - this.async = Mono.from(mapper.apply(this.async)); + this.async = Mono.fromDirect(mapper.apply(this.async)); } @Override diff --git a/hsweb-core/src/test/java/org/hswebframework/web/event/EventTest.java b/hsweb-core/src/test/java/org/hswebframework/web/event/EventTest.java new file mode 100644 index 000000000..1c9bbb5b0 --- /dev/null +++ b/hsweb-core/src/test/java/org/hswebframework/web/event/EventTest.java @@ -0,0 +1,27 @@ +package org.hswebframework.web.event; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +public class EventTest { + + @Test + public void testMonoFrom() { + Flux source = Flux.just("1", "2", "3").doOnNext(s -> log.info("get {}", s)); + + Mono.from(source).subscribe(); + + Mono.fromDirect(source).subscribe(); + } + + @Test + public void testAsync() { + Flux source = Flux.just("1", "2", "3").doOnNext(s -> log.info("get {}", s)); + AsyncEvent event = new DefaultAsyncEvent(); + event.async(source); + event.getAsync().subscribe(); + } +} From 54e892375ee8727b880d530b3d9152eabb983af2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 20 Jun 2022 11:50:27 +0800 Subject: [PATCH 202/542] easyorm 4.0.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 592e7028c..06b004dfe 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.14-SNAPSHOT + 4.0.14 3.0.2 3.0.2 2.7.0 From 5b5ef55e65496b25d6b7b81bd2be677e03579b91 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 20 Jun 2022 13:49:46 +0800 Subject: [PATCH 203/542] 4.0.14 --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index b78ebb166..1c90aee12 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 1d9548f1c..a0dbb5491 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index cfd6f7ffa..58eaba9ef 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index eae29abb9..1661afed4 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 13481ca8d..219ea6baf 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 3d80c02ed..dcaf82ba6 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index a95048ed0..81d29d19e 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 27e913412..0aae21c47 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index 678172be7..c74a4c38d 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index b38151361..624b800ec 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index 017bd92ca..f2d290491 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 494446890..5abc007aa 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index 6d4b217fb..da091a257 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index c9449114e..491972668 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 51d34eb87..7b76fe432 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index 72dd5b811..efae95a43 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index c0b0adaa1..78bce87e2 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 4ee82b842..93b2f5329 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index 0958d3092..c45a3a813 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 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 c5269c3f5..23b9932f1 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 9a2488316..7dbdacf68 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index 081cf8074..ee7943885 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 00ee64ca2..89f5fa072 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index c0f869ecc..0e45685db 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index eb48a52e7..db79806b6 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14-SNAPSHOT + 4.0.14 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 06b004dfe..d59e18fc0 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.14-SNAPSHOT + 4.0.14 hsweb-starter hsweb-core From c655a20a357e27705ab63c6742954cc8227b15ca Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 27 Jun 2022 09:54:52 +0800 Subject: [PATCH 204/542] 4.0.15-SNAPSHOT --- hsweb-authorization/hsweb-authorization-api/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-basic/pom.xml | 2 +- hsweb-authorization/hsweb-authorization-oauth2/pom.xml | 2 +- hsweb-authorization/pom.xml | 2 +- hsweb-commons/hsweb-commons-api/pom.xml | 2 +- hsweb-commons/hsweb-commons-crud/pom.xml | 2 +- hsweb-commons/pom.xml | 2 +- hsweb-concurrent/hsweb-concurrent-cache/pom.xml | 2 +- hsweb-concurrent/pom.xml | 2 +- hsweb-core/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-api/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-jta/pom.xml | 2 +- hsweb-datasource/hsweb-datasource-web/pom.xml | 2 +- hsweb-datasource/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-aop/pom.xml | 2 +- hsweb-logging/hsweb-access-logging-api/pom.xml | 2 +- hsweb-logging/pom.xml | 2 +- hsweb-starter/pom.xml | 2 +- .../hsweb-system-authorization-api/pom.xml | 2 +- .../hsweb-system-authorization-default/pom.xml | 2 +- .../hsweb-system-authorization-oauth2/pom.xml | 2 +- hsweb-system/hsweb-system-authorization/pom.xml | 2 +- hsweb-system/hsweb-system-dictionary/pom.xml | 2 +- hsweb-system/hsweb-system-file/pom.xml | 2 +- hsweb-system/pom.xml | 2 +- pom.xml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/pom.xml b/hsweb-authorization/hsweb-authorization-api/pom.xml index 1c90aee12..787d6abe2 100644 --- a/hsweb-authorization/hsweb-authorization-api/pom.xml +++ b/hsweb-authorization/hsweb-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index a0dbb5491..615c07198 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml index 58eaba9ef..f86d28db9 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/pom.xml +++ b/hsweb-authorization/hsweb-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-authorization/pom.xml b/hsweb-authorization/pom.xml index 1661afed4..e5a24f830 100644 --- a/hsweb-authorization/pom.xml +++ b/hsweb-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-api/pom.xml b/hsweb-commons/hsweb-commons-api/pom.xml index 219ea6baf..b4ac2168d 100644 --- a/hsweb-commons/hsweb-commons-api/pom.xml +++ b/hsweb-commons/hsweb-commons-api/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index dcaf82ba6..e029e2a4e 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -5,7 +5,7 @@ hsweb-commons org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-commons/pom.xml b/hsweb-commons/pom.xml index 81d29d19e..a3fed49ca 100644 --- a/hsweb-commons/pom.xml +++ b/hsweb-commons/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml index 0aae21c47..fe2f8afce 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/pom.xml +++ b/hsweb-concurrent/hsweb-concurrent-cache/pom.xml @@ -5,7 +5,7 @@ hsweb-concurrent org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-concurrent/pom.xml b/hsweb-concurrent/pom.xml index c74a4c38d..4b6c20efb 100644 --- a/hsweb-concurrent/pom.xml +++ b/hsweb-concurrent/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-core/pom.xml b/hsweb-core/pom.xml index 624b800ec..e432f92e6 100644 --- a/hsweb-core/pom.xml +++ b/hsweb-core/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index f2d290491..c7782bc93 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-jta/pom.xml b/hsweb-datasource/hsweb-datasource-jta/pom.xml index 5abc007aa..a758c5894 100644 --- a/hsweb-datasource/hsweb-datasource-jta/pom.xml +++ b/hsweb-datasource/hsweb-datasource-jta/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/hsweb-datasource-web/pom.xml b/hsweb-datasource/hsweb-datasource-web/pom.xml index da091a257..fc4644372 100644 --- a/hsweb-datasource/hsweb-datasource-web/pom.xml +++ b/hsweb-datasource/hsweb-datasource-web/pom.xml @@ -5,7 +5,7 @@ hsweb-datasource org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml diff --git a/hsweb-datasource/pom.xml b/hsweb-datasource/pom.xml index 491972668..f125b2e11 100644 --- a/hsweb-datasource/pom.xml +++ b/hsweb-datasource/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml diff --git a/hsweb-logging/hsweb-access-logging-aop/pom.xml b/hsweb-logging/hsweb-access-logging-aop/pom.xml index 7b76fe432..0f7157c35 100644 --- a/hsweb-logging/hsweb-access-logging-aop/pom.xml +++ b/hsweb-logging/hsweb-access-logging-aop/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/hsweb-access-logging-api/pom.xml b/hsweb-logging/hsweb-access-logging-api/pom.xml index efae95a43..3313185c8 100644 --- a/hsweb-logging/hsweb-access-logging-api/pom.xml +++ b/hsweb-logging/hsweb-access-logging-api/pom.xml @@ -5,7 +5,7 @@ hsweb-logging org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-logging/pom.xml b/hsweb-logging/pom.xml index 78bce87e2..3b773da34 100644 --- a/hsweb-logging/pom.xml +++ b/hsweb-logging/pom.xml @@ -23,7 +23,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index 93b2f5329..d45ac4ec7 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml index c45a3a813..c867f8768 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 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 23b9932f1..bbb0f6646 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 @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml index 7dbdacf68..32095d63b 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml @@ -5,7 +5,7 @@ hsweb-system-authorization org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/hsweb-system/hsweb-system-authorization/pom.xml b/hsweb-system/hsweb-system-authorization/pom.xml index ee7943885..bc4bbd91b 100644 --- a/hsweb-system/hsweb-system-authorization/pom.xml +++ b/hsweb-system/hsweb-system-authorization/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 pom diff --git a/hsweb-system/hsweb-system-dictionary/pom.xml b/hsweb-system/hsweb-system-dictionary/pom.xml index 89f5fa072..7ebc9237b 100644 --- a/hsweb-system/hsweb-system-dictionary/pom.xml +++ b/hsweb-system/hsweb-system-dictionary/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-system/hsweb-system-file/pom.xml b/hsweb-system/hsweb-system-file/pom.xml index 0e45685db..e15b4a25f 100644 --- a/hsweb-system/hsweb-system-file/pom.xml +++ b/hsweb-system/hsweb-system-file/pom.xml @@ -5,7 +5,7 @@ hsweb-system org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT 4.0.0 diff --git a/hsweb-system/pom.xml b/hsweb-system/pom.xml index db79806b6..8dba5961d 100644 --- a/hsweb-system/pom.xml +++ b/hsweb-system/pom.xml @@ -5,7 +5,7 @@ hsweb-framework org.hswebframework.web - 4.0.14 + 4.0.15-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index d59e18fc0..8854cd5de 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.hswebframework.web hsweb-framework - 4.0.14 + 4.0.15-SNAPSHOT hsweb-starter hsweb-core From 9788fd80464d983f3baab3c5721f52846e50e596 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 27 Jun 2022 09:55:03 +0800 Subject: [PATCH 205/542] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=87=E4=BB=B6=E6=9D=83=E9=99=90=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/file/FileUploadProperties.java | 25 +++++++++++++++++++ .../file/service/LocalFileStorageService.java | 6 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java index 7412302de..88eb89afe 100644 --- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java +++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/FileUploadProperties.java @@ -9,6 +9,13 @@ import org.springframework.http.MediaType; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Collections; import java.util.Date; import java.util.Locale; import java.util.Set; @@ -33,6 +40,24 @@ public class FileUploadProperties { private Set denyMediaType; + private Set permissions; + + public void applyFilePermission(File file) { + + if (CollectionUtils.isEmpty(permissions)) { + return; + } + try { + Path path = Paths.get(file.toURI()); + PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class); + view.setPermissions(permissions); + } catch (Throwable ignore) { + + } + + + } + public boolean denied(String name, MediaType mediaType) { String suffix = (name.contains(".") ? name.substring(name.lastIndexOf(".") + 1) : "").toLowerCase(Locale.ROOT); boolean defaultDeny = false; diff --git a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java index 4d46cd7db..e30b34db5 100644 --- a/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java +++ b/hsweb-system/hsweb-system-file/src/main/java/org/hswebframework/web/file/service/LocalFileStorageService.java @@ -24,8 +24,11 @@ public class LocalFileStorageService implements FileStorageService { @Override public Mono saveFile(FilePart filePart) { FileUploadProperties.StaticFileInfo info = properties.createStaticSavePath(filePart.filename()); + File file = new File(info.getSavePath()); + return (filePart) - .transferTo(new File(info.getSavePath())) + .transferTo(file) + .then(Mono.fromRunnable(()->properties.applyFilePermission(file))) .thenReturn(info.getLocation()); } @@ -57,6 +60,7 @@ public Mono saveFile(InputStream inputStream, String fileType) { return info.getLocation(); } }) + .doOnSuccess((ignore)-> properties.applyFilePermission(new File(info.getSavePath()))) .subscribeOn(Schedulers.boundedElastic()); } } From 1da33b79d225bec82972ba08bfbb189710316d86 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 30 Jun 2022 19:43:21 +0800 Subject: [PATCH 206/542] =?UTF-8?q?ClearUserAuthorizationCacheEvent=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=93=8D=E5=BA=94=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClearUserAuthorizationCacheEvent.java | 19 +++++++- .../DefaultAuthorizationSettingService.java | 3 +- .../service/DefaultDimensionUserService.java | 13 +++--- .../service/DefaultPermissionService.java | 18 +++++--- .../DefaultReactiveAuthenticationManager.java | 43 ++++++++++++------- .../service/DefaultReactiveUserService.java | 7 +-- 6 files changed, 69 insertions(+), 34 deletions(-) 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 index 6f6dfc02c..685838bbd 100644 --- 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 @@ -1,6 +1,9 @@ package org.hswebframework.web.system.authorization.api.event; import lombok.Getter; +import org.hswebframework.web.event.DefaultAsyncEvent; +import org.springframework.context.ApplicationEventPublisher; +import reactor.core.publisher.Mono; import java.util.Arrays; import java.util.Collection; @@ -13,11 +16,13 @@ * @since 3.0.0-RC */ @Getter -public class ClearUserAuthorizationCacheEvent { +public class ClearUserAuthorizationCacheEvent extends DefaultAsyncEvent { private Set userId; private boolean all; + private boolean async; + public static ClearUserAuthorizationCacheEvent of(Collection collection) { ClearUserAuthorizationCacheEvent event = new ClearUserAuthorizationCacheEvent(); if (collection == null || collection.isEmpty()) { @@ -32,6 +37,18 @@ public static ClearUserAuthorizationCacheEvent all() { return ClearUserAuthorizationCacheEvent.of((String[]) null); } + //兼容async + public ClearUserAuthorizationCacheEvent useAsync() { + this.async = true; + return this; + } + + @Override + public Mono publish(ApplicationEventPublisher eventPublisher) { + this.async = true; + return super.publish(eventPublisher); + } + public static ClearUserAuthorizationCacheEvent of(String... userId) { return of(userId == null ? null : Arrays.asList(userId)); diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java index 1a9fe3d43..3f3af051a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java @@ -93,8 +93,7 @@ protected Mono clearUserAuthCache(List setting .justOrEmpty(typeProviderMapping.get(setting.getDimensionType())) .flatMapMany(provider -> provider.getUserIdByDimensionId(setting.getDimensionTarget())))) .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .doOnNext(eventPublisher::publishEvent) + .flatMap(lst-> ClearUserAuthorizationCacheEvent.of(lst).publish(eventPublisher)) .then(); } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index 2ab396a51..af9489925 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -123,10 +123,11 @@ private Flux publishEvent(Publisher st return dimensionIdGroup .map(DimensionUserEntity::getUserId) .collectList() - .flatMap(userIdList -> { - eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(userIdList)); - return event.apply(type, dimensionId, userIdList).publish(eventPublisher); - }); + .flatMap(userIdList -> ClearUserAuthorizationCacheEvent + .of(userIdList) + .publish(eventPublisher) + .then(event.apply(type, dimensionId, userIdList) + .publish(eventPublisher))); }); }) .thenMany(cache); @@ -137,9 +138,7 @@ private Mono clearUserCache(List entities) { .map(DimensionUserEntity::getUserId) .distinct() .collectList() - .map(ClearUserAuthorizationCacheEvent::of) - .doOnNext(eventPublisher::publishEvent) - .then(); + .flatMap(list -> ClearUserAuthorizationCacheEvent.of(list).publish(eventPublisher)); } } \ 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/DefaultPermissionService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultPermissionService.java index a59a7fe32..bdd207544 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultPermissionService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultPermissionService.java @@ -19,31 +19,39 @@ public class DefaultPermissionService extends GenericReactiveCrudService save(Publisher entityPublisher) { return super.save(entityPublisher) - .doOnSuccess(r -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of())); + .flatMap(e -> ClearUserAuthorizationCacheEvent.all().publish(eventPublisher).thenReturn(e)); } @Override public Mono updateById(String id, Mono entityPublisher) { return super.updateById(id, entityPublisher) - .doOnSuccess(r -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of())); + .flatMap(e -> ClearUserAuthorizationCacheEvent.all().publish(eventPublisher).thenReturn(e)); } @Override public Mono deleteById(Publisher idPublisher) { return super.deleteById(idPublisher) - .doOnSuccess(r -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of())); + .flatMap(e -> ClearUserAuthorizationCacheEvent.all().publish(eventPublisher).thenReturn(e)); } @Override public ReactiveDelete createDelete() { return super.createDelete() - .onExecute((ignore,i) -> i.doOnSuccess(r -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of()))); + .onExecute((ignore, i) -> i + .flatMap(e -> ClearUserAuthorizationCacheEvent + .all() + .publish(eventPublisher) + .thenReturn(e))); } @Override public ReactiveUpdate createUpdate() { return super.createUpdate() - .onExecute((ignore,i) -> i.doOnSuccess(r -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of()))); + .onExecute((ignore, i) -> i + .flatMap(e -> ClearUserAuthorizationCacheEvent + .all() + .publish(eventPublisher) + .thenReturn(e))); } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java index cb4ec3b8c..a0eb4f30f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java @@ -1,18 +1,17 @@ package org.hswebframework.web.system.authorization.defaults.service; import lombok.extern.slf4j.Slf4j; -import org.hswebframework.web.authorization.*; -import org.hswebframework.web.authorization.exception.AccessDenyException; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.AuthenticationRequest; +import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService; +import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider; import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; import org.hswebframework.web.cache.ReactiveCacheManager; import org.hswebframework.web.system.authorization.api.entity.UserEntity; import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.CacheManager; -import org.springframework.cache.support.SimpleValueWrapper; import org.springframework.context.event.EventListener; -import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import reactor.core.publisher.Mono; @@ -32,18 +31,25 @@ public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticat @EventListener public void handleClearAuthCache(ClearUserAuthorizationCacheEvent event) { if (cacheManager != null) { + Mono operator; if (event.isAll()) { - cacheManager.getCache("user-auth") + operator = cacheManager + .getCache("user-auth") .clear() .doOnSuccess(nil -> log.info("clear all user authentication cache success")) - .doOnError(err -> log.error(err.getMessage(), err)) - .subscribe(); + .doOnError(err -> log.error(err.getMessage(), err)); } else { - cacheManager.getCache("user-auth") + operator = cacheManager + .getCache("user-auth") .evictAll(event.getUserId()) .doOnError(err -> log.error(err.getMessage(), err)) - .doOnSuccess(__ -> log.info("clear user {} authentication cache success", event.getUserId())) - .subscribe(); + .doOnSuccess(__ -> log.info("clear user {} authentication cache success", event.getUserId())); + } + if (event.isAsync()) { + event.async(operator); + } else { + log.warn("please use async for ClearUserAuthorizationCacheEvent"); + operator.subscribe(); } } } @@ -62,11 +68,16 @@ public Mono authenticate(Mono request) { @Override public Mono getByUserId(String userId) { + if (userId == null) { + return Mono.empty(); + } + if (cacheManager == null) { + return initializeService.initUserAuthorization(userId); + } - return Mono.justOrEmpty(userId) - .flatMap(_id -> Mono.justOrEmpty(cacheManager) - .map(cm -> cacheManager.getCache("user-auth")) - .flatMap(cache -> cache.mono(userId).onCacheMissResume(() -> initializeService.initUserAuthorization(userId))) - .cast(Authentication.class)); + return cacheManager + .getCache("user-auth") + .mono(userId) + .onCacheMissResume(() -> initializeService.initUserAuthorization(userId)); } } 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 index 2f771c7a3..b90247e24 100644 --- 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 @@ -110,9 +110,10 @@ protected Mono doUpdate(UserEntity userEntity) { .execute() .flatMap(__ -> new UserModifiedEvent(userEntity, passwordChanged).publish(eventPublisher)) .thenReturn(userEntity) - .doOnNext(e -> { - eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(e.getId())); - }); + .flatMap(e -> ClearUserAuthorizationCacheEvent + .of(e.getId()) + .publish(eventPublisher) + .thenReturn(e)); }); } From 6814c8305095852bd6393e347b91b8e8130a58ad Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 1 Jul 2022 18:20:18 +0800 Subject: [PATCH 207/542] =?UTF-8?q?=E4=BC=98=E5=8C=96token=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/token/LocalUserToken.java | 12 ++++++++++++ .../token/redis/SimpleUserToken.java | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalUserToken.java index c562e1b0e..a157ee7f9 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalUserToken.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/LocalUserToken.java @@ -74,9 +74,21 @@ public String getToken() { @Override public TokenState getState() { + if (state == TokenState.normal) { + checkExpired(); + } return state; } + @Override + public boolean checkExpired() { + if (UserToken.super.checkExpired()) { + setState(TokenState.expired); + return true; + } + return false; + } + public void setState(TokenState state) { this.state = state; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java index d986bda34..6e931ba73 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/SimpleUserToken.java @@ -35,18 +35,25 @@ public class SimpleUserToken implements UserToken { public static SimpleUserToken of(Map map) { Object authentication = map.get("authentication"); - if(authentication instanceof Authentication){ + if (authentication instanceof Authentication) { return FastBeanCopier.copy(map, new SimpleAuthenticationUserToken(((Authentication) authentication))); } return FastBeanCopier.copy(map, new SimpleUserToken()); } + public TokenState getState() { + if (state == TokenState.normal) { + checkExpired(); + } + return state; + } + @Override - public boolean isNormal() { - if (checkExpired()) { + public boolean checkExpired() { + if (UserToken.super.checkExpired()) { setState(TokenState.expired); - return false; + return true; } - return UserToken.super.isNormal(); + return false; } } From 45059239f45afaf35dc6a081b4685709a508ee10 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 20 Jul 2022 18:36:39 +0800 Subject: [PATCH 208/542] =?UTF-8?q?=E4=BC=98=E5=8C=96autoinit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/starter/HswebAutoConfiguration.java | 36 +++++++++++-------- .../starter/initialize/SystemInitialize.java | 1 + 2 files changed, 22 insertions(+), 15 deletions(-) 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 f8e3f7009..f78873797 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 @@ -37,9 +37,9 @@ public class HswebAutoConfiguration { @PostConstruct public void init() { engines = Stream.of("js", "groovy") - .map(DynamicScriptEngineFactory::getEngine) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + .map(DynamicScriptEngineFactory::getEngine) + .filter(Objects::nonNull) + .collect(Collectors.toList()); addGlobalVariable("logger", LoggerFactory.getLogger("org.hswebframework.script")); @@ -48,11 +48,11 @@ public void init() { private void addGlobalVariable(String var, Object val) { engines.forEach(engine -> { - try { - engine.addGlobalVariable(Collections.singletonMap(var, val)); - } catch (NullPointerException ignore) { - } - } + try { + engine.addGlobalVariable(Collections.singletonMap(var, val)); + } catch (NullPointerException ignore) { + } + } ); } @@ -61,15 +61,21 @@ public CommandLineRunner systemInit(DatabaseOperator database, AppProperties properties) { addGlobalVariable("database", database); - addGlobalVariable("sqlExecutor", database.getMetadata().getFeature(SyncSqlExecutor.ID) - .orElseGet(() -> database.getMetadata().getFeature(ReactiveSqlExecutor.ID) - .map(ReactiveSyncSqlExecutor::of).orElse(null))); + addGlobalVariable("sqlExecutor", database + .getMetadata() + .getFeature(SyncSqlExecutor.ID) + .orElseGet(() -> database + .getMetadata() + .getFeature(ReactiveSqlExecutor.ID) + .map(ReactiveSyncSqlExecutor::of) + .orElse(null))); SystemVersion version = properties.build(); return args -> { - - SystemInitialize initialize = new SystemInitialize(database, version); - initialize.setExcludeTables(properties.getInitTableExcludes()); - initialize.install(); + if (properties.isAutoInit()) { + SystemInitialize initialize = new SystemInitialize(database, version); + initialize.setExcludeTables(properties.getInitTableExcludes()); + initialize.install(); + } }; } diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemInitialize.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemInitialize.java index b544fc23f..2c8dc32e9 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemInitialize.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/initialize/SystemInitialize.java @@ -184,6 +184,7 @@ protected void initInstallInfo() { .addDecoder(ClobValueCodec.INSTANCE) .addDecoder(JsonValueCodec.ofCollection(List.class, Dependency.class)))).notNull().comment("依赖详情").commit() .comment("系统信息") + .allowAlter(false) .commit() .sync(); system = database.dml().createRepository("s_system"); From 5f3bc0fcaf23538b9c2f3ce1e9d787c89432bb82 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 21 Jul 2022 18:35:07 +0800 Subject: [PATCH 209/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 9595da9cc..94e82b682 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -16,6 +16,7 @@ import org.hswebframework.ezorm.rdb.mapping.events.ReactiveResultHolder; import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; import org.hswebframework.ezorm.rdb.metadata.TableOrViewMetadata; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.NativeSql; import org.hswebframework.web.api.crud.entity.Entity; import org.hswebframework.web.bean.FastBeanCopier; import org.hswebframework.web.event.AsyncEvent; @@ -147,30 +148,23 @@ protected List createAfterData(List olds, } for (Object old : olds) { Object newValue = context - .get(MappingContextKeys.instance) - .filter(Entity.class::isInstance) - .map(Entity.class::cast) - .orElseGet(() -> { - return context - .get(MappingContextKeys.updateColumnInstance) - .map(map -> { - Object data = FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType())); - //set null - for (Map.Entry stringObjectEntry : map.entrySet()) { - if (stringObjectEntry.getValue() == null || stringObjectEntry.getValue() instanceof NullValue) { - GlobalConfig - .getPropertyOperator() - .setProperty(data, stringObjectEntry.getKey(), null); - } - } - return data; - }) - .map(Entity.class::cast) - .orElse(null); + .get(MappingContextKeys.updateColumnInstance) + .map(map -> { + Object data = FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.newInstance())); + for (Map.Entry entry : map.entrySet()) { + //set null + if (entry.getValue() == null + || entry.getValue() instanceof NullValue) { + GlobalConfig + .getPropertyOperator() + .setProperty(data, entry.getKey(), null); + } + } + return data; + }) + .orElseThrow(() -> { + return new IllegalArgumentException("can not get update instance"); }); - if (newValue != null) { - FastBeanCopier.copy(old, newValue, FastBeanCopier.include(idColumn.getAlias())); - } newValues.add(newValue); } return newValues; From 9b4280ade1dcf3bcca3d074a60dd316e1dde3e65 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 28 Jul 2022 15:18:57 +0800 Subject: [PATCH 210/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/bean/ClassDescription.java | 7 ++++ .../web/bean/ClassDescriptions.java | 4 +- .../web/bean/FastBeanCopier.java | 40 ++++++++++++++----- .../web/bean/SingleValueMap.java | 6 +-- .../org/hswebframework/web/dict/EnumDict.java | 24 +++++++---- .../web/bean/FastBeanCopierTest.java | 9 +++++ 6 files changed, 68 insertions(+), 22 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java index 9de02b6b0..df1893ed3 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescription.java @@ -15,6 +15,8 @@ public class ClassDescription { private final boolean enumDict; private final int fieldSize; + private final Object[] enums; + public ClassDescription(Class type) { this.type = type; collectionType = Collection.class.isAssignableFrom(type); @@ -22,6 +24,11 @@ public ClassDescription(Class type) { arrayType = type.isArray(); enumType = type.isEnum(); fieldSize = type.getDeclaredFields().length; + if (enumType) { + enums = type.getEnumConstants(); + } else { + enums = null; + } } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java index c5af73b58..731a50b41 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassDescriptions.java @@ -1,12 +1,12 @@ package org.hswebframework.web.bean; -import org.jctools.maps.NonBlockingHashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class ClassDescriptions { - private static final Map, ClassDescription> CACHE = new NonBlockingHashMap<>(); + private static final Map, ClassDescription> CACHE = new ConcurrentHashMap<>(); public static ClassDescription getDescription(Class type) { return CACHE.computeIfAbsent(type, ClassDescription::new); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index 23c6919c8..de0eea385 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -14,6 +14,7 @@ import org.jctools.maps.NonBlockingHashMap; import org.springframework.core.ResolvableType; import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.beans.PropertyDescriptor; @@ -88,6 +89,9 @@ public boolean contains(Object o) { } public static Object getProperty(Object source, String key) { + if (source instanceof Map) { + return ((Map) source).get(key); + } SingleValueMap map = new SingleValueMap<>(); copy(source, map, include(key)); return map.getValue(); @@ -117,7 +121,16 @@ public static T copy(S source, T target, Set ignore) { @SuppressWarnings("all") public static T copy(S source, T target, Converter converter, Set ignore) { if (source instanceof Map && target instanceof Map) { - ((Map) target).putAll(((Map) source)); + if (CollectionUtils.isEmpty(ignore)) { + ((Map) target).putAll(((Map) source)); + } else { + ((Map) source) + .forEach((k, v) -> { + if (!ignore.contains(k)) { + ((Map) target).put(k, v); + } + }); + } return target; } @@ -584,20 +597,29 @@ public T convert(Object source, Class targetClass, Class[] genericType) { if (target.isEnumType()) { if (target.isEnumDict()) { String strVal = String.valueOf(source); - - Object val = EnumDict.find((Class) targetClass, e -> { - return e.eq(source) || e.name().equalsIgnoreCase(strVal); - }).orElse(null); + Object val = null; + for (Object anEnum : target.getEnums()) { + EnumDict dic = ((EnumDict) anEnum); + Enum e = ((Enum) anEnum); + if (dic.eq(source) || e.name().equalsIgnoreCase(strVal)) { + val = (T) anEnum; + break; + } + } + if (val == null) { + return null; + } if (targetClass.isInstance(val)) { return ((T) val); } return convert(val, targetClass, genericType); } String strSource = String.valueOf(source); - for (T t : targetClass.getEnumConstants()) { - if (((Enum) t).name().equalsIgnoreCase(strSource) - || Objects.equals(String.valueOf(((Enum) t).ordinal()), strSource)) { - return t; + for (Object e : target.getEnums()) { + Enum t = ((Enum) e); + if ((t.name().equalsIgnoreCase(strSource) + || Objects.equals(String.valueOf(t.ordinal()), strSource))) { + return (T)e; } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java index 08c024c61..b37221a38 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/SingleValueMap.java @@ -28,7 +28,7 @@ public boolean containsValue(Object value) { @Override public V get(Object key) { - return null; + return Objects.equals(key, this.key) ? value : null; } @Override @@ -50,9 +50,9 @@ public V remove(Object key) { } @Override - public void putAll(Map m) { + public void putAll(Map m) { if (m.size() > 0) { - Map.Entry entry = m.entrySet().iterator().next(); + Map.Entry entry = m.entrySet().iterator().next(); this.key = entry.getKey(); this.value = entry.getValue(); } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java index ac5494c0b..5d4e1137a 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java @@ -19,6 +19,8 @@ import lombok.NoArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.hswebframework.web.bean.ClassDescription; +import org.hswebframework.web.bean.ClassDescriptions; import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.i18n.LocaleUtils; import org.springframework.beans.BeanUtils; @@ -135,20 +137,25 @@ default String getComments() { * @param 枚举类型 * @return 查找到的结果 */ + @SuppressWarnings("all") static Optional find(Class type, Predicate predicate) { - if (type.isEnum()) { - for (T enumDict : type.getEnumConstants()) { - if (predicate.test(enumDict)) { - return Optional.of(enumDict); + ClassDescription description = ClassDescriptions.getDescription(type); + if (description.isEnumType()) { + for (Object enumDict : description.getEnums()) { + if (predicate.test((T) enumDict)) { + return Optional.of((T) enumDict); } } } return Optional.empty(); } + @SuppressWarnings("all") static List findList(Class type, Predicate predicate) { - if (type.isEnum()) { - return Arrays.stream(type.getEnumConstants()) + ClassDescription description = ClassDescriptions.getDescription(type); + if (description.isEnumType()) { + return Arrays.stream(description.getEnums()) + .map(v -> (T) v) .filter(predicate) .collect(Collectors.toList()); } @@ -199,7 +206,8 @@ static long toMask(T... t) { @SafeVarargs static boolean in(T target, T... t) { - Enum[] all = target.getClass().getEnumConstants(); + ClassDescription description= ClassDescriptions.getDescription(target.getClass()); + Object[] all = description.getEnums(); if (all.length >= 64) { List list = Arrays.asList(t); @@ -385,7 +393,7 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE return e.name(); }).collect(Collectors.toList()); - return new ValidationException(currentName,"validation.parameter_does_not_exist_in_enums", currentName); + return new ValidationException(currentName, "validation.parameter_does_not_exist_in_enums", currentName); }; if (EnumDict.class.isAssignableFrom(findPropertyType) && findPropertyType.isEnum()) { if (node.isObject()) { diff --git a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java index f04d33f0f..fe7e177e4 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java @@ -1,5 +1,7 @@ package org.hswebframework.web.bean; +import com.google.common.collect.ImmutableMap; +import jdk.nashorn.internal.objects.annotations.Getter; import org.junit.Assert; import org.junit.Test; @@ -113,6 +115,13 @@ public void testProxy() { Assert.assertEquals(reference.get(),source.getName()); } + @Test + public void testGetProperty(){ + + Assert.assertEquals(1,FastBeanCopier.getProperty(ImmutableMap.of("a",1,"b",2),"a")); + + } + public interface ProxyTest { String getName(); From 4f30e44f1104707685df902902122c12a4ccaf1f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 29 Jul 2022 16:42:26 +0800 Subject: [PATCH 211/542] =?UTF-8?q?=E5=A6=82=E6=9E=9C=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E4=BA=86=E6=8E=92=E5=BA=8F=E5=88=99=E4=B8=8D?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=BA=8F=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/api/crud/entity/TreeSupportEntity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index 10dc2f3b9..9d01bca8f 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -224,7 +224,9 @@ static , PK> void expandTree2List(T root, List Date: Fri, 29 Jul 2022 17:29:31 +0800 Subject: [PATCH 212/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/i18n/authentication/messages_zh.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties index a9bd62303..4c349297b 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties +++ b/hsweb-authorization/hsweb-authorization-api/src/main/resources/i18n/authentication/messages_zh.properties @@ -1,4 +1,4 @@ -error.access_denied=权限不足,拒绝访问! +error.access_denied=暂无权限,请联系管理员! error.permission_denied=当前用户无权限[{0}]:{1} error.logged_in_elsewhere=该用户已在其他地方登陆 error.illegal_password=用户名或密码错误 From 63a15a1af37e6df8a94ca6fad5b7152f16bdc653 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Sat, 30 Jul 2022 10:08:54 +0800 Subject: [PATCH 213/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonWebFluxConfiguration.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index 9a2c8e7b6..dc3f338a4 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.web; -import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import org.hswebframework.web.i18n.WebFluxLocaleFilter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -33,12 +32,6 @@ public ResponseMessageWrapper responseMessageWrapper(ServerCodecConfigurer codec return new ResponseMessageWrapper(codecConfigurer.getWriters(), resolver, registry); } - @Bean - public R2dbcDataIntegrityViolationException r2dbcDataIntegrityViolationException(){ - return new R2dbcDataIntegrityViolationException(); - } - - @Bean public WebFilter localeWebFilter() { return new WebFluxLocaleFilter(); From 3416fd24d6388701b111418bc11da1aa48d24097 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 09:22:27 +0800 Subject: [PATCH 214/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=BA=AF=E6=BA=90=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 2 +- .../web/exception/TraceSourceException.java | 50 +++++++++++++++++++ .../web/validator/ValidatorUtils.java | 6 +-- 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 6213a36c8..21341a0e9 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -19,7 +19,7 @@ */ @Getter @Setter(AccessLevel.PROTECTED) -public class I18nSupportException extends RuntimeException { +public class I18nSupportException extends TraceSourceException { /** * 消息code,在message.properties文件中定义的key diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java new file mode 100644 index 000000000..89174fa8e --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -0,0 +1,50 @@ +package org.hswebframework.web.exception; + +import javax.annotation.Nullable; +import java.util.Optional; + +/** + * 支持溯源的异常,通过{@link TraceSourceException#withSource(Object) }来标识异常的源头. + * 在捕获异常的地方通过获取异常源来处理一些逻辑,比如判断是由哪条数据发生的错误等操作. + * + * @author zhouhao + * @since 4.0.15 + */ +public class TraceSourceException extends RuntimeException { + + private Object source; + + public TraceSourceException() { + + } + + public TraceSourceException(String message) { + super(message); + } + + public TraceSourceException(Throwable e) { + super(e); + } + + public TraceSourceException(String message, Throwable e) { + super(message, e); + } + + public Optional sourceOptional() { + return Optional.ofNullable(source); + } + + @Nullable + public Object getSource() { + return source; + } + + public TraceSourceException withSource(Object source) { + this.source = source; + return self(); + } + + protected TraceSourceException self() { + return this; + } +} 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 index 3db2fad56..4c5a1a748 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -38,7 +38,7 @@ public static Validator getValidator() { public static T tryValidate(T bean, Class... group) { Set> violations = getValidator().validate(bean, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(bean); } return bean; @@ -47,7 +47,7 @@ public static T tryValidate(T bean, Class... group) { public static T tryValidate(T bean, String property, Class... group) { Set> violations = getValidator().validateProperty(bean, property, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(bean); } return bean; @@ -56,7 +56,7 @@ public static T tryValidate(T bean, String property, Class... group) { public static void tryValidate(Class bean, String property, Object value, Class... group) { Set> violations = getValidator().validateValue(bean, property, value, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(value); } } From 1284a3ec21979824139fe67bcb05baa3e28020a5 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 14:02:34 +0800 Subject: [PATCH 215/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 26 ++++ .../web/exception/TraceSourceException.java | 117 +++++++++++++++++- 2 files changed, 139 insertions(+), 4 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 21341a0e9..2478ab72b 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.Locale; @@ -70,4 +71,29 @@ public final Mono getLocalizedMessageReactive() { .currentReactive() .map(this::getLocalizedMessage); } + + public static String tryGetLocalizedMessage(Throwable error, Locale locale) { + if (error instanceof I18nSupportException) { + return ((I18nSupportException) error).getLocalizedMessage(locale); + } + String msg = error.getMessage(); + + if (!StringUtils.hasText(msg)) { + msg = "error." + error.getClass().getSimpleName(); + } + if (msg.contains(".")) { + return LocaleUtils.resolveMessage(msg, locale, msg); + } + return msg; + } + + public static String tryGetLocalizedMessage(Throwable error) { + return tryGetLocalizedMessage(error, LocaleUtils.current()); + } + + public static Mono tryGetLocalizedMessageReactive(Throwable error) { + return LocaleUtils + .currentReactive() + .map(locale -> tryGetLocalizedMessage(error, locale)); + } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java index 89174fa8e..28341cbbe 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -1,7 +1,14 @@ package org.hswebframework.web.exception; +import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Mono; +import reactor.util.context.Context; + import javax.annotation.Nullable; +import java.util.Locale; import java.util.Optional; +import java.util.function.Function; /** * 支持溯源的异常,通过{@link TraceSourceException#withSource(Object) }来标识异常的源头. @@ -12,6 +19,11 @@ */ public class TraceSourceException extends RuntimeException { + private static final String deepTraceKey = TraceSourceException.class.getName() + "_deep"; + private static final Context deepTraceContext = Context.of(deepTraceKey, true); + + private String operation; + private Object source; public TraceSourceException() { @@ -30,21 +42,118 @@ public TraceSourceException(String message, Throwable e) { super(message, e); } - public Optional sourceOptional() { - return Optional.ofNullable(source); - } - @Nullable public Object getSource() { return source; } + @Nullable + public String getOperation() { + return operation; + } + public TraceSourceException withSource(Object source) { this.source = source; return self(); } + public TraceSourceException withSource(String operation, Object source) { + this.operation = operation; + this.source = source; + return self(); + } + protected TraceSourceException self() { return this; } + + /** + * 深度溯源上下文,用来标识是否是深度溯源的异常.开启深度追踪后,会创建新的{@link TraceSourceException}对象. + * + * @return 上下文 + * @see reactor.core.publisher.Flux#subscriberContext(Context) + * @see Mono#subscriberContext(Context) + */ + public static Context deepTraceContext() { + return deepTraceContext; + } + + public static Function> transfer(Object source) { + return transfer(null, source); + } + + + /** + * 溯源异常转换器.通常配合{@link Mono#onErrorResume(Function)}使用. + *

+ * 转换逻辑: + *

+ * 1. 如果捕获的异常不是TraceSourceException,则直接创建新的TraceSourceException并返回. + *

+ * 2. 如果捕获的异常是TraceSourceException,并且上下文没有指定{@link TraceSourceException#deepTraceContext()}, + * 则修改捕获的TraceSourceException异常中的source.如果上下文中指定了{@link TraceSourceException#deepTraceContext()} + * 则创建新的TraceSourceException + * + *

{@code
+     *
+     *  doSomething()
+     *  .onErrorResume(TraceSourceException.transfer(data))
+     *
+     * }
+ * + * @param operation 操作名称 + * @param source 源 + * @param 泛型 + * @return 转换器 + * @see reactor.core.publisher.Flux#onErrorResume(Function) + * @see Mono#onErrorResume(Function) + */ + public static Function> transfer(String operation, Object source) { + if (source == null && operation == null) { + return Mono::error; + } + return err -> { + if (err instanceof TraceSourceException) { + return Mono + .deferWithContext(ctx -> { + if (ctx.hasKey(deepTraceKey)) { + return Mono.error(new TraceSourceException(err).withSource(operation,source)); + } else { + return Mono.error(((TraceSourceException) err).withSource(operation,source)); + } + }); + } + return Mono.error(new TraceSourceException(err).withSource(operation,source)); + }; + } + + public static Object tryGetSource(Throwable err) { + if (err instanceof TraceSourceException) { + return ((TraceSourceException) err).getSource(); + } + return null; + } + + public static String tryGetOperation(Throwable err) { + if (err instanceof TraceSourceException) { + return ((TraceSourceException) err).getOperation(); + } + return null; + } + + public static String tryGetOperationLocalized(Throwable err, Locale locale) { + String opt = tryGetOperation(err); + return StringUtils.hasText(opt) ? LocaleUtils.resolveMessage(opt, locale, opt) : opt; + } + + public static Mono tryGetOperationLocalizedReactive(Throwable err) { + return LocaleUtils + .currentReactive() + .handle((locale, sink) -> { + String opt = tryGetOperationLocalized(err, locale); + if (opt != null) { + sink.next(opt); + } + }); + } } From 1a707a29eb0520f5f9db3ab3d1659f71e9515c30 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 15:18:25 +0800 Subject: [PATCH 216/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/aop/AopAuthorizingController.java | 6 +++--- .../define/DefaultBasicAuthorizeDefinition.java | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java index d1d59ba53..23171ebd2 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java @@ -64,7 +64,8 @@ protected Publisher handleReactive0(AuthorizeDefinition definition, AuthorizingContext context, Supplier> invoker) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .switchIfEmpty(Mono.error(UnAuthorizedException::new)) .flatMapMany(auth -> { context.setAuthentication(auth); @@ -133,8 +134,7 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable { context.setAuthentication(authentication); isControl = true; - Phased dataAccessPhased = null; - dataAccessPhased = definition.getResources().getPhased(); + Phased dataAccessPhased = definition.getResources().getPhased(); if (definition.getPhased() == Phased.before) { //RDAC before authorizingHandler.handRBAC(context); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java index d5c556493..dd334acf8 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java @@ -38,7 +38,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { private String message = "error.access_denied"; - private Phased phased; + private Phased phased = Phased.before; @Override public boolean isEmpty() { @@ -65,6 +65,7 @@ public void putAnnotation(Authorize ann) { getResources().getResources().clear(); getDimensions().getDimensions().clear(); } + setPhased(ann.phased()); getResources().setPhased(ann.phased()); for (Resource resource : ann.resources()) { putAnnotation(resource); @@ -97,6 +98,8 @@ public void putAnnotation(Resource ann) { putAnnotation(resource, action); } resource.setGroup(new ArrayList<>(Arrays.asList(ann.group()))); + setPhased(ann.phased()); + getResources().setPhased(ann.phased()); resources.addResource(resource, ann.merge()); } @@ -132,8 +135,8 @@ public void putAnnotation(ResourceActionDefinition definition, DataAccess ann) { return; } definition.getDataAccess() - .getDataAccessTypes() - .add(typeDefinition); + .getDataAccessTypes() + .add(typeDefinition); } public void putAnnotation(ResourceActionDefinition definition, DataAccessType dataAccessType) { @@ -147,8 +150,8 @@ public void putAnnotation(ResourceActionDefinition definition, DataAccessType da typeDefinition.setConfiguration(dataAccessType.configuration()); typeDefinition.setDescription(String.join("\n", dataAccessType.description())); definition.getDataAccess() - .getDataAccessTypes() - .add(typeDefinition); + .getDataAccessTypes() + .add(typeDefinition); } } From 69ab5f632d56cb71bbbba4fc412453068a7bdc02 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 20:01:26 +0800 Subject: [PATCH 217/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BB=A5=E5=8F=8A=E6=9D=83=E9=99=90=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../events/AuthorizationInitializeEvent.java | 5 +- .../simple/SimpleAuthentication.java | 18 ++-- ...activeAuthenticationInitializeService.java | 88 +++++++++++-------- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java index 6144f6c5f..93f9bb261 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java @@ -2,11 +2,14 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.event.DefaultAsyncEvent; @Getter +@Setter @AllArgsConstructor -public class AuthorizationInitializeEvent { +public class AuthorizationInitializeEvent extends DefaultAsyncEvent { private Authentication authentication; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 8d8ef7e7d..720e20c56 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -58,10 +58,16 @@ public Map getAttributes() { } public SimpleAuthentication merge(Authentication authentication) { - Map mePermissionGroup = permissions.stream() + Map mePermissionGroup = permissions + .stream() .collect(Collectors.toMap(Permission::getId, Function.identity())); - user = authentication.getUser(); + + if (authentication.getUser() != null) { + user = authentication.getUser(); + } + attributes.putAll(authentication.getAttributes()); + for (Permission permission : authentication.getPermissions()) { Permission me = mePermissionGroup.get(permission.getId()); if (me == null) { @@ -88,10 +94,10 @@ public Authentication copy(BiPredicate permissionFilter, authentication.setUser(user); authentication.setDimensions(dimensions.stream().filter(dimension).collect(Collectors.toList())); authentication.setPermissions(permissions - .stream() - .map(permission -> permission.copy(action -> permissionFilter.test(permission, action), conf -> true)) - .filter(per -> !per.getActions().isEmpty()) - .collect(Collectors.toList()) + .stream() + .map(permission -> permission.copy(action -> permissionFilter.test(permission, action), conf -> true)) + .filter(per -> !per.getActions().isEmpty()) + .collect(Collectors.toList()) ); return authentication; } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index b3fc14096..44d431e14 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -10,6 +10,7 @@ import org.hswebframework.web.authorization.access.DataAccessConfig; import org.hswebframework.web.authorization.access.DataAccessType; import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; +import org.hswebframework.web.authorization.events.AuthorizationInitializeEvent; import org.hswebframework.web.authorization.simple.SimpleAuthentication; import org.hswebframework.web.authorization.simple.SimplePermission; import org.hswebframework.web.authorization.simple.SimpleUser; @@ -21,6 +22,7 @@ import org.hswebframework.web.system.authorization.api.entity.UserEntity; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -48,6 +50,9 @@ public class DefaultReactiveAuthenticationInitializeService @Autowired(required = false) private List dimensionProviders = new ArrayList<>(); + @Autowired + private ApplicationEventPublisher eventPublisher; + @Override public Mono initUserAuthorization(String userId) { return doInit(userService.findById(userId)); @@ -58,17 +63,23 @@ public Mono doInit(Mono userEntityMono) { return userEntityMono.flatMap(user -> { SimpleAuthentication authentication = new SimpleAuthentication(); authentication.setUser(SimpleUser - .builder() - .id(user.getId()) - .name(user.getName()) - .username(user.getUsername()) - .userType(user.getType()) - .build()); + .builder() + .id(user.getId()) + .name(user.getName()) + .username(user.getUsername()) + .userType(user.getType()) + .build()); return initPermission(authentication) .switchIfEmpty(Mono.just(authentication)) .onErrorResume(err -> { log.warn(err.getMessage(), err); return Mono.just(authentication); + }) + .flatMap(auth -> { + AuthorizationInitializeEvent event = new AuthorizationInitializeEvent(auth); + return event + .publish(eventPublisher) + .then(Mono.fromSupplier(event::getAuthentication)); }); }); @@ -76,31 +87,31 @@ public Mono doInit(Mono userEntityMono) { protected Flux getSettings(List dimensions) { return Flux.fromIterable(dimensions) - .filter(dimension -> dimension.getType() != null) - .groupBy(d -> d.getType().getId(), (Function) Dimension::getId) - .flatMap(group -> - group.collectList() - .flatMapMany(list -> settingRepository - .createQuery() - .where(AuthorizationSettingEntity::getState, 1) - .and(AuthorizationSettingEntity::getDimensionType, group.key()) - .in(AuthorizationSettingEntity::getDimensionTarget, list) - .fetch())); + .filter(dimension -> dimension.getType() != null) + .groupBy(d -> d.getType().getId(), (Function) Dimension::getId) + .flatMap(group -> + group.collectList() + .flatMapMany(list -> settingRepository + .createQuery() + .where(AuthorizationSettingEntity::getState, 1) + .and(AuthorizationSettingEntity::getDimensionType, group.key()) + .in(AuthorizationSettingEntity::getDimensionTarget, list) + .fetch())); } protected Mono initPermission(SimpleAuthentication authentication) { return Flux.fromIterable(dimensionProviders) - .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) - .cast(Dimension.class) - .collectList() - .doOnNext(authentication::setDimensions) - .flatMap(allDimension -> - Mono.zip( - getAllPermission() - , getSettings(allDimension) - .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) - , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) - )); + .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) + .cast(Dimension.class) + .collectList() + .doOnNext(authentication::setDimensions) + .flatMap(allDimension -> + Mono.zip( + getAllPermission() + , getSettings(allDimension) + .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) + , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) + )); } @@ -134,16 +145,19 @@ protected SimpleAuthentication handlePermission(SimpleAuthentication authenticat if (permissionSetting.getDataAccesses() != null) { permissionSetting.getDataAccesses() - .stream() - .map(conf -> { - DataAccessConfig config = builderFactory.create().fromMap(conf.toMap()).build(); - if (config == null) { - log.warn("unsupported data access:{}", conf.toMap()); - } - return config; - }) - .filter(Objects::nonNull) - .forEach(configs::add); + .stream() + .map(conf -> { + DataAccessConfig config = builderFactory + .create() + .fromMap(conf.toMap()) + .build(); + if (config == null) { + log.warn("unsupported data access:{}", conf.toMap()); + } + return config; + }) + .filter(Objects::nonNull) + .forEach(configs::add); } if (CollectionUtils.isNotEmpty(permissionSetting.getActions())) { permission.getActions().addAll(permissionSetting.getActions()); From c5b9adabbea1a8db161607f02ea18520d0383a03 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 10 Aug 2022 17:27:53 +0800 Subject: [PATCH 218/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/events/ValidateEventListener.java | 7 +- .../web/exception/TraceSourceException.java | 2 +- .../hswebframework/web/i18n/LocaleUtils.java | 116 ++++++++++++++++-- .../web/i18n/WebFluxLocaleFilter.java | 1 + .../web/i18n/LocaleUtilsTest.java | 32 ++++- .../jackson/CustomJackson2JsonDecoder.java | 45 +++---- .../jackson/CustomJackson2jsonEncoder.java | 115 ++++++++--------- 7 files changed, 208 insertions(+), 110 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index be7e1fb00..342dc9e92 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -35,9 +35,10 @@ public void onEvent(EventType type, EventContext context) { resultHolder .ifPresent(holder -> holder .invoke(LocaleUtils - .currentReactive() - .doOnNext(locale -> LocaleUtils.doWith(locale, (l) -> tryValidate(type, context))) - .then() + .doInReactive(() -> { + tryValidate(type, context); + return null; + }) )); } else { tryValidate(type, context); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java index 28341cbbe..30ab58049 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -35,7 +35,7 @@ public TraceSourceException(String message) { } public TraceSourceException(Throwable e) { - super(e); + super(e.getMessage(),e); } public TraceSourceException(String message, Throwable e) { diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index d3c66ade3..156d4a989 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -1,15 +1,17 @@ package org.hswebframework.web.i18n; +import lombok.AllArgsConstructor; import org.hswebframework.web.exception.I18nSupportException; import org.reactivestreams.Publisher; +import org.reactivestreams.Subscription; import org.springframework.context.MessageSource; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.publisher.Signal; -import reactor.core.publisher.SignalType; +import reactor.core.CoreSubscriber; +import reactor.core.publisher.*; import reactor.util.context.Context; +import javax.annotation.Nonnull; import java.util.Locale; +import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -23,7 +25,6 @@ *
  • {@link LocaleUtils#current()}
  • *
  • {@link LocaleUtils#currentReactive()}
  • *
  • {@link LocaleUtils#resolveMessageReactive(String, Object...)}
  • - *
  • {@link LocaleUtils#doOnNext(BiConsumer)}
  • * * * @author zhouhao @@ -63,11 +64,12 @@ public static Locale current() { * @return 返回值 */ public static R doWith(T data, Locale locale, BiFunction mapper) { + Locale old = CONTEXT_THREAD_LOCAL.get(); try { CONTEXT_THREAD_LOCAL.set(locale); return mapper.apply(data, locale); } finally { - CONTEXT_THREAD_LOCAL.remove(); + CONTEXT_THREAD_LOCAL.set(old); } } @@ -78,11 +80,12 @@ public static R doWith(T data, Locale locale, BiFunction ma * @param consumer 任务 */ public static void doWith(Locale locale, Consumer consumer) { + Locale old = CONTEXT_THREAD_LOCAL.get(); try { CONTEXT_THREAD_LOCAL.set(locale); consumer.accept(locale); } finally { - CONTEXT_THREAD_LOCAL.remove(); + CONTEXT_THREAD_LOCAL.set(old); } } @@ -112,6 +115,23 @@ public static Mono currentReactive() { .subscriberContext() .map(ctx -> ctx.getOrDefault(Locale.class, DEFAULT_LOCALE)); } + public static Mono doInReactive(Callable call) { + return currentReactive() + .handle((locale, sink) -> { + Locale old = CONTEXT_THREAD_LOCAL.get(); + try { + CONTEXT_THREAD_LOCAL.set(locale); + T data = call.call(); + if (data != null) { + sink.next(data); + } + } catch (Throwable e) { + sink.error(e); + } finally { + CONTEXT_THREAD_LOCAL.set(old); + } + }); + } /** * 响应式方式解析出异常的区域消息,并进行结果转换. @@ -450,4 +470,86 @@ public static > Function doOnError(BiConsumer operation.accept(s.getThrowable(), l)); } + public static Flux transform(Flux flux) { + return new LocaleFlux<>(flux); + } + + public static Mono transform(Mono mono) { + return new LocaleMono<>(mono); + } + + @AllArgsConstructor + static class LocaleMono extends Mono { + private final Mono source; + + @Override + public void subscribe(@Nonnull CoreSubscriber actual) { + doWith(actual, + actual.currentContext().getOrDefault(Locale.class, DEFAULT_LOCALE), + (a, l) -> { + source.subscribe( + new LocaleSwitchSubscriber<>(a) + ); + return null; + } + ); + } + } + + @AllArgsConstructor + static class LocaleFlux extends Flux { + private final Flux source; + + @Override + public void subscribe(@Nonnull CoreSubscriber actual) { + source.subscribe( + new LocaleSwitchSubscriber<>(actual) + ); + } + } + + @AllArgsConstructor + static class LocaleSwitchSubscriber extends BaseSubscriber { + private final CoreSubscriber actual; + + @Override + @Nonnull + public Context currentContext() { + return actual + .currentContext(); + } + + @Override + protected void hookOnSubscribe(@Nonnull Subscription subscription) { + actual.onSubscribe(this); + } + + private Locale current() { + return currentContext() + .getOrDefault(Locale.class, DEFAULT_LOCALE); + } + + @Override + protected void hookOnComplete() { + doWith(current(), (l) -> actual.onComplete()); + } + + @Override + protected void hookOnError(@Nonnull Throwable error) { + + doWith(error, current(), (v, l) -> { + actual.onError(v); + return null; + }); + } + + @Override + protected void hookOnNext(@Nonnull T value) { + + doWith(value, current(), (v, l) -> { + actual.onNext(v); + return null; + }); + } + } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java index 748d7faee..61a34e1d6 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java @@ -15,6 +15,7 @@ public class WebFluxLocaleFilter implements WebFilter { public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { return chain .filter(exchange) + .as(LocaleUtils::transform) .subscriberContext(LocaleUtils.useLocale(getLocaleContext(exchange))); } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java index e68469bf4..0ce7042a2 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java @@ -2,6 +2,8 @@ import org.junit.Test; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import java.util.Locale; @@ -11,15 +13,35 @@ public class LocaleUtilsTest { @Test - public void testOnNext() { + public void testFlux() { Flux.just(1) - .as(LocaleUtils.doOnNext((i, l) -> { + .as(LocaleUtils::transform) + .doOnNext(i -> { assertEquals(i.intValue(), 1); - assertEquals(l, Locale.CHINA); - })) - .subscriberContext(LocaleUtils.useLocale(Locale.CHINA)) + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + }) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) .blockLast(); } + @Test + public void testMono() { + Mono.just(1) + .doOnNext(i -> { + assertEquals(i.intValue(), 1); + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + }) + .as(LocaleUtils::transform) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) + .block(); + + LocaleUtils + .doInReactive(()->{ + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + return null; + }) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) + .block(); + } } \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index cbf0100b8..454933464 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -28,12 +28,10 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import javax.annotation.Nonnull; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.Collection; import java.util.List; import java.util.Map; @@ -70,23 +68,19 @@ public Flux decode(@NonNull Publisher input, @NonNull Resolv ObjectReader reader = getObjectReader(elementType, hints); - return LocaleUtils - .currentReactive() - .flatMapMany(locale -> tokens - .handle((tokenBuffer, sink) -> { - LocaleUtils.doWith(locale, l -> { - try { - Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); - logValue(value, hints); - if (value != null) { - sink.next(value); - } - } catch (IOException ex) { - sink.error(processException(ex)); - } - }); - - })); + return tokens + .as(LocaleUtils::transform) + .handle((tokenBuffer, sink) -> { + try { + Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); + logValue(value, hints); + if (value != null) { + sink.next(value); + } + } catch (IOException ex) { + sink.error(processException(ex)); + } + }); } @Override @@ -94,15 +88,10 @@ public Flux decode(@NonNull Publisher input, @NonNull Resolv public Mono decodeToMono(@NonNull Publisher input, @NonNull ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { - return LocaleUtils - .currentReactive() - .flatMap(locale -> DataBufferUtils - .join(input) - .map(dataBuffer -> LocaleUtils - .doWith(dataBuffer, - locale, - (buf, l) -> decode(buf, elementType, mimeType, hints))) - ); + return DataBufferUtils + .join(input) + .as(LocaleUtils::transform) + .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); } @Override diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java index a999fb9f6..27c42a42d 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java @@ -116,72 +116,55 @@ public Flux encode(Publisher inputStream, DataBufferFactory buffe Assert.notNull(bufferFactory, "'bufferFactory' must not be null"); Assert.notNull(elementType, "'elementType' must not be null"); - return LocaleUtils - .currentReactive() - .flatMapMany(locale -> { - if (inputStream instanceof Mono) { - return Mono.from(inputStream) - .map(value -> LocaleUtils - .doWith(value, locale, - ((val, loc) -> - encodeValue(val, bufferFactory, elementType, mimeType, hints) - ) - )) - .flux(); - } else { - byte[] separator = streamSeparator(mimeType); - if (separator != null) { // streaming - try { - ObjectWriter writer = createObjectWriter(elementType, mimeType, hints); - ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer - .getFactory() - ._getBufferRecycler()); - JsonEncoding encoding = getJsonEncoding(mimeType); - JsonGenerator generator = getObjectMapper() - .getFactory() - .createGenerator(byteBuilder, encoding); - SequenceWriter sequenceWriter = writer.writeValues(generator); - - return Flux - .from(inputStream) - .map(value -> LocaleUtils - .doWith(value, - locale, - ((val, loc) -> this - .encodeStreamingValue(val, - bufferFactory, - hints, - sequenceWriter, - byteBuilder, - separator) - ) - )) - .doAfterTerminate(() -> { - try { - byteBuilder.release(); - generator.close(); - } catch (IOException ex) { - logger.error("Could not close Encoder resources", ex); - } - }); - } catch (IOException ex) { - return Flux.error(ex); - } - } else { // non-streaming - ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); - return Flux.from(inputStream) - .collectList() - .map(value -> LocaleUtils - .doWith(value, locale, - ((val, loc) -> - encodeValue(val, bufferFactory, listType, mimeType, hints) - ) - )) - .flux(); - } - - } - }); + if (inputStream instanceof Mono) { + return Mono.from(inputStream) + .as(LocaleUtils::transform) + .map(value -> encodeValue(value, bufferFactory, elementType, mimeType, hints)) + .flux(); + } else { + byte[] separator = streamSeparator(mimeType); + if (separator != null) { // streaming + try { + ObjectWriter writer = createObjectWriter(elementType, mimeType, hints); + ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer + .getFactory() + ._getBufferRecycler()); + JsonEncoding encoding = getJsonEncoding(mimeType); + JsonGenerator generator = getObjectMapper() + .getFactory() + .createGenerator(byteBuilder, encoding); + SequenceWriter sequenceWriter = writer.writeValues(generator); + + return Flux + .from(inputStream) + .as(LocaleUtils::transform) + .map(value -> this.encodeStreamingValue(value, + bufferFactory, + hints, + sequenceWriter, + byteBuilder, + separator)) + .doAfterTerminate(() -> { + try { + byteBuilder.release(); + generator.close(); + } catch (IOException ex) { + logger.error("Could not close Encoder resources", ex); + } + }); + } catch (IOException ex) { + return Flux.error(ex); + } + } else { // non-streaming + ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); + return Flux.from(inputStream) + .collectList() + .as(LocaleUtils::transform) + .map(value -> encodeValue(value, bufferFactory, listType, mimeType, hints)) + .flux(); + } + + } } @Override From fa3b4dded9d33072e7053e4693d334a98196ce28 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 10 Aug 2022 17:40:46 +0800 Subject: [PATCH 219/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/i18n/LocaleUtils.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 156d4a989..44c524ae2 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -502,8 +502,14 @@ static class LocaleFlux extends Flux { @Override public void subscribe(@Nonnull CoreSubscriber actual) { - source.subscribe( - new LocaleSwitchSubscriber<>(actual) + doWith(actual, + actual.currentContext().getOrDefault(Locale.class, DEFAULT_LOCALE), + (a, l) -> { + source.subscribe( + new LocaleSwitchSubscriber<>(a) + ); + return null; + } ); } } From 03c47f12283d230caf21122730ed1add2cac85f0 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 17 Aug 2022 20:38:29 +0800 Subject: [PATCH 220/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/SimpleAuthentication.java | 8 +- .../AuthorizingHandlerAutoConfiguration.java | 6 ++ .../basic/web/BearerTokenParser.java | 22 ++++++ .../basic/web/DefaultUserTokenGenPar.java | 12 +-- .../server/OAuth2ServerAutoConfiguration.java | 23 +++--- .../code/DefaultAuthorizationCodeGranter.java | 5 +- .../server/impl/RedisAccessTokenManager.java | 74 ++++++++++++++----- .../oauth2/server/utils/OAuth2ScopeUtils.java | 11 ++- .../authorization/api/entity/UserEntity.java | 12 ++- .../service/reactive/ReactiveUserService.java | 2 + ...AuthorizationServiceAutoConfiguration.java | 8 +- ...activeAuthenticationInitializeService.java | 4 +- .../service/DefaultReactiveUserService.java | 12 ++- 13 files changed, 147 insertions(+), 52 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 720e20c56..e318c6c19 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -78,7 +78,6 @@ public SimpleAuthentication merge(Authentication authentication) { me.getDataAccesses().addAll(permission.getDataAccesses()); } - for (Dimension dimension : authentication.getDimensions()) { if (!getDimension(dimension.getType(), dimension.getId()).isPresent()) { dimensions.add(dimension); @@ -91,7 +90,6 @@ public SimpleAuthentication merge(Authentication authentication) { public Authentication copy(BiPredicate permissionFilter, Predicate dimension) { SimpleAuthentication authentication = new SimpleAuthentication(); - authentication.setUser(user); authentication.setDimensions(dimensions.stream().filter(dimension).collect(Collectors.toList())); authentication.setPermissions(permissions .stream() @@ -99,6 +97,12 @@ public Authentication copy(BiPredicate permissionFilter, .filter(per -> !per.getActions().isEmpty()) .collect(Collectors.toList()) ); + authentication.setUser(user); return authentication; } + + public void setUser(User user) { + this.user = user; + dimensions.add(user); + } } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java index 50e4510a9..3ba9465d1 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java @@ -145,6 +145,12 @@ public ReactiveUserTokenController userTokenController() { return new ReactiveUserTokenController(); } + @Bean + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) + public BearerTokenParser bearerTokenParser() { + return new BearerTokenParser(); + } + @Configuration public static class DataAccessHandlerProcessor implements BeanPostProcessor { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java new file mode 100644 index 000000000..d7c49d176 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java @@ -0,0 +1,22 @@ +package org.hswebframework.web.authorization.basic.web; + +import org.hswebframework.web.authorization.token.ParsedToken; +import org.springframework.http.HttpHeaders; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +public class BearerTokenParser implements ReactiveUserTokenParser { + @Override + public Mono parseToken(ServerWebExchange exchange) { + + String token = exchange + .getRequest() + .getHeaders() + .getFirst(HttpHeaders.AUTHORIZATION); + + if (token != null && token.startsWith("Bearer ")) { + return Mono.just(ParsedToken.of("bearer", token.substring(7))); + } + return Mono.empty(); + } +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java index 0e4c1810f..b1948ef42 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java @@ -62,16 +62,6 @@ public Mono parseToken(ServerWebExchange exchange) { if (token == null) { return Mono.empty(); } - return Mono.just(new ParsedToken() { - @Override - public String getToken() { - return token; - } - - @Override - public String getType() { - return getTokenType(); - } - }); + return Mono.just(ParsedToken.of(getTokenType(),token)); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index 6003a593f..842e21125 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -3,6 +3,8 @@ import org.hswebframework.web.authorization.ReactiveAuthenticationHolder; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser; +import org.hswebframework.web.authorization.token.UserToken; +import org.hswebframework.web.authorization.token.UserTokenManager; import org.hswebframework.web.oauth2.server.auth.ReactiveOAuth2AccessTokenParser; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeGranter; import org.hswebframework.web.oauth2.server.code.DefaultAuthorizationCodeGranter; @@ -22,6 +24,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; +import org.springframework.data.redis.core.ReactiveRedisOperations; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(OAuth2Properties.class) @@ -32,13 +35,13 @@ public class OAuth2ServerAutoConfiguration { @ConditionalOnClass(ReactiveUserTokenParser.class) static class ReactiveOAuth2AccessTokenParserConfiguration { - @Bean - @ConditionalOnBean(AccessTokenManager.class) - public ReactiveOAuth2AccessTokenParser reactiveOAuth2AccessTokenParser(AccessTokenManager accessTokenManager) { - ReactiveOAuth2AccessTokenParser parser = new ReactiveOAuth2AccessTokenParser(accessTokenManager); - ReactiveAuthenticationHolder.addSupplier(parser); - return parser; - } +// @Bean +// @ConditionalOnBean(AccessTokenManager.class) +// public ReactiveOAuth2AccessTokenParser reactiveOAuth2AccessTokenParser(AccessTokenManager accessTokenManager) { +// ReactiveOAuth2AccessTokenParser parser = new ReactiveOAuth2AccessTokenParser(accessTokenManager); +// ReactiveAuthenticationHolder.addSupplier(parser); +// return parser; +// } } @Configuration(proxyBeanMethods = false) @@ -48,9 +51,11 @@ static class ReactiveOAuth2ServerAutoConfiguration { @Bean @ConditionalOnMissingBean - public AccessTokenManager accessTokenManager(ReactiveRedisConnectionFactory redisConnectionFactory, + public AccessTokenManager accessTokenManager(ReactiveRedisOperations redis, + UserTokenManager tokenManager, OAuth2Properties properties) { - RedisAccessTokenManager manager = new RedisAccessTokenManager(redisConnectionFactory); + @SuppressWarnings("all") + RedisAccessTokenManager manager = new RedisAccessTokenManager((ReactiveRedisOperations) redis, tokenManager); manager.setTokenExpireIn((int) properties.getTokenExpireIn().getSeconds()); manager.setRefreshExpireIn((int) properties.getRefreshTokenIn().getSeconds()); return manager; diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java index c3b53cabd..472cedfa0 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java @@ -48,9 +48,12 @@ public Mono requestCode(AuthorizationCodeRequest requ request.getParameter(OAuth2Constants.scope).map(String::valueOf).ifPresent(codeCache::setScope); codeCache.setCode(code); codeCache.setClientId(client.getClientId()); + ScopePredicate permissionPredicate = OAuth2ScopeUtils.createScopePredicate(codeCache.getScope()); - codeCache.setAuthentication(authentication.copy((permission, action) -> permissionPredicate.test(permission.getId(), action), dimension -> true)); + codeCache.setAuthentication(authentication.copy( + (permission, action) -> permissionPredicate.test(permission.getId(), action), + dimension -> permissionPredicate.test(dimension.getType().getId(), dimension.getId()))); return redis diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index e6a0a0ac6..fe1e9b39b 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -4,6 +4,9 @@ import lombok.Setter; import org.apache.commons.codec.digest.DigestUtils; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.token.AuthenticationUserToken; +import org.hswebframework.web.authorization.token.UserTokenManager; +import org.hswebframework.web.authorization.token.redis.RedisUserTokenManager; import org.hswebframework.web.oauth2.ErrorType; import org.hswebframework.web.oauth2.OAuth2Exception; import org.hswebframework.web.oauth2.server.AccessToken; @@ -13,6 +16,7 @@ import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; @@ -22,6 +26,8 @@ public class RedisAccessTokenManager implements AccessTokenManager { private final ReactiveRedisOperations tokenRedis; + private final UserTokenManager userTokenManager; + @Getter @Setter private int tokenExpireIn = 7200;//2小时 @@ -30,29 +36,32 @@ public class RedisAccessTokenManager implements AccessTokenManager { @Setter private int refreshExpireIn = 2592000; //30天 - public RedisAccessTokenManager(ReactiveRedisOperations tokenRedis) { + public RedisAccessTokenManager(ReactiveRedisOperations tokenRedis, + UserTokenManager userTokenManager) { this.tokenRedis = tokenRedis; + this.userTokenManager = userTokenManager; } @SuppressWarnings("all") public RedisAccessTokenManager(ReactiveRedisConnectionFactory connectionFactory) { - this(new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext + ReactiveRedisTemplate redis = new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext .newSerializationContext() .key((RedisSerializer) RedisSerializer.string()) .value(RedisSerializer.java()) .hashKey(RedisSerializer.string()) .hashValue(RedisSerializer.java()) - .build() - )); + .build()); + this.tokenRedis = redis; + this.userTokenManager = new RedisUserTokenManager(redis); } + @Override public Mono getAuthenticationByToken(String accessToken) { - - return tokenRedis - .opsForValue() - .get(createTokenRedisKey(accessToken)) - .map(RedisAccessToken::getAuthentication); + return userTokenManager + .getByToken(accessToken) + .filter(token -> token instanceof AuthenticationUserToken) + .map(t -> ((AuthenticationUserToken) t).getAuthentication()); } private String createTokenRedisKey(String token) { @@ -75,12 +84,36 @@ private Mono doCreateAccessToken(String clientId, Authenticati return storeToken(accessToken).thenReturn(accessToken); } + private Mono storeAuthToken(RedisAccessToken token) { + if (token.isSingleton()) { + return userTokenManager + .signIn(token.getAccessToken(), + "oauth2", + token.getAuthentication().getUser().getId(), + tokenExpireIn * 1000L) + .then(); + } else { + return userTokenManager + .signIn(token.getAccessToken(), + "oauth2", + token.getAuthentication().getUser().getId(), + tokenExpireIn * 1000L, + token.getAuthentication()) + .then(); + } + } + private Mono storeToken(RedisAccessToken token) { - return Mono - .zip( - tokenRedis.opsForValue().set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), - tokenRedis.opsForValue().set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn)) - ).then(); + + return Flux + .merge(storeAuthToken(token), + tokenRedis + .opsForValue() + .set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + tokenRedis + .opsForValue() + .set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) + .then(); } private Mono doCreateSingletonAccessToken(String clientId, Authentication authentication) { @@ -129,10 +162,15 @@ public Mono refreshAccessToken(String clientId, String refreshToken .as(result -> { // 单例token if (token.isSingleton()) { - return tokenRedis - .opsForValue() - .set(createSingletonTokenRedisKey(clientId), token, Duration.ofSeconds(tokenExpireIn)) - .then(result); + return userTokenManager + .signOutByToken(token.getAccessToken()) + .then( + tokenRedis + .opsForValue() + .set(createSingletonTokenRedisKey(clientId), token, Duration.ofSeconds(tokenExpireIn)) + .then(result) + ) + ; } return result; }) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java index 4ac30fff0..40806f974 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java @@ -6,6 +6,10 @@ import java.util.*; /** + *
    {@code
    + *   role:* user:* device-manager:*
    + * }
    + * * @author zhouhao * @since 4.0.8 */ @@ -23,10 +27,13 @@ public static ScopePredicate createScopePredicate(String scopeStr) { Set acts = actions.computeIfAbsent(per, k -> new HashSet<>()); acts.addAll(Arrays.asList(permissions).subList(1, permissions.length)); } - + //全部授权 + if (actions.containsKey("*")) { + return ((permission, action) -> true); + } return ((permission, action) -> Optional .ofNullable(actions.get(permission)) - .map(acts -> action.length == 0 || acts.containsAll(Arrays.asList(action))) + .map(acts -> action.length == 0 || acts.contains("*") || acts.containsAll(Arrays.asList(action))) .orElse(false)); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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 index d903669aa..2e831be27 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/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,5 +1,7 @@ package org.hswebframework.web.system.authorization.api.entity; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.media.Schema; @@ -9,15 +11,18 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.api.crud.entity.RecordCreationEntity; import org.hswebframework.web.bean.ToString; import org.hswebframework.web.validator.CreateGroup; +import org.springframework.util.StringUtils; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.Index; import javax.persistence.Table; import javax.validation.constraints.NotBlank; +import java.util.Objects; /** * 系统用户实体 @@ -85,7 +90,10 @@ public String getId() { return super.getId(); } - public void generateId(){ - setId(DigestUtils.md5Hex(username)); + public void generateId() { + if (StringUtils.hasText(getId())) { + return; + } + setId(DigestUtils.md5Hex(username)); } } 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 index d7d3ace6d..209196cde 100644 --- 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 @@ -29,6 +29,8 @@ public interface ReactiveUserService { */ Mono saveUser(Mono userEntity); + Mono addUser(UserEntity userEntity); + /** * 根据用户名查询用户实体,如果用户不存在则返回{@link Mono#empty()} * diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java index 2d80c4fba..47f501d6f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java @@ -55,10 +55,10 @@ public DefaultDimensionService defaultDimensionService() { return new DefaultDimensionService(); } - @Bean - public UserDimensionProvider userPermissionDimensionProvider() { - return new UserDimensionProvider(); - } +// @Bean +// public UserDimensionProvider userPermissionDimensionProvider() { +// return new UserDimensionProvider(); +// } @Bean public DefaultDimensionUserService defaultDimensionUserService() { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index 44d431e14..2cce5809b 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -69,8 +69,9 @@ public Mono doInit(Mono userEntityMono) { .username(user.getUsername()) .userType(user.getType()) .build()); + return initPermission(authentication) - .switchIfEmpty(Mono.just(authentication)) + .defaultIfEmpty(authentication) .onErrorResume(err -> { log.warn(err.getMessage(), err); return Mono.just(authentication); @@ -82,7 +83,6 @@ public Mono doInit(Mono userEntityMono) { .then(Mono.fromSupplier(event::getAuthentication)); }); }); - } protected Flux getSettings(List dimensions) { 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 index b90247e24..7a730552a 100644 --- 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 @@ -24,6 +24,7 @@ import reactor.core.publisher.Mono; import javax.validation.ValidationException; +import java.util.Objects; public class DefaultReactiveUserService extends GenericReactiveCrudService implements ReactiveUserService { @@ -61,10 +62,19 @@ public Mono saveUser(Mono request) { } return findById(userEntity.getId()) .flatMap(ignore -> doUpdate(userEntity)) - .switchIfEmpty(Mono.error(NotFoundException::new)); + .switchIfEmpty( + Objects.equals(userEntity.getId(),userEntity.getUsername()) ? + doAdd(userEntity) : + Mono.error(NotFoundException::new) + ); }).thenReturn(true); } + @Override + public Mono addUser(UserEntity userEntity) { + return doAdd(userEntity); + } + protected Mono doAdd(UserEntity userEntity) { return Mono From f728de139939a21f40a59fccead5bf4940233222 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 10:01:50 +0800 Subject: [PATCH 221/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aop/ReactiveAopAccessLoggerSupport.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 76b5cf295..f7130b11d 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -39,7 +39,7 @@ * @author zhouhao * @since 3.0 */ -public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutAdvisor implements WebFilter { +public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutAdvisor implements WebFilter{ @Autowired(required = false) private final List loggerParsers = new ArrayList<>(); @@ -58,9 +58,11 @@ public ReactiveAopAccessLoggerSupport() { AccessLoggerInfo info = createLogger(methodInterceptorHolder); Object response = methodInvocation.proceed(); if (response instanceof Mono) { - return wrapMonoResponse(((Mono) response), info); + return wrapMonoResponse(((Mono) response), info) + .subscriberContext(Context.of(AccessLoggerInfo.class, info)); } else if (response instanceof Flux) { - return wrapFluxResponse(((Flux) response), info); + return wrapFluxResponse(((Flux) response), info) + .subscriberContext(Context.of(AccessLoggerInfo.class, info)); } return response; }); @@ -183,7 +185,7 @@ protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; + return Ordered.HIGHEST_PRECEDENCE; } @Override @@ -217,10 +219,12 @@ private RequestInfo createAccessInfo(ServerWebExchange exchange) { return info; } + @AllArgsConstructor @EqualsAndHashCode - private static class CacheKey{ + private static class CacheKey { private Class type; private Method method; } + } From ffb0e24acc29d05a2108d5caa5acdf1b230969c1 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 10:32:42 +0800 Subject: [PATCH 222/542] =?UTF-8?q?=E5=A2=9E=E5=8A=A0OAuth2GrantedEvent?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/AccessTokenManager.java | 1 + .../server/OAuth2ServerAutoConfiguration.java | 9 +++-- .../code/DefaultAuthorizationCodeGranter.java | 34 ++++++++++++++----- .../DefaultClientCredentialGranter.java | 20 ++++++++++- .../server/event/OAuth2GrantedEvent.java | 32 +++++++++++++++++ .../server/impl/RedisAccessTokenManager.java | 10 ++++++ .../server/web/OAuth2AuthorizeController.java | 2 ++ .../DefaultAuthorizationCodeGranterTest.java | 3 +- 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java index e90793c6c..37b484e85 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java @@ -40,4 +40,5 @@ Mono createAccessToken(String clientId, */ Mono refreshAccessToken(String clientId, String refreshToken); + Mono removeToken(String clientId,String token); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index 842e21125..42f1a575c 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; @@ -64,15 +65,17 @@ public AccessTokenManager accessTokenManager(ReactiveRedisOperations redis; @SuppressWarnings("all") - public DefaultAuthorizationCodeGranter(AccessTokenManager accessTokenManager, ReactiveRedisConnectionFactory connectionFactory) { - this(accessTokenManager, new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext + public DefaultAuthorizationCodeGranter(AccessTokenManager accessTokenManager, + ApplicationEventPublisher eventPublisher, + ReactiveRedisConnectionFactory connectionFactory) { + this(accessTokenManager, eventPublisher, new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext .newSerializationContext() .key((RedisSerializer) RedisSerializer.string()) .value(RedisSerializer.java()) @@ -75,16 +82,27 @@ public Mono requestToken(AuthorizationCodeTokenRequest request) { .map(this::getRedisKey) .flatMap(redis.opsForValue()::get) .switchIfEmpty(Mono.error(() -> new OAuth2Exception(ErrorType.ILLEGAL_CODE))) - .flatMap(cache -> redis - .opsForValue() - .delete(getRedisKey(cache.getCode())) - .thenReturn(cache)) + //移除code + .flatMap(cache -> redis.opsForValue().delete(getRedisKey(cache.getCode())).thenReturn(cache)) .flatMap(cache -> { if (!request.getClient().getClientId().equals(cache.getClientId())) { return Mono.error(new OAuth2Exception(ErrorType.ILLEGAL_CLIENT_ID)); } - return accessTokenManager.createAccessToken(cache.getClientId(), cache.getAuthentication(), false); - }); + return accessTokenManager + .createAccessToken(cache.getClientId(), cache.getAuthentication(), false) + .flatMap(token -> new OAuth2GrantedEvent(request.getClient(), + token, + cache.getAuthentication(), + cache.getScope(), + GrantType.authorization_code, + request.getParameters()) + .publish(eventPublisher) + .onErrorResume(err -> accessTokenManager + .removeToken(cache.getClientId(), token.getAccessToken()) + .then(Mono.error(err))) + .thenReturn(token)); + }) + ; } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java index 74155bc44..08a78cf29 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java @@ -2,9 +2,12 @@ import lombok.AllArgsConstructor; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.oauth2.GrantType; import org.hswebframework.web.oauth2.server.AccessToken; import org.hswebframework.web.oauth2.server.AccessTokenManager; import org.hswebframework.web.oauth2.server.OAuth2Client; +import org.hswebframework.web.oauth2.server.event.OAuth2GrantedEvent; +import org.springframework.context.ApplicationEventPublisher; import reactor.core.publisher.Mono; @AllArgsConstructor @@ -14,6 +17,8 @@ public class DefaultClientCredentialGranter implements ClientCredentialGranter { private final AccessTokenManager accessTokenManager; + private final ApplicationEventPublisher eventPublisher; + @Override public Mono requestToken(ClientCredentialRequest request) { @@ -21,6 +26,19 @@ public Mono requestToken(ClientCredentialRequest request) { return authenticationManager .getByUserId(client.getUserId()) - .flatMap(auth -> accessTokenManager.createAccessToken(client.getClientId(), auth, true)); + .flatMap(auth -> accessTokenManager + .createAccessToken(client.getClientId(), auth, true) + .flatMap(token -> new OAuth2GrantedEvent(client, + token, + auth, + "*", + GrantType.client_credentials, + request.getParameters()) + .publish(eventPublisher) + .onErrorResume(err -> accessTokenManager + .removeToken(client.getClientId(), token.getAccessToken()) + .then(Mono.error(err))) + .thenReturn(token)) + ); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java new file mode 100644 index 000000000..38b341dcb --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java @@ -0,0 +1,32 @@ +package org.hswebframework.web.oauth2.server.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.event.DefaultAsyncEvent; +import org.hswebframework.web.oauth2.server.AccessToken; +import org.hswebframework.web.oauth2.server.OAuth2Client; + +import java.util.Map; + +/** + * OAuth2授权成功事件 + * + * @author zhouhao + * @since 4.0.15 + */ +@Getter +@AllArgsConstructor +public class OAuth2GrantedEvent extends DefaultAsyncEvent { + private final OAuth2Client client; + + private final AccessToken accessToken; + + private final Authentication authentication; + + private final String scope; + + private final String grantType; + + private final Map parameters; +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index fe1e9b39b..1de7183fa 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -178,4 +178,14 @@ public Mono refreshAccessToken(String clientId, String refreshToken }); } + + @Override + public Mono removeToken(String clientId, String token) { + + return Flux + .merge(userTokenManager.signOutByToken(token), + tokenRedis.delete(createSingletonTokenRedisKey(clientId)), + tokenRedis.delete(createTokenRedisKey(token))) + .then(); + } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java index b71ee6468..123ab20f9 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java @@ -19,7 +19,9 @@ import org.hswebframework.web.oauth2.server.code.AuthorizationCodeRequest; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeTokenRequest; import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; +import org.hswebframework.web.oauth2.server.event.OAuth2GrantedEvent; import org.hswebframework.web.oauth2.server.refresh.RefreshTokenRequest; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java index 4f9fdaacc..6e0545441 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java @@ -7,6 +7,7 @@ import org.hswebframework.web.oauth2.server.RedisHelper; import org.hswebframework.web.oauth2.server.impl.RedisAccessTokenManager; import org.junit.Test; +import org.springframework.context.support.StaticApplicationContext; import reactor.test.StepVerifier; import java.util.Collections; @@ -20,7 +21,7 @@ public class DefaultAuthorizationCodeGranterTest { public void testRequestToken() { DefaultAuthorizationCodeGranter codeGranter = new DefaultAuthorizationCodeGranter( - new RedisAccessTokenManager(RedisHelper.factory), RedisHelper.factory + new RedisAccessTokenManager(RedisHelper.factory), new StaticApplicationContext(), RedisHelper.factory ); OAuth2Client client = new OAuth2Client(); From f2c45b037467ecf7a9e434c3e992169fbf9e5d7f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 13:54:01 +0800 Subject: [PATCH 223/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/simple/SimpleAuthentication.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index e318c6c19..96b36a096 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -105,4 +105,8 @@ public void setUser(User user) { this.user = user; dimensions.add(user); } + + public void setDimensions(List dimensions) { + this.dimensions.addAll(dimensions); + } } From 6aede9dafb99eb623b4f4a4be674611584e5ee09 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 14:04:31 +0800 Subject: [PATCH 224/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/SimpleAuthentication.java | 4 ++++ ...ltReactiveAuthenticationInitializeService.java | 15 ++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 96b36a096..f4aac6b40 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -109,4 +109,8 @@ public void setUser(User user) { public void setDimensions(List dimensions) { this.dimensions.addAll(dimensions); } + + public void addDimension(Dimension dimension) { + this.dimensions.add(dimension); + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index 2cce5809b..e96e69d7a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -103,20 +103,17 @@ protected Mono initPermission(SimpleAuthentication authenticatio return Flux.fromIterable(dimensionProviders) .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) .cast(Dimension.class) + .doOnNext(authentication::addDimension) .collectList() - .doOnNext(authentication::setDimensions) - .flatMap(allDimension -> - Mono.zip( - getAllPermission() - , getSettings(allDimension) - .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) - , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) - )); + .then(Mono.defer(() -> Mono + .zip(getAllPermission(), + getSettings(authentication.getDimensions()).collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)), + (_p, _s) -> handlePermission(authentication, _p, _s) + ))); } protected SimpleAuthentication handlePermission(SimpleAuthentication authentication, - List dimensionList, Map permissions, Map> settings) { Map permissionMap = new HashMap<>(); From 48068826e1cb6d5a27e57e0865e3f652e69fff10 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 17:00:06 +0800 Subject: [PATCH 225/542] =?UTF-8?q?=E4=BC=98=E5=8C=96token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/AccessTokenManager.java | 18 ++++- .../server/impl/RedisAccessTokenManager.java | 69 ++++++++++++++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java index 37b484e85..7762b4e4c 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java @@ -40,5 +40,21 @@ Mono createAccessToken(String clientId, */ Mono refreshAccessToken(String clientId, String refreshToken); - Mono removeToken(String clientId,String token); + /** + * 移除token + * + * @param clientId clientId + * @param token token + * @return void + */ + Mono removeToken(String clientId, String token); + + /** + * 取消对用户的授权 + * + * @param clientId clientId + * @param userId 用户ID + * @return void + */ + Mono cancelGrant(String clientId, String userId); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index 1de7183fa..c42540124 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -64,12 +64,21 @@ public Mono getAuthenticationByToken(String accessToken) { .map(t -> ((AuthenticationUserToken) t).getAuthentication()); } - private String createTokenRedisKey(String token) { - return "oauth2-token:" + token; + private String createTokenRedisKey(String clientId, String token) { + return "oauth2-token:" + clientId + ":" + token; } - private String createRefreshTokenRedisKey(String token) { - return "oauth2-refresh-token:" + token; + private String createUserTokenRedisKey(RedisAccessToken token) { + return createUserTokenRedisKey(token.getClientId(), token.getAuthentication().getUser().getId()); + } + + private String createUserTokenRedisKey(String clientId, String userId) { + return "oauth2-user-tokens:" + clientId + ":" + userId; + } + + + private String createRefreshTokenRedisKey(String clientId, String token) { + return "oauth2-refresh-token:" + clientId + ":" + token; } private String createSingletonTokenRedisKey(String clientId) { @@ -88,14 +97,14 @@ private Mono storeAuthToken(RedisAccessToken token) { if (token.isSingleton()) { return userTokenManager .signIn(token.getAccessToken(), - "oauth2", + createTokenType(token.getClientId()), token.getAuthentication().getUser().getId(), tokenExpireIn * 1000L) .then(); } else { return userTokenManager .signIn(token.getAccessToken(), - "oauth2", + createTokenType(token.getClientId()), token.getAuthentication().getUser().getId(), tokenExpireIn * 1000L, token.getAuthentication()) @@ -109,10 +118,15 @@ private Mono storeToken(RedisAccessToken token) { .merge(storeAuthToken(token), tokenRedis .opsForValue() - .set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + .set(createUserTokenRedisKey(token), token, Duration.ofSeconds(tokenExpireIn)), tokenRedis .opsForValue() - .set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) + .set(createTokenRedisKey(token.getClientId(), + token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + tokenRedis + .opsForValue() + .set(createRefreshTokenRedisKey(token.getClientId(), + token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) .then(); } @@ -144,7 +158,7 @@ public Mono createAccessToken(String clientId, @Override public Mono refreshAccessToken(String clientId, String refreshToken) { - String redisKey = createRefreshTokenRedisKey(refreshToken); + String redisKey = createRefreshTokenRedisKey(clientId, refreshToken); return tokenRedis .opsForValue() @@ -185,7 +199,42 @@ public Mono removeToken(String clientId, String token) { return Flux .merge(userTokenManager.signOutByToken(token), tokenRedis.delete(createSingletonTokenRedisKey(clientId)), - tokenRedis.delete(createTokenRedisKey(token))) + tokenRedis.delete(createTokenRedisKey(clientId, token))) .then(); } + + @Override + public Mono cancelGrant(String clientId, String userId) { + //删除refresh_token + Mono removeRefreshToken = tokenRedis + .opsForValue() + .get(createUserTokenRedisKey(clientId, userId)) + .flatMap(t -> tokenRedis + .opsForValue() + .delete(createRefreshTokenRedisKey(t.getClientId(), t.getRefreshToken()))) + .then(); + + //删除access_token + Mono removeAccessToken = userTokenManager + .getByUserId(userId) + .flatMap(token -> { + //其他类型的token 忽略 + if (!(createTokenType(clientId)).equals(token.getType())) { + return Mono.empty(); + } + //移除token + return tokenRedis + .delete(createTokenRedisKey(clientId, token.getToken())) + .then(userTokenManager.signOutByToken(token.getToken())); + }) + .then(); + + return Flux + .merge(removeRefreshToken, removeAccessToken) + .then(); + } + + private String createTokenType(String clientId) { + return "oauth2-" + clientId; + } } From 7160e859bc488baeb38564e5e7005c1bfa18af57 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 17:13:22 +0800 Subject: [PATCH 226/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/impl/RedisAccessTokenManager.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index c42540124..412cb00b8 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -20,6 +20,8 @@ import reactor.core.publisher.Mono; import java.time.Duration; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; public class RedisAccessTokenManager implements AccessTokenManager { @@ -205,7 +207,7 @@ public Mono removeToken(String clientId, String token) { @Override public Mono cancelGrant(String clientId, String userId) { - //删除refresh_token + //删除最新的refresh_token Mono removeRefreshToken = tokenRedis .opsForValue() .get(createUserTokenRedisKey(clientId, userId)) @@ -222,9 +224,18 @@ public Mono cancelGrant(String clientId, String userId) { if (!(createTokenType(clientId)).equals(token.getType())) { return Mono.empty(); } - //移除token return tokenRedis - .delete(createTokenRedisKey(clientId, token.getToken())) + .opsForValue() + .get(createTokenRedisKey(clientId, token.getToken())) + .flatMap(t -> { + //移除token + return tokenRedis + .delete(createTokenRedisKey(t.getClientId(), t.getAccessToken())) + //移除token对应的refresh_token + .then(tokenRedis + .opsForValue() + .delete(createRefreshTokenRedisKey(t.getClientId(), t.getRefreshToken()))); + }) .then(userTokenManager.signOutByToken(token.getToken())); }) .then(); From 9a48d78abe5335a8d79f38f90d906afc1fea3b3e Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 9 Sep 2022 14:18:45 +0800 Subject: [PATCH 227/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../token/redis/RedisUserTokenManager.java | 10 +++++--- .../web/bean/FastBeanCopier.java | 25 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index a33b5fa3f..f8b80b9e6 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -53,9 +53,13 @@ public RedisUserTokenManager(ReactiveRedisOperations operations) .buffer(Flux.interval(Duration.ofSeconds(10)), HashSet::new) .flatMap(list -> Flux .fromIterable(list) - .flatMap(token -> operations - .expire(getTokenRedisKey(token.getToken()), Duration.ofMillis(token.getMaxInactiveInterval())) - .then()) + .flatMap(token -> { + String key = getTokenRedisKey(token.getToken()); + return Mono + .zip(userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), + operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) + .then(); + }) .onErrorResume(err -> Mono.empty())) .subscribe(); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index de0eea385..b8ad202e9 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -21,6 +21,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -513,6 +514,8 @@ public Collection newCollection(Class targetClass) { if (targetClass == List.class) { return new ArrayList<>(); + } else if (targetClass == ConcurrentHashMap.KeySetView.class) { + return ConcurrentHashMap.newKeySet(); } else if (targetClass == Set.class) { return new HashSet<>(); } else if (targetClass == Queue.class) { @@ -568,7 +571,7 @@ public T convert(Object source, Class targetClass, Class[] genericType) { return (T) new Date(((Date) source).getTime()); } } - if (Collection.class.isAssignableFrom(targetClass)) { + if (target.isCollectionType()) { Collection collection = newCollection(targetClass); Collection sourceCollection; if (source instanceof Collection) { @@ -619,7 +622,7 @@ public T convert(Object source, Class targetClass, Class[] genericType) { Enum t = ((Enum) e); if ((t.name().equalsIgnoreCase(strSource) || Objects.equals(String.valueOf(t.ordinal()), strSource))) { - return (T)e; + return (T) e; } } @@ -642,7 +645,7 @@ public T convert(Object source, Class targetClass, Class[] genericType) { //快速复制map if (targetClass == Map.class) { if (source instanceof Map) { - return (T) new HashMap(((Map) source)); + return (T) copyMap(((Map) source)); } ClassDescription sourType = ClassDescriptions.getDescription(source.getClass()); return (T) copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize())); @@ -656,6 +659,22 @@ public T convert(Object source, Class targetClass, Class[] genericType) { // return null; } + private Map copyMap(Map map) { + if (map instanceof TreeMap) { + return new TreeMap<>(map); + } + + if (map instanceof LinkedHashMap) { + return new LinkedHashMap<>(map); + } + + if (map instanceof ConcurrentHashMap) { + return new ConcurrentHashMap<>(map); + } + + return new HashMap<>(map); + } + private Object converterByApache(Class targetClass, Object source) { org.apache.commons.beanutils.Converter converter = convertUtils.lookup(targetClass); if (null != converter) { From 24d8550bf6126d5e2bf307c0ead4de986be70f3c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 9 Sep 2022 14:19:30 +0800 Subject: [PATCH 228/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/token/redis/RedisUserTokenManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index f8b80b9e6..3ff4c2b26 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -56,8 +56,8 @@ public RedisUserTokenManager(ReactiveRedisOperations operations) .flatMap(token -> { String key = getTokenRedisKey(token.getToken()); return Mono - .zip(userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), - operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) + .zip(this.userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), + this.operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) .then(); }) .onErrorResume(err -> Mono.empty())) From c654222054c3a0ffed7b9693ba10755f2841826a Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 21 Sep 2022 11:06:05 +0800 Subject: [PATCH 229/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8DUpdateEvent=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E8=8E=B7=E5=8F=96=E4=BF=AE=E6=94=B9=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 94e82b682..aa4ae38b2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -133,39 +133,37 @@ protected void handleQueryBefore(EntityColumnMapping mapping, EventContext conte protected List createAfterData(List olds, EventContext context) { List newValues = new ArrayList<>(olds.size()); + EntityColumnMapping mapping = context .get(MappingContextKeys.columnMapping) .orElseThrow(UnsupportedOperationException::new); - TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new); - RDBColumnMetadata idColumn = table - .getColumns() - .stream() - .filter(RDBColumnMetadata::isPrimaryKey) - .findFirst() - .orElse(null); - if (idColumn == null) { - return Collections.emptyList(); - } + + Map columns = context + .get(MappingContextKeys.updateColumnInstance) + .orElse(Collections.emptyMap()); + for (Object old : olds) { - Object newValue = context - .get(MappingContextKeys.updateColumnInstance) - .map(map -> { - Object data = FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.newInstance())); - for (Map.Entry entry : map.entrySet()) { - //set null - if (entry.getValue() == null - || entry.getValue() instanceof NullValue) { - GlobalConfig - .getPropertyOperator() - .setProperty(data, entry.getKey(), null); - } - } - return data; - }) - .orElseThrow(() -> { - return new IllegalArgumentException("can not get update instance"); - }); - newValues.add(newValue); + Object data = FastBeanCopier.copy(old, mapping.newInstance()); + for (Map.Entry entry : columns.entrySet()) { + + RDBColumnMetadata column = mapping.getColumnByName(entry.getKey()).orElse(null); + if (column == null) { + continue; + } + + Object value = entry.getValue(); + + //set null + if (value instanceof NullValue) { + value = null; + } + + GlobalConfig + .getPropertyOperator() + .setProperty(data, column.getAlias(), value); + + } + newValues.add(data); } return newValues; } From 3e6bcec8115c5d5fe495cf4eaeb0a0ffe1e44e37 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 21 Sep 2022 11:06:09 +0800 Subject: [PATCH 230/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/factory/MapperEntityFactory.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) 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 c61c6f805..d1a201c41 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 @@ -27,8 +27,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; /** @@ -37,9 +39,11 @@ */ @SuppressWarnings("unchecked") public class MapperEntityFactory implements EntityFactory, BeanFactory { - private Map realTypeMapper = new HashMap<>(); - private Logger logger = LoggerFactory.getLogger(this.getClass()); - private Map copierCache = new HashMap<>(); + @SuppressWarnings("all") + private final Map, Mapper> realTypeMapper = new ConcurrentHashMap<>(); + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @SuppressWarnings("all") + private final Map copierCache = new ConcurrentHashMap<>(); private static final DefaultMapperFactory DEFAULT_MAPPER_FACTORY = clazz -> { String simpleClassName = clazz.getPackage().getName().concat(".Simple").concat(clazz.getSimpleName()); @@ -68,6 +72,16 @@ public MapperEntityFactory(Map, Mapper> realTypeMapper) { this.realTypeMapper.putAll(realTypeMapper); } + public MapperEntityFactory addMapping(Class target, Supplier mapper) { + realTypeMapper.put(target, new Mapper(target, mapper)); + return this; + } + + public MapperEntityFactory addMappingIfAbsent(Class target, Supplier mapper) { + realTypeMapper.putIfAbsent(target, new Mapper(target, mapper)); + return this; + } + public MapperEntityFactory addMapping(Class target, Mapper mapper) { realTypeMapper.put(target, mapper); return this; @@ -216,8 +230,8 @@ public void setDefaultPropertyCopier(DefaultPropertyCopier defaultPropertyCopier } public static class Mapper { - Class target; - Supplier instanceGetter; + final Class target; + final Supplier instanceGetter; public Mapper(Class target, Supplier instanceGetter) { this.target = target; @@ -242,16 +256,17 @@ public static Supplier defaultInstanceGetter(Class clazz) { } static class DefaultInstanceGetter implements Supplier { - Class type; + final Constructor constructor; + @SneakyThrows public DefaultInstanceGetter(Class type) { - this.type = type; + this.constructor = type.getConstructor(); } @Override @SneakyThrows public T get() { - return type.newInstance(); + return constructor.newInstance(); } } } From 87b921528f794d5e7994ed8fdcf8331cbbc7c8bf Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 28 Sep 2022 18:47:24 +0800 Subject: [PATCH 231/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A1=A8=E5=90=8D?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/terms/DimensionTerm.java | 20 +++++++++---------- .../service/terms/UserDimensionTerm.java | 2 +- pom.xml | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java index 9760376d2..11b447e7d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java @@ -28,19 +28,19 @@ public DimensionTerm() { } public static > T inject(T query, - String column, - String dimensionType, - List userId) { + String column, + String dimensionType, + List userId) { return inject(query, column, dimensionType, false, false, userId); } public static > T inject(T query, - String column, - String dimensionType, - boolean not, - boolean any, - List userId) { - return (T)query.accept(column, createTermType(dimensionType, not, any), userId); + String column, + String dimensionType, + boolean not, + boolean any, + List userId) { + return (T) query.accept(column, createTermType(dimensionType, not, any), userId); } public static String createTermType(String dimensionType, boolean not, boolean any) { @@ -73,7 +73,7 @@ public SqlFragments createFragments(String columnFullName, RDBColumnMetadata col fragments.addSql("not "); } fragments - .addSql("exists(select 1 from s_dimension_user d where d.dimension_type_id = ? and d.dimension_id =", columnFullName) + .addSql("exists(select 1 from", getTableName("s_dimension_user", column), "d where d.dimension_type_id = ? and d.dimension_id =", columnFullName) .addParameter(options.get(0)); if (!options.contains("any")) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java index 7078b197d..b63fc2b4f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java @@ -37,7 +37,7 @@ public SqlFragments createFragments(String columnFullName, RDBColumnMetadata col fragments.addSql("not"); } - fragments.addSql("exists(select 1 from s_dimension_user d where d.user_id =", columnFullName); + fragments.addSql("exists(select 1 from ",getTableName("s_dimension_user",column)," d where d.user_id =", columnFullName); if (options.size() > 0) { String typeId = options.get(0); diff --git a/pom.xml b/pom.xml index 8854cd5de..c2ad6774a 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.14 + 4.1.0-SNAPSHOT 3.0.2 3.0.2 2.7.0 From ffdd084920ed6e17c10e24032d887c67b16602e2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 14 Oct 2022 20:11:28 +0800 Subject: [PATCH 232/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/EasyormConfiguration.java | 18 +++-- .../crud/events/CompositeEventListener.java | 3 + .../web/crud/events/CreatorEventListener.java | 71 +++++++++++++------ .../web/crud/events/EntityEventListener.java | 11 +++ 4 files changed, 76 insertions(+), 27 deletions(-) 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 9042b6c9d..393ca3cb8 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 @@ -38,6 +38,8 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; @@ -112,22 +114,24 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw }; } + @Bean - public EntityEventListener entityEventListener(ApplicationEventPublisher eventPublisher, - ObjectProvider customizers) { - DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); - customizers.forEach(customizer -> customizer.customize(configure)); - return new EntityEventListener(eventPublisher, configure); + public CreatorEventListener creatorEventListener() { + return new CreatorEventListener(); } + @Bean public ValidateEventListener validateEventListener() { return new ValidateEventListener(); } @Bean - public CreatorEventListener creatorEventListener() { - return new CreatorEventListener(); + public EntityEventListener entityEventListener(ApplicationEventPublisher eventPublisher, + ObjectProvider customizers) { + DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); + customizers.forEach(customizer -> customizer.customize(configure)); + return new EntityEventListener(eventPublisher, configure); } @Bean diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java index 638850b9f..f07ece5db 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java @@ -5,7 +5,9 @@ import org.hswebframework.ezorm.rdb.events.EventContext; import org.hswebframework.ezorm.rdb.events.EventListener; import org.hswebframework.ezorm.rdb.events.EventType; +import org.springframework.core.Ordered; +import java.util.Comparator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -24,5 +26,6 @@ public void onEvent(EventType type, EventContext context) { public void addListener(EventListener eventListener) { eventListeners.add(eventListener); + eventListeners.sort(Comparator.comparingLong(e -> e instanceof Ordered ? ((Ordered) e).getOrder() : Ordered.LOWEST_PRECEDENCE)); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java index 9662899d3..722f18a11 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -12,19 +12,21 @@ import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.validator.CreateGroup; import org.hswebframework.web.validator.UpdateGroup; +import org.springframework.core.Ordered; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Consumer; /** * 自动填充创建人和修改人信息 */ -public class CreatorEventListener implements EventListener { +public class CreatorEventListener implements EventListener, Ordered { @Override public String getId() { @@ -60,27 +62,45 @@ public void onEvent(EventType type, EventContext context) { } protected void doApplyCreator(EventType type, EventContext context, Authentication auth) { - context.get(MappingContextKeys.instance) - .ifPresent(obj -> { - if (obj instanceof Collection) { - applyCreator(auth, ((Collection) obj), type != MappingEventTypes.update_before); - } else { - applyCreator(auth, obj, type != MappingEventTypes.update_before); - } - }); + Object instance = context.get(MappingContextKeys.instance).orElse(null); + if (instance != null) { + if (instance instanceof Collection) { + applyCreator(auth, context, ((Collection) instance), type != MappingEventTypes.update_before); + } else { + applyCreator(auth, context, instance, type != MappingEventTypes.update_before); + } + } else { + context.get(MappingContextKeys.updateColumnInstance) + .ifPresent(map -> { + applyCreator(auth, context, map, type != MappingEventTypes.update_before); + }); + } + + } - public void applyCreator(Authentication auth, Object entity, boolean updateCreator) { - if (updateCreator && entity instanceof RecordCreationEntity) { - RecordCreationEntity e = (RecordCreationEntity) entity; - if (ObjectUtils.isEmpty(e.getCreatorId())) { - e.setCreatorId(auth.getUser().getId()); - e.setCreatorName(auth.getUser().getName()); - } - if (e.getCreateTime() == null) { - e.setCreateTimeNow(); + public void applyCreator(Authentication auth, + EventContext context, + Object entity, + boolean updateCreator) { + if (updateCreator) { + if (entity instanceof RecordCreationEntity) { + RecordCreationEntity e = (RecordCreationEntity) entity; + if (ObjectUtils.isEmpty(e.getCreatorId())) { + e.setCreatorId(auth.getUser().getId()); + e.setCreatorName(auth.getUser().getName()); + } + if (e.getCreateTime() == null) { + e.setCreateTimeNow(); + } + } else if (entity instanceof Map) { + Map map = ((Map) entity); + map.putIfAbsent("creatorId", auth.getUser().getId()); + map.putIfAbsent("creatorName", auth.getUser().getName()); + map.putIfAbsent("createTime", auth.getUser().getId()); } + } if (entity instanceof RecordModifierEntity) { RecordModifierEntity e = (RecordModifierEntity) entity; @@ -91,13 +111,24 @@ public void applyCreator(Authentication auth, Object entity, boolean updateCreat if (e.getModifyTime() == null) { e.setModifyTimeNow(); } + } else if (entity instanceof Map) { + Map map = ((Map) entity); + map.putIfAbsent("modifierId", auth.getUser().getId()); + map.putIfAbsent("modifierName", auth.getUser().getName()); + map.putIfAbsent("modifyTime", auth.getUser().getId()); + } } - public void applyCreator(Authentication auth, Collection entities, boolean updateCreator) { + public void applyCreator(Authentication auth, EventContext context, Collection entities, boolean updateCreator) { for (Object entity : entities) { - applyCreator(auth, entity, updateCreator); + applyCreator(auth, context, entity, updateCreator); } } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index aa4ae38b2..b88ea7ecf 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -142,6 +142,17 @@ protected List createAfterData(List olds, .get(MappingContextKeys.updateColumnInstance) .orElse(Collections.emptyMap()); + List newerInstance = context + .get(MappingContextKeys.instance) + .map(instance -> { + if (instance instanceof List) { + return ((List) instance); + } + return Collections.singletonList(instance); + }) + .orElse(null); + + for (Object old : olds) { Object data = FastBeanCopier.copy(old, mapping.newInstance()); for (Map.Entry entry : columns.entrySet()) { From bff95506b158037c5208abef6bb3c64862319598 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 14 Oct 2022 20:12:36 +0800 Subject: [PATCH 233/542] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E6=B8=85=E9=99=A4=E7=94=A8=E6=88=B7=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/DefaultDimensionUserService.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index af9489925..538d345a7 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -56,9 +56,6 @@ public void handleUserDeleteEntity(UserDeletedEvent event) { public void dispatchDimensionBind(EntitySavedEvent event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } @@ -67,9 +64,6 @@ public void dispatchDimensionBind(EntitySavedEvent event) { public void dispatchDimensionBind(EntityCreatedEvent event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } @@ -78,9 +72,6 @@ public void dispatchDimensionBind(EntityCreatedEvent event) public void dispatchDimensionUnbind(EntityDeletedEvent event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionUnbindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } From df145478164f82467d86173899ad3c8842232899 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 17 Oct 2022 11:32:32 +0800 Subject: [PATCH 234/542] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/CreatorEventListener.java | 17 ++++++++-------- .../web/crud/events/EntityEventListener.java | 20 ++++++++----------- .../crud/events/ValidateEventListener.java | 8 +++++++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java index 722f18a11..54f1f14af 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -69,13 +69,11 @@ protected void doApplyCreator(EventType type, EventContext context, Authenticati } else { applyCreator(auth, context, instance, type != MappingEventTypes.update_before); } - } else { - context.get(MappingContextKeys.updateColumnInstance) - .ifPresent(map -> { - applyCreator(auth, context, map, type != MappingEventTypes.update_before); - }); } + context + .get(MappingContextKeys.updateColumnInstance) + .ifPresent(map -> applyCreator(auth, context, map, type != MappingEventTypes.update_before)); } @@ -83,6 +81,7 @@ public void applyCreator(Authentication auth, EventContext context, Object entity, boolean updateCreator) { + long now = System.currentTimeMillis(); if (updateCreator) { if (entity instanceof RecordCreationEntity) { RecordCreationEntity e = (RecordCreationEntity) entity; @@ -91,13 +90,13 @@ public void applyCreator(Authentication auth, e.setCreatorName(auth.getUser().getName()); } if (e.getCreateTime() == null) { - e.setCreateTimeNow(); + e.setCreateTime(now); } } else if (entity instanceof Map) { Map map = ((Map) entity); map.putIfAbsent("creatorId", auth.getUser().getId()); map.putIfAbsent("creatorName", auth.getUser().getName()); - map.putIfAbsent("createTime", auth.getUser().getId()); + map.putIfAbsent("createTime", now); } @@ -109,13 +108,13 @@ public void applyCreator(Authentication auth, e.setModifierName(auth.getUser().getName()); } if (e.getModifyTime() == null) { - e.setModifyTimeNow(); + e.setModifyTime(now); } } else if (entity instanceof Map) { Map map = ((Map) entity); map.putIfAbsent("modifierId", auth.getUser().getId()); map.putIfAbsent("modifierName", auth.getUser().getName()); - map.putIfAbsent("modifyTime", auth.getUser().getId()); + map.putIfAbsent("modifyTime", now); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index b88ea7ecf..033719238 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -22,6 +22,7 @@ import org.hswebframework.web.event.AsyncEvent; import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.Ordered; import reactor.core.publisher.Mono; import reactor.function.Function3; import reactor.util.function.Tuple2; @@ -36,7 +37,7 @@ @SuppressWarnings("all") @AllArgsConstructor -public class EntityEventListener implements EventListener { +public class EntityEventListener implements EventListener, Ordered { private final ApplicationEventPublisher eventPublisher; @@ -142,17 +143,6 @@ protected List createAfterData(List olds, .get(MappingContextKeys.updateColumnInstance) .orElse(Collections.emptyMap()); - List newerInstance = context - .get(MappingContextKeys.instance) - .map(instance -> { - if (instance instanceof List) { - return ((List) instance); - } - return Collections.singletonList(instance); - }) - .orElse(null); - - for (Object old : olds) { Object data = FastBeanCopier.copy(old, mapping.newInstance()); for (Map.Entry entry : columns.entrySet()) { @@ -239,6 +229,7 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) holder.invoke(this.doAsyncEvent(() -> { Tuple2, List> _tmp = updated.get(); if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), _tmp.getT2(), entityType, @@ -477,4 +468,9 @@ protected Mono doAsyncEvent(Supplier> eventSupplier) { return eventSupplier.get(); }); } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 342dc9e92..75f70d816 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -10,11 +10,12 @@ import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.validator.CreateGroup; import org.hswebframework.web.validator.UpdateGroup; +import org.springframework.core.Ordered; import java.util.List; import java.util.Optional; -public class ValidateEventListener implements EventListener { +public class ValidateEventListener implements EventListener, Ordered { @Override public String getId() { @@ -73,4 +74,9 @@ public void tryValidate(EventType type, EventContext context) { .ifPresent(entity -> entity.tryValidate(UpdateGroup.class)); } } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE - 100; + } } From 7529d9201ffa45dca41c46f0b5122b717a362f65 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 21 Oct 2022 19:13:16 +0800 Subject: [PATCH 235/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/CompositeReactiveAuthenticationManager.java | 7 ++++++- .../web/cache/supports/RedisReactiveCache.java | 5 ++--- .../web/cache/supports/UnSupportedReactiveCache.java | 5 +++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java index 7a1d5502e..79c2037c4 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -1,6 +1,7 @@ package org.hswebframework.web.authorization.simple; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.hswebframework.web.authorization.*; import reactor.core.publisher.Flux; @@ -11,6 +12,7 @@ import java.util.stream.Collectors; @AllArgsConstructor +@Slf4j public class CompositeReactiveAuthenticationManager implements ReactiveAuthenticationManager { private final List providers; @@ -34,7 +36,10 @@ public Mono getByUserId(String userId) { .stream() .map(manager -> manager .getByUserId(userId) - .onErrorResume((err) -> Mono.empty()) + .onErrorResume((err) -> { + log.warn("get user [{}] authentication error", userId, err); + return Mono.empty(); + }) )) .flatMap(Function.identity()) .collectList() diff --git a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java index df5b53a8c..c8d6f4387 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java +++ b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java @@ -64,9 +64,8 @@ public Flux getFlux(Object key) { } protected Mono handleError(Throwable error) { - return Mono.fromRunnable(() -> { - log.error(error.getMessage(), error); - }); + log.error(error.getMessage(), error); + return Mono.empty(); } @Override diff --git a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java index 4200e2de7..68a2b8ed2 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java +++ b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java @@ -15,10 +15,11 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class UnSupportedReactiveCache implements ReactiveCache { - private static final UnSupportedReactiveCache INSTANCE = new UnSupportedReactiveCache(); + private static final UnSupportedReactiveCache INSTANCE = new UnSupportedReactiveCache<>(); + @SuppressWarnings("all") public static ReactiveCache getInstance() { - return INSTANCE; + return (UnSupportedReactiveCache)INSTANCE; } @Override From ce703c401efd0496c2ca5f85018cf2a60134369b Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 21 Oct 2022 19:14:49 +0800 Subject: [PATCH 236/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/CompositeReactiveAuthenticationManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java index 79c2037c4..c7a6dc643 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -23,7 +23,10 @@ public Mono authenticate(Mono request) { .stream() .map(manager -> manager .authenticate(request) - .onErrorResume((err) -> Mono.empty())) + .onErrorResume((err) -> { + log.warn("get user authenticate error", err); + return Mono.empty(); + })) .collect(Collectors.toList())) .take(1) .next(); From b3ba02961bc59715e90c370cf1483150a66a3559 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 24 Oct 2022 13:35:48 +0800 Subject: [PATCH 237/542] =?UTF-8?q?=E4=BC=98=E5=8C=96cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/crud/events/EntityEventListener.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 033719238..6366b0a68 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -39,6 +39,9 @@ @AllArgsConstructor public class EntityEventListener implements EventListener, Ordered { + public static final ContextKey> readyToDeleteContextKey = ContextKey.of("readyToDelete"); + public static final ContextKey> readyToUpdateContextKey = ContextKey.of("readyToUpdate"); + private final ApplicationEventPublisher eventPublisher; private final EntityEventListenerConfigure listenerConfigure; @@ -214,6 +217,7 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) .collectList() .flatMap((list) -> { List after = createAfterData(list, context); + context.set(readyToUpdateContextKey,after); updated.set(Tuples.of(list, after)); return sendUpdateEvent(list, after, @@ -299,6 +303,7 @@ protected void handleDeleteBefore(Class entityType, EventContext context .collectList() .filter(CollectionUtils::isNotEmpty) .flatMap(list -> { + context.set(readyToDeleteContextKey,list); deleted.set(list); return this .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); From fa3b0a67d0b98294f8e72af17faba01b9bf154bb Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 25 Oct 2022 18:42:42 +0800 Subject: [PATCH 238/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 7 ++++--- .../web/crud/events/ValidateEventListener.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 6366b0a68..80e31bf9a 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -217,7 +217,6 @@ protected void handleUpdateBefore(DSLUpdate update, EventContext context) .collectList() .flatMap((list) -> { List after = createAfterData(list, context); - context.set(readyToUpdateContextKey,after); updated.set(Tuples.of(list, after)); return sendUpdateEvent(list, after, @@ -301,9 +300,11 @@ protected void handleDeleteBefore(Class entityType, EventContext context .setParam(dslUpdate.toQueryParam()) .fetch() .collectList() + .doOnNext(list->{ + context.set(readyToDeleteContextKey, list); + }) .filter(CollectionUtils::isNotEmpty) .flatMap(list -> { - context.set(readyToDeleteContextKey,list); deleted.set(list); return this .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); @@ -476,6 +477,6 @@ protected Mono doAsyncEvent(Supplier> eventSupplier) { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; + return Ordered.LOWEST_PRECEDENCE - 100; } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 75f70d816..4d52c1c14 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -77,6 +77,6 @@ public void tryValidate(EventType type, EventContext context) { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE - 100; + return Ordered.LOWEST_PRECEDENCE - 1000; } } From 8fad92100a6e672a0adaf64f29857f3e70f5b77c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 27 Oct 2022 17:20:01 +0800 Subject: [PATCH 239/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=86=85=E5=B5=8C?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../embed/EmbedAuthenticationProperties.java | 31 ++++++++++++------- .../EmbedReactiveAuthenticationManager.java | 13 +++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java index e4a09e3c0..1b35e4b1a 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java @@ -2,6 +2,7 @@ import lombok.Getter; import lombok.Setter; +import org.apache.commons.collections4.MapUtils; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationRequest; import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; @@ -69,7 +70,10 @@ public void afterPropertiesSet() { for (Map.Entry stringObjectEntry : objectMap.entrySet()) { if (stringObjectEntry.getValue() instanceof Map) { Map mapVal = ((Map) stringObjectEntry.getValue()); - boolean maybeIsList = mapVal.keySet().stream().allMatch(org.hswebframework.utils.StringUtils::isInt); + boolean maybeIsList = mapVal + .keySet() + .stream() + .allMatch(org.hswebframework.utils.StringUtils::isInt); if (maybeIsList) { stringObjectEntry.setValue(mapVal.values()); } @@ -82,20 +86,23 @@ public void afterPropertiesSet() { } public Authentication authenticate(AuthenticationRequest request) { - if(request instanceof PlainTextUsernamePasswordAuthenticationRequest){ + if (MapUtils.isEmpty(users)) { + return null; + } + if (request instanceof PlainTextUsernamePasswordAuthenticationRequest) { PlainTextUsernamePasswordAuthenticationRequest pwdReq = ((PlainTextUsernamePasswordAuthenticationRequest) request); - return users.values() - .stream() - .filter(user -> - pwdReq.getUsername().equals(user.getUsername()) - && pwdReq.getPassword().equals(user.getPassword())) - .findFirst() - .map(EmbedAuthenticationInfo::getId) - .map(authentications::get) - .orElseThrow(() -> new ValidationException("用户不存在")); + for (EmbedAuthenticationInfo user : users.values()) { + if (pwdReq.getUsername().equals(user.getUsername())) { + if (pwdReq.getPassword().equals(user.getPassword())) { + return user.toAuthentication(dataAccessConfigBuilderFactory); + } + return null; + } + } + return null; } - throw new UnsupportedOperationException("不支持的授权请求:"+request); + throw new UnsupportedOperationException("不支持的授权请求:" + request); } public Optional getAuthentication(String userId) { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java index 6aabf28d9..94fbd6739 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java @@ -1,6 +1,8 @@ package org.hswebframework.web.authorization.basic.embed; import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationRequest; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; @@ -22,7 +24,16 @@ public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticatio @Override public Mono authenticate(Mono request) { - return request.map(properties::authenticate); + if (MapUtils.isEmpty(properties.getUsers())) { + return Mono.empty(); + } + return request. + handle((req, sink) -> { + Authentication auth = properties.authenticate(req); + if (auth != null) { + sink.next(auth); + } + }); } From 1bef816dc64956f8af622927d99272b1f0a31359 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 31 Oct 2022 19:03:34 +0800 Subject: [PATCH 240/542] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/ResponseMessageWrapperAdvice.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java index b57bcc504..d4f32299c 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java @@ -20,6 +20,7 @@ import reactor.core.publisher.Mono; import javax.annotation.Nonnull; +import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; @@ -82,17 +83,21 @@ public Object beforeBodyWrite(Object body, if (body instanceof Mono) { return ((Mono) body) .map(ResponseMessage::ok) - .switchIfEmpty(Mono.just(ResponseMessage.ok())); + .switchIfEmpty(Mono.fromSupplier(ResponseMessage::ok)); } if (body instanceof Flux) { return ((Flux) body) .collectList() .map(ResponseMessage::ok) - .switchIfEmpty(Mono.just(ResponseMessage.ok())); + .switchIfEmpty(Mono.fromSupplier(ResponseMessage::ok)); } - if (body instanceof String) { + + Method method = returnType.getMethod(); + + if (method != null && returnType.getMethod().getReturnType() == String.class) { return JSON.toJSONString(ResponseMessage.ok(body)); } + return ResponseMessage.ok(body); } From 50667b9b21dc4cb748b4952537261e533b8362da Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 28 Nov 2022 11:56:57 +0800 Subject: [PATCH 241/542] =?UTF-8?q?=E4=BC=98=E5=8C=96map=E8=BD=AClist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/bean/FastBeanCopier.java | 15 +++++ .../web/bean/FastBeanCopierTest.java | 61 +++++++++++++++---- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index b8ad202e9..909c99343 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -578,6 +578,8 @@ public T convert(Object source, Class targetClass, Class[] genericType) { sourceCollection = (Collection) source; } else if (source instanceof Object[]) { sourceCollection = Arrays.asList((Object[]) source); + } else if (source instanceof Map) { + sourceCollection = ((Map) source).values(); } else { if (source instanceof String) { String stringValue = ((String) source); @@ -647,6 +649,19 @@ public T convert(Object source, Class targetClass, Class[] genericType) { if (source instanceof Map) { return (T) copyMap(((Map) source)); } + if (source instanceof Collection) { + Map map = new LinkedHashMap<>(); + int i = 0; + for (Object o : ((Collection) source)) { + if (genericType.length >= 2) { + map.put(convert(i++, genericType[0], EMPTY_CLASS_ARRAY), convert(o, genericType[1], EMPTY_CLASS_ARRAY)); + } else { + map.put(i++, o); + } + } + return (T) map; + + } ClassDescription sourType = ClassDescriptions.getDescription(source.getClass()); return (T) copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize())); } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java index fe7e177e4..0c73a2b45 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java @@ -1,16 +1,14 @@ package org.hswebframework.web.bean; import com.google.common.collect.ImmutableMap; -import jdk.nashorn.internal.objects.annotations.Getter; +import lombok.Getter; +import lombok.Setter; import org.junit.Assert; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; /** @@ -61,6 +59,43 @@ public void testMapArray() { } + @Test + public void testMapList() { + Map data = new HashMap<>(); + data.put("templates", new HashMap() { + { + put("0", Collections.singletonMap("name", "test")); + put("1", Collections.singletonMap("name", "test")); + } + }); + + Config config = FastBeanCopier.copy(data, new Config()); + + Assert.assertNotNull(config); + Assert.assertNotNull(config.templates); + System.out.println(config.templates); + Assert.assertEquals(2,config.templates.size()); + + + } + + @Getter + @Setter + public static class Config { + private List