xiejun
2024-11-01 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a
Revert "集成获取mdm分发通用数据格式接口集成"

This reverts commit 7f5df0954989899974bdb891fde11431b7048e9f.
已修改1个文件
已删除9个文件
已添加648个文件
62674 ■■■■■ 文件已修改
Source/BladeX-Tool/.editorconfig 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/.gitignore 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/LICENSE 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/README.md 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-bom/pom.xml 626 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/README.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/pom.xml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoContextInitializer.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoEnvPostProcessor.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoFailureAnalyzer.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoIgnore.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoListener.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoRunListener.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/AbstractBladeProcessor.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/BootAutoType.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/MultiSetMap.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/Sets.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/TypeHelper.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/factories/AutoFactoriesProcessor.java 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/factories/FactoriesFiles.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/AutoService.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/AutoServiceProcessor.java 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/ServicesFiles.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-auto/src/main/resources/META-INF/services/javax.annotation.processing.Processor 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/pom.xml 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeBootAutoConfiguration.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeExecutorConfiguration.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeRetryConfiguration.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeWebMvcConfiguration.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/RequestConfiguration.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/ctrl/BladeController.java 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/error/ErrorType.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/error/ErrorUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/BladeFileUtil.java 240 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/FileProxyManager.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/IFileProxy.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/LocalFile.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/LocalFileProxyFactory.java 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/props/BladeFileProperties.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/props/BladeUploadProperties.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/BladeHttpServletRequestWrapper.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/BladeRequestFilter.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/RequestProperties.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssHtmlFilter.java 536 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssHttpServletRequestWrapper.java 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssProperties.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/resolver/TokenArgumentResolver.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/resources/banner.txt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/resources/blade-boot.yml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-boot/src/main/resources/static/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/pom.xml 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/ApiVersion.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/UrlVersion.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/VersionMapping.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/client/BladeCloudApplication.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFallbackFactory.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignFallback.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignRequestInterceptor.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/EnableBladeFeign.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpConfiguration.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpProperties.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/LbRestTemplate.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateHeaderInterceptor.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/logger/HttpLoggingInterceptor.java 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/logger/OkHttpSlf4jLogger.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeFeignSentinel.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelAutoConfiguration.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelFilterConfiguration.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelInvocationHandler.java 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/server/UndertowHttp2Configuration.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeMediaType.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeRequestMappingHandlerMapping.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeSpringMvcContract.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeWebMvcRegistrations.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/VersionMappingAutoConfiguration.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/pom.xml 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeCallableWrapper.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeContext.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeHttpHeadersGetter.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeRunnableWrapper.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeServletContext.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/ServletHttpHeadersGetter.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/config/BladeContextAutoConfiguration.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/config/BladeServletListenerConfiguration.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/listener/BladeServletRequestListener.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/props/BladeContextProperties.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-db/pom.xml 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-db/src/main/java/org/springblade/core/db/config/DbConfiguration.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-db/src/main/java/org/springblade/core/db/package-info.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-db/src/main/resources/blade-db.yml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/pom.xml 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/StartEventListener.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladeLaunchConfiguration.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladePropertyConfiguration.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/ConsulConstant.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/FlowConstant.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/ZookeeperConstant.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/log/BladeLogLevel.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladeProperties.java 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySource.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySourcePostProcessor.java 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/server/ServerInfo.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/service/LauncherService.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/utils/INetUtil.java 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/utils/PropsUtil.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/java/org/springblade/core/log4j2/LogLauncherServiceImpl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/java/org/springblade/core/log4j2/LogPrintStream.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_appenders.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_dev.xml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_ontest.xml 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_prod.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_test.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/pom.xml 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/aspect/AuthAspect.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/auth/AuthFun.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/AuthConstant.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/PermissionConstant.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/SecureConstant.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/BladePermissionHandler.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/IPermissionHandler.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/ISecureHandler.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/SecureHandlerHandler.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/AuthInterceptor.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/BasicInterceptor.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/ClientInterceptor.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SignInterceptor.java 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/TokenInterceptor.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/AuthSecure.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/BasicSecure.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeSecureProperties.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/ClientSecure.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/SignSecure.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetails.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetailsServiceImpl.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/HttpMethod.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetails.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetailsService.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ResponseProvider.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-test/pom.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeBootTest.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeBootTestException.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeSpringExtension.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/pom.xml 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/IResultCode.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/R.java 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/ResultCode.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BeanProperty.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java 405 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopierKey.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMap.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMapEmitter.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMapKey.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/CopyProperty.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/BladeConverterConfiguration.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/ToolConfiguration.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/constant/RoleConstant.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/BladeConversionService.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/BladeConverter.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/EnumToStringConverter.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/StringToEnumConverter.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedCallable.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedComparator.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedConsumer.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedFunction.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedRunnable.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedSupplier.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BigNumberSerializer.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeBeanSerializerModifier.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJacksonProperties.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJavaTimeModule.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeNumberModule.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java 705 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/BaseNode.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNode.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNodeManager.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNodeMerger.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/INode.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/NodeTest.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/TreeNode.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/spel/BladeExpressionEvaluator.java 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/spel/BladeExpressionRootObject.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/ssl/DisableValidationTrustManager.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/ssl/TrustAllHostNames.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/BeanDiff.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/BinderSupplier.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/CoreMain.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/FastStringWriter.java 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/IMultiOutputStream.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/ImagePosition.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/StrSpliter.java 501 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/Try.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/tuple/KeyPair.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/tuple/Pair.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AntPathFilter.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Base64Util.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java 424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CharPool.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CollectionUtil.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ConcurrentDateFormat.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ConvertUtil.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DatatypeConverterUtil.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateTimeUtil.java 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java 634 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DesUtil.java 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DigestUtil.java 450 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Exceptions.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/FileUtil.java 383 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Func.java 2156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/HexUtil.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Holder.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ImageUtil.java 489 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/IntegerPool.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/IoUtil.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Lazy.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/NumberUtil.java 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ObjectUtil.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PathUtil.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PlaceholderUtil.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ProtostuffUtil.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RandomType.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ReflectUtil.java 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RegexUtil.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ResourceUtil.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RsaUtil.java 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RuntimeUtil.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SpringUtil.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringPool.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java 1577 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SuffixFileFilter.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ThreadLocalUtil.java 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ThreadUtil.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Unchecked.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/UrlUtil.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Version.java 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/XmlUtil.java 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/yml/YmlPropertyLoaderFactory.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/README.md 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/pom.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/BladeHttpCacheProperties.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheAble.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheConfiguration.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheInterceptor.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheService.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/README.md 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/pom.xml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCrypto.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoAes.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoDes.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoRsa.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecrypt.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptAes.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptDes.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptRsa.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncrypt.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptAes.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptDes.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptRsa.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/bean/CryptoInfoBean.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/bean/DecryptHttpInputMessage.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoConfiguration.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoProperties.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptParamResolver.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptRequestBodyAdvice.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiEncryptResponseBodyAdvice.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/enums/CryptoType.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/DecryptBodyFailException.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptBodyFailException.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptMethodNotFoundException.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/KeyNotConfiguredException.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/util/ApiCryptoUtil.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/pom.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/AuthInfo.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/BladeUser.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/TokenInfo.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/exception/SecureException.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/utils/AuthUtil.java 449 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-cache/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/config/CacheConfiguration.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/constant/CacheConstant.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/utils/CacheUtil.java 331 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/pom.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/annotation/DataAuth.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/config/DataScopeConfiguration.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/constant/DataScopeConstant.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/enums/DataScopeEnum.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/exception/DataScopeException.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/BladeDataScopeHandler.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/BladeScopeModelHandler.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/DataScopeHandler.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/ScopeModelHandler.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/interceptor/DataScopeInterceptor.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/props/DataScopeProperties.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/CodeGenerator.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/support/BladeTemplateEngine.java 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/beetl.properties 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/controller.java.btl 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entity.java.btl 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entityDTO.java.btl 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entityVO.java.btl 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/feign.java.btl 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/feignclient.java.btl 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/mapper.java.btl 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/mapper.xml.btl 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/service.java.btl 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/serviceImpl.java.btl 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/wrapper.java.btl 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/code.properties 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/api.js.btl 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/const.js.btl 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/crud.vue.btl 347 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/api.js.btl 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/const.js.btl 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/crud.vue.btl 375 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/sub.vue.btl 358 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/api.js.btl 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/const.js.btl 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/crud.vue.btl 360 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/Modal.vue.btl 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/data.data.ts.btl 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/data.ts.btl 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/index.vue.btl 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/Modal.vue.btl 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/data.data.ts.btl 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/data.ts.btl 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/index.vue.btl 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/sub.vue.btl 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/Modal.vue.btl 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/data.data.ts.btl 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/data.ts.btl 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/index.vue.btl 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/api.js.btl 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/const.js.btl 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/crud.vue.btl 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/api.js.btl 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/const.js.btl 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/crud.vue.btl 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/api.js.btl 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/const.js.btl 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/crud.vue.btl 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sql/menu.sql.btl 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/action.js.vm 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/add.js.vm 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/edit.js.vm 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/list.js.vm 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/model.js.vm 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/service.js.vm 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/view.js.vm 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-ehcache/pom.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-ehcache/src/main/java/org/springblade/core/ehcache/EhcacheConfiguration.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-ehcache/src/main/resources/ehcache.xml 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/pom.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/listener/DataListener.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/listener/ImportListener.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/support/ExcelException.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/support/ExcelImporter.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/util/ExcelUtil.java 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-flowable/pom.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-flowable/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java 1647 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-flowable/src/main/java/org/flowable/common/engine/impl/db/LiquibaseBasedSchemaManager.java 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-flowable/src/main/resources/processes/LeaveProcess.bpmn20.xml 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/pom.xml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/AsyncCall.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/AsyncCallback.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/BaseAuthenticator.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/CssQuery.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/CssQueryMethodInterceptor.java 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/DomMapper.java 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Exchange.java 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/FormBuilder.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/HttpRequest.java 492 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/HttpResponse.java 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/LogLevel.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Method.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/MultipartFormBuilder.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/ResponseSpec.java 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/RetryInterceptor.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/RetryPolicy.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Slf4jLogger.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/util/HttpUtil.java 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/BladeProxySelector.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/HttpRequestDemo.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/HttpRequestProxyTest.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/OsChina.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/OsChinaTest.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/VBlog.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/VNews.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/JwtUtil.java 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/config/JwtConfiguration.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/config/JwtRedisConfiguration.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/constant/JwtConstant.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/props/JwtProperties.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/serializer/JwtRedisKeySerializer.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/pom.xml 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/config/BladeLoadBalancerConfiguration.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/constant/LoadBalancerConstant.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/rule/GrayscaleEnvPostProcessor.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/rule/GrayscaleLoadBalancer.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/pom.xml 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/annotation/ApiLog.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/ApiLogAspect.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/LogTraceAspect.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/RequestLogAspect.java 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/constant/EventConstant.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/RestExceptionTranslator.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ApiLogEvent.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ApiLogListener.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ErrorLogEvent.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/UsualLogEvent.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/UsualLogListener.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/exception/ServiceException.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/feign/ILogClient.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/feign/LogClientFallback.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/filter/LogTraceFilter.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/launch/LogLauncherServiceImpl.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/listener/LoggerStartupListener.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/logger/BladeLogger.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogAbstract.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogApi.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogError.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogUsual.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/props/BladeRequestLogProperties.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/ElkPropsUtil.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/LogTraceUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/resources/blade-log.yml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-dev.xml 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-prod.xml 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-test.xml 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-metrics/pom.xml 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/druid/DruidDataSourceMetadataProviderConfiguration.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/druid/DruidDataSourcePoolMetadata.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/sentinel/SentinelMetricsExtension.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/pom.xml 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/config/MongoConfiguration.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/converter/DBObjectToJsonNodeConverter.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/converter/JsonNodeToDocumentConverter.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/utils/JsonNodeInfo.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/utils/MongoJsonUtils.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/pom.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/BladeMetaObjectHandler.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/config/MybatisPlusConfiguration.java 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/BladeSqlInjector.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/BladeSqlMethod.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/AbstractInsertMethod.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/InsertIgnore.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/Replace.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/mapper/BladeMapper.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/BladePaginationInterceptor.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/QueryInterceptorExecutor.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/SqlLogInterceptor.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/props/MybatisPlusProperties.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/resolver/PageArgumentResolver.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/service/BladeService.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/service/impl/BladeServiceImpl.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/BaseEntityWrapper.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/BladePage.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/Condition.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/Query.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/SqlKeyword.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/utils/PageUtil.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-mybatis/src/main/resources/blade-mybatis.yml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/pom.xml 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/HuaweiObsTemplate.java 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/MinioTemplate.java 418 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/OssTemplate.java 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/TencentCosTemplate.java 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/HuaweiObsConfiguration.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/MinioConfiguration.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/OssConfiguration.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/TencentCosConfiguration.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/OssEnum.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/OssStatusEnum.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/PolicyType.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/MinioItem.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/OssFile.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/rule/BladeOssRule.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/rule/OssRule.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/pom.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/config/PrometheusConfiguration.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Agent.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/ChangeItem.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Config.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Service.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/ServiceHealth.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/endpoint/AgentEndpoint.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/endpoint/ServiceEndpoint.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/service/RegistrationService.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-prometheus/src/main/resources/blade-prometheus.yml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/pom.xml 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/BladeRedis.java 824 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/CacheKey.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/ICacheKey.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisCacheAutoConfiguration.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisProperties.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisSerializerConfigAble.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/ProtoStuffSerializerConfiguration.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RateLimiterAutoConfiguration.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisAutoCacheManager.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisCacheManagerConfig.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisTemplateConfiguration.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/BladeLockAutoConfiguration.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/BladeLockProperties.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/LockType.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLock.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockAspect.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockClient.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockClientImpl.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiter.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiterClient.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiterException.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RedisRateLimiterAspect.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RedisRateLimiterClient.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/BytesWrapper.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/ProtoStuffSerializer.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/RedisKeySerializer.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/resources/META-INF/scripts/blade_rate_limiter.lua 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-redis/src/main/resources/additional-spring-configuration-metadata.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/pom.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/datasource/ReportDataSource.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/endpoint/ReportBootEndpoint.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/endpoint/ReportEndpoint.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/entity/ReportFileEntity.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/mapper/ReportFileMapper.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportDatabaseProperties.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/provider/DatabaseProvider.java 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/provider/ReportPlaceholderProvider.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/service/IReportFileService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/service/impl/ReportFileServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/pom.xml 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/AliSmsTemplate.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/QiniuSmsTemplate.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/SmsTemplate.java 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/TencentSmsTemplate.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/YunpianSmsTemplate.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/AliSmsConfiguration.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/QiniuSmsConfiguration.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/SmsConfiguration.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/TencentSmsConfiguration.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/YunpianSmsConfiguration.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/constant/SmsConstant.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/enums/SmsEnum.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/enums/SmsStatusEnum.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsCode.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsData.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsInfo.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsResponse.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/props/SmsProperties.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/cache/AuthStateRedisCache.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/config/SocialConfiguration.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/props/SocialProperties.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/utils/SocialUtil.java 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-social/src/main/resources/blade-social.yml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/pom.xml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/EnableSwagger.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerAutoConfiguration.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerHandlerConfiguration.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerUtil.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerWebConfiguration.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-swagger/src/main/resources/blade-swagger.yml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/pom.xml 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantHandler.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantHolder.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantId.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantInterceptor.java 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantProperties.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/TenantId.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/NonDS.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TableExclude.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantDS.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantIgnore.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantParamDS.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/aspect/BladeTenantAspect.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/config/TenantConfiguration.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/config/TenantDataSourceConfiguration.java 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/constant/TenantBaseConstant.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/DsTenantIdProcessor.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSource.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceAnnotationInterceptor.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceGlobalAdvisor.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceGlobalInterceptor.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceHolder.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceJdbcProvider.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/exception/TenantDataSourceException.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/launcher/TenantLauncherServiceImpl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/mp/TenantEntity.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-trace/pom.xml 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-trace/src/main/java/org/springblade/core/trace/TraceAutoConfiguration.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-trace/src/main/resources/blade-trace.yml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-transaction/pom.xml 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-transaction/src/main/java/org/springblade/core/transaction/annotation/SeataCloudApplication.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-transaction/src/main/java/org/springblade/core/transaction/config/TransactionConfiguration.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-transaction/src/main/resources/blade-transaction.yml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/blade-starter-transaction/src/main/resources/file.conf 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/doc/mvn/mvn命令.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/pom.xml 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MDMData.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MDMParamData.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MdmResultData.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/data.json 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/CodeSyncUniversalController.java 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/RedirectViewController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/CodeMdmInfaceI.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeMdmInfaceImpl.java 808 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/webService/config/ClassifyConfig.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/webService/config/MDMInterFaceConfig.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/BladeX-Tool/.editorconfig
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
# http://editorconfig.org
root = true
# ç©ºæ ¼æ›¿ä»£Tab缩进在各种编辑工具下效果一致
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.java]
indent_style = tab
[*.{json,yml}]
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
Source/BladeX-Tool/.gitignore
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
# maven #
target
logs
# windows #
Thumbs.db
# Mac #
.DS_Store
# eclipse #
.settings
.project
.classpath
.log
*.class
# idea #
.idea
*.iml
# Package Files #
*.jar
*.war
*.ear
/target
Source/BladeX-Tool/LICENSE
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
BladeX商业授权许可协议
一、 çŸ¥è¯†äº§æƒï¼š
BladeX系列产品知识产权归上海布雷德科技有限公司独立所有
二、 è®¸å¯ï¼š
1. åœ¨æ‚¨å®Œå…¨æŽ¥å—并遵守本协议的基础上,本协议授予您使用BladeX的某些权利和非独占性许可。
2. æœ¬åè®®ä¸­ï¼Œå°†æœ¬äº§å“ä½¿ç”¨ç”¨é€”分为“专业版用途”和“企业版用途”。
3. â€œä¸“业版用途”定义:指个人在非团体机构中出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
4. â€œä¼ä¸šç‰ˆç”¨é€””定义:指团体机构(例如公司企业、政府、学校、军队、医院、社会团体等各类组织)(不包含集团,若集团使用则需为各个子公司分别购买企业授权)出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
三、 çº¦æŸå’Œé™åˆ¶ï¼š
1. æœ¬äº§å“åªèƒ½ç”±æ‚¨ä¸ºæœ¬åè®®è®¸å¯çš„目的而使用,您不得透露给任何第三方;
2. ä»Žæœ¬äº§å“å–得的任何信息、软件、产品或服务,您不得对其进行修改、改编或基于以上内容创建同种类别的衍生产品并售卖。
3. æ‚¨ä¸å¾—对本产品以及与之关联的商业授权进行发布、出租、销售、分销、抵押、转让、许可或发放子许可证。
4. æœ¬äº§å“å•†ä¸šæŽˆæƒç‰ˆå¯èƒ½åŒ…含一些独立功能或特性,这些功能只有在您购买商业授权后才可以使用。在未取得商业授权的情况下,您不得使用、尝试使用或复制这些授权版独立功能。
5. è‹¥æ‚¨çš„客户要求以源码方式交付软件,需缴纳企业版授权费用,否则本产品部分不得提供源码。
四、 ä¸å¾—用于非法或禁止的用途:
您在使用本产品或服务时,不得将本产品产品或服务用于任何非法用途或本协议条款、条件和声明禁止的用途。
五、 å…è´£è¯´æ˜Žï¼š
1. æœ¬äº§å“æŒ‰â€œçŽ°çŠ¶â€æŽˆäºˆè®¸å¯ï¼Œæ‚¨é¡»è‡ªè¡Œæ‰¿æ‹…ä½¿ç”¨æœ¬äº§å“çš„é£Žé™©ã€‚BladeX团队不对此提供任何明示、暗示或任何其它形式的担保和表示。在任何情况下,对于因使用或无法使用本软件而导致的任何损失(包括但不仅限于商业利润损失、业务中断或业务信息丢失),BladeX团队无需向您或任何第三方负责,即使BladeX团队已被告知可能会造成此类损失。在任何情况下, BladeX团队均不就任何直接的、间接的、附带的、后果性的、特别的、惩戒性的和处罚性的损害赔偿承担任何责任,无论该主张是基于保证、合同、侵权(包括疏忽)或是基于其他原因作出。
2. æœ¬äº§å“å¯èƒ½å†…置有第三方服务,您应自行评估使用这些第三方服务的风险,由使用此类第三方服务而产生的纠纷,全部责任由您自行承担。
3. BladeX团队不对使用本产品构建的网站中任何信息内容以及导致的任何版权纠纷、法律争议和后果承担任何责任,全部责任由您自行承担。
4. BladeX团队可能会经常提供产品更新或升级,但BladeX团队没有为根据本协议许可的产品提供维护或更新的责任。
5. BladeX团队可能会按照官方制定的答疑规则为您进行答疑,但BladeX团队没有为根据本协议许可的产品提供技术支持的义务或责任。
六、 æƒåˆ©å’Œæ‰€æœ‰æƒçš„保留:
BladeX团队保留所有未在本协议中明确授予您的所有权利。BladeX团队保留随时更新本协议的权利,并只需公示于对应产品项目的LICENSE文件,无需征得您的事先同意且无需另行通知,更新后的内容应于公示即时生效。您可以随时访问产品地址并查阅最新版许可条款,在更新生效后您继续使用本产品则被视作您已接受了新的条款。
七、 åè®®ç»ˆæ­¢
1. æ‚¨ä¸€æ—¦å¼€å§‹å¤åˆ¶ã€ä¸‹è½½ã€å®‰è£…或者使用本产品,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的许可权力同时,也受到相关的约束和限制,本协议许可范围以外的行为,将直接违反本协议并构成侵权。
2. ä¸€æ—¦æ‚¨è¿åæœ¬åè®®çš„æ¡æ¬¾ï¼ŒBladeX团队随时可能终止本协议、收回许可和授权,并要求您承担相应法律和经济责任。
Source/BladeX-Tool/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
## ç‰ˆæƒå£°æ˜Ž
* BladeX是一个商业化软件,系列产品知识产权归**上海布雷德科技有限公司**独立所有
* æ‚¨ä¸€æ—¦å¼€å§‹å¤åˆ¶ã€ä¸‹è½½ã€å®‰è£…或者使用本产品,即被视为完全理解并接受本协议的各项条款
* æ›´å¤šè¯¦æƒ…请看:[BladeX商业授权许可协议](/LICENSE)
## ç­”疑流程
>1. é‡åˆ°é—®é¢˜æˆ–Bug
>2. ä¸šåŠ¡åž‹é—®é¢˜æ‰“æ–­ç‚¹è°ƒè¯•å°è¯•æ‰¾å‡ºé—®é¢˜æ‰€åœ¨
>3. ç³»ç»Ÿåž‹é—®é¢˜é€šè¿‡ç™¾åº¦ã€è°·æ­Œã€ç¤¾åŒºæŸ¥æ‰¾è§£å†³æ–¹æ¡ˆ
>4. æœªè§£å†³é—®é¢˜åˆ™è¿›å…¥æŠ€æœ¯ç¤¾åŒºè¿›è¡Œå‘帖提问:[https://sns.bladex.vip/](https://sns.bladex.vip/)
>5. å°†å¸–子地址发至商业群,特别简单三言两语就能描述清楚的也可在答疑时间内发至商业群提问
>6. å‘帖的时候一定要描述清楚,详细描述遇到问题的**重现步骤**、**报错详细信息**、**相关代码与逻辑**、**使用软件版本**以及**操作系统版本**,否则随意发帖提问将会提高我们的答疑难度。
## ç­”ç–‘æ—¶é—´
* å·¥ä½œæ—¥ï¼š9:00 ~ 17:00 æä¾›ç­”疑,周末、节假日休息,暂停答疑
* è¯·å‹¿**私聊提问**,以免被其他用户的消息覆盖从而无法获得答疑
* ç­”疑时间外遇到问题可以将问题发帖至[技术社区](https://sns.bladex.vip/),我们后续会逐个回复
## æŽˆæƒèŒƒå›´
* ä¸“业版:只可用于**个人学习**及**个人私活**项目,不可用于公司或团队,不可泄露给任何第三方
* ä¼ä¸šç‰ˆï¼šå¯ç”¨äºŽ**企业名下**的任何项目,企业版员工在**未购买**专业版授权前,只授权开发**所在授权企业名下**的项目,**不得将BladeX用于个人私活**
* å…±åŒéµå®ˆï¼šè‹¥ç”²æ–¹éœ€è¦æ‚¨æä¾›é¡¹ç›®æºç ï¼Œåˆ™éœ€ä»£ä¸ºç”²æ–¹è´­ä¹°BladeX企业授权,甲方购买后续的所有项目都无需再次购买授权
## å•†ç”¨æƒç›Š
* âœ”️ éµå®ˆ[商业协议](/LICENSE)的前提下,将BladeX系列产品用于授权范围内的商用项目,并上线运营
* âœ”️ éµå®ˆ[商业协议](/LICENSE)的前提下,不限制项目数,不限制服务器数
* âœ”️ éµå®ˆ[商业协议](/LICENSE)的前提下,将自行编写的业务代码申请软件著作权
## ä½•为侵权
* âŒ ä¸éµå®ˆå•†ä¸šåè®®ï¼Œç§è‡ªé”€å”®å•†ä¸šæºç 
* âŒ ä»¥ä»»ä½•理由将BladeX源码用于申请软件著作权
* âŒ å°†å•†ä¸šæºç ä»¥ä»»ä½•途径任何理由泄露给未授权的单位或个人
* âŒ å¼€å‘完毕项目,没有为甲方购买企业授权,向甲方提供了BladeX代码
* âŒ åŸºäºŽBladeX拓展研发与BladeX有竞争关系的衍生框架,并将其开源或销售
## ä¾µæƒåŽæžœ
* æƒ…节较轻:第一次发现警告处理
* æƒ…节较重:封禁账号,踢出商业群,并保留追究法律责任的权利
* æƒ…节严重:与本地律师事务所合作,以公司名义起诉侵犯计算机软件著作权
## ä¸¾æŠ¥æœ‰å¥–
* å‘官方提供有用线索并成功捣毁盗版个人或窝点,将会看成果给予 500~10000 ä¸ç­‰çš„现金奖励
* å®˜æ–¹å”¯ä¸€æŒ‡å®šQQ:1272154962
Source/BladeX-Tool/blade-bom/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,626 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath />
    </parent>
    <groupId>org.springblade.platform</groupId>
    <artifactId>blade-bom</artifactId>
    <packaging>pom</packaging>
    <version>${bladex.tool.version}</version>
    <description>bladex统一版本配置</description>
    <properties>
        <bladex.tool.version>3.0.1.RELEASE</bladex.tool.version>
        <swagger.version>2.10.5</swagger.version>
        <swagger.models.version>1.6.2</swagger.models.version>
        <knife4j.version>2.0.9</knife4j.version>
        <mybatis.plus.version>3.5.2</mybatis.plus.version>
        <mybatis.plus.generator.version>3.5.3</mybatis.plus.generator.version>
        <mybatis.plus.dynamic.version>3.3.6</mybatis.plus.dynamic.version>
        <protostuff.version>1.6.0</protostuff.version>
        <disruptor.version>3.4.2</disruptor.version>
        <logstash.version>6.2</logstash.version>
        <druid.version>1.2.8</druid.version>
        <jackson.version>2.13.3</jackson.version>
        <okhttp.version>4.9.3</okhttp.version>
        <xxl.job.version>2.1.2</xxl.job.version>
        <log4j2.version>2.18.0</log4j2.version>
        <logback.version>1.2.11</logback.version>
        <mysql.connector.version>8.0.22</mysql.connector.version>
        <oracle.connector.version>12.2.0.1</oracle.connector.version>
        <postgresql.connector.version>42.2.22</postgresql.connector.version>
        <sqlserver.connector.version>8.4.1.jre8</sqlserver.connector.version>
        <dameng.connector.version>8.1.2.141</dameng.connector.version>
        <spring.boot.admin.version>2.7.1</spring.boot.admin.version>
        <alibaba.cloud.version>2021.0.1.0</alibaba.cloud.version>
        <alibaba.seata.version>1.5.2</alibaba.seata.version>
        <alibaba.nacos.version>2.1.0</alibaba.nacos.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!-- Blade -->
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-auto</artifactId>
                <version>${bladex.tool.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-boot</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-cloud</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-context</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-db</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-launch</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-log4j2</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-secure</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-test</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-core-tool</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-actuate</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-api-crypto</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-auth</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-cache</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-datascope</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-develop</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-ehcache</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-excel</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-flowable</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-http</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-jwt</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-log</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-metrics</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-mongo</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-mybatis</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-oss</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-prometheus</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-redis</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-report</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-loadbalancer</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-sms</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-social</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-swagger</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-tenant</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-trace</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springblade</groupId>
                <artifactId>blade-starter-transaction</artifactId>
                <version>${bladex.tool.version}</version>
            </dependency>
            <!-- Nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
                <version>${alibaba.nacos.version}</version>
            </dependency>
            <!-- Sentinel -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <!-- Seata-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-spring-boot-starter</artifactId>
                <version>${alibaba.seata.version}</version>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-all</artifactId>
                <version>${alibaba.seata.version}</version>
            </dependency>
            <!--Mybatis-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-extension</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-generator</artifactId>
                <version>${mybatis.plus.generator.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
                <version>${mybatis.plus.dynamic.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-typehandlers-jsr310</artifactId>
                <version>1.0.2</version>
            </dependency>
            <!-- JWT -->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-impl</artifactId>
                <version>0.11.2</version>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-jackson</artifactId>
                <version>0.11.2</version>
            </dependency>
            <!-- Admin -->
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-server</artifactId>
                <version>${spring.boot.admin.version}</version>
            </dependency>
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-client</artifactId>
                <version>${spring.boot.admin.version}</version>
            </dependency>
            <!-- Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!-- MySql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.connector.version}</version>
            </dependency>
            <!-- Oracle -->
            <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc7</artifactId>
                <version>${oracle.connector.version}</version>
            </dependency>
            <!-- PostgreSql -->
            <dependency>
                <groupId>org.postgresql</groupId>
                <artifactId>postgresql</artifactId>
                <version>${postgresql.connector.version}</version>
            </dependency>
            <!-- SqlServer -->
            <dependency>
                <groupId>com.microsoft.sqlserver</groupId>
                <artifactId>mssql-jdbc</artifactId>
                <version>${sqlserver.connector.version}</version>
            </dependency>
            <!-- DaMeng -->
            <dependency>
                <groupId>com.dameng</groupId>
                <artifactId>DmJdbcDriver18</artifactId>
                <version>${dameng.connector.version}</version>
            </dependency>
            <!--Swagger-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
                <version>${swagger.models.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-micro-spring-boot-starter</artifactId>
                <version>${knife4j.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
                <version>${knife4j.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-spring-ui</artifactId>
                <version>${knife4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.plugin</groupId>
                <artifactId>spring-plugin-core</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.plugin</groupId>
                <artifactId>spring-plugin-metadata</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
            <!-- protostuff -->
            <dependency>
                <groupId>io.protostuff</groupId>
                <artifactId>protostuff-core</artifactId>
                <version>${protostuff.version}</version>
            </dependency>
            <dependency>
                <groupId>io.protostuff</groupId>
                <artifactId>protostuff-runtime</artifactId>
                <version>${protostuff.version}</version>
            </dependency>
            <!-- http -->
            <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.12.1</version>
            </dependency>
            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>${okhttp.version}</version>
            </dependency>
            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>logging-interceptor</artifactId>
                <version>${okhttp.version}</version>
            </dependency>
            <!-- redisson -->
            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.11.6</version>
            </dependency>
            <!-- Disruptor -->
            <dependency>
                <groupId>com.lmax</groupId>
                <artifactId>disruptor</artifactId>
                <version>${disruptor.version}</version>
            </dependency>
            <!-- Logstash -->
            <dependency>
                <groupId>net.logstash.logback</groupId>
                <artifactId>logstash-logback-encoder</artifactId>
                <version>${logstash.version}</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.janino</groupId>
                <artifactId>janino</artifactId>
                <version>3.0.15</version>
            </dependency>
            <!-- xxljob -->
            <dependency>
                <groupId>com.xuxueli</groupId>
                <artifactId>xxl-job-core</artifactId>
                <version>${xxl.job.version}</version>
            </dependency>
            <!-- captcha -->
            <dependency>
                <groupId>com.github.whvcse</groupId>
                <artifactId>easy-captcha</artifactId>
                <version>1.6.2</version>
            </dependency>
            <!-- jackson -->
            <dependency>
                <groupId>com.fasterxml.jackson.module</groupId>
                <artifactId>jackson-module-jaxb-annotations</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <!-- fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.83_noneautotype</version>
            </dependency>
            <!-- sentinel -->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-core</artifactId>
                <version>1.8.4</version>
            </dependency>
            <!-- easyexcel -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>2.2.11</version>
            </dependency>
            <!-- JustAuth -->
            <dependency>
                <groupId>me.zhyd.oauth</groupId>
                <artifactId>JustAuth</artifactId>
                <version>1.16.5</version>
            </dependency>
            <!-- Guava -->
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>30.1.1-jre</version>
            </dependency>
            <!-- Prometheus -->
            <dependency>
                <groupId>io.micrometer</groupId>
                <artifactId>micrometer-core</artifactId>
                <version>1.9.1</version>
            </dependency>
            <dependency>
                <groupId>io.micrometer</groupId>
                <artifactId>micrometer-registry-prometheus</artifactId>
                <version>1.9.1</version>
            </dependency>
            <!--AliOss-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.14.0</version>
            </dependency>
            <!--MinIO-->
            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>8.3.7</version>
            </dependency>
            <!--QiNiu-->
            <dependency>
                <groupId>com.qiniu</groupId>
                <artifactId>qiniu-java-sdk</artifactId>
                <version>7.9.4</version>
            </dependency>
            <!--腾讯COS-->
            <dependency>
                <groupId>com.qcloud</groupId>
                <artifactId>cos_api</artifactId>
                <version>5.6.69</version>
            </dependency>
            <!--华为云Obs-->
            <dependency>
                <groupId>com.huaweicloud</groupId>
                <artifactId>esdk-obs-java</artifactId>
                <version>3.21.12</version>
            </dependency>
            <!--AliSms-->
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>4.5.30</version>
            </dependency>
            <!--YunPian-->
            <dependency>
                <groupId>com.yunpian.sdk</groupId>
                <artifactId>yunpian-java-sdk</artifactId>
                <version>1.2.7</version>
            </dependency>
            <!--腾讯SMS-->
            <dependency>
                <groupId>com.github.qcloudsms</groupId>
                <artifactId>qcloudsms</artifactId>
                <version>1.0.6</version>
            </dependency>
            <!-- oauth2 -->
            <dependency>
                <groupId>org.springframework.security.oauth</groupId>
                <artifactId>spring-security-oauth2</artifactId>
                <version>2.3.8.RELEASE</version>
            </dependency>
            <!-- findbugs -->
            <dependency>
                <groupId>com.google.code.findbugs</groupId>
                <artifactId>jsr305</artifactId>
                <version>3.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.22</version>
            </dependency>
            <!-- log4j2 -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>${log4j2.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>${log4j2.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-jul</artifactId>
                <version>${log4j2.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
                <version>${log4j2.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-to-slf4j</artifactId>
                <version>${log4j2.version}</version>
            </dependency>
            <!-- logback -->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>${logback.version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${logback.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <distributionManagement>
        <repository>
            <id>blade-release</id>
            <name>Release Repository</name>
            <url>http://nexus.javablade.com/repository/maven-releases/</url>
        </repository>
    </distributionManagement>
</project>
Source/BladeX-Tool/blade-core-auto/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
# auto ä»£ç è‡ªåŠ¨ç”Ÿæˆ
## è§„划
1. ç”Ÿæˆ java spi
2. ç”¨æ¥ç”Ÿæˆ `spring.factories`
3. è€ƒè™‘生成 `spring-devtools.properties`
4. è€ƒè™‘?生成 `swagger` æ³¨è§£
## å‚考
Google Auto: https://github.com/google/auto
Spring 5 - spring-context-indexer:https://github.com/spring-projects/spring-framework/tree/master/spring-context-indexer
Source/BladeX-Tool/blade-core-auto/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-auto</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.plugin.version}</version>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.hibernate.validator</groupId>
                            <artifactId>hibernate-validator-annotation-processor</artifactId>
                            <version>6.0.13.Final</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoContextInitializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * ApplicationContextInitializer å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoContextInitializer {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoEnvPostProcessor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * EnvironmentPostProcessor å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoEnvPostProcessor {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoFailureAnalyzer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * FailureAnalyzer å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoFailureAnalyzer {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoIgnore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * AutoIgnore å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoIgnore {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * ApplicationListener å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoListener {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/annotation/AutoRunListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
 * SpringApplicationRunListener å¤„理
 *
 * @author L.cm
 */
@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface AutoRunListener {
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/AbstractBladeProcessor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.common;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Set;
/**
 * æŠ½è±¡ å¤„理器
 *
 * @author L.cm
 */
public abstract class AbstractBladeProcessor extends AbstractProcessor {
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
    /**
     * AutoService æ³¨è§£å¤„理器
     * @param annotations æ³¨è§£ getSupportedAnnotationTypes
     * @param roundEnv æ‰«æåˆ°çš„ æ³¨è§£æ–°
     * @return æ˜¯å¦å®Œæˆ
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        try {
            return processImpl(annotations, roundEnv);
        } catch (Exception e) {
            fatalError(e);
            return false;
        }
    }
    protected abstract boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
    protected void log(String msg) {
        if (processingEnv.getOptions().containsKey("debug")) {
            processingEnv.getMessager().printMessage(Kind.NOTE, msg);
        }
    }
    protected void error(String msg, Element element, AnnotationMirror annotation) {
        processingEnv.getMessager().printMessage(Kind.ERROR, msg, element, annotation);
    }
    protected void fatalError(Exception e) {
        // We don't allow exceptions of any kind to propagate to the compiler
        StringWriter writer = new StringWriter();
        e.printStackTrace(new PrintWriter(writer));
        fatalError(writer.toString());
    }
    protected void fatalError(String msg) {
        processingEnv.getMessager().printMessage(Kind.ERROR, "FATAL ERROR: " + msg);
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/BootAutoType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.common;
import org.springblade.core.auto.annotation.*;
/**
 * æ³¨è§£ç±»åž‹
 *
 * @author L.cm
 */
public enum BootAutoType {
    /**
     * Component,组合注解,添加到 spring.factories
     */
    COMPONENT("org.springframework.stereotype.Component", "org.springframework.boot.autoconfigure.EnableAutoConfiguration"),
    /**
     * ApplicationContextInitializer æ·»åŠ åˆ° spring.factories
     */
    CONTEXT_INITIALIZER(AutoContextInitializer.class.getName(), "org.springframework.context.ApplicationContextInitializer"),
    /**
     * ApplicationListener æ·»åŠ åˆ° spring.factories
     */
    LISTENER(AutoListener.class.getName(), "org.springframework.context.ApplicationListener"),
    /**
     * SpringApplicationRunListener æ·»åŠ åˆ° spring.factories
     */
    RUN_LISTENER(AutoRunListener.class.getName(), "org.springframework.boot.SpringApplicationRunListener"),
    /**
     * FailureAnalyzer æ·»åŠ åˆ° spring.factories
     */
    FAILURE_ANALYZER(AutoFailureAnalyzer.class.getName(), "org.springframework.boot.diagnostics.FailureAnalyzer"),
    /**
     * EnvironmentPostProcessor æ·»åŠ åˆ° spring.factories
     */
    ENV_POST_PROCESSOR(AutoEnvPostProcessor.class.getName(), "org.springframework.boot.env.EnvironmentPostProcessor");
    private final String annotationName;
    private final String configureKey;
    BootAutoType(String annotationName, String configureKey) {
        this.annotationName = annotationName;
        this.configureKey = configureKey;
    }
    public final String getAnnotationName() {
        return annotationName;
    }
    public final String getConfigureKey() {
        return configureKey;
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/MultiSetMap.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.common;
import java.util.*;
/**
 * MultiSetMap
 *
 * @author L.cm
 */
public class MultiSetMap<K, V> {
    private transient final Map<K, Set<V>> map;
    public MultiSetMap() {
        map = new HashMap<>();
    }
    private Set<V> createSet() {
        return new HashSet<>();
    }
    /**
     * put to MultiSetMap
     *
     * @param key   é”®
     * @param value å€¼
     * @return boolean
     */
    public boolean put(K key, V value) {
        Set<V> set = map.get(key);
        if (set == null) {
            set = createSet();
            if (set.add(value)) {
                map.put(key, set);
                return true;
            } else {
                throw new AssertionError("New set violated the set spec");
            }
        } else if (set.add(value)) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * æ˜¯å¦åŒ…含某个key
     *
     * @param key key
     * @return ç»“æžœ
     */
    public boolean containsKey(K key) {
        return map.containsKey(key);
    }
    /**
     * æ˜¯å¦åŒ…含 value ä¸­çš„æŸä¸ªå€¼
     *
     * @param value value
     * @return æ˜¯å¦åŒ…含
     */
    public boolean containsVal(V value) {
        Collection<Set<V>> values = map.values();
        return values.stream().anyMatch(vs -> vs.contains(value));
    }
    /**
     * key é›†åˆ
     *
     * @return keys
     */
    public Set<K> keySet() {
        return map.keySet();
    }
    /**
     * put list to MultiSetMap
     *
     * @param key é”®
     * @param set å€¼åˆ—表
     * @return boolean
     */
    public boolean putAll(K key, Set<V> set) {
        if (set == null) {
            return false;
        } else {
            map.put(key, set);
            return true;
        }
    }
    /**
     * get List by key
     *
     * @param key é”®
     * @return List
     */
    public Set<V> get(K key) {
        return map.get(key);
    }
    /**
     * clear MultiSetMap
     */
    public void clear() {
        map.clear();
    }
    /**
     * isEmpty
     *
     * @return isEmpty
     */
    public boolean isEmpty() {
        return map.isEmpty();
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/Sets.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.common;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * é›†åˆ å·¥å…·ç±»
 *
 * @author L.cm
 */
public class Sets {
    /**
     * ä¸å¯å˜ é›†åˆ
     *
     * @param es  å¯¹è±¡
     * @param <E> æ³›åž‹
     * @return é›†åˆ
     */
    @SafeVarargs
    public static <E> Set<E> ofImmutableSet(E... es) {
        Objects.requireNonNull(es);
        return Stream.of(es).collect(Collectors.toSet());
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/common/TypeHelper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.common;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import java.util.ArrayList;
import java.util.List;
/**
 * Type utilities.
 *
 * @author Stephane Nicoll
 * @since 5.0
 */
public class TypeHelper {
    private final ProcessingEnvironment env;
    private final Types types;
    public TypeHelper(ProcessingEnvironment env) {
        this.env = env;
        this.types = env.getTypeUtils();
    }
    public String getType(Element element) {
        return getType(element != null ? element.asType() : null);
    }
    public String getType(AnnotationMirror annotation) {
        return getType(annotation != null ? annotation.getAnnotationType() : null);
    }
    public String getType(TypeMirror type) {
        if (type == null) {
            return null;
        }
        if (type instanceof DeclaredType) {
            DeclaredType declaredType = (DeclaredType) type;
            Element enclosingElement = declaredType.asElement().getEnclosingElement();
            if (enclosingElement != null && enclosingElement instanceof TypeElement) {
                return getQualifiedName(enclosingElement) + "$" + declaredType.asElement().getSimpleName().toString();
            } else {
                return getQualifiedName(declaredType.asElement());
            }
        }
        return type.toString();
    }
    private String getQualifiedName(Element element) {
        if (element instanceof QualifiedNameable) {
            return ((QualifiedNameable) element).getQualifiedName().toString();
        }
        return element.toString();
    }
    /**
     * Return the super class of the specified {@link Element} or null if this
     * {@code element} represents {@link Object}.
     *
     * @param element Element
     * @return Element
     */
    public Element getSuperClass(Element element) {
        List<? extends TypeMirror> superTypes = this.types.directSupertypes(element.asType());
        if (superTypes.isEmpty()) {
            // reached java.lang.Object
            return null;
        }
        return this.types.asElement(superTypes.get(0));
    }
    /**
     * Return the interfaces that are <strong>directly</strong> implemented by the
     * specified {@link Element} or an empty list if this {@code element} does not
     * implement any interface.
     *
     * @param element Element
     * @return Element list
     */
    public List<Element> getDirectInterfaces(Element element) {
        List<? extends TypeMirror> superTypes = this.types.directSupertypes(element.asType());
        List<Element> directInterfaces = new ArrayList<>();
        // index 0 is the super class
        if (superTypes.size() > 1) {
            for (int i = 1; i < superTypes.size(); i++) {
                Element e = this.types.asElement(superTypes.get(i));
                if (e != null) {
                    directInterfaces.add(e);
                }
            }
        }
        return directInterfaces;
    }
    public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
        return this.env.getElementUtils().getAllAnnotationMirrors(e);
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/factories/AutoFactoriesProcessor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,199 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.factories;
import org.springblade.core.auto.annotation.AutoIgnore;
import org.springblade.core.auto.common.AbstractBladeProcessor;
import org.springblade.core.auto.common.BootAutoType;
import org.springblade.core.auto.common.MultiSetMap;
import org.springblade.core.auto.service.AutoService;
import javax.annotation.processing.*;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * spring boot è‡ªåŠ¨é…ç½®å¤„ç†å™¨
 *
 * @author L.cm
 */
@AutoService(Processor.class)
@SupportedAnnotationTypes("*")
@SupportedOptions("debug")
public class AutoFactoriesProcessor extends AbstractBladeProcessor {
    /**
     * å¤„理的注解 @FeignClient
     */
    private static final String FEIGN_CLIENT_ANNOTATION = "org.springframework.cloud.openfeign.FeignClient";
    /**
     * Feign è‡ªåŠ¨é…ç½®
     */
    private static final String FEIGN_AUTO_CONFIGURE_KEY = "org.springblade.core.cloud.feign.BladeFeignAutoConfiguration";
    /**
     * The location to look for factories.
     * <p>Can be present in multiple JAR files.
     */
    private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    /**
     * devtools,有 Configuration æ³¨è§£çš„ jar ä¸€èˆ¬éœ€è¦ devtools é…ç½®æ–‡ä»¶
     */
    private static final String DEVTOOLS_RESOURCE_LOCATION = "META-INF/spring-devtools.properties";
    /**
     * æ•°æ®æ‰¿è½½
     */
    private final MultiSetMap<String, String> factories = new MultiSetMap<>();
    /**
     * å…ƒç´ è¾…助类
     */
    private Elements elementUtils;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        elementUtils = processingEnv.getElementUtils();
    }
    @Override
    protected boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (roundEnv.processingOver()) {
            generateFactoriesFiles();
        } else {
            processAnnotations(annotations, roundEnv);
        }
        return false;
    }
    private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // æ—¥å¿— æ‰“印信息 gradle build --debug
        log(annotations.toString());
        Set<? extends Element> elementSet = roundEnv.getRootElements();
        log("All Element set: " + elementSet.toString());
        // è¿‡æ»¤ TypeElement
        Set<TypeElement> typeElementSet = elementSet.stream()
            .filter(this::isClassOrInterface)
            .filter(e -> e instanceof TypeElement)
            .map(e -> (TypeElement) e)
            .collect(Collectors.toSet());
        // å¦‚果为空直接跳出
        if (typeElementSet.isEmpty()) {
            log("Annotations elementSet is isEmpty");
            return;
        }
        for (TypeElement typeElement : typeElementSet) {
            if (isAnnotation(elementUtils, typeElement, AutoIgnore.class.getName())) {
                log("Found @AutoIgnore annotation,ignore Element: " + typeElement.toString());
            } else if (isAnnotation(elementUtils, typeElement, FEIGN_CLIENT_ANNOTATION)) {
                log("Found @FeignClient Element: " + typeElement.toString());
                ElementKind elementKind = typeElement.getKind();
                // Feign Client åªå¤„理 æŽ¥å£
                if (ElementKind.INTERFACE != elementKind) {
                    fatalError("@FeignClient Element " + typeElement.toString() + " ä¸æ˜¯æŽ¥å£ã€‚");
                    continue;
                }
                String factoryName = typeElement.getQualifiedName().toString();
                if (factories.containsVal(factoryName)) {
                    continue;
                }
                log("读取到新配置 spring.factories factoryName:" + factoryName);
                factories.put(FEIGN_AUTO_CONFIGURE_KEY, factoryName);
            } else {
                for (BootAutoType autoType : BootAutoType.values()) {
                    String annotation = autoType.getAnnotationName();
                    if (isAnnotation(elementUtils, typeElement, annotation)) {
                        log("Found @" + annotation + " Element: " + typeElement.toString());
                        String factoryName = typeElement.getQualifiedName().toString();
                        if (factories.containsVal(factoryName)) {
                            continue;
                        }
                        log("读取到新配置 spring.factories factoryName:" + factoryName);
                        factories.put(autoType.getConfigureKey(), factoryName);
                    }
                }
            }
        }
    }
    private void generateFactoriesFiles() {
        if (factories.isEmpty()) {
            return;
        }
        Filer filer = processingEnv.getFiler();
        try {
            // 1. spring.factories
            FileObject factoriesFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION);
            FactoriesFiles.writeFactoriesFile(factories, factoriesFile.openOutputStream());
            String classesPath = factoriesFile.toUri().toString().split("classes")[0];
            Path projectPath = Paths.get(new URI(classesPath)).getParent();
            // 2. devtools é…ç½®ï¼Œå› ä¸ºæœ‰ @Configuration æ³¨è§£çš„需要 devtools
            String projectName = projectPath.getFileName().toString();
            FileObject devToolsFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", DEVTOOLS_RESOURCE_LOCATION);
            FactoriesFiles.writeDevToolsFile(projectName, devToolsFile.openOutputStream());
        } catch (IOException | URISyntaxException e) {
            fatalError(e);
        }
    }
    private boolean isClassOrInterface(Element e) {
        ElementKind kind = e.getKind();
        return kind == ElementKind.CLASS || kind == ElementKind.INTERFACE;
    }
    private boolean isAnnotation(Elements elementUtils, Element e, String annotationFullName) {
        List<? extends AnnotationMirror> annotationList = elementUtils.getAllAnnotationMirrors(e);
        for (AnnotationMirror annotation : annotationList) {
            // å¦‚果是对于的注解
            if (isAnnotation(annotationFullName, annotation)) {
                return true;
            }
            // å¤„理组合注解
            Element element = annotation.getAnnotationType().asElement();
            // å¦‚果是 java å…ƒæ³¨è§£ï¼Œç»§ç»­å¾ªçޝ
            if (element.toString().startsWith("java.lang")) {
                continue;
            }
            // é€’归处理 ç»„合注解
            if (isAnnotation(elementUtils, element, annotationFullName)) {
                return true;
            }
        }
        return false;
    }
    private boolean isAnnotation(String annotationFullName, AnnotationMirror annotation) {
        return annotationFullName.equals(annotation.getAnnotationType().toString());
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/factories/FactoriesFiles.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.factories;
import org.springblade.core.auto.common.MultiSetMap;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.StringJoiner;
/**
 * spring boot è‡ªåŠ¨åŒ–é…ç½®å·¥å…·ç±»
 *
 * @author L.cm
 */
class FactoriesFiles {
    private static final Charset UTF_8 = StandardCharsets.UTF_8;
    /**
     * å†™å‡º spring.factories æ–‡ä»¶
     * @param factories factories ä¿¡æ¯
     * @param output è¾“出流
     * @throws IOException å¼‚常信息
     */
    static void writeFactoriesFile(MultiSetMap<String, String> factories,
                                   OutputStream output) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8));
        Set<String> keySet = factories.keySet();
        for (String key : keySet) {
            Set<String> values = factories.get(key);
            if (values == null || values.isEmpty()) {
                continue;
            }
            writer.write(key);
            writer.write("=\\\n  ");
            StringJoiner joiner = new StringJoiner(",\\\n  ");
            for (String value : values) {
                joiner.add(value);
            }
            writer.write(joiner.toString());
            writer.newLine();
        }
        writer.flush();
        output.close();
    }
    /**
     * å†™å‡º spring-devtools.properties
     * @param projectName é¡¹ç›®å
     * @param output è¾“出流
     * @throws IOException å¼‚常信息
     */
    static void writeDevToolsFile(String projectName,
                                  OutputStream output) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8));
        String format = "restart.include.%s=/%s[\\\\w-]+\\.jar";
        writer.write(String.format(format, projectName, projectName));
        writer.flush();
        output.close();
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/AutoService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.service;
import java.lang.annotation.*;
/**
 * An annotation for service providers as described in {@link java.util.ServiceLoader}. The {@link
 * AutoServiceProcessor} generates the configuration files which
 * allows service providers to be loaded with {@link java.util.ServiceLoader#load(Class)}.
 *
 * <p>Service providers assert that they conform to the service provider specification.
 * Specifically, they must:
 *
 * <ul>
 * <li>be a non-inner, non-anonymous, concrete class
 * <li>have a publicly accessible no-arg constructor
 * <li>implement the interface type returned by {@code value()}
 * </ul>
 *
 * @author google
 */
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AutoService {
    /**
     * Returns the interfaces implemented by this service provider.
     *
     * @return interface array
     */
    Class<?>[] value();
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/AutoServiceProcessor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,254 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.service;
import org.springblade.core.auto.common.AbstractBladeProcessor;
import org.springblade.core.auto.common.MultiSetMap;
import org.springblade.core.auto.common.Sets;
import org.springblade.core.auto.common.TypeHelper;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleAnnotationValueVisitor8;
import javax.lang.model.util.Types;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;
/**
 * java spi æœåŠ¡è‡ªåŠ¨å¤„ç†å™¨ å‚考:google auto
 *
 * @author L.cm
 */
@SupportedOptions("debug")
public class AutoServiceProcessor extends AbstractBladeProcessor {
    /**
     * spi æœåŠ¡é›†åˆï¼Œkey æŽ¥å£ -> value å®žçŽ°åˆ—è¡¨
     */
    private final MultiSetMap<String, String> providers = new MultiSetMap<>();
    private TypeHelper typeHelper;
    @Override
    public synchronized void init(ProcessingEnvironment env) {
        super.init(env);
        this.typeHelper = new TypeHelper(env);
    }
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Sets.ofImmutableSet(AutoService.class.getName());
    }
    @Override
    protected boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (roundEnv.processingOver()) {
            generateConfigFiles();
        } else {
            processAnnotations(annotations, roundEnv);
        }
        return true;
    }
    private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(AutoService.class);
        log(annotations.toString());
        log(elements.toString());
        for (Element e : elements) {
            TypeElement providerImplementer = (TypeElement) e;
            AnnotationMirror annotationMirror = getAnnotationMirror(e, AutoService.class);
            if (annotationMirror == null) {
                continue;
            }
            Set<TypeMirror> typeMirrors = getValueFieldOfClasses(annotationMirror);
            if (typeMirrors.isEmpty()) {
                error("No service interfaces provided for element!", e, annotationMirror);
                continue;
            }
            for (TypeMirror typeMirror : typeMirrors) {
                String providerInterfaceName = typeHelper.getType(typeMirror);
                Name providerImplementerName = providerImplementer.getQualifiedName();
                log("provider interface: " + providerInterfaceName);
                log("provider implementer: " + providerImplementerName);
                if (checkImplementer(providerImplementer, typeMirror)) {
                    providers.put(providerInterfaceName, typeHelper.getType(providerImplementer));
                } else {
                    String message = "ServiceProviders must implement their service provider interface. "
                        + providerImplementerName + " does not implement " + providerInterfaceName;
                    error(message, e, annotationMirror);
                }
            }
        }
    }
    private void generateConfigFiles() {
        Filer filer = processingEnv.getFiler();
        for (String providerInterface : providers.keySet()) {
            String resourceFile = "META-INF/services/" + providerInterface;
            log("Working on resource file: " + resourceFile);
            try {
                SortedSet<String> allServices = new TreeSet<>();
                try {
                    FileObject existingFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", resourceFile);
                    log("Looking for existing resource file at " + existingFile.toUri());
                    Set<String> oldServices = ServicesFiles.readServiceFile(existingFile.openInputStream());
                    log("Existing service entries: " + oldServices);
                    allServices.addAll(oldServices);
                } catch (IOException e) {
                    log("Resource file did not already exist.");
                }
                Set<String> newServices = new HashSet<>(providers.get(providerInterface));
                if (allServices.containsAll(newServices)) {
                    log("No new service entries being added.");
                    return;
                }
                allServices.addAll(newServices);
                log("New service file contents: " + allServices);
                FileObject fileObject = filer.createResource(StandardLocation.CLASS_OUTPUT, "", resourceFile);
                OutputStream out = fileObject.openOutputStream();
                ServicesFiles.writeServiceFile(allServices, out);
                out.close();
                log("Wrote to: " + fileObject.toUri());
            } catch (IOException e) {
                fatalError("Unable to create " + resourceFile + ", " + e);
                return;
            }
        }
    }
    /**
     * Verifies {@link java.util.spi.LocaleServiceProvider} constraints on the concrete provider class.
     * Note that these constraints are enforced at runtime via the ServiceLoader,
     * we're just checking them at compile time to be extra nice to our users.
     */
    private boolean checkImplementer(TypeElement providerImplementer, TypeMirror providerType) {
        // TODO: We're currently only enforcing the subtype relationship
        // constraint. It would be nice to enforce them all.
        Types types = processingEnv.getTypeUtils();
        return types.isSubtype(providerImplementer.asType(), providerType);
    }
    /**
     * è¯»å– AutoService ä¸Šçš„ value å€¼
     *
     * @param annotationMirror AnnotationMirror
     * @return value é›†åˆ
     */
    private Set<TypeMirror> getValueFieldOfClasses(AnnotationMirror annotationMirror) {
        return getAnnotationValue(annotationMirror, "value")
            .accept(new SimpleAnnotationValueVisitor8<Set<TypeMirror>, Void>() {
                @Override
                public Set<TypeMirror> visitType(TypeMirror typeMirror, Void v) {
                    Set<TypeMirror> declaredTypeSet = new HashSet<>(1);
                    declaredTypeSet.add(typeMirror);
                    return Collections.unmodifiableSet(declaredTypeSet);
                }
                @Override
                public Set<TypeMirror> visitArray(
                    List<? extends AnnotationValue> values, Void v) {
                    return values
                        .stream()
                        .flatMap(value -> value.accept(this, null).stream())
                        .collect(Collectors.toSet());
                }
            }, null);
    }
    /**
     * Returns a {@link ExecutableElement} and its associated {@link AnnotationValue} if such
     * an element was either declared in the usage represented by the provided
     * {@link AnnotationMirror}, or if such an element was defined with a default.
     *
     * @param annotationMirror AnnotationMirror
     * @param elementName      elementName
     * @return AnnotationValue map
     * @throws IllegalArgumentException if no element is defined with the given elementName.
     */
    public AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String elementName) {
        Objects.requireNonNull(annotationMirror);
        Objects.requireNonNull(elementName);
        for (Map.Entry<ExecutableElement, AnnotationValue> entry : getAnnotationValuesWithDefaults(annotationMirror).entrySet()) {
            if (entry.getKey().getSimpleName().contentEquals(elementName)) {
                return entry.getValue();
            }
        }
        String name = typeHelper.getType(annotationMirror);
        throw new IllegalArgumentException(String.format("@%s does not define an element %s()", name, elementName));
    }
    /**
     * Returns the {@link AnnotationMirror}'s map of {@link AnnotationValue} indexed by {@link
     * ExecutableElement}, supplying default values from the annotation if the annotation property has
     * not been set. This is equivalent to {@link
     * Elements#getElementValuesWithDefaults(AnnotationMirror)} but can be called statically without
     * an {@link Elements} instance.
     *
     * <p>The iteration order of elements of the returned map will be the order in which the {@link
     * ExecutableElement}s are defined in {@code annotation}'s {@linkplain
     * AnnotationMirror#getAnnotationType() type}.
     *
     * @param annotation AnnotationMirror
     * @return AnnotationValue Map
     */
    public Map<ExecutableElement, AnnotationValue> getAnnotationValuesWithDefaults(AnnotationMirror annotation) {
        Map<ExecutableElement, AnnotationValue> values = new HashMap<>(32);
        Map<? extends ExecutableElement, ? extends AnnotationValue> declaredValues = annotation.getElementValues();
        for (ExecutableElement method : ElementFilter.methodsIn(annotation.getAnnotationType().asElement().getEnclosedElements())) {
            // Must iterate and put in this order, to ensure consistency in generated code.
            if (declaredValues.containsKey(method)) {
                values.put(method, declaredValues.get(method));
            } else if (method.getDefaultValue() != null) {
                values.put(method, method.getDefaultValue());
            } else {
                String name = typeHelper.getType(method);
                throw new IllegalStateException(
                    "Unset annotation value without default should never happen: " + name + '.' + method.getSimpleName() + "()");
            }
        }
        return Collections.unmodifiableMap(values);
    }
    public AnnotationMirror getAnnotationMirror(Element element, Class<? extends Annotation> annotationClass) {
        String annotationClassName = annotationClass.getCanonicalName();
        for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
            String name = typeHelper.getType(annotationMirror);
            if (name.contentEquals(annotationClassName)) {
                return annotationMirror;
            }
        }
        return null;
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/java/org/springblade/core/auto/service/ServicesFiles.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.auto.service;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
 * A helper class for reading and writing Services files.
 *
 * @author L.cm
 */
class ServicesFiles {
    private static final Charset UTF_8 = StandardCharsets.UTF_8;
    /**
     * Reads the set of service classes from a service file.
     *
     * @param input not {@code null}. Closed after use.
     * @return a not {@code null Set} of service class names.
     * @throws IOException
     */
    static Set<String> readServiceFile(InputStream input) throws IOException {
        HashSet<String> serviceClasses = new HashSet<>();
        try (
            InputStreamReader isr = new InputStreamReader(input, UTF_8);
            BufferedReader r = new BufferedReader(isr)
        ) {
            String line;
            while ((line = r.readLine()) != null) {
                int commentStart = line.indexOf('#');
                if (commentStart >= 0) {
                    line = line.substring(0, commentStart);
                }
                line = line.trim();
                if (!line.isEmpty()) {
                    serviceClasses.add(line);
                }
            }
            return serviceClasses;
        }
    }
    /**
     * Writes the set of service class names to a service file.
     *
     * @param output   not {@code null}. Not closed after use.
     * @param services a not {@code null Collection} of service class names.
     * @throws IOException
     */
    static void writeServiceFile(Collection<String> services, OutputStream output) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8));
        for (String service : services) {
            writer.write(service);
            writer.newLine();
        }
        writer.flush();
    }
}
Source/BladeX-Tool/blade-core-auto/src/main/resources/META-INF/services/javax.annotation.processing.Processor
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2 @@
org.springblade.core.auto.service.AutoServiceProcessor
org.springblade.core.auto.factories.AutoFactoriesProcessor
Source/BladeX-Tool/blade-core-boot/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springblade</groupId>
        <artifactId>BladeX-Tool</artifactId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-boot</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Blade -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-db</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-secure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-cloud</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-log</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-mybatis</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeBootAutoConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.props.BladePropertySource;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
 * blade自动配置类
 *
 * @author Chill
 */
@Slf4j
@AutoConfiguration
@AllArgsConstructor
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@BladePropertySource(value = "classpath:/blade-boot.yml")
public class BladeBootAutoConfiguration {
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeExecutorConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.config;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.error.ErrorType;
import org.springblade.core.boot.error.ErrorUtil;
import org.springblade.core.context.BladeContext;
import org.springblade.core.context.BladeRunnableWrapper;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.log.constant.EventConstant;
import org.springblade.core.log.event.ErrorLogEvent;
import org.springblade.core.log.model.LogError;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.task.TaskExecutorCustomizer;
import org.springframework.boot.task.TaskSchedulerCustomizer;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.ErrorHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * å¼‚步处理
 *
 * @author Chill
 */
@Slf4j
@Configuration
@EnableAsync
@EnableScheduling
@AllArgsConstructor
public class BladeExecutorConfiguration extends AsyncConfigurerSupport {
    private final BladeContext bladeContext;
    private final BladeProperties bladeProperties;
    private final ApplicationEventPublisher publisher;
    @Bean
    public TaskExecutorCustomizer taskExecutorCustomizer() {
        return taskExecutor -> {
            taskExecutor.setThreadNamePrefix("async-task-");
            taskExecutor.setTaskDecorator(BladeRunnableWrapper::new);
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        };
    }
    @Bean
    public TaskSchedulerCustomizer taskSchedulerCustomizer() {
        return taskExecutor -> {
            taskExecutor.setThreadNamePrefix("async-scheduler");
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            taskExecutor.setErrorHandler(new BladeErrorHandler(bladeContext, bladeProperties, publisher));
        };
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new BladeAsyncUncaughtExceptionHandler(bladeContext, bladeProperties, publisher);
    }
    @RequiredArgsConstructor
    private static class BladeAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
        private final BladeContext bladeContext;
        private final BladeProperties bladeProperties;
        private final ApplicationEventPublisher eventPublisher;
        @Override
        public void handleUncaughtException(@NonNull Throwable error, @NonNull Method method, @NonNull Object... params) {
            log.error("Unexpected exception occurred invoking async method: {}", method, error);
            LogError logError = new LogError();
            // æœåŠ¡ä¿¡æ¯ã€çŽ¯å¢ƒã€å¼‚å¸¸ç±»åž‹
            logError.setParams(ErrorType.ASYNC.getType());
            logError.setEnv(bladeProperties.getEnv());
            logError.setServiceId(bladeProperties.getName());
            logError.setRequestUri(bladeContext.getRequestId());
            // å †æ ˆä¿¡æ¯
            ErrorUtil.initErrorInfo(error, logError);
            Map<String, Object> event = new HashMap<>(16);
            event.put(EventConstant.EVENT_LOG, logError);
            eventPublisher.publishEvent(new ErrorLogEvent(event));
        }
    }
    @RequiredArgsConstructor
    private static class BladeErrorHandler implements ErrorHandler {
        private final BladeContext bladeContext;
        private final BladeProperties bladeProperties;
        private final ApplicationEventPublisher eventPublisher;
        @Override
        public void handleError(@NonNull Throwable error) {
            log.error("Unexpected scheduler exception", error);
            LogError logError = new LogError();
            // æœåŠ¡ä¿¡æ¯ã€çŽ¯å¢ƒã€å¼‚å¸¸ç±»åž‹
            logError.setParams(ErrorType.SCHEDULER.getType());
            logError.setServiceId(bladeProperties.getName());
            logError.setEnv(bladeProperties.getEnv());
            logError.setRequestUri(bladeContext.getRequestId());
            // å †æ ˆä¿¡æ¯
            ErrorUtil.initErrorInfo(error, logError);
            Map<String, Object> event = new HashMap<>(16);
            event.put(EventConstant.EVENT_LOG, logError);
            eventPublisher.publishEvent(new ErrorLogEvent(event));
        }
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeRetryConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
/**
 * é‡è¯•机制
 *
 * @author Chill
 */
@Slf4j
@AutoConfiguration
public class BladeRetryConfiguration {
    @Bean
    @ConditionalOnMissingBean(name = "configServerRetryInterceptor")
    public RetryOperationsInterceptor configServerRetryInterceptor() {
        log.info(String.format(
            "configServerRetryInterceptor: Changing backOffOptions " +
                "to initial: %s, multiplier: %s, maxInterval: %s",
            1000, 1.2, 5000));
        return RetryInterceptorBuilder
            .stateless()
            .backOffOptions(1000, 1.2, 5000)
            .maxAttempts(10)
            .build();
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeWebMvcConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.props.BladeFileProperties;
import org.springblade.core.boot.props.BladeUploadProperties;
import org.springblade.core.boot.resolver.TokenArgumentResolver;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
 * WEB配置
 *
 * @author Chill
 */
@Slf4j
@AutoConfiguration
@Order(Ordered.HIGHEST_PRECEDENCE)
@AllArgsConstructor
@EnableConfigurationProperties({
    BladeUploadProperties.class, BladeFileProperties.class
})
public class BladeWebMvcConfiguration implements WebMvcConfigurer {
    private final BladeUploadProperties bladeUploadProperties;
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String path = bladeUploadProperties.getSavePath();
        registry.addResourceHandler("/upload/**")
            .addResourceLocations("file:" + path + "/upload/");
    }
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new TokenArgumentResolver());
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/config/RequestConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.config;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.request.BladeRequestFilter;
import org.springblade.core.boot.request.RequestProperties;
import org.springblade.core.boot.request.XssProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import javax.servlet.DispatcherType;
/**
 * è¿‡æ»¤å™¨é…ç½®ç±»
 *
 * @author Chill
 */
@AutoConfiguration
@AllArgsConstructor
@EnableConfigurationProperties({RequestProperties.class, XssProperties.class})
public class RequestConfiguration {
    private final RequestProperties requestProperties;
    private final XssProperties xssProperties;
    /**
     * å…¨å±€è¿‡æ»¤å™¨
     */
    @Bean
    public FilterRegistrationBean<BladeRequestFilter> bladeFilterRegistration() {
        FilterRegistrationBean<BladeRequestFilter> registration = new FilterRegistrationBean<>();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new BladeRequestFilter(requestProperties, xssProperties));
        registration.addUrlPatterns("/*");
        registration.setName("bladeRequestFilter");
        registration.setOrder(Ordered.LOWEST_PRECEDENCE);
        return registration;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/ctrl/BladeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,279 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.ctrl;
import org.springblade.core.boot.file.LocalFile;
import org.springblade.core.boot.file.BladeFileUtil;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Charsets;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourceRegion;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
 * Blade控制器封装类
 *
 * @author Chill
 */
public class BladeController {
    /**
     * ============================     REQUEST    =================================================
     */
    @Autowired
    private HttpServletRequest request;
    /**
     * èŽ·å–request
     */
    public HttpServletRequest getRequest() {
        return this.request;
    }
    /**
     * èŽ·å–å½“å‰ç”¨æˆ·
     *
     * @return
     */
    public BladeUser getUser() {
        return AuthUtil.getUser();
    }
    /** ============================     API_RESULT    =================================================  */
    /**
     * è¿”回ApiResult
     *
     * @param data
     * @return R
     */
    public <T> R<T> data(T data) {
        return R.data(data);
    }
    /**
     * è¿”回ApiResult
     *
     * @param data
     * @param message
     * @return R
     */
    public <T> R<T> data(T data, String message) {
        return R.data(data, message);
    }
    /**
     * è¿”回ApiResult
     *
     * @param data
     * @param message
     * @param code
     * @return R
     */
    public <T> R<T> data(T data, String message, int code) {
        return R.data(code, data, message);
    }
    /**
     * è¿”回ApiResult
     *
     * @param message
     * @return R
     */
    public R success(String message) {
        return R.success(message);
    }
    /**
     * è¿”回ApiResult
     *
     * @param message
     * @return R
     */
    public R fail(String message) {
        return R.fail(message);
    }
    /**
     * è¿”回ApiResult
     *
     * @param flag
     * @return R
     */
    public R status(boolean flag) {
        return R.status(flag);
    }
    /**============================     FILE    =================================================  */
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file
     * @return
     */
    public LocalFile getFile(MultipartFile file) {
        return BladeFileUtil.getFile(file);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file
     * @param dir
     * @return
     */
    public LocalFile getFile(MultipartFile file, String dir) {
        return BladeFileUtil.getFile(file, dir);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file
     * @param dir
     * @param path
     * @param virtualPath
     * @return
     */
    public LocalFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
        return BladeFileUtil.getFile(file, dir, path, virtualPath);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files
     * @return
     */
    public List<LocalFile> getFiles(List<MultipartFile> files) {
        return BladeFileUtil.getFiles(files);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files
     * @param dir
     * @return
     */
    public List<LocalFile> getFiles(List<MultipartFile> files, String dir) {
        return BladeFileUtil.getFiles(files, dir);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files
     * @param path
     * @param virtualPath
     * @return
     */
    public List<LocalFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
        return BladeFileUtil.getFiles(files, dir, path, virtualPath);
    }
    /**
     * ä¸‹è½½æ–‡ä»¶
     *
     * @param file æ–‡ä»¶
     * @return {ResponseEntity}
     * @throws IOException io异常
     */
    protected ResponseEntity<ResourceRegion> download(File file) throws IOException {
        String fileName = file.getName();
        return download(file, fileName);
    }
    /**
     * ä¸‹è½½
     *
     * @param file     æ–‡ä»¶
     * @param fileName ç”Ÿæˆçš„æ–‡ä»¶å
     * @return {ResponseEntity}
     * @throws IOException io异常
     */
    protected ResponseEntity<ResourceRegion> download(File file, String fileName) throws IOException {
        Resource resource = new FileSystemResource(file);
        return download(resource, fileName);
    }
    /**
     * ä¸‹è½½
     *
     * @param resource èµ„源
     * @param fileName ç”Ÿæˆçš„æ–‡ä»¶å
     * @return {ResponseEntity}
     * @throws IOException io异常
     */
    protected ResponseEntity<ResourceRegion> download(Resource resource, String fileName) throws IOException {
        HttpServletRequest request = WebUtil.getRequest();
        String header = request.getHeader(HttpHeaders.USER_AGENT);
        // é¿å…ç©ºæŒ‡é’ˆ
        header = header == null ? StringPool.EMPTY : header.toUpperCase();
        HttpStatus status;
        String msie= "MSIE";
        String trident= "TRIDENT";
        String edge= "EDGE";
        if (header.contains(msie) || header.contains(trident) || header.contains(edge)) {
            status = HttpStatus.OK;
        } else {
            status = HttpStatus.CREATED;
        }
        // æ–­ç‚¹ç»­ä¼ 
        long position = 0;
        long count = resource.contentLength();
        String range = request.getHeader(HttpHeaders.RANGE);
        if (null != range) {
            status = HttpStatus.PARTIAL_CONTENT;
            String[] rangeRange = range.replace("bytes=", StringPool.EMPTY).split(StringPool.DASH);
            position = Long.parseLong(rangeRange[0]);
            if (rangeRange.length > 1) {
                long end = Long.parseLong(rangeRange[1]);
                count = end - position + 1;
            }
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        String encodeFileName = UriUtils.encode(fileName, Charsets.UTF_8);
        // å…¼å®¹å„种浏览器下载:
        // https://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/
        String disposition = "attachment;" +
            "filename=\"" + encodeFileName + "\";" +
            "filename*=utf-8''" + encodeFileName;
        headers.set(HttpHeaders.CONTENT_DISPOSITION, disposition);
        return new ResponseEntity<>(new ResourceRegion(resource, position, count), headers, status);
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/error/ErrorType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.boot.error;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.lang.Nullable;
/**
 * å¼‚常类型
 *
 * @author L.cm
 */
@Getter
@RequiredArgsConstructor
public enum ErrorType {
    /**
     * å¼‚常类型
     */
    REQUEST("request"),
    ASYNC("async"),
    SCHEDULER("scheduler"),
    WEB_SOCKET("websocket"),
    OTHER("other");
    @JsonValue
    private final String type;
    @Nullable
    @JsonCreator
    public static ErrorType of(String type) {
        ErrorType[] values = ErrorType.values();
        for (ErrorType errorType : values) {
            if (errorType.type.equals(type)) {
                return errorType;
            }
        }
        return null;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/error/ErrorUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.boot.error;
import org.springblade.core.log.model.LogError;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Exceptions;
import org.springblade.core.tool.utils.ObjectUtil;
/**
 * å¼‚常工具类
 *
 * @author L.cm
 */
public class ErrorUtil {
    /**
     * åˆå§‹åŒ–异常信息
     *
     * @param error å¼‚常
     * @param event å¼‚常事件封装
     */
    public static void initErrorInfo(Throwable error, LogError event) {
        // å †æ ˆä¿¡æ¯
        event.setStackTrace(Exceptions.getStackTraceAsString(error));
        event.setExceptionName(error.getClass().getName());
        event.setMessage(error.getMessage());
        event.setCreateTime(DateUtil.now());
        StackTraceElement[] elements = error.getStackTrace();
        if (ObjectUtil.isNotEmpty(elements)) {
            // æŠ¥é”™çš„类信息
            StackTraceElement element = elements[0];
            event.setMethodClass(element.getClassName());
            event.setFileName(element.getFileName());
            event.setMethodName(element.getMethodName());
            event.setLineNumber(element.getLineNumber());
        }
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/BladeFileUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,240 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.file;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
/**
 * æ–‡ä»¶å·¥å…·ç±»
 *
 * @author Chill
 */
public class BladeFileUtil {
    /**
     * å®šä¹‰å…è®¸ä¸Šä¼ çš„æ–‡ä»¶æ‰©å±•名
     */
    private static final HashMap<String, String> EXT_MAP = new HashMap<>();
    private static final String IS_DIR = "is_dir";
    private static final String FILE_NAME = "filename";
    private static final String FILE_SIZE = "filesize";
    /**
     * å›¾ç‰‡æ‰©å±•名
     */
    private static final String[] FILE_TYPES = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};
    static {
        EXT_MAP.put("image", ".gif,.jpg,.jpeg,.png,.bmp,.JPG,.JPEG,.PNG");
        EXT_MAP.put("flash", ".swf,.flv");
        EXT_MAP.put("media", ".swf,.flv,.mp3,.mp4,.wav,.wma,.wmv,.mid,.avi,.mpg,.asf,.rm,.rmvb");
        EXT_MAP.put("file", ".doc,.docx,.xls,.xlsx,.ppt,.htm,.html,.txt,.zip,.rar,.gz,.bz2");
        EXT_MAP.put("allfile", ".gif,.jpg,.jpeg,.png,.bmp,.swf,.flv,.mp3,.mp4,.wav,.wma,.wmv,.mid,.avi,.mpg,.asf,.rm,.rmvb,.doc,.docx,.xls,.xlsx,.ppt,.htm,.html,.txt,.zip,.rar,.gz,.bz2");
    }
    /**
     * èŽ·å–æ–‡ä»¶åŽç¼€
     *
     * @param fileName æ–‡ä»¶å
     * @return String è¿”回后缀
     */
    public static String getFileExt(String fileName) {
        return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
    }
    /**
     * æµ‹è¯•文件后缀 åªè®©æŒ‡å®šåŽç¼€çš„æ–‡ä»¶ä¸Šä¼ ï¼Œåƒjsp,war,sh等危险的后缀禁止
     *
     * @param dir      ç›®å½•
     * @param fileName æ–‡ä»¶å
     * @return è¿”回成功与否
     */
    public static boolean testExt(String dir, String fileName) {
        String fileExt = getFileExt(fileName);
        String ext = EXT_MAP.get(dir);
        return StringUtil.isNotBlank(ext) && (ext.contains(fileExt.toLowerCase()) || ext.contains(fileExt.toUpperCase()));
    }
    /**
     * æ–‡ä»¶ç®¡ç†æŽ’序
     */
    public enum FileSort {
        /**
         * å¤§å°
         */
        size,
        /**
         * ç±»åž‹
         */
        type,
        /**
         * åç§°
         */
        name;
        /**
         * æ–‡æœ¬æŽ’序转换成枚举
         *
         * @param sort
         * @return
         */
        public static FileSort of(String sort) {
            try {
                return FileSort.valueOf(sort);
            } catch (Exception e) {
                return FileSort.name;
            }
        }
    }
    public static class NameComparator implements Comparator {
        @Override
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
                return -1;
            } else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
                return 1;
            } else {
                return ((String) hashA.get(FILE_NAME)).compareTo((String) hashB.get(FILE_NAME));
            }
        }
    }
    public static class SizeComparator implements Comparator {
        @Override
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
                return -1;
            } else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
                return 1;
            } else {
                if (((Long) hashA.get(FILE_SIZE)) > ((Long) hashB.get(FILE_SIZE))) {
                    return 1;
                } else if (((Long) hashA.get(FILE_SIZE)) < ((Long) hashB.get(FILE_SIZE))) {
                    return -1;
                } else {
                    return 0;
                }
            }
        }
    }
    public static class TypeComparator implements Comparator {
        @Override
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
                return -1;
            } else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
                return 1;
            } else {
                return ((String) hashA.get("filetype")).compareTo((String) hashB.get("filetype"));
            }
        }
    }
    public static String formatUrl(String url) {
        return url.replaceAll("\\\\", "/");
    }
    /********************************BladeFile封装********************************************************/
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file æ–‡ä»¶
     * @return BladeFile
     */
    public static LocalFile getFile(MultipartFile file) {
        return getFile(file, "image", null, null);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file æ–‡ä»¶
     * @param dir  ç›®å½•
     * @return BladeFile
     */
    public static LocalFile getFile(MultipartFile file, String dir) {
        return getFile(file, dir, null, null);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param file        æ–‡ä»¶
     * @param dir         ç›®å½•
     * @param path        è·¯å¾„
     * @param virtualPath è™šæ‹Ÿè·¯å¾„
     * @return BladeFile
     */
    public static LocalFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
        return new LocalFile(file, dir, path, virtualPath);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files æ–‡ä»¶é›†åˆ
     * @return BladeFile
     */
    public static List<LocalFile> getFiles(List<MultipartFile> files) {
        return getFiles(files, "image", null, null);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files æ–‡ä»¶é›†åˆ
     * @param dir   ç›®å½•
     * @return BladeFile
     */
    public static List<LocalFile> getFiles(List<MultipartFile> files, String dir) {
        return getFiles(files, dir, null, null);
    }
    /**
     * èŽ·å–BladeFile封装类
     *
     * @param files       æ–‡ä»¶é›†åˆ
     * @param path        è·¯å¾„
     * @param virtualPath è™šæ‹Ÿè·¯å¾„
     * @return BladeFile
     */
    public static List<LocalFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
        List<LocalFile> list = new ArrayList<>();
        for (MultipartFile file : files) {
            list.add(new LocalFile(file, dir, path, virtualPath));
        }
        return list;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/FileProxyManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.file;
import java.io.File;
/**
 * æ–‡ä»¶ç®¡ç†ç±»
 *
 * @author Chill
 */
public class FileProxyManager {
    private IFileProxy defaultFileProxyFactory = new LocalFileProxyFactory();
    private static final FileProxyManager ME = new FileProxyManager();
    public static FileProxyManager me() {
        return ME;
    }
    public IFileProxy getDefaultFileProxyFactory() {
        return defaultFileProxyFactory;
    }
    public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) {
        this.defaultFileProxyFactory = defaultFileProxyFactory;
    }
    public String[] path(File file, String dir) {
        return defaultFileProxyFactory.path(file, dir);
    }
    public File rename(File file, String path) {
        return defaultFileProxyFactory.rename(file, path);
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/IFileProxy.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.file;
import java.io.File;
/**
 * æ–‡ä»¶ä»£ç†æŽ¥å£
 *
 * @author Chill
 */
public interface IFileProxy {
    /**
     * è¿”回路径[物理路径][虚拟路径]
     *
     * @param file æ–‡ä»¶
     * @param dir  ç›®å½•
     * @return
     */
    String[] path(File file, String dir);
    /**
     * æ–‡ä»¶é‡å‘½åç­–ç•¥
     *
     * @param file æ–‡ä»¶
     * @param path è·¯å¾„
     * @return
     */
    File rename(File file, String path);
    /**
     * å›¾ç‰‡åŽ‹ç¼©
     *
     * @param path è·¯å¾„
     */
    void compress(String path);
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/LocalFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,157 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.file;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springblade.core.boot.props.BladeFileProperties;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
 * ä¸Šä¼ æ–‡ä»¶å°è£…
 *
 * @author Chill
 */
@Data
public class LocalFile {
    /**
     * ä¸Šä¼ æ–‡ä»¶åœ¨é™„件表中的id
     */
    private Object fileId;
    /**
     * ä¸Šä¼ æ–‡ä»¶
     */
    @JsonIgnore
    private MultipartFile file;
    /**
     * æ–‡ä»¶å¤–网地址
     */
    private String domain;
    /**
     * ä¸Šä¼ åˆ†ç±»æ–‡ä»¶å¤¹
     */
    private String dir;
    /**
     * ä¸Šä¼ ç‰©ç†è·¯å¾„
     */
    private String uploadPath;
    /**
     * ä¸Šä¼ è™šæ‹Ÿè·¯å¾„
     */
    private String uploadVirtualPath;
    /**
     * æ–‡ä»¶å
     */
    private String fileName;
    /**
     * çœŸå®žæ–‡ä»¶å
     */
    private String originalFileName;
    /**
     * æ–‡ä»¶é…ç½®
     */
    private static BladeFileProperties fileProperties;
    private static BladeFileProperties getBladeFileProperties() {
        if (fileProperties == null) {
            fileProperties = SpringUtil.getBean(BladeFileProperties.class);
        }
        return fileProperties;
    }
    public LocalFile(MultipartFile file, String dir) {
        this.dir = dir;
        this.file = file;
        this.fileName = file.getName();
        this.originalFileName = file.getOriginalFilename();
        this.domain = getBladeFileProperties().getUploadDomain();
        this.uploadPath = BladeFileUtil.formatUrl(File.separator + getBladeFileProperties().getUploadRealPath() + File.separator + dir + File.separator + DateUtil.format(DateUtil.now(), "yyyyMMdd") + File.separator + this.originalFileName);
        this.uploadVirtualPath = BladeFileUtil.formatUrl(getBladeFileProperties().getUploadCtxPath().replace(getBladeFileProperties().getContextPath(), "") + File.separator + dir + File.separator + DateUtil.format(DateUtil.now(), "yyyyMMdd") + File.separator + this.originalFileName);
    }
    public LocalFile(MultipartFile file, String dir, String uploadPath, String uploadVirtualPath) {
        this(file, dir);
        if (null != uploadPath) {
            this.uploadPath = BladeFileUtil.formatUrl(uploadPath);
            this.uploadVirtualPath = BladeFileUtil.formatUrl(uploadVirtualPath);
        }
    }
    /**
     * å›¾ç‰‡ä¸Šä¼ 
     */
    public void transfer() {
        transfer(getBladeFileProperties().getCompress());
    }
    /**
     * å›¾ç‰‡ä¸Šä¼ 
     *
     * @param compress æ˜¯å¦åŽ‹ç¼©
     */
    public void transfer(boolean compress) {
        IFileProxy fileFactory = FileProxyManager.me().getDefaultFileProxyFactory();
        this.transfer(fileFactory, compress);
    }
    /**
     * å›¾ç‰‡ä¸Šä¼ 
     *
     * @param fileFactory æ–‡ä»¶ä¸Šä¼ å·¥åŽ‚ç±»
     * @param compress    æ˜¯å¦åŽ‹ç¼©
     */
    public void transfer(IFileProxy fileFactory, boolean compress) {
        try {
            File file = new File(uploadPath);
            if (null != fileFactory) {
                String[] path = fileFactory.path(file, dir);
                this.uploadPath = path[0];
                this.uploadVirtualPath = path[1];
                file = fileFactory.rename(file, path[0]);
            }
            File pfile = file.getParentFile();
            if (!pfile.exists()) {
                pfile.mkdirs();
            }
            this.file.transferTo(file);
            if (compress) {
                fileFactory.compress(this.uploadPath);
            }
        } catch (IllegalStateException | IOException e) {
            e.printStackTrace();
        }
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/file/LocalFileProxyFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.file;
import org.springblade.core.boot.props.BladeFileProperties;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.ImageUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
 * æ–‡ä»¶ä»£ç†ç±»
 *
 * @author Chill
 */
public class LocalFileProxyFactory implements IFileProxy {
    /**
     * æ–‡ä»¶é…ç½®
     */
    private static BladeFileProperties fileProperties;
    private static BladeFileProperties getBladeFileProperties() {
        if (fileProperties == null) {
            fileProperties = SpringUtil.getBean(BladeFileProperties.class);
        }
        return fileProperties;
    }
    @Override
    public File rename(File f, String path) {
        File dest = new File(path);
        f.renameTo(dest);
        return dest;
    }
    @Override
    public String[] path(File f, String dir) {
        //避免网络延迟导致时间不同步
        long time = System.nanoTime();
        StringBuilder uploadPath = new StringBuilder()
            .append(getFileDir(dir, getBladeFileProperties().getUploadRealPath()))
            .append(time)
            .append(getFileExt(f.getName()));
        StringBuilder virtualPath = new StringBuilder()
            .append(getFileDir(dir, getBladeFileProperties().getUploadCtxPath()))
            .append(time)
            .append(getFileExt(f.getName()));
        return new String[]{BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())};
    }
    /**
     * èŽ·å–æ–‡ä»¶åŽç¼€
     *
     * @param fileName æ–‡ä»¶å
     * @return æ–‡ä»¶åŽç¼€
     */
    public static String getFileExt(String fileName) {
        if (!fileName.contains(StringPool.DOT)) {
            return ".jpg";
        } else {
            return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
        }
    }
    /**
     * èŽ·å–æ–‡ä»¶ä¿å­˜åœ°å€
     *
     * @param dir     ç›®å½•
     * @param saveDir ä¿å­˜ç›®å½•
     * @return åœ°å€
     */
    public static String getFileDir(String dir, String saveDir) {
        StringBuilder newFileDir = new StringBuilder();
        newFileDir.append(saveDir)
            .append(File.separator).append(dir).append(File.separator).append(DateUtil.format(DateUtil.now(), "yyyyMMdd"))
            .append(File.separator);
        return newFileDir.toString();
    }
    /**
     * å›¾ç‰‡åŽ‹ç¼©
     *
     * @param path æ–‡ä»¶åœ°å€
     */
    @Override
    public void compress(String path) {
        try {
            ImageUtil.zoomScale(ImageUtil.readImage(path), new FileOutputStream(new File(path)), null, getBladeFileProperties().getCompressScale(), getBladeFileProperties().getCompressFlag());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/props/BladeFileProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package org.springblade.core.boot.props;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * BladeFileProperties
 *
 * @author Chill
 */
@Getter
@Setter
@ConfigurationProperties("blade.file")
public class BladeFileProperties {
    /**
     * è¿œç¨‹ä¸Šä¼ æ¨¡å¼
     */
    private boolean remoteMode = false;
    /**
     * å¤–网地址
     */
    private String uploadDomain = "http://127.0.0.1:8999";
    /**
     * ä¸Šä¼ ä¸‹è½½è·¯å¾„(物理路径)
     */
    private String remotePath = System.getProperty("user.dir") + "/target/blade";
    /**
     * ä¸Šä¼ è·¯å¾„(相对路径)
     */
    private String uploadPath = "/upload";
    /**
     * ä¸‹è½½è·¯å¾„
     */
    private String downloadPath = "/download";
    /**
     * å›¾ç‰‡åŽ‹ç¼©
     */
    private Boolean compress = false;
    /**
     * å›¾ç‰‡åŽ‹ç¼©æ¯”ä¾‹
     */
    private Double compressScale = 2.00;
    /**
     * å›¾ç‰‡ç¼©æ”¾é€‰æ‹©:true放大;false缩小
     */
    private Boolean compressFlag = false;
    /**
     * é¡¹ç›®ç‰©ç†è·¯å¾„
     */
    private String realPath = System.getProperty("user.dir");
    /**
     * é¡¹ç›®ç›¸å¯¹è·¯å¾„
     */
    private String contextPath = "/";
    public String getUploadRealPath() {
        return (remoteMode ? remotePath : realPath) + uploadPath;
    }
    public String getUploadCtxPath() {
        return contextPath + uploadPath;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/props/BladeUploadProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.props;
import lombok.Getter;
import lombok.Setter;
import org.springblade.core.tool.utils.PathUtil;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.lang.Nullable;
/**
 * æ–‡ä»¶ä¸Šä¼ é…ç½®
 *
 * @author Chill
 */
@Getter
@Setter
@RefreshScope
@ConfigurationProperties("blade.upload")
public class BladeUploadProperties {
    /**
     * æ–‡ä»¶ä¿å­˜ç›®å½•,默认:jar åŒ…同级目录
     */
    @Nullable
    private String savePath = PathUtil.getJarPath();
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/BladeHttpServletRequestWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.request;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * å…¨å±€Request包装
 *
 * @author Chill
 */
public class BladeHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**
     * æ²¡è¢«åŒ…装过的HttpServletRequest(特殊场景,需要自己过滤)
     */
    private final HttpServletRequest orgRequest;
    /**
     * ç¼“存报文,支持多次读取流
     */
    private byte[] body;
    public BladeHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (super.getHeader(HttpHeaders.CONTENT_TYPE) == null) {
            return super.getInputStream();
        }
        if (super.getHeader(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            return super.getInputStream();
        }
        if (body == null) {
            body = WebUtil.getRequestBody(super.getInputStream()).getBytes();
        }
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
    /**
     * èŽ·å–åˆå§‹request
     *
     * @return HttpServletRequest
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }
    /**
     * èŽ·å–åˆå§‹request
     *
     * @param request request
     * @return HttpServletRequest
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
        if (request instanceof BladeHttpServletRequestWrapper) {
            return ((BladeHttpServletRequestWrapper) request).getOrgRequest();
        }
        return request;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/BladeRequestFilter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,75 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.request;
import lombok.AllArgsConstructor;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * Request全局过滤
 *
 * @author Chill
 */
@AllArgsConstructor
public class BladeRequestFilter implements Filter {
    private final RequestProperties requestProperties;
    private final XssProperties xssProperties;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Override
    public void init(FilterConfig config) {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = ((HttpServletRequest) request).getServletPath();
        // è·³è¿‡ Request åŒ…装
        if (!requestProperties.getEnabled() || isRequestSkip(path)) {
            chain.doFilter(request, response);
        }
        // é»˜è®¤ Request åŒ…装
        else if (!xssProperties.getEnabled() || isXssSkip(path)) {
            BladeHttpServletRequestWrapper bladeRequest = new BladeHttpServletRequestWrapper((HttpServletRequest) request);
            chain.doFilter(bladeRequest, response);
        }
        // Xss Request åŒ…装
        else {
            XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
            chain.doFilter(xssRequest, response);
        }
    }
    private boolean isRequestSkip(String path) {
        return requestProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }
    private boolean isXssSkip(String path) {
        return xssProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }
    @Override
    public void destroy() {
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/RequestProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.request;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
 * Request配置类
 *
 * @author Chill
 */
@Data
@ConfigurationProperties("blade.request")
public class RequestProperties {
    /**
     * å¼€å¯è‡ªå®šä¹‰request
     */
    private Boolean enabled = true;
    /**
     * æ”¾è¡Œurl
     */
    private List<String> skipUrl = new ArrayList<>();
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssHtmlFilter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,536 @@
package org.springblade.core.boot.request;
import org.springblade.core.tool.utils.StringPool;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * HTML filtering utility for protecting against XSS (Cross Site Scripting).
 * <p>
 * This code is licensed LGPLv3
 * <p>
 * This code is a Java port of the original work in PHP by Cal Hendersen.
 * http://code.iamcal.com/php/lib_filter/
 * <p>
 * The trickiest part of the translation was handling the differences in regex handling
 * between PHP and Java.  These resources were helpful in the process:
 * <p>
 * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
 * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
 * http://www.regular-expressions.info/modifiers.html
 * <p>
 * A note on naming conventions: instance variables are prefixed with a "v"; global
 * constants are in all caps.
 * <p>
 * Sample use:
 * String input = ...
 * String clean = new HtmlFilter().filter( input );
 * <p>
 * The class is not thread safe. Create a new instance if in doubt.
 * <p>
 * If you find bugs or have suggestions on improvement (especially regarding
 * performance), please contact us.  The latest version of this
 * source, and our contact details, can be found at http://xss-html-filter.sf.net
 *
 * @author Joseph O'Connell
 * @author Cal Hendersen
 * @author Michael Semb Wever
 */
public final class XssHtmlFilter {
    /**
     * regex flag union representing /si modifiers in php
     **/
    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
    private static final Pattern P_END_ARROW = Pattern.compile("^>");
    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_AMP = Pattern.compile("&");
    private static final Pattern P_QUOTE = Pattern.compile("<");
    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
    private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
    private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
    /**
     * set of allowed html elements, along with allowed attributes for each element
     **/
    private final Map<String, List<String>> vAllowed;
    /**
     * counts of open tags for each (allowable) html element
     **/
    private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
    /**
     * html elements which must always be self-closing (e.g. "<img />")
     **/
    private final String[] vSelfClosingTags;
    /**
     * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
     **/
    private final String[] vNeedClosingTags;
    /**
     * set of disallowed html elements
     **/
    private final String[] vDisallowed;
    /**
     * attributes which should be checked for valid protocols
     **/
    private final String[] vProtocolAtts;
    /**
     * allowed protocols
     **/
    private final String[] vAllowedProtocols;
    /**
     * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
     **/
    private final String[] vRemoveBlanks;
    /**
     * entities allowed within html markup
     **/
    private final String[] vAllowedEntities;
    /**
     * flag determining whether comments are allowed in input String.
     */
    private final boolean stripComment;
    private final boolean encodeQuotes;
    private boolean vDebug = false;
    /**
     * flag determining whether to try to make tags when presented with "unbalanced"
     * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>").  If set to false,
     * unbalanced angle brackets will be html escaped.
     */
    private final boolean alwaysMakeTags;
    /**
     * Default constructor.
     */
    public XssHtmlFilter() {
        vAllowed = new HashMap<>();
        final ArrayList<String> aAtts = new ArrayList<String>();
        aAtts.add("href");
        aAtts.add("target");
        vAllowed.put("a", aAtts);
        final ArrayList<String> imgAtts = new ArrayList<String>();
        imgAtts.add("src");
        imgAtts.add("width");
        imgAtts.add("height");
        imgAtts.add("alt");
        vAllowed.put("img", imgAtts);
        final ArrayList<String> noAtts = new ArrayList<String>();
        vAllowed.put("b", noAtts);
        vAllowed.put("strong", noAtts);
        vAllowed.put("i", noAtts);
        vAllowed.put("em", noAtts);
        vSelfClosingTags = new String[]{"img"};
        vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
        vDisallowed = new String[]{};
        vAllowedProtocols = new String[]{"http", "mailto", "https"};
        vProtocolAtts = new String[]{"src", "href"};
        vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
        vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
        stripComment = true;
        encodeQuotes = true;
        alwaysMakeTags = false;
    }
    /**
     * Set debug flag to true. Otherwise use default settings. See the default constructor.
     *
     * @param debug turn debug on with a true argument
     */
    public XssHtmlFilter(final boolean debug) {
        this();
        vDebug = debug;
    }
    /**
     * Map-parameter configurable constructor.
     *
     * @param conf map containing configuration. keys match field names.
     */
    public XssHtmlFilter(final Map<String, Object> conf) {
        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
        vDisallowed = (String[]) conf.get("vDisallowed");
        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
        stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
    }
    private void reset() {
        vTagCounts.clear();
    }
    private void debug(final String msg) {
        if (vDebug) {
            Logger.getAnonymousLogger().info(msg);
        }
    }
    public static String chr(final int decimal) {
        return String.valueOf((char) decimal);
    }
    public static String htmlSpecialChars(final String s) {
        String result = s;
        result = regexReplace(P_AMP, "&amp;", result);
        result = regexReplace(P_QUOTE, "&quot;", result);
        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
        return result;
    }
    //---------------------------------------------------------------
    /**
     * given a user submitted input String, filter out any invalid or restricted
     * html.
     *
     * @param input text (i.e. submitted by a user) than may contain html
     * @return "clean" version of input, with only valid, whitelisted html elements allowed
     */
    public String filter(final String input) {
        reset();
        String s = input;
        debug("************************************************");
        debug("              INPUT: " + input);
        s = escapeComments(s);
        debug("     escapeComments: " + s);
        s = balanceHtml(s);
        debug("        balanceHtml: " + s);
        s = checkTags(s);
        debug("          checkTags: " + s);
        s = processRemoveBlanks(s);
        debug("processRemoveBlanks: " + s);
        s = validateEntities(s);
        debug("    validateEntites: " + s);
        debug("************************************************\n\n");
        return s;
    }
    public boolean isAlwaysMakeTags() {
        return alwaysMakeTags;
    }
    public boolean isStripComments() {
        return stripComment;
    }
    private String escapeComments(final String s) {
        final Matcher m = P_COMMENTS.matcher(s);
        final StringBuffer buf = new StringBuffer();
        if (m.find()) {
            final String match = m.group(1);
            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
        }
        m.appendTail(buf);
        return buf.toString();
    }
    private String balanceHtml(String s) {
        if (alwaysMakeTags) {
            //
            // try and form html
            //
            s = regexReplace(P_END_ARROW, "", s);
            s = regexReplace(P_BODY_TO_END, "<$1>", s);
            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
        } else {
            //
            // escape stray brackets
            //
            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
            //
            // the last regexp causes '<>' entities to appear
            // (we need to do a lookahead assertion so that the last bracket can
            // be used in the next pass of the regexp)
            //
            s = regexReplace(P_BOTH_ARROWS, "", s);
        }
        return s;
    }
    private String checkTags(String s) {
        Matcher m = P_TAGS.matcher(s);
        final StringBuffer buf = new StringBuffer();
        while (m.find()) {
            String replaceStr = m.group(1);
            replaceStr = processTag(replaceStr);
            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
        }
        m.appendTail(buf);
        s = buf.toString();
        // these get tallied in processTag
        // (remember to reset before subsequent calls to filter method)
        for (String key : vTagCounts.keySet()) {
            for (int ii = 0; ii < vTagCounts.get(key); ii++) {
                s += "</" + key + ">";
            }
        }
        return s;
    }
    private String processRemoveBlanks(final String s) {
        String result = s;
        for (String tag : vRemoveBlanks) {
            if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
            }
            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
            if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
            }
            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
        }
        return result;
    }
    private static String regexReplace(final Pattern regexPattern, final String replacement, final String s) {
        Matcher m = regexPattern.matcher(s);
        return m.replaceAll(replacement);
    }
    private String processTag(final String s) {
        Matcher m = P_END_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            if (allowed(name)) {
                if (!inArray(name, vSelfClosingTags)) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) - 1);
                        return "</" + name + ">";
                    }
                }
            }
        }
        m = P_START_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            final String body = m.group(2);
            String ending = m.group(3);
            if (allowed(name)) {
                String params = "";
                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
                final List<String> paramNames = new ArrayList<String>();
                final List<String> paramValues = new ArrayList<String>();
                while (m2.find()) {
                    paramNames.add(m2.group(1));
                    paramValues.add(m2.group(3));
                }
                while (m3.find()) {
                    paramNames.add(m3.group(1));
                    paramValues.add(m3.group(3));
                }
                String paramName, paramValue;
                for (int ii = 0; ii < paramNames.size(); ii++) {
                    paramName = paramNames.get(ii).toLowerCase();
                    paramValue = paramValues.get(ii);
                    if (allowedAttribute(name, paramName)) {
                        if (inArray(paramName, vProtocolAtts)) {
                            paramValue = processParamProtocol(paramValue);
                        }
                        params += " " + paramName + "=\"" + paramValue + "\"";
                    }
                }
                if (inArray(name, vSelfClosingTags)) {
                    ending = " /";
                }
                if (inArray(name, vNeedClosingTags)) {
                    ending = "";
                }
                if (ending == null || ending.length() < 1) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) + 1);
                    } else {
                        vTagCounts.put(name, 1);
                    }
                } else {
                    ending = " /";
                }
                return "<" + name + params + ending + ">";
            } else {
                return "";
            }
        }
        m = P_COMMENT.matcher(s);
        if (!stripComment && m.find()) {
            return "<" + m.group() + ">";
        }
        return "";
    }
    private String processParamProtocol(String s) {
        s = decodeEntities(s);
        final Matcher m = P_PROTOCOL.matcher(s);
        if (m.find()) {
            final String protocol = m.group(1);
            if (!inArray(protocol, vAllowedProtocols)) {
                // bad protocol, turn into local anchor link instead
                s = "#" + s.substring(protocol.length() + 1);
                if (s.startsWith(StringPool.DOUBLE_SLASH)) {
                    s = "#" + s.substring(3);
                }
            }
        }
        return s;
    }
    private String decodeEntities(String s) {
        StringBuffer buf = new StringBuffer();
        Matcher m = P_ENTITY.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.decode(match);
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        buf = new StringBuffer();
        m = P_ENTITY_UNICODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        buf = new StringBuffer();
        m = P_ENCODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        s = validateEntities(s);
        return s;
    }
    private String validateEntities(final String s) {
        StringBuffer buf = new StringBuffer();
        // validate entities throughout the string
        Matcher m = P_VALID_ENTITIES.matcher(s);
        while (m.find()) {
            final String one = m.group(1);
            final String two = m.group(2);
            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
        }
        m.appendTail(buf);
        return encodeQuotes(buf.toString());
    }
    private String encodeQuotes(final String s) {
        if (encodeQuotes) {
            StringBuffer buf = new StringBuffer();
            Matcher m = P_VALID_QUOTES.matcher(s);
            while (m.find()) {
                final String one = m.group(1);
                final String two = m.group(2);
                final String three = m.group(3);
                m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
            }
            m.appendTail(buf);
            return buf.toString();
        } else {
            return s;
        }
    }
    private String checkEntity(final String preamble, final String term) {
        return ";".equals(term) && isValidEntity(preamble)
            ? '&' + preamble
            : "&amp;" + preamble;
    }
    private boolean isValidEntity(final String entity) {
        return inArray(entity, vAllowedEntities);
    }
    private static boolean inArray(final String s, final String[] array) {
        for (String item : array) {
            if (item != null && item.equals(s)) {
                return true;
            }
        }
        return false;
    }
    private boolean allowed(final String name) {
        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
    }
    private boolean allowedAttribute(final String name, final String paramName) {
        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssHttpServletRequestWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,175 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.request;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 * XSS过滤
 *
 * @author Chill
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**
     * æ²¡è¢«åŒ…装过的HttpServletRequest(特殊场景,需要自己过滤)
     */
    private final HttpServletRequest orgRequest;
    /**
     * ç¼“存报文,支持多次读取流
     */
    private byte[] body;
    /**
     * html过滤
     */
    private final static XssHtmlFilter HTML_FILTER = new XssHtmlFilter();
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (super.getHeader(HttpHeaders.CONTENT_TYPE) == null) {
            return super.getInputStream();
        }
        if (super.getHeader(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            return super.getInputStream();
        }
        if (body == null) {
            body = xssEncode(WebUtil.getRequestBody(super.getInputStream())).getBytes();
        }
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(xssEncode(name));
        if (StringUtil.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    }
    @Override
    public String[] getParameterValues(String name) {
        String[] parameters = super.getParameterValues(name);
        if (parameters == null || parameters.length == 0) {
            return null;
        }
        for (int i = 0; i < parameters.length; i++) {
            parameters[i] = xssEncode(parameters[i]);
        }
        return parameters;
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> map = new LinkedHashMap<>();
        Map<String, String[]> parameters = super.getParameterMap();
        for (String key : parameters.keySet()) {
            String[] values = parameters.get(key);
            for (int i = 0; i < values.length; i++) {
                values[i] = xssEncode(values[i]);
            }
            map.put(key, values);
        }
        return map;
    }
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(xssEncode(name));
        if (StringUtil.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    }
    private String xssEncode(String input) {
        return HTML_FILTER.filter(input);
    }
    /**
     * èŽ·å–åˆå§‹request
     *
     * @return HttpServletRequest
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }
    /**
     * èŽ·å–åˆå§‹request
     *
     * @param request request
     * @return HttpServletRequest
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
        if (request instanceof XssHttpServletRequestWrapper) {
            return ((XssHttpServletRequestWrapper) request).getOrgRequest();
        }
        return request;
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/request/XssProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.request;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
 * Xss配置类
 *
 * @author Chill
 */
@Data
@ConfigurationProperties("blade.xss")
public class XssProperties {
    /**
     * å¼€å¯xss
     */
    private Boolean enabled = true;
    /**
     * æ”¾è¡Œurl
     */
    private List<String> skipUrl = new ArrayList<>();
}
Source/BladeX-Tool/blade-core-boot/src/main/java/org/springblade/core/boot/resolver/TokenArgumentResolver.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.boot.resolver;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
 * Token转化BladeUser
 *
 * @author Chill
 */
@Slf4j
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
    /**
     * å…¥å‚筛选
     *
     * @param methodParameter å‚数集合
     * @return æ ¼å¼åŒ–后的参数
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.getParameterType().equals(BladeUser.class);
    }
    /**
     * å‡ºå‚设置
     *
     * @param methodParameter       å…¥å‚集合
     * @param modelAndViewContainer model å’Œ view
     * @param nativeWebRequest      web相关
     * @param webDataBinderFactory  å…¥å‚解析
     * @return åŒ…装对象
     */
    @Override
    public Object resolveArgument(MethodParameter methodParameter,
                                  ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest,
                                  WebDataBinderFactory webDataBinderFactory) {
        return AuthUtil.getUser();
    }
}
Source/BladeX-Tool/blade-core-boot/src/main/resources/banner.txt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
${AnsiColor.BLUE}                   ______  _             _       ___   ___
${AnsiColor.BLUE}                   | ___ \| |           | |      \  \ /  /
${AnsiColor.BLUE}                   | |_/ /| |  __ _   __| |  ___  \  V  /
${AnsiColor.BLUE}                   | ___ \| | / _` | / _` | / _ \   > <
${AnsiColor.BLUE}                   | |_/ /| || (_| || (_| ||  __/ /  .  \
${AnsiColor.BLUE}                   \____/ |_| \__,_| \__,_| \___|/__/ \__\
${AnsiColor.BLUE}:: BladeX ${blade.service.version} :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}
Source/BladeX-Tool/blade-core-boot/src/main/resources/blade-boot.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
#服务器配置
server:
  undertow:
    # çº¿ç¨‹é…ç½®
    threads:
      # è®¾ç½®IO线程数, å®ƒä¸»è¦æ‰§è¡Œéžé˜»å¡žçš„任务,它们会负责多个连接, é»˜è®¤è®¾ç½®æ¯ä¸ªCPU核心一个线程
      io: 16
      # é˜»å¡žä»»åŠ¡çº¿ç¨‹æ± , å½“执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
      worker: 400
    # ä»¥ä¸‹çš„配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
    buffer-size: 1024
    # æ˜¯å¦åˆ†é…çš„直接内存
    direct-buffers: true
  servlet:
    # ç¼–码配置
    encoding:
      charset: UTF-8
      force: true
#spring配置
spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 1024MB
      max-request-size: 1024MB
  mvc:
    throw-exception-if-no-handler-found: true
  web:
    resources:
      add-mappings: false
  devtools:
    restart:
      log-condition-evaluation-delta: false
Source/BladeX-Tool/blade-core-boot/src/main/resources/static/favicon.ico
Source/BladeX-Tool/blade-core-cloud/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-cloud</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Blade -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-launch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-auth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-loadbalancer</artifactId>
        </dependency>
        <!-- Admin -->
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!-- Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/ApiVersion.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.annotation;
import java.lang.annotation.*;
/**
 * header ç‰ˆæœ¬ å¤„理
 *
 * @author L.cm
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiVersion {
    /**
     * header è·¯å¾„中的版本
     *
     * @return ç‰ˆæœ¬å·
     */
    String value() default "";
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/UrlVersion.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.annotation;
import java.lang.annotation.*;
/**
 * æ³¨è§£ç”¨äºŽç”Ÿæˆ requestMappingInfo æ—¶å€™ç›´æŽ¥æ‹¼æŽ¥è·¯å¾„规则,自动放置于方法路径开始部分
 *
 * @author L.cm
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface UrlVersion {
    /**
     * url è·¯å¾„中的版本
     *
     * @return ç‰ˆæœ¬å·
     */
    String value() default "";
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/annotation/VersionMapping.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.annotation.*;
/**
 * ç‰ˆæœ¬å·å¤„理
 *
 * <p>
 *     1. url ç‰ˆæœ¬å·ï¼šæ·»åŠ åˆ° url å‰
 *     2. Accept ç‰ˆæœ¬ï¼šapplication/vnd.blade.VERSION+json
 * </p>
 *
 * @author L.cm
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping
@UrlVersion
@ApiVersion
@Validated
public @interface VersionMapping {
    /**
     * Alias for {@link RequestMapping#name}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String name() default "";
    /**
     * Alias for {@link RequestMapping#value}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};
    /**
     * Alias for {@link RequestMapping#path}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] path() default {};
    /**
     * Alias for {@link RequestMapping#params}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] params() default {};
    /**
     * Alias for {@link RequestMapping#headers}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] headers() default {};
    /**
     * Alias for {@link RequestMapping#consumes}.
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] consumes() default {};
    /**
     * Alias for {@link RequestMapping#produces}.
     * default json utf-8
     * @return {String[]}
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] produces() default {};
    /**
     * Alias for {@link UrlVersion#value}.
     * @return {String}
     */
    @AliasFor(annotation = UrlVersion.class, attribute = "value")
    String urlVersion() default "";
    /**
     * Alias for {@link ApiVersion#value}.
     * @return {String}
     */
    @AliasFor(annotation = ApiVersion.class, attribute = "value")
    String apiVersion() default "";
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/client/BladeCloudApplication.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.cloud.client;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.lang.annotation.*;
/**
 * Cloud启动注解配置
 *
 * @author Chill
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableDiscoveryClient
@EnableFeignClients(AppConstant.BASE_PACKAGES)
@SpringBootApplication
public @interface BladeCloudApplication {
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFallbackFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.feign;
import feign.Target;
import org.springframework.cloud.openfeign.FallbackFactory;
import lombok.AllArgsConstructor;
import org.springframework.cglib.proxy.Enhancer;
/**
 * é»˜è®¤ Fallback,避免写过多fallbackç±»
 *
 * @param <T> æ³›åž‹æ ‡è®°
 * @author L.cm
 */
@AllArgsConstructor
public class BladeFallbackFactory<T> implements FallbackFactory<T> {
    private final Target<T> target;
    @Override
    @SuppressWarnings("unchecked")
    public T create(Throwable cause) {
        final Class<T> targetType = target.type();
        final String targetName = target.name();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetType);
        enhancer.setUseCache(true);
        enhancer.setCallback(new BladeFeignFallback<>(targetType, targetName, cause));
        return (T) enhancer.create();
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignFallback.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.feign;
import com.fasterxml.jackson.databind.JsonNode;
import feign.FeignException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
import java.util.*;
/**
 * blade fallBack ä»£ç†å¤„理
 *
 * @author L.cm
 */
@Slf4j
@AllArgsConstructor
public class BladeFeignFallback<T> implements MethodInterceptor {
    private final Class<T> targetType;
    private final String targetName;
    private final Throwable cause;
    private final static String CODE = "code";
    @Nullable
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String errorMessage = cause.getMessage();
        log.error("BladeFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);
        Class<?> returnType = method.getReturnType();
        // é›†åˆç±»åž‹åé¦ˆç©ºé›†åˆ
        if (List.class == returnType || Collection.class == returnType) {
            return Collections.emptyList();
        }
        if (Set.class == returnType) {
            return Collections.emptySet();
        }
        if (Map.class == returnType) {
            return Collections.emptyMap();
        }
        // æš‚时不支持 flux,rx,异步等,返回值不是 R,直接返回 null。
        if (R.class != returnType) {
            return null;
        }
        // éž FeignException
        if (!(cause instanceof FeignException)) {
            return R.fail(ResultCode.INTERNAL_SERVER_ERROR, errorMessage);
        }
        FeignException exception = (FeignException) cause;
        byte[] content = exception.content();
        // å¦‚果返回的数据为空
        if (ObjectUtil.isEmpty(content)) {
            return R.fail(ResultCode.INTERNAL_SERVER_ERROR, errorMessage);
        }
        // è½¬æ¢æˆ jsonNode è¯»å–,因为直接转换,可能 å¯¹æ–¹æ”¾å›žçš„å¹¶ ä¸æ˜¯ R çš„æ ¼å¼ã€‚
        JsonNode resultNode = JsonUtil.readTree(content);
        // åˆ¤æ–­æ˜¯å¦ R æ ¼å¼ è¿”回体
        if (resultNode.has(CODE)) {
            return JsonUtil.getInstance().convertValue(resultNode, R.class);
        }
        return R.fail(resultNode.toString());
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        BladeFeignFallback<?> that = (BladeFeignFallback<?>) o;
        return targetType.equals(that.targetType);
    }
    @Override
    public int hashCode() {
        return Objects.hash(targetType);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignRequestInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.feign;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.http.HttpHeaders;
/**
 * feign ä¼ é€’Request header
 *
 * <p>
 *     https://blog.csdn.net/u014519194/article/details/77160958
 *     http://tietang.wang/2016/02/25/hystrix/Hystrix%E5%8F%82%E6%95%B0%E8%AF%A6%E8%A7%A3/
 *     https://github.com/Netflix/Hystrix/issues/92#issuecomment-260548068
 * </p>
 *
 * @author L.cm
 */
public class BladeFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        HttpHeaders headers = ThreadLocalUtil.get(BladeConstant.CONTEXT_KEY);
        if (headers != null && !headers.isEmpty()) {
            headers.forEach((key, values) ->
                values.forEach(value -> requestTemplate.header(key, value))
            );
        }
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/EnableBladeFeign.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.cloud.feign;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.lang.annotation.*;
/**
 * å¼€å¯Feign注解
 *
 * @author Chill
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableFeignClients(AppConstant.BASE_PACKAGES)
public @interface EnableBladeFeign {
    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
     * {@code @ComponentScan(basePackages="org.my.pkg")}.
     *
     * @return the array of 'basePackages'.
     */
    String[] value() default {};
    /**
     * Base packages to scan for annotated components.
     * <p>
     * {@link #value()} is an alias for (and mutually exclusive with) this attribute.
     * <p>
     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
     * package names.
     *
     * @return the array of 'basePackages'.
     */
    String[] basePackages() default {};
    /**
     * Type-safe alternative to {@link #basePackages()} for specifying the packages to
     * scan for annotated components. The package of each class specified will be scanned.
     * <p>
     * Consider creating a special no-op marker class or interface in each package that
     * serves no purpose other than being referenced by this attribute.
     *
     * @return the array of 'basePackageClasses'.
     */
    Class<?>[] basePackageClasses() default {};
    /**
     * A custom <code>@Configuration</code> for all feign clients. Can contain override
     * <code>@Bean</code> definition for the pieces that make up the client, for instance
     * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
     */
    Class<?>[] defaultConfiguration() default {};
    /**
     * List of classes annotated with @FeignClient. If not empty, disables classpath scanning.
     *
     * @return
     */
    Class<?>[] clients() default {};
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
 * http é…ç½®
 *
 * @author L.cm
 */
@AutoConfiguration
@EnableConfigurationProperties(BladeHttpProperties.class)
public class BladeHttpConfiguration {
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http;
import lombok.Getter;
import lombok.Setter;
import org.springblade.core.launch.log.BladeLogLevel;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import java.util.concurrent.TimeUnit;
/**
 * http é…ç½®
 *
 * @author L.cm
 */
@Getter
@Setter
@RefreshScope
@ConfigurationProperties("blade.http")
public class BladeHttpProperties {
    /**
     * æœ€å¤§è¿žæŽ¥æ•°ï¼Œé»˜è®¤ï¼š200
     */
    private int maxConnections = 200;
    /**
     * è¿žæŽ¥å­˜æ´»æ—¶é—´ï¼Œé»˜è®¤ï¼š900L
     */
    private long timeToLive = 900L;
    /**
     * è¿žæŽ¥æ± å­˜æ´»æ—¶é—´å•位,默认:秒
     */
    private TimeUnit timeUnit = TimeUnit.SECONDS;
    /**
     * é“¾æŽ¥è¶…时,默认:2000毫秒
     */
    private int connectionTimeout = 2000;
    /**
     * æ˜¯å¦æ”¯æŒé‡å®šå‘,默认:true
     */
    private boolean followRedirects = true;
    /**
     * å…³é—­è¯ä¹¦æ ¡éªŒ
     */
    private boolean disableSslValidation = true;
    /**
     * æ—¥å¿—级别
     */
    private BladeLogLevel level = BladeLogLevel.NONE;
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/LbRestTemplate.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package org.springblade.core.cloud.http;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
 * Loadbalancer RestTemplate
 *
 * @author L.cm
 */
public class LbRestTemplate extends RestTemplate {
    public LbRestTemplate() {
        super();
    }
    public LbRestTemplate(ClientHttpRequestFactory requestFactory) {
        super(requestFactory);
    }
    public LbRestTemplate(List<HttpMessageConverter<?>> messageConverters) {
        super(messageConverters);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,191 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springblade.core.cloud.http.logger.HttpLoggingInterceptor;
import org.springblade.core.cloud.http.logger.OkHttpSlf4jLogger;
import org.springblade.core.tool.ssl.DisableValidationTrustManager;
import org.springblade.core.tool.ssl.TrustAllHostNames;
import org.springblade.core.tool.utils.Charsets;
import org.springblade.core.tool.utils.Holder;
import org.springframework.boot.autoconfigure.AutoConfiguration;
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.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * Http RestTemplateHeaderInterceptor é…ç½®
 *
 * @author L.cm
 */
@Slf4j
@RequiredArgsConstructor
@AutoConfiguration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty(value = "blade.http.enabled", matchIfMissing = true)
public class RestTemplateConfiguration {
    private final BladeHttpProperties properties;
    /**
     * okhttp3 è¯·æ±‚日志拦截器
     *
     * @return HttpLoggingInterceptor
     */
    @Bean
    public HttpLoggingInterceptor loggingInterceptor() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new OkHttpSlf4jLogger());
        interceptor.setLevel(properties.getLevel());
        return interceptor;
    }
    /**
     * okhttp3 é“¾æŽ¥æ± é…ç½®
     *
     * @return okhttp3.ConnectionPool
     */
    @Bean
    @ConditionalOnMissingBean
    public ConnectionPool httpClientConnectionPool() {
        int maxTotalConnections = properties.getMaxConnections();
        long timeToLive = properties.getTimeToLive();
        TimeUnit ttlUnit = properties.getTimeUnit();
        return new ConnectionPool(maxTotalConnections, timeToLive, ttlUnit);
    }
    /**
     * é…ç½®OkHttpClient
     *
     * @param connectionPool é“¾æŽ¥æ± é…ç½®
     * @param interceptor    æ‹¦æˆªå™¨
     * @return OkHttpClient
     */
    @Bean
    @ConditionalOnMissingBean
    public OkHttpClient okHttpClient(ConnectionPool connectionPool, HttpLoggingInterceptor interceptor) {
        boolean followRedirects = properties.isFollowRedirects();
        int connectTimeout = properties.getConnectionTimeout();
        return this.createBuilder(properties.isDisableSslValidation())
            .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .followRedirects(followRedirects)
            .connectionPool(connectionPool)
            .addInterceptor(interceptor)
            .build();
    }
    private OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        if (disableSslValidation) {
            try {
                X509TrustManager disabledTrustManager = DisableValidationTrustManager.INSTANCE;
                TrustManager[] trustManagers = new TrustManager[]{disabledTrustManager};
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustManagers, Holder.SECURE_RANDOM);
                SSLSocketFactory disabledSslSocketFactory = sslContext.getSocketFactory();
                builder.sslSocketFactory(disabledSslSocketFactory, disabledTrustManager);
                builder.hostnameVerifier(TrustAllHostNames.INSTANCE);
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                log.warn("Error setting SSLSocketFactory in OKHttpClient", e);
            }
        }
        return builder;
    }
    @Bean
    public RestTemplateHeaderInterceptor requestHeaderInterceptor() {
        return new RestTemplateHeaderInterceptor();
    }
    @AutoConfiguration
    @RequiredArgsConstructor
    @ConditionalOnClass(OkHttpClient.class)
    @ConditionalOnProperty(value = "blade.http.rest-template.enable")
    public static class RestTemplateAutoConfiguration {
        private final ApplicationContext context;
        /**
         * æ™®é€šçš„ RestTemplate,不透传请求头,一般只做外部 http è°ƒç”¨
         *
         * @param okHttpClient OkHttpClient
         * @return RestTemplate
         */
        @Bean
        @ConditionalOnMissingBean
        public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
            restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
            RestTemplate restTemplate = restTemplateBuilder.build();
            configMessageConverters(context, restTemplate.getMessageConverters());
            return restTemplate;
        }
    }
    @AutoConfiguration
    @RequiredArgsConstructor
    @ConditionalOnClass(OkHttpClient.class)
    @ConditionalOnProperty(value = "blade.http.lb-rest-template.enable")
    public static class LbRestTemplateAutoConfiguration {
        private final ApplicationContext context;
        /**
         * æ”¯æŒè´Ÿè½½å‡è¡¡çš„ LbRestTemplate
         *
         * @param okHttpClient OkHttpClient
         * @return LbRestTemplate
         */
        @Bean
        @LoadBalanced
        @ConditionalOnMissingBean
        public LbRestTemplate lbRestTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
            restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
            LbRestTemplate restTemplate = restTemplateBuilder.build(LbRestTemplate.class);
            restTemplate.getInterceptors().add(context.getBean(RestTemplateHeaderInterceptor.class));
            configMessageConverters(context, restTemplate.getMessageConverters());
            return restTemplate;
        }
    }
    private static void configMessageConverters(ApplicationContext context, List<HttpMessageConverter<?>> converters) {
        converters.removeIf(x -> x instanceof StringHttpMessageConverter || x instanceof MappingJackson2HttpMessageConverter);
        converters.add(new StringHttpMessageConverter(Charsets.UTF_8));
        converters.add(new MappingJackson2HttpMessageConverter(context.getBean(ObjectMapper.class)));
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateHeaderInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull;
import java.io.IOException;
/**
 * RestTemplateHeaderInterceptor ä¼ é€’Request header
 *
 * @author L.cm
 */
@AllArgsConstructor
public class RestTemplateHeaderInterceptor implements ClientHttpRequestInterceptor {
    @NonNull
    @Override
    public ClientHttpResponse intercept(@NonNull HttpRequest request, @NonNull byte[] bytes, @NonNull ClientHttpRequestExecution execution) throws IOException {
        HttpHeaders headers = ThreadLocalUtil.get(BladeConstant.CONTEXT_KEY);
        if (headers != null && !headers.isEmpty()) {
            HttpHeaders httpHeaders = request.getHeaders();
            headers.forEach((key, values) -> values.forEach(value -> httpHeaders.add(key, value)));
        }
        return execution.execute(request, bytes);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/logger/HttpLoggingInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,257 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http.logger;
import okhttp3.*;
import okhttp3.internal.http.HttpHeaders;
import okio.Buffer;
import okio.BufferedSource;
import okio.GzipSource;
import org.springblade.core.launch.log.BladeLogLevel;
import java.io.EOFException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
 * An OkHttp interceptor which logs request and response information. Can be applied as an
 * {@linkplain OkHttpClient#interceptors() application interceptor} or as a {@linkplain
 * OkHttpClient#networkInterceptors() network interceptor}. <p> The format of the logs created by
 * this class should not be considered stable and may change slightly between releases. If you need
 * a stable logging format, use your own interceptor.
 *
 * @author L.cm
 */
public final class HttpLoggingInterceptor implements Interceptor {
    private static final Charset UTF8 = StandardCharsets.UTF_8;
    private final Logger logger;
    private volatile BladeLogLevel level = BladeLogLevel.NONE;
    public interface Logger {
        /**
         * log
         * @param message message
         */
        void log(String message);
    }
    public HttpLoggingInterceptor(Logger logger) {
        this.logger = logger;
    }
    /**
     * Change the level at which this interceptor logs.
     * @param level log Level
     * @return HttpLoggingInterceptor
     */
    public HttpLoggingInterceptor setLevel(BladeLogLevel level) {
        this.level = Objects.requireNonNull(level, "level == null. Use Level.NONE instead.");
        return this;
    }
    public BladeLogLevel getLevel() {
        return level;
    }
    @Override
    public Response intercept(Chain chain) throws IOException {
        BladeLogLevel level = this.level;
        Request request = chain.request();
        if (level == BladeLogLevel.NONE) {
            return chain.proceed(request);
        }
        boolean logBody = level == BladeLogLevel.BODY;
        boolean logHeaders = logBody || level == BladeLogLevel.HEADERS;
        RequestBody requestBody = request.body();
        boolean hasRequestBody = requestBody != null;
        Connection connection = chain.connection();
        String requestStartMessage = "--> "
            + request.method()
            + ' ' + request.url()
            + (connection != null ? " " + connection.protocol() : "");
        if (!logHeaders && hasRequestBody) {
            requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
        }
        logger.log(requestStartMessage);
        if (logHeaders) {
            if (hasRequestBody) {
                // Request body headers are only present when installed as a network interceptor. Force
                // them to be included (when available) so there values are known.
                if (requestBody.contentType() != null) {
                    logger.log("Content-Type: " + requestBody.contentType());
                }
                if (requestBody.contentLength() != -1) {
                    logger.log("Content-Length: " + requestBody.contentLength());
                }
            }
            Headers headers = request.headers();
            for (int i = 0, count = headers.size(); i < count; i++) {
                String name = headers.name(i);
                // Skip headers from the request body as they are explicitly logged above.
                if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
                    logger.log(name + ": " + headers.value(i));
                }
            }
            if (!logBody || !hasRequestBody) {
                logger.log("--> END " + request.method());
            } else if (bodyHasUnknownEncoding(request.headers())) {
                logger.log("--> END " + request.method() + " (encoded body omitted)");
            } else {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                Charset charset = UTF8;
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                }
                logger.log("");
                if (isPlaintext(buffer)) {
                    logger.log(buffer.readString(charset));
                    logger.log("--> END " + request.method()
                        + " (" + requestBody.contentLength() + "-byte body)");
                } else {
                    logger.log("--> END " + request.method() + " (binary "
                        + requestBody.contentLength() + "-byte body omitted)");
                }
            }
        }
        long startNs = System.nanoTime();
        Response response;
        try {
            response = chain.proceed(request);
        } catch (Exception e) {
            logger.log("<-- HTTP FAILED: " + e);
            throw e;
        }
        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();
        String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
        logger.log("<-- "
            + response.code()
            + (response.message().isEmpty() ? "" : ' ' + response.message())
            + ' ' + response.request().url()
            + " (" + tookMs + "ms" + (!logHeaders ? ", " + bodySize + " body" : "") + ')');
        if (logHeaders) {
            Headers headers = response.headers();
            int count = headers.size();
            for (int i = 0; i < count; i++) {
                logger.log(headers.name(i) + ": " + headers.value(i));
            }
            if (!logBody || !HttpHeaders.hasBody(response)) {
                logger.log("<-- END HTTP");
            } else if (bodyHasUnknownEncoding(response.headers())) {
                logger.log("<-- END HTTP (encoded body omitted)");
            } else {
                BufferedSource source = responseBody.source();
                // Buffer the entire body.
                source.request(Long.MAX_VALUE);
                Buffer buffer = source.getBuffer();
                Long gzippedLength = null;
                if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
                    gzippedLength = buffer.size();
                    GzipSource gzippedResponseBody = null;
                    try {
                        gzippedResponseBody = new GzipSource(buffer.clone());
                        buffer = new Buffer();
                        buffer.writeAll(gzippedResponseBody);
                    } finally {
                        if (gzippedResponseBody != null) {
                            gzippedResponseBody.close();
                        }
                    }
                }
                Charset charset = UTF8;
                MediaType contentType = responseBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                }
                if (!isPlaintext(buffer)) {
                    logger.log("");
                    logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)");
                    return response;
                }
                if (contentLength != 0) {
                    logger.log("");
                    logger.log(buffer.clone().readString(charset));
                }
                if (gzippedLength != null) {
                    logger.log("<-- END HTTP (" + buffer.size() + "-byte, "
                        + gzippedLength + "-gzipped-byte body)");
                } else {
                    logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
                }
            }
        }
        return response;
    }
    /**
     * Returns true if the body in question probably contains human readable text. Uses a small sample
     * of code points to detect unicode control characters commonly used in binary file signatures.
     */
    private static boolean isPlaintext(Buffer buffer) {
        try {
            Buffer prefix = new Buffer();
            long byteCount = buffer.size() < 64 ? buffer.size() : 64;
            buffer.copyTo(prefix, 0, byteCount);
            for (int i = 0; i < 16; i++) {
                if (prefix.exhausted()) {
                    break;
                }
                int codePoint = prefix.readUtf8CodePoint();
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                    return false;
                }
            }
            return true;
        } catch (EOFException e) {
            // Truncated UTF-8 sequence.
            return false;
        }
    }
    private boolean bodyHasUnknownEncoding(Headers headers) {
        String contentEncoding = headers.get("Content-Encoding");
        return contentEncoding != null
            && !"identity".equalsIgnoreCase(contentEncoding)
            && !"gzip".equalsIgnoreCase(contentEncoding);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/logger/OkHttpSlf4jLogger.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.http.logger;
import lombok.extern.slf4j.Slf4j;
/**
 * OkHttp Slf4j logger
 *
 * @author L.cm
 */
@Slf4j
public class OkHttpSlf4jLogger implements HttpLoggingInterceptor.Logger {
    @Override
    public void log(String message) {
        log.info(message);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package org.springblade.core.cloud.sentinel;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Sentinel统一限流策略
 *
 * @author Chill
 */
public class BladeBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        // Return 429 (Too Many Requests) by default.
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().print(JsonUtil.toJson(R.fail(e.getMessage())));
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeFeignSentinel.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,128 @@
/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * 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.springblade.core.cloud.sentinel;
import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
import feign.Contract;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import org.springframework.cloud.openfeign.FallbackFactory;
import lombok.SneakyThrows;
import org.springblade.core.cloud.feign.BladeFallbackFactory;
import org.springframework.beans.BeansException;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
/**
 * feign集成sentinel自动配置
 * é‡å†™ {@link com.alibaba.cloud.sentinel.feign.SentinelFeign} é€‚配最新API
 *
 * @author Chill
 */
public class BladeFeignSentinel {
    public static Builder builder() {
        return new Builder();
    }
    public static final class Builder extends Feign.Builder implements ApplicationContextAware {
        private Contract contract = new Contract.Default();
        private ApplicationContext applicationContext;
        private FeignContext feignContext;
        @Override
        public Feign.Builder invocationHandlerFactory(
            InvocationHandlerFactory invocationHandlerFactory) {
            throw new UnsupportedOperationException();
        }
        @Override
        public Builder contract(Contract contract) {
            this.contract = contract;
            return this;
        }
        @Override
        public Feign build() {
            super.invocationHandlerFactory(new InvocationHandlerFactory() {
                @SneakyThrows
                @Override
                public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
                    // æ³¨è§£å–值以避免循环依赖的问题
                    FeignClient feignClient = AnnotationUtils.findAnnotation(target.type(), FeignClient.class);
                    Class fallback = feignClient.fallback();
                    Class fallbackFactory = feignClient.fallbackFactory();
                    String contextId = feignClient.contextId();
                    if (!StringUtils.hasText(contextId)) {
                        contextId = feignClient.name();
                    }
                    Object fallbackInstance;
                    FallbackFactory fallbackFactoryInstance;
                    // åˆ¤æ–­fallback类型
                    if (void.class != fallback) {
                        fallbackInstance = getFromContext(contextId, "fallback", fallback, target.type());
                        return new BladeSentinelInvocationHandler(target, dispatch, new FallbackFactory.Default(fallbackInstance));
                    }
                    if (void.class != fallbackFactory) {
                        fallbackFactoryInstance = (FallbackFactory) getFromContext(contextId, "fallbackFactory", fallbackFactory, FallbackFactory.class);
                        return new BladeSentinelInvocationHandler(target, dispatch, fallbackFactoryInstance);
                    }
                    // é»˜è®¤fallbackFactory
                    BladeFallbackFactory bladeFallbackFactory = new BladeFallbackFactory(target);
                    return new BladeSentinelInvocationHandler(target, dispatch, bladeFallbackFactory);
                }
                private Object getFromContext(String name, String type, Class fallbackType, Class targetType) {
                    Object fallbackInstance = feignContext.getInstance(name, fallbackType);
                    if (fallbackInstance == null) {
                        throw new IllegalStateException(
                            String.format("No %s instance of type %s found for feign client %s",
                                type, fallbackType, name)
                        );
                    }
                    if (!targetType.isAssignableFrom(fallbackType)) {
                        throw new IllegalStateException(
                            String.format("Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
                                type, fallbackType, targetType, name)
                        );
                    }
                    return fallbackInstance;
                }
            });
            super.contract(new SentinelContractHolder(contract));
            return super.build();
        }
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
            feignContext = this.applicationContext.getBean(FeignContext.class);
        }
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelAutoConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.cloud.sentinel;
import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import feign.Feign;
import feign.RequestInterceptor;
import lombok.AllArgsConstructor;
import org.springblade.core.cloud.feign.BladeFeignRequestInterceptor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
/**
 * Sentinel配置类
 *
 * @author Chill
 */
@AllArgsConstructor
@AutoConfiguration(before = SentinelFeignAutoConfiguration.class)
@ConditionalOnProperty(name = "feign.sentinel.enabled")
public class BladeSentinelAutoConfiguration {
    @Bean
    @Primary
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Feign.Builder feignSentinelBuilder(RequestInterceptor requestInterceptor) {
        return BladeFeignSentinel.builder().requestInterceptor(requestInterceptor);
    }
    @Bean
    @ConditionalOnMissingBean
    public RequestInterceptor requestInterceptor() {
        return new BladeFeignRequestInterceptor();
    }
    @Bean
    @ConditionalOnMissingBean
    public BlockExceptionHandler blockExceptionHandler() {
        return new BladeBlockExceptionHandler();
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelFilterConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.cloud.sentinel;
import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.DefaultBlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.util.StringUtils;
import java.util.Optional;
/**
 * å¤„理sentinel2021兼容问题
 *
 * @author Chill
 */
@RequiredArgsConstructor
@Import(BladeSentinelFilterConfiguration.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class BladeSentinelFilterConfiguration {
    @Bean
    public SentinelWebInterceptor sentinelWebInterceptor(SentinelWebMvcConfig sentinelWebMvcConfig) {
        return new SentinelWebInterceptor(sentinelWebMvcConfig);
    }
    @Bean
    public SentinelWebMvcConfig sentinelWebMvcConfig(SentinelProperties properties,
                                                     Optional<UrlCleaner> urlCleanerOptional, Optional<BlockExceptionHandler> blockExceptionHandlerOptional,
                                                     Optional<RequestOriginParser> requestOriginParserOptional) {
        SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
        sentinelWebMvcConfig.setHttpMethodSpecify(properties.getHttpMethodSpecify());
        sentinelWebMvcConfig.setWebContextUnify(properties.getWebContextUnify());
        if (blockExceptionHandlerOptional.isPresent()) {
            blockExceptionHandlerOptional.ifPresent(sentinelWebMvcConfig::setBlockExceptionHandler);
        } else {
            if (StringUtils.hasText(properties.getBlockPage())) {
                sentinelWebMvcConfig.setBlockExceptionHandler(
                    ((request, response, e) -> response.sendRedirect(properties.getBlockPage())));
            } else {
                sentinelWebMvcConfig.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
            }
        }
        urlCleanerOptional.ifPresent(sentinelWebMvcConfig::setUrlCleaner);
        requestOriginParserOptional.ifPresent(sentinelWebMvcConfig::setOriginParser);
        return sentinelWebMvcConfig;
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelInvocationHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.cloud.sentinel;
import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.MethodMetadata;
import feign.Target;
import org.springframework.cloud.openfeign.FallbackFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;
import static feign.Util.checkNotNull;
/**
 * é‡å†™ {@link com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler} é€‚配最新API
 *
 * @author Chill
 */
public class BladeSentinelInvocationHandler implements InvocationHandler {
    private final Target<?> target;
    private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
    private FallbackFactory fallbackFactory;
    private Map<Method, Method> fallbackMethodMap;
    public BladeSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch,
                                   FallbackFactory fallbackFactory) {
        this.target = checkNotNull(target, "target");
        this.dispatch = checkNotNull(dispatch, "dispatch");
        this.fallbackFactory = fallbackFactory;
        this.fallbackMethodMap = toFallbackMethod(dispatch);
    }
    public BladeSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
        this.target = checkNotNull(target, "target");
        this.dispatch = checkNotNull(dispatch, "dispatch");
    }
    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args)
        throws Throwable {
        if ("equals".equals(method.getName())) {
            try {
                Object otherHandler = args.length > 0 && args[0] != null
                    ? Proxy.getInvocationHandler(args[0]) : null;
                return equals(otherHandler);
            } catch (IllegalArgumentException e) {
                return false;
            }
        } else if ("hashCode".equals(method.getName())) {
            return hashCode();
        } else if ("toString".equals(method.getName())) {
            return toString();
        }
        Object result;
        InvocationHandlerFactory.MethodHandler methodHandler = this.dispatch.get(method);
        // only handle by HardCodedTarget
        if (target instanceof Target.HardCodedTarget) {
            Target.HardCodedTarget hardCodedTarget = (Target.HardCodedTarget) target;
            MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP
                .get(hardCodedTarget.type().getName()
                    + Feign.configKey(hardCodedTarget.type(), method));
            // resource default is HttpMethod:protocol://url
            if (methodMetadata == null) {
                result = methodHandler.invoke(args);
            } else {
                String resourceName = methodMetadata.template().method().toUpperCase()
                    + ":" + hardCodedTarget.url() + methodMetadata.template().path();
                Entry entry = null;
                try {
                    ContextUtil.enter(resourceName);
                    entry = SphU.entry(resourceName, EntryType.OUT, 1, args);
                    result = methodHandler.invoke(args);
                } catch (Throwable ex) {
                    // fallback handle
                    if (!BlockException.isBlockException(ex)) {
                        Tracer.trace(ex);
                    }
                    if (fallbackFactory != null) {
                        try {
                            Object fallbackResult = fallbackMethodMap.get(method)
                                .invoke(fallbackFactory.create(ex), args);
                            return fallbackResult;
                        } catch (IllegalAccessException e) {
                            // shouldn't happen as method is public due to being an
                            // interface
                            throw new AssertionError(e);
                        } catch (InvocationTargetException e) {
                            throw new AssertionError(e.getCause());
                        }
                    } else {
                        // throw exception if fallbackFactory is null
                        throw ex;
                    }
                } finally {
                    if (entry != null) {
                        entry.exit(1, args);
                    }
                    ContextUtil.exit();
                }
            }
        } else {
            // other target type using default strategy
            result = methodHandler.invoke(args);
        }
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BladeSentinelInvocationHandler) {
            BladeSentinelInvocationHandler other = (BladeSentinelInvocationHandler) obj;
            return target.equals(other.target);
        }
        return false;
    }
    @Override
    public int hashCode() {
        return target.hashCode();
    }
    @Override
    public String toString() {
        return target.toString();
    }
    static Map<Method, Method> toFallbackMethod(Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
        Map<Method, Method> result = new LinkedHashMap<>();
        for (Method method : dispatch.keySet()) {
            method.setAccessible(true);
            result.put(method, method);
        }
        return result;
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/server/UndertowHttp2Configuration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.server;
import io.undertow.Undertow;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import static io.undertow.UndertowOptions.ENABLE_HTTP2;
/**
 * Undertow http2 h2c é…ç½®ï¼Œå¯¹ servlet å¼€å¯
 *
 * @author L.cm
 */
@AutoConfiguration(before = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnClass(Undertow.class)
public class UndertowHttp2Configuration {
    @Bean
    public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowHttp2WebServerFactoryCustomizer() {
        return factory -> factory.addBuilderCustomizers(builder -> builder.setServerOption(ENABLE_HTTP2, true));
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeMediaType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.version;
import lombok.Getter;
import org.springframework.http.MediaType;
/**
 * blade Media Types,application/vnd.github.VERSION+json
 *
 * <p>
 * https://developer.github.com/v3/media/
 * </p>
 *
 * @author L.cm
 */
@Getter
public class BladeMediaType {
    private static final String MEDIA_TYPE_TEMP = "application/vnd.%s.%s+json";
    private final String appName = "blade";
    private final String version;
    private final MediaType mediaType;
    public BladeMediaType(String version) {
        this.version = version;
        this.mediaType = MediaType.valueOf(String.format(MEDIA_TYPE_TEMP, appName, version));
    }
    @Override
    public String toString() {
        return mediaType.toString();
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeRequestMappingHandlerMapping.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.version;
import org.springblade.core.cloud.annotation.ApiVersion;
import org.springblade.core.cloud.annotation.UrlVersion;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
import java.util.Map;
/**
 * url版本号处理 å’Œ header ç‰ˆæœ¬å¤„理
 *
 * <p>
 *     url: /v1/user/{id}
 *     header: Accept application/vnd.blade.VERSION+json
 * </p>
 *
 * æ³¨æ„ï¼šc ä»£è¡¨å®¢æˆ·ç«¯ç‰ˆæœ¬
 *
 * @author L.cm
 */
public class BladeRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    @Nullable
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo mappinginfo = super.getMappingForMethod(method, handlerType);
        if (mappinginfo != null) {
            RequestMappingInfo apiVersionMappingInfo = getApiVersionMappingInfo(method, handlerType);
            return apiVersionMappingInfo == null ? mappinginfo : apiVersionMappingInfo.combine(mappinginfo);
        }
        return null;
    }
    @Nullable
    private RequestMappingInfo getApiVersionMappingInfo(Method method, Class<?> handlerType) {
        // url ä¸Šçš„版本,优先获取方法上的版本
        UrlVersion urlVersion = AnnotatedElementUtils.findMergedAnnotation(method, UrlVersion.class);
        // å†æ¬¡å°è¯•类上的版本
        if (urlVersion == null || StringUtil.isBlank(urlVersion.value())) {
            urlVersion = AnnotatedElementUtils.findMergedAnnotation(handlerType, UrlVersion.class);
        }
        // Media Types ç‰ˆæœ¬ä¿¡æ¯
        ApiVersion apiVersion = AnnotatedElementUtils.findMergedAnnotation(method, ApiVersion.class);
        // å†æ¬¡å°è¯•类上的版本
        if (apiVersion == null || StringUtil.isBlank(apiVersion.value())) {
            apiVersion = AnnotatedElementUtils.findMergedAnnotation(handlerType, ApiVersion.class);
        }
        boolean nonUrlVersion = urlVersion == null || StringUtil.isBlank(urlVersion.value());
        boolean nonApiVersion = apiVersion == null || StringUtil.isBlank(apiVersion.value());
        // å…ˆåˆ¤æ–­åŒæ—¶ä¸çº¯åœ¨
        if (nonUrlVersion && nonApiVersion) {
            return null;
        }
        // å¦‚æžœ header ç‰ˆæœ¬ä¸å­˜åœ¨
        RequestMappingInfo.Builder mappingInfoBuilder = null;
        if (nonApiVersion) {
            mappingInfoBuilder = RequestMappingInfo.paths(urlVersion.value());
        } else {
            mappingInfoBuilder = RequestMappingInfo.paths(StringPool.EMPTY);
        }
        // å¦‚æžœurl版本不存在
        if (nonUrlVersion) {
            String vsersionMediaTypes = new BladeMediaType(apiVersion.value()).toString();
            mappingInfoBuilder.produces(vsersionMediaTypes);
        }
        return mappingInfoBuilder.build();
    }
    @Override
    protected void handlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
        // æ‰“印路由信息 spring boot 2.1 åŽ»æŽ‰äº†è¿™ä¸ª æ—¥å¿—的打印
        if (logger.isInfoEnabled()) {
            for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
                RequestMappingInfo mapping = entry.getKey();
                HandlerMethod handlerMethod = entry.getValue();
                logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
            }
        }
        super.handlerMethodsInitialized(handlerMethods);
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeSpringMvcContract.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,101 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.version;
import feign.MethodMetadata;
import org.springblade.core.cloud.annotation.ApiVersion;
import org.springblade.core.cloud.annotation.UrlVersion;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
/**
 * æ”¯æŒ blade-boot çš„ ç‰ˆæœ¬ å¤„理
 *
 * @see org.springblade.core.cloud.annotation.UrlVersion
 * @see org.springblade.core.cloud.annotation.ApiVersion
 * @author L.cm
 */
public class BladeSpringMvcContract extends SpringMvcContract {
    public BladeSpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors, ConversionService conversionService) {
        super(annotatedParameterProcessors, conversionService);
    }
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
        if (RequestMapping.class.isInstance(methodAnnotation) || methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {
            Class<?> targetType = method.getDeclaringClass();
            // url ä¸Šçš„版本,优先获取方法上的版本
            UrlVersion urlVersion = AnnotatedElementUtils.findMergedAnnotation(method, UrlVersion.class);
            // å†æ¬¡å°è¯•类上的版本
            if (urlVersion == null || StringUtil.isBlank(urlVersion.value())) {
                urlVersion = AnnotatedElementUtils.findMergedAnnotation(targetType, UrlVersion.class);
            }
            if (urlVersion != null && StringUtil.isNotBlank(urlVersion.value())) {
                String versionUrl = "/" + urlVersion.value();
                data.template().uri(versionUrl);
            }
            // æ³¨æ„ï¼šåœ¨çˆ¶ç±»ä¹‹å‰ æ·»åŠ  url版本,在父类之后,处理 Media Types ç‰ˆæœ¬
            super.processAnnotationOnMethod(data, methodAnnotation, method);
            // å¤„理 Media Types ç‰ˆæœ¬ä¿¡æ¯
            ApiVersion apiVersion = AnnotatedElementUtils.findMergedAnnotation(method, ApiVersion.class);
            // å†æ¬¡å°è¯•类上的版本
            if (apiVersion == null || StringUtil.isBlank(apiVersion.value())) {
                apiVersion = AnnotatedElementUtils.findMergedAnnotation(targetType, ApiVersion.class);
            }
            if (apiVersion != null && StringUtil.isNotBlank(apiVersion.value())) {
                BladeMediaType bladeMediaType = new BladeMediaType(apiVersion.value());
                data.template().header(HttpHeaders.ACCEPT, bladeMediaType.toString());
            }
        }
    }
    /**
     * å‚考:https://gist.github.com/rmfish/0ed59a9af6c05157be2a60c9acea2a10
     * @param annotations æ³¨è§£
     * @param paramIndex å‚数索引
     * @return æ˜¯å¦ http æ³¨è§£
     */
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
        boolean httpAnnotation = super.processAnnotationsOnParameter(data, annotations, paramIndex);
        // åœ¨ springMvc ä¸­å¦‚果是 Get è¯·æ±‚且参数中是对象 æ²¡æœ‰å£°æ˜Žä¸º@RequestBody åˆ™é»˜è®¤ä¸º Param
        if (!httpAnnotation && StringPool.GET.equals(data.template().method().toUpperCase())) {
            for (Annotation parameterAnnotation : annotations) {
                if (!(parameterAnnotation instanceof RequestBody)) {
                    return false;
                }
            }
            data.queryMapIndex(paramIndex);
            return true;
        }
        return httpAnnotation;
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeWebMvcRegistrations.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.version;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
 * url版本号处理
 *
 * @author L.cm
 */
public class BladeWebMvcRegistrations implements WebMvcRegistrations {
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new BladeRequestMappingHandlerMapping();
    }
    @Override
    public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
        return null;
    }
    @Override
    public ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
        return null;
    }
}
Source/BladeX-Tool/blade-core-cloud/src/main/java/org/springblade/core/cloud/version/VersionMappingAutoConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.cloud.version;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
/**
 * url版本号处理
 *
 * å‚考:https://gitee.com/lianqu1990/spring-boot-starter-version-mapping
 *
 * @author L.cm
 */
@AutoConfiguration
@ConditionalOnWebApplication
public class VersionMappingAutoConfiguration {
    @Bean
    public WebMvcRegistrations bladeWebMvcRegistrations() {
        return new BladeWebMvcRegistrations();
    }
}
Source/BladeX-Tool/blade-core-context/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-context</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-tool</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeCallableWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import org.slf4j.MDC;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.lang.Nullable;
import java.util.Map;
import java.util.concurrent.Callable;
/**
 * å¤šçº¿ç¨‹ä¸­ä¼ é€’ context å’Œ mdc
 *
 * @author L.cm
 */
public class BladeCallableWrapper<V> implements Callable<V> {
    private final Callable<V> delegate;
    private final Map<String, Object> tlMap;
    /**
     * logback ä¸‹æœ‰å¯èƒ½ä¸º null
     */
    @Nullable
    private final Map<String, String> mdcMap;
    public BladeCallableWrapper(Callable<V> callable) {
        this.delegate = callable;
        this.tlMap = ThreadLocalUtil.getAll();
        this.mdcMap = MDC.getCopyOfContextMap();
    }
    @Override
    public V call() throws Exception {
        if (!tlMap.isEmpty()) {
            ThreadLocalUtil.put(tlMap);
        }
        if (mdcMap != null && !mdcMap.isEmpty()) {
            MDC.setContextMap(mdcMap);
        }
        try {
            return delegate.call();
        } finally {
            tlMap.clear();
            if (mdcMap != null) {
                mdcMap.clear();
            }
            ThreadLocalUtil.clear();
            MDC.clear();
        }
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeContext.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import org.springframework.lang.Nullable;
import java.util.function.Function;
/**
 * Blade微服务上下文
 *
 * @author L.cm
 */
public interface BladeContext {
    /**
     * èŽ·å– è¯·æ±‚ id
     *
     * @return è¯·æ±‚id
     */
    @Nullable
    String getRequestId();
    /**
     * è´¦å·id
     *
     * @return è´¦å·id
     */
    @Nullable
    String getAccountId();
    /**
     * èŽ·å–ç§Ÿæˆ·id
     *
     * @return ç§Ÿæˆ·id
     */
    @Nullable
    String getTenantId();
    /**
     * èŽ·å–ä¸Šä¸‹æ–‡ä¸­çš„æ•°æ®
     *
     * @param ctxKey ä¸Šä¸‹æ–‡ä¸­çš„key
     * @return è¿”回对象
     */
    @Nullable
    String get(String ctxKey);
    /**
     * èŽ·å–ä¸Šä¸‹æ–‡ä¸­çš„æ•°æ®
     *
     * @param ctxKey   ä¸Šä¸‹æ–‡ä¸­çš„key
     * @param function å‡½æ•°å¼
     * @param <T>      æ³›åž‹å¯¹è±¡
     * @return è¿”回对象
     */
    @Nullable
    <T> T get(String ctxKey, Function<String, T> function);
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeHttpHeadersGetter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import javax.servlet.http.HttpServletRequest;
/**
 * HttpHeaders èŽ·å–å™¨ï¼Œç”¨äºŽè·¨æœåŠ¡å’Œçº¿ç¨‹çš„ä¼ é€’ï¼Œ
 * <p>
 * æš‚时不支持 webflux。
 *
 * @author L.cm
 */
public interface BladeHttpHeadersGetter {
    /**
     * èŽ·å– HttpHeaders
     *
     * @return HttpHeaders
     */
    @Nullable
    HttpHeaders get();
    /**
     * èŽ·å– HttpHeaders
     *
     * @param request è¯·æ±‚
     * @return HttpHeaders
     */
    @Nullable
    HttpHeaders get(HttpServletRequest request);
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeRunnableWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import org.slf4j.MDC;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.lang.Nullable;
import java.util.Map;
/**
 * å¤šçº¿ç¨‹ä¸­ä¼ é€’ context å’Œ mdc
 *
 * @author L.cm
 */
public class BladeRunnableWrapper implements Runnable {
    private final Runnable delegate;
    private final Map<String, Object> tlMap;
    /**
     * logback ä¸‹æœ‰å¯èƒ½ä¸º null
     */
    @Nullable
    private final Map<String, String> mdcMap;
    public BladeRunnableWrapper(Runnable runnable) {
        this.delegate = runnable;
        this.tlMap = ThreadLocalUtil.getAll();
        this.mdcMap = MDC.getCopyOfContextMap();
    }
    @Override
    public void run() {
        if (!tlMap.isEmpty()) {
            ThreadLocalUtil.put(tlMap);
        }
        if (mdcMap != null && !mdcMap.isEmpty()) {
            MDC.setContextMap(mdcMap);
        }
        try {
            delegate.run();
        } finally {
            tlMap.clear();
            if (mdcMap != null) {
                mdcMap.clear();
            }
            ThreadLocalUtil.clear();
            MDC.clear();
        }
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/BladeServletContext.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import lombok.RequiredArgsConstructor;
import org.springblade.core.context.props.BladeContextProperties;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import java.util.function.Function;
import static org.springblade.core.tool.constant.BladeConstant.CONTEXT_KEY;
/**
 * blade servlet ä¸Šä¸‹æ–‡ï¼Œè·¨çº¿ç¨‹å¤±æ•ˆ
 *
 * @author L.cm
 */
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class BladeServletContext implements BladeContext {
    private final BladeContextProperties contextProperties;
    private final BladeHttpHeadersGetter httpHeadersGetter;
    @Nullable
    @Override
    public String getRequestId() {
        return get(contextProperties.getHeaders().getRequestId());
    }
    @Nullable
    @Override
    public String getAccountId() {
        return get(contextProperties.getHeaders().getAccountId());
    }
    @Nullable
    @Override
    public String getTenantId() {
        return get(contextProperties.getHeaders().getTenantId());
    }
    @Nullable
    @Override
    public String get(String ctxKey) {
        HttpHeaders headers = ThreadLocalUtil.getIfAbsent(CONTEXT_KEY, httpHeadersGetter::get);
        if (headers == null || headers.isEmpty()) {
            return null;
        }
        return headers.getFirst(ctxKey);
    }
    @Nullable
    @Override
    public <T> T get(String ctxKey, Function<String, T> function) {
        String ctxValue = get(ctxKey);
        if (StringUtil.isBlank(ctxValue)) {
            return null;
        }
        return function.apply(ctxKey);
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/ServletHttpHeadersGetter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,75 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context;
import lombok.RequiredArgsConstructor;
import org.springblade.core.context.props.BladeContextProperties;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.List;
/**
 * HttpHeaders èŽ·å–å™¨
 *
 * @author L.cm
 */
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class ServletHttpHeadersGetter implements BladeHttpHeadersGetter {
    private final BladeContextProperties properties;
    @Nullable
    @Override
    public HttpHeaders get() {
        HttpServletRequest request = WebUtil.getRequest();
        if (request == null) {
            return null;
        }
        return get(request);
    }
    @Nullable
    @Override
    public HttpHeaders get(HttpServletRequest request) {
        HttpHeaders headers = new HttpHeaders();
        List<String> crossHeaders = properties.getCrossHeaders();
        // ä¼ é€’请求头
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            List<String> allowed = properties.getHeaders().getAllowed();
            while (headerNames.hasMoreElements()) {
                String key = headerNames.nextElement();
                // åªæ”¯æŒé…ç½®çš„ header
                if (crossHeaders.contains(key) || allowed.contains(key)) {
                    String values = request.getHeader(key);
                    // header value ä¸ä¸ºç©ºçš„ ä¼ é€’
                    if (StringUtil.isNotBlank(values)) {
                        headers.add(key, values);
                    }
                }
            }
        }
        return headers;
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/config/BladeContextAutoConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context.config;
import org.springblade.core.context.BladeContext;
import org.springblade.core.context.BladeHttpHeadersGetter;
import org.springblade.core.context.BladeServletContext;
import org.springblade.core.context.ServletHttpHeadersGetter;
import org.springblade.core.context.props.BladeContextProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
 * blade æœåŠ¡ä¸Šä¸‹æ–‡é…ç½®
 *
 * @author L.cm
 */
@AutoConfiguration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties(BladeContextProperties.class)
public class BladeContextAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public BladeHttpHeadersGetter bladeHttpHeadersGetter(BladeContextProperties contextProperties) {
        return new ServletHttpHeadersGetter(contextProperties);
    }
    @Bean
    @ConditionalOnMissingBean
    public BladeContext bladeContext(BladeContextProperties contextProperties, BladeHttpHeadersGetter httpHeadersGetter) {
        return new BladeServletContext(contextProperties, httpHeadersGetter);
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/config/BladeServletListenerConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context.config;
import org.springblade.core.context.BladeHttpHeadersGetter;
import org.springblade.core.context.listener.BladeServletRequestListener;
import org.springblade.core.context.props.BladeContextProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
/**
 * Servlet ç›‘听器自动配置
 *
 * @author L.cm
 */
@AutoConfiguration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class BladeServletListenerConfiguration {
    @Bean
    public ServletListenerRegistrationBean<?> registerCustomListener(BladeContextProperties properties,
                                                                     BladeHttpHeadersGetter httpHeadersGetter) {
        return new ServletListenerRegistrationBean<>(new BladeServletRequestListener(properties, httpHeadersGetter));
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/listener/BladeServletRequestListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context.listener;
import lombok.RequiredArgsConstructor;
import org.slf4j.MDC;
import org.springblade.core.context.BladeHttpHeadersGetter;
import org.springblade.core.context.props.BladeContextProperties;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.ThreadLocalUtil;
import org.springframework.http.HttpHeaders;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
/**
 * Servlet è¯·æ±‚监听器
 *
 * @author L.cm
 */
@RequiredArgsConstructor
public class BladeServletRequestListener implements ServletRequestListener {
    private final BladeContextProperties contextProperties;
    private final BladeHttpHeadersGetter httpHeadersGetter;
    @Override
    public void requestInitialized(ServletRequestEvent event) {
        HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
        // MDC èŽ·å–é€ä¼ çš„ å˜é‡
        BladeContextProperties.Headers headers = contextProperties.getHeaders();
        String requestId = request.getHeader(headers.getRequestId());
        if (StringUtil.isNotBlank(requestId)) {
            MDC.put(BladeConstant.MDC_REQUEST_ID_KEY, requestId);
        }
        String accountId = request.getHeader(headers.getAccountId());
        if (StringUtil.isNotBlank(accountId)) {
            MDC.put(BladeConstant.MDC_ACCOUNT_ID_KEY, accountId);
        }
        String tenantId = request.getHeader(headers.getTenantId());
        if (StringUtil.isNotBlank(tenantId)) {
            MDC.put(BladeConstant.MDC_TENANT_ID_KEY, tenantId);
        }
        // å¤„理 context,直接传递 request,因为 spring ä¸­çš„尚未初始化完成
        HttpHeaders httpHeaders = httpHeadersGetter.get(request);
        ThreadLocalUtil.put(BladeConstant.CONTEXT_KEY, httpHeaders);
    }
    @Override
    public void requestDestroyed(ServletRequestEvent event) {
        // ä¼šè¯é”€æ¯æ—¶ï¼Œæ¸…除上下文
        ThreadLocalUtil.clear();
        // ä¼šè¯é”€æ¯æ—¶ï¼Œæ¸…除 mdc
        MDC.remove(BladeConstant.MDC_REQUEST_ID_KEY);
        MDC.remove(BladeConstant.MDC_ACCOUNT_ID_KEY);
        MDC.remove(BladeConstant.MDC_TENANT_ID_KEY);
    }
}
Source/BladeX-Tool/blade-core-context/src/main/java/org/springblade/core/context/props/BladeContextProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.context.props;
import lombok.Getter;
import lombok.Setter;
import org.springblade.core.launch.constant.TokenConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * Headers é…ç½®
 *
 * @author L.cm
 */
@Getter
@Setter
@ConfigurationProperties(BladeContextProperties.PREFIX)
public class BladeContextProperties {
    /**
     * é…ç½®å‰ç¼€
     */
    public static final String PREFIX = "blade.context";
    /**
     * ä¸Šä¸‹æ–‡ä¼ é€’çš„ headers ä¿¡æ¯
     */
    private Headers headers = new Headers();
    @Getter
    @Setter
    public static class Headers {
        /**
         * è¯·æ±‚id,默认:Blade-RequestId
         */
        private String requestId = "Blade-RequestId";
        /**
         * ç”¨äºŽ èšåˆå±‚ å‘调用层传递用户信息 çš„请求头,默认:Blade-AccountId
         */
        private String accountId = "Blade-AccountId";
        /**
         * ç”¨äºŽ èšåˆå±‚ å‘调用层传递租户id çš„请求头,默认:Blade-TenantId
         */
        private String tenantId = "Blade-TenantId";
        /**
         * è‡ªå®šä¹‰ RestTemplate å’Œ Feign é€ä¼ åˆ°ä¸‹å±‚çš„ Headers åç§°åˆ—表
         */
        private List<String> allowed = Arrays.asList("X-Real-IP", "x-forwarded-for", "version", "VERSION", "authorization", "Authorization", TokenConstant.HEADER.toLowerCase(), TokenConstant.HEADER);
    }
    /**
     * èŽ·å–è·¨æœåŠ¡çš„è¯·æ±‚å¤´
     *
     * @return è¯·æ±‚头列表
     */
    public List<String> getCrossHeaders() {
        List<String> headerList = new ArrayList<>();
        headerList.add(headers.getRequestId());
        headerList.add(headers.getAccountId());
        headerList.add(headers.getTenantId());
        headerList.addAll(headers.getAllowed());
        return headerList;
    }
}
Source/BladeX-Tool/blade-core-db/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-db</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!--Blade-->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-tool</artifactId>
        </dependency>
        <!--Spring-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>tomcat-jdbc</artifactId>
                    <groupId>org.apache.tomcat</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--Mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!-- Druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- Oracle -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc7</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- PostgreSql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- SqlServer -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- DaMeng -->
        <dependency>
            <groupId>com.dameng</groupId>
            <artifactId>DmJdbcDriver18</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-db/src/main/java/org/springblade/core/db/config/DbConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.db.config;
import org.springblade.core.launch.props.BladePropertySource;
import org.springframework.boot.autoconfigure.AutoConfiguration;
/**
 * æ•°æ®æºé…ç½®ç±»
 *
 * @author Chill
 */
@AutoConfiguration
@BladePropertySource(value = "classpath:/blade-db.yml")
public class DbConfiguration {
}
Source/BladeX-Tool/blade-core-db/src/main/java/org/springblade/core/db/package-info.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
/**
 * Created by Blade.
 *
 * @author zhuangqian
 */
package org.springblade.core.db;
Source/BladeX-Tool/blade-core-db/src/main/resources/blade-db.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
#spring-datasource配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      initial-size: 5
      max-active: 20
      min-idle: 5
      max-wait: 60000
      # MySql、PostgreSQL校验
      validation-query: select 1
      # Oracle校验
      #validation-query: select 1 from dual
      validation-query-timeout: 2000
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      stat-view-servlet:
        enabled: true
        login-username: blade
        login-password: 1qaz@WSX
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*'
        session-stat-enable: true
        session-stat-max-count: 10
      #hikari:
      #connection-test-query: SELECT 1 FROM DUAL
      #connection-timeout: 30000
      #maximum-pool-size: 5
      #max-lifetime: 1800000
      #minimum-idle: 1
Source/BladeX-Tool/blade-core-launch/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-launch</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!--Spring-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.launch.constant.NacosConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.*;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
 * é¡¹ç›®å¯åŠ¨å™¨ï¼Œæžå®šçŽ¯å¢ƒå˜é‡é—®é¢˜
 *
 * @author Chill
 */
public class BladeApplication {
    /**
     * Create an application context
     * java -jar app.jar --spring.profiles.active=prod --server.port=2333
     *
     * @param appName application name
     * @param source  The sources
     * @return an application context created from the current state
     */
    public static ConfigurableApplicationContext run(String appName, Class source, String... args) {
        SpringApplicationBuilder builder = createSpringApplicationBuilder(appName, source, args);
        return builder.run(args);
    }
    public static SpringApplicationBuilder createSpringApplicationBuilder(String appName, Class source, String... args) {
        Assert.hasText(appName, "[appName]服务名不能为空");
        // è¯»å–环境变量,使用spring boot的规则
        ConfigurableEnvironment environment = new StandardEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addFirst(new SimpleCommandLinePropertySource(args));
        propertySources.addLast(new MapPropertySource(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, environment.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, environment.getSystemEnvironment()));
        // èŽ·å–é…ç½®çš„çŽ¯å¢ƒå˜é‡
        String[] activeProfiles = environment.getActiveProfiles();
        // åˆ¤æ–­çŽ¯å¢ƒ:dev、test、prod
        List<String> profiles = Arrays.asList(activeProfiles);
        // é¢„设的环境
        List<String> presetProfiles = new ArrayList<>(Arrays.asList(AppConstant.DEV_CODE, AppConstant.TEST_CODE, AppConstant.PROD_CODE));
        // äº¤é›†
        presetProfiles.retainAll(profiles);
        // å½“前使用
        List<String> activeProfileList = new ArrayList<>(profiles);
        Function<Object[], String> joinFun = StringUtils::arrayToCommaDelimitedString;
        SpringApplicationBuilder builder = new SpringApplicationBuilder(source);
        String profile;
        if (activeProfileList.isEmpty()) {
            // é»˜è®¤dev开发
            profile = AppConstant.DEV_CODE;
            activeProfileList.add(profile);
            builder.profiles(profile);
        } else if (activeProfileList.size() == 1) {
            profile = activeProfileList.get(0);
        } else {
            // åŒæ—¶å­˜åœ¨dev、test、prod环境时
            throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]");
        }
        String startJarPath = BladeApplication.class.getResource("/").getPath().split("!")[0];
        String activePros = joinFun.apply(activeProfileList.toArray());
        System.out.printf("----启动中,读取到的环境变量:[%s],jar地址:[%s]----%n", activePros, startJarPath);
        Properties props = System.getProperties();
        props.setProperty("spring.application.name", appName);
        props.setProperty("spring.profiles.active", profile);
        props.setProperty("info.version", AppConstant.APPLICATION_VERSION);
        props.setProperty("info.desc", appName);
        props.setProperty("file.encoding", StandardCharsets.UTF_8.name());
        props.setProperty("blade.env", profile);
        props.setProperty("blade.name", appName);
        props.setProperty("blade.is-local", String.valueOf(isLocalDev()));
        props.setProperty("blade.dev-mode", profile.equals(AppConstant.PROD_CODE) ? "false" : "true");
        props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
        props.setProperty("loadbalancer.client.name", appName);
        Properties defaultProperties = new Properties();
        defaultProperties.setProperty("spring.main.allow-bean-definition-overriding", "true");
        defaultProperties.setProperty("spring.sleuth.sampler.percentage", "1.0");
        defaultProperties.setProperty("spring.cloud.alibaba.seata.tx-service-group", appName.concat(NacosConstant.NACOS_GROUP_SUFFIX));
        defaultProperties.setProperty("spring.cloud.nacos.config.file-extension", NacosConstant.NACOS_CONFIG_FORMAT);
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[0].data-id", NacosConstant.sharedDataId());
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[0].group", NacosConstant.NACOS_CONFIG_GROUP);
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[0].refresh", NacosConstant.NACOS_CONFIG_REFRESH);
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[1].data-id", NacosConstant.sharedDataId(profile));
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[1].group", NacosConstant.NACOS_CONFIG_GROUP);
        defaultProperties.setProperty("spring.cloud.nacos.config.shared-configs[1].refresh", NacosConstant.NACOS_CONFIG_REFRESH);
        builder.properties(defaultProperties);
        // åŠ è½½è‡ªå®šä¹‰ç»„ä»¶
        List<LauncherService> launcherList = new ArrayList<>();
        ServiceLoader.load(LauncherService.class).forEach(launcherList::add);
        launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList())
            .forEach(launcherService -> launcherService.launcher(builder, appName, profile, isLocalDev()));
        return builder;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦ä¸ºæœ¬åœ°å¼€å‘环境
     *
     * @return boolean
     */
    public static boolean isLocalDev() {
        String osName = System.getProperty("os.name");
        return StringUtils.hasText(osName) && !(AppConstant.OS_NAME_LINUX.equalsIgnoreCase(osName));
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/StartEventListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;
/**
 * é¡¹ç›®å¯åŠ¨äº‹ä»¶é€šçŸ¥
 *
 * @author Chill
 */
@Slf4j
@AutoConfiguration
public class StartEventListener {
    @Async
    @Order
    @EventListener(WebServerInitializedEvent.class)
    public void afterStart(WebServerInitializedEvent event) {
        Environment environment = event.getApplicationContext().getEnvironment();
        String appName = environment.getProperty("spring.application.name").toUpperCase();
        int localPort = event.getWebServer().getPort();
        String profile = StringUtils.arrayToCommaDelimitedString(environment.getActiveProfiles());
        log.info("---[{}]---启动完成,当前使用的端口:[{}],环境变量:[{}]---", appName, localPort, profile);
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladeLaunchConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.config;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
 * é…ç½®ç±»
 *
 * @author Chill
 */
@AutoConfiguration
@AllArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BladeLaunchConfiguration {
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladePropertyConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.launch.config;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.props.BladePropertySourcePostProcessor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
 * blade property config
 *
 * @author L.cm
 */
@AutoConfiguration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties(BladeProperties.class)
public class BladePropertyConfiguration {
    @Bean
    public BladePropertySourcePostProcessor bladePropertySourcePostProcessor() {
        return new BladePropertySourcePostProcessor();
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * ç³»ç»Ÿå¸¸é‡
 *
 * @author Chill
 */
public interface AppConstant {
    /**
     * åº”用版本
     */
    String APPLICATION_VERSION = "3.0.1.RELEASE";
    /**
     * åŸºç¡€åŒ…
     */
    String BASE_PACKAGES = "org.springblade";
    /**
     * åº”用名前缀
     */
    String APPLICATION_NAME_PREFIX = "blade-";
    /**
     * ç½‘关模块名称
     */
    String APPLICATION_GATEWAY_NAME = APPLICATION_NAME_PREFIX + "gateway";
    /**
     * æŽˆæƒæ¨¡å—名称
     */
    String APPLICATION_AUTH_NAME = APPLICATION_NAME_PREFIX + "auth";
    /**
     * ç›‘控模块名称
     */
    String APPLICATION_ADMIN_NAME = APPLICATION_NAME_PREFIX + "admin";
    /**
     * æŠ¥è¡¨ç³»ç»Ÿåç§°
     */
    String APPLICATION_REPORT_NAME = APPLICATION_NAME_PREFIX + "report";
    /**
     * é›†ç¾¤ç›‘控名称
     */
    String APPLICATION_TURBINE_NAME = APPLICATION_NAME_PREFIX + "turbine";
    /**
     * é“¾è·¯è¿½è¸ªåç§°
     */
    String APPLICATION_ZIPKIN_NAME = APPLICATION_NAME_PREFIX + "zipkin";
    /**
     * websocket名称
     */
    String APPLICATION_WEBSOCKET_NAME = APPLICATION_NAME_PREFIX + "websocket";
    /**
     * é¦–页模块名称
     */
    String APPLICATION_DESK_NAME = APPLICATION_NAME_PREFIX + "desk";
    /**
     * ç³»ç»Ÿæ¨¡å—名称
     */
    String APPLICATION_SYSTEM_NAME = APPLICATION_NAME_PREFIX + "system";
    /**
     * ç”¨æˆ·æ¨¡å—名称
     */
    String APPLICATION_USER_NAME = APPLICATION_NAME_PREFIX + "user";
    /**
     * æ—¥å¿—模块名称
     */
    String APPLICATION_LOG_NAME = APPLICATION_NAME_PREFIX + "log";
    /**
     * å¼€å‘模块名称
     */
    String APPLICATION_DEVELOP_NAME = APPLICATION_NAME_PREFIX + "develop";
    /**
     * æµç¨‹è®¾è®¡å™¨æ¨¡å—名称
     */
    String APPLICATION_FLOWDESIGN_NAME = APPLICATION_NAME_PREFIX + "flowdesign";
    /**
     * å·¥ä½œæµæ¨¡å—名称
     */
    String APPLICATION_FLOW_NAME = APPLICATION_NAME_PREFIX + "flow";
    /**
     * èµ„源模块名称
     */
    String APPLICATION_RESOURCE_NAME = APPLICATION_NAME_PREFIX + "resource";
    /**
     * æŽ¥å£æ–‡æ¡£æ¨¡å—名称
     */
    String APPLICATION_SWAGGER_NAME = APPLICATION_NAME_PREFIX + "swagger";
    /**
     * æµ‹è¯•模块名称
     */
    String APPLICATION_TEST_NAME = APPLICATION_NAME_PREFIX + "test";
    /**
     * æ¼”示模块名称
     */
    String APPLICATION_DEMO_NAME = APPLICATION_NAME_PREFIX + "demo";
    /**
     * å¼€å‘环境
     */
    String DEV_CODE = "dev";
    /**
     * ç”Ÿäº§çŽ¯å¢ƒ
     */
    String PROD_CODE = "prod";
    /**
     * æµ‹è¯•环境
     */
    String TEST_CODE = "test";
    /**
     * ä»£ç éƒ¨ç½²äºŽ linux ä¸Šï¼Œå·¥ä½œé»˜è®¤ä¸º mac å’Œ Windows
     */
    String OS_NAME_LINUX = "LINUX";
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/ConsulConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * Consul常量.
 *
 * @author Chill
 */
public interface ConsulConstant {
    /**
     * consul dev åœ°å€
     */
    String CONSUL_HOST = "http://localhost";
    /**
     * consul端口
     */
    String CONSUL_PORT = "8500";
    /**
     * consul端口
     */
    String CONSUL_CONFIG_FORMAT = "yaml";
    /**
     * consul端口
     */
    String CONSUL_WATCH_DELAY = "1000";
    /**
     * consul端口
     */
    String CONSUL_WATCH_ENABLED = "true";
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/FlowConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * æµç¨‹å¸¸é‡.
 *
 * @author Chill
 */
public interface FlowConstant {
    /**
     * ä»»åŠ¡ç”¨æˆ·æ ‡è¯†å‰ç¼€
     */
    String TASK_USR_PREFIX = "taskUser_";
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,128 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * Nacos常量.
 *
 * @author Chill
 */
public interface NacosConstant {
    /**
     * nacos åœ°å€
     */
    String NACOS_ADDR = "127.0.0.1:8848";
    /**
     * nacos é…ç½®å‰ç¼€
     */
    String NACOS_CONFIG_PREFIX = "blade";
    /**
     * nacos ç»„配置后缀
     */
    String NACOS_GROUP_SUFFIX = "-group";
    /**
     * nacos é…ç½®æ–‡ä»¶ç±»åž‹
     */
    String NACOS_CONFIG_FORMAT = "yaml";
    /**
     * nacos json配置文件类型
     */
    String NACOS_CONFIG_JSON_FORMAT = "json";
    /**
     * nacos æ˜¯å¦åˆ·æ–°
     */
    String NACOS_CONFIG_REFRESH = "true";
    /**
     * nacos åˆ†ç»„
     */
    String NACOS_CONFIG_GROUP = "DEFAULT_GROUP";
    /**
     * seata åˆ†ç»„
     */
    String NACOS_SEATA_GROUP = "SEATA_GROUP";
    /**
     * æž„建服务对应的 dataId
     *
     * @param appName æœåŠ¡å
     * @return dataId
     */
    static String dataId(String appName) {
        return appName + "." + NACOS_CONFIG_FORMAT;
    }
    /**
     * æž„建服务对应的 dataId
     *
     * @param appName æœåŠ¡å
     * @param profile çŽ¯å¢ƒå˜é‡
     * @return dataId
     */
    static String dataId(String appName, String profile) {
        return dataId(appName, profile, NACOS_CONFIG_FORMAT);
    }
    /**
     * æž„建服务对应的 dataId
     *
     * @param appName æœåŠ¡å
     * @param profile çŽ¯å¢ƒå˜é‡
     * @param format  æ–‡ä»¶ç±»åž‹
     * @return dataId
     */
    static String dataId(String appName, String profile, String format) {
        return appName + "-" + profile + "." + format;
    }
    /**
     * æœåŠ¡é»˜è®¤åŠ è½½çš„é…ç½®
     *
     * @return sharedDataIds
     */
    static String sharedDataId() {
        return NACOS_CONFIG_PREFIX + "." + NACOS_CONFIG_FORMAT;
    }
    /**
     * æœåŠ¡é»˜è®¤åŠ è½½çš„é…ç½®
     *
     * @param profile çŽ¯å¢ƒå˜é‡
     * @return sharedDataIds
     */
    static String sharedDataId(String profile) {
        return NACOS_CONFIG_PREFIX + "-" + profile + "." + NACOS_CONFIG_FORMAT;
    }
    /**
     * æœåŠ¡é»˜è®¤åŠ è½½çš„é…ç½®
     *
     * @param profile çŽ¯å¢ƒå˜é‡
     * @return sharedDataIds
     */
    static String sharedDataIds(String profile) {
        return NACOS_CONFIG_PREFIX + "." + NACOS_CONFIG_FORMAT + "," + NACOS_CONFIG_PREFIX + "-" + profile + "." + NACOS_CONFIG_FORMAT;
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/SentinelConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * sentinel配置.
 *
 * @author Chill
 */
public interface SentinelConstant {
    /**
     * sentinel åœ°å€
     */
    String SENTINEL_ADDR = "127.0.0.1:8858";
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * Token配置常量.
 *
 * @author Chill
 */
public interface TokenConstant {
    String AVATAR = "avatar";
    String HEADER = "Blade-Auth";
    String BEARER = "bearer";
    String ACCESS_TOKEN = "access_token";
    String REFRESH_TOKEN = "refresh_token";
    String TOKEN_TYPE = "token_type";
    String EXPIRES_IN = "expires_in";
    String ACCOUNT = "account";
    String USER_NAME = "user_name";
    String NICK_NAME = "nick_name";
    String REAL_NAME = "real_name";
    String USER_ID = "user_id";
    String DEPT_ID = "dept_id";
    String POST_ID = "post_id";
    String ROLE_ID = "role_id";
    String ROLE_NAME = "role_name";
    String TENANT_ID = "tenant_id";
    String OAUTH_ID = "oauth_id";
    String CLIENT_ID = "client_id";
    String DETAIL = "detail";
    String LICENSE = "license";
    String LICENSE_NAME = "powered by bladex";
    String DEFAULT_AVATAR = "";
    Integer AUTH_LENGTH = 7;
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/constant/ZookeeperConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.constant;
/**
 * zookeeper é…ç½®.
 *
 * @author Chill
 */
public interface ZookeeperConstant {
    /**
     * zookeeper id
     */
    String ZOOKEEPER_ID = "zk";
    /**
     * zookeeper connect string
     */
    String ZOOKEEPER_CONNECT_STRING = "127.0.0.1:2181";
    /**
     * zookeeper address
     */
    String ZOOKEEPER_ADDRESS = "zookeeper://" + ZOOKEEPER_CONNECT_STRING;
    /**
     * zookeeper root
     */
    String ZOOKEEPER_ROOT = "/blade-services";
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/log/BladeLogLevel.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.launch.log;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
 * è¯·æ±‚日志级别,来源 okHttp
 *
 * @author L.cm
 */
@Getter
@RequiredArgsConstructor
public enum BladeLogLevel {
    /**
     * No logs.
     */
    NONE(0),
    /**
     * Logs request and response lines.
     *
     * <p>Example:
     * <pre>{@code
     * --> POST /greeting http/1.1 (3-byte body)
     *
     * <-- 200 OK (22ms, 6-byte body)
     * }</pre>
     */
    BASIC(1),
    /**
     * Logs request and response lines and their respective headers.
     *
     * <p>Example:
     * <pre>{@code
     * --> POST /greeting http/1.1
     * Host: example.com
     * Content-Type: plain/text
     * Content-Length: 3
     * --> END POST
     *
     * <-- 200 OK (22ms)
     * Content-Type: plain/text
     * Content-Length: 6
     * <-- END HTTP
     * }</pre>
     */
    HEADERS(2),
    /**
     * Logs request and response lines and their respective headers and bodies (if present).
     *
     * <p>Example:
     * <pre>{@code
     * --> POST /greeting http/1.1
     * Host: example.com
     * Content-Type: plain/text
     * Content-Length: 3
     *
     * Hi?
     * --> END POST
     *
     * <-- 200 OK (22ms)
     * Content-Type: plain/text
     * Content-Length: 6
     *
     * Hello!
     * <-- END HTTP
     * }</pre>
     */
    BODY(3);
    /**
     * è¯·æ±‚日志配置前缀
     */
    public static final String REQ_LOG_PROPS_PREFIX = "blade.log.request";
    /**
     * æŽ§åˆ¶å°æ—¥å¿—是否启用
     */
    public static final String CONSOLE_LOG_ENABLED_PROP = "blade.log.console.enabled";
    /**
     * çº§åˆ«
     */
    private final int level;
    /**
     * å½“前版本 å°äºŽå’Œç­‰äºŽ æ¯”较的版本
     *
     * @param level LogLevel
     * @return æ˜¯å¦å°äºŽå’Œç­‰äºŽ
     */
    public boolean lte(BladeLogLevel level) {
        return this.level <= level.level;
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladeProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,226 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.props;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
 * é…ç½®æ–‡ä»¶
 *
 * @author Chill
 */
@ConfigurationProperties("blade")
public class BladeProperties implements EnvironmentAware, EnvironmentCapable {
    @Nullable
    private Environment environment;
    /**
     * è£…载自定义配置blade.prop.xxx
     */
    @Getter
    private final Map<String, String> prop = new HashMap<>();
    /**
     * èŽ·å–é…ç½®
     *
     * @param key key
     * @return value
     */
    @Nullable
    public String get(String key) {
        return get(key, null);
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key          key
     * @param defaultValue é»˜è®¤å€¼
     * @return value
     */
    @Nullable
    public String get(String key, @Nullable String defaultValue) {
        String value = prop.get(key);
        if (value == null) {
            return defaultValue;
        }
        return value;
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key key
     * @return int value
     */
    @Nullable
    public Integer getInt(String key) {
        return getInt(key, null);
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key          key
     * @param defaultValue é»˜è®¤å€¼
     * @return int value
     */
    @Nullable
    public Integer getInt(String key, @Nullable Integer defaultValue) {
        String value = prop.get(key);
        if (value != null) {
            return Integer.valueOf(value.trim());
        }
        return defaultValue;
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key key
     * @return long value
     */
    @Nullable
    public Long getLong(String key) {
        return getLong(key, null);
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key          key
     * @param defaultValue é»˜è®¤å€¼
     * @return long value
     */
    @Nullable
    public Long getLong(String key, @Nullable Long defaultValue) {
        String value = prop.get(key);
        if (value != null) {
            return Long.valueOf(value.trim());
        }
        return defaultValue;
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key key
     * @return Boolean value
     */
    @Nullable
    public Boolean getBoolean(String key) {
        return getBoolean(key, null);
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key          key
     * @param defaultValue é»˜è®¤å€¼
     * @return Boolean value
     */
    @Nullable
    public Boolean getBoolean(String key, @Nullable Boolean defaultValue) {
        String value = prop.get(key);
        if (value != null) {
            value = value.toLowerCase().trim();
            return Boolean.parseBoolean(value);
        }
        return defaultValue;
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key key
     * @return double value
     */
    @Nullable
    public Double getDouble(String key) {
        return getDouble(key, null);
    }
    /**
     * èŽ·å–é…ç½®
     *
     * @param key          key
     * @param defaultValue é»˜è®¤å€¼
     * @return double value
     */
    @Nullable
    public Double getDouble(String key, @Nullable Double defaultValue) {
        String value = prop.get(key);
        if (value != null) {
            return Double.parseDouble(value.trim());
        }
        return defaultValue;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å­˜åœ¨key
     *
     * @param key prop key
     * @return boolean
     */
    public boolean containsKey(String key) {
        return prop.containsKey(key);
    }
    /**
     * çŽ¯å¢ƒï¼Œæ–¹ä¾¿åœ¨ä»£ç ä¸­èŽ·å–
     *
     * @return çŽ¯å¢ƒ env
     */
    public String getEnv() {
        Objects.requireNonNull(environment, "Spring boot çŽ¯å¢ƒä¸‹ Environment ä¸å¯èƒ½ä¸ºnull");
        String env = environment.getProperty("blade.env");
        Assert.notNull(env, "请使用 BladeApplication å¯åЍ...");
        return env;
    }
    /**
     * åº”用名称${spring.application.name}
     *
     * @return åº”用名
     */
    public String getName() {
        Objects.requireNonNull(environment, "Spring boot çŽ¯å¢ƒä¸‹ Environment ä¸å¯èƒ½ä¸ºnull");
        return environment.getProperty("spring.application.name", environment.getProperty("blade.name", ""));
    }
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
    @Override
    public Environment getEnvironment() {
        Objects.requireNonNull(environment, "Spring boot çŽ¯å¢ƒä¸‹ Environment ä¸å¯èƒ½ä¸ºnull");
        return this.environment;
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySource.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.launch.props;
import org.springframework.core.Ordered;
import java.lang.annotation.*;
/**
 * è‡ªå®šä¹‰èµ„源文件读取,优先级最低
 *
 * @author L.cm
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BladePropertySource {
    /**
     * Indicate the resource location(s) of the properties file to be loaded.
     * for example, {@code "classpath:/com/example/app.yml"}
     *
     * @return location(s)
     */
    String value();
    /**
     * load app-{activeProfile}.yml
     *
     * @return {boolean}
     */
    boolean loadActiveProfile() default true;
    /**
     * Get the order value of this resource.
     *
     * @return order
     */
    int order() default Ordered.LOWEST_PRECEDENCE;
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySourcePostProcessor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,179 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.launch.props;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
 * è‡ªå®šä¹‰èµ„源文件读取,优先级最低
 *
 * @author L.cm
 */
@Slf4j
public class BladePropertySourcePostProcessor implements BeanFactoryPostProcessor, InitializingBean, Ordered {
    private final ResourceLoader resourceLoader;
    private final List<PropertySourceLoader> propertySourceLoaders;
    public BladePropertySourcePostProcessor() {
        this.resourceLoader = new DefaultResourceLoader();
        this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("BladePropertySourcePostProcessor process @BladePropertySource bean.");
        Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(BladePropertySource.class);
        Set<Map.Entry<String, Object>> beanEntrySet = beansWithAnnotation.entrySet();
        // æ²¡æœ‰ @YmlPropertySource æ³¨è§£ï¼Œè·³å‡º
        if (beanEntrySet.isEmpty()) {
            log.warn("Not found @BladePropertySource on spring bean class.");
            return;
        }
        // ç»„装资源
        List<PropertyFile> propertyFileList = new ArrayList<>();
        for (Map.Entry<String, Object> entry : beanEntrySet) {
            Class<?> beanClass = ClassUtils.getUserClass(entry.getValue());
            BladePropertySource propertySource = AnnotationUtils.getAnnotation(beanClass, BladePropertySource.class);
            if (propertySource == null) {
                continue;
            }
            int order = propertySource.order();
            boolean loadActiveProfile = propertySource.loadActiveProfile();
            String location = propertySource.value();
            propertyFileList.add(new PropertyFile(order, location, loadActiveProfile));
        }
        // è£…è½½ PropertySourceLoader
        Map<String, PropertySourceLoader> loaderMap = new HashMap<>(16);
        for (PropertySourceLoader loader : propertySourceLoaders) {
            String[] loaderExtensions = loader.getFileExtensions();
            for (String extension : loaderExtensions) {
                loaderMap.put(extension, loader);
            }
        }
        // åŽ»é‡ï¼ŒæŽ’åº
        List<PropertyFile> sortedPropertyList = propertyFileList.stream()
            .distinct()
            .sorted()
            .collect(Collectors.toList());
        ConfigurableEnvironment environment = beanFactory.getBean(ConfigurableEnvironment.class);
        MutablePropertySources propertySources = environment.getPropertySources();
        // åªæ”¯æŒ activeProfiles,没有必要支持 spring.profiles.include。
        String[] activeProfiles = environment.getActiveProfiles();
        ArrayList<PropertySource> propertySourceList = new ArrayList<>();
        for (String profile : activeProfiles) {
            for (PropertyFile propertyFile : sortedPropertyList) {
                // ä¸åŠ è½½ ActiveProfile çš„配置文件
                if (!propertyFile.loadActiveProfile) {
                    continue;
                }
                String extension = propertyFile.getExtension();
                PropertySourceLoader loader = loaderMap.get(extension);
                if (loader == null) {
                    throw new IllegalArgumentException("Can't find PropertySourceLoader for PropertySource extension:" + extension);
                }
                String location = propertyFile.getLocation();
                String filePath = StringUtils.stripFilenameExtension(location);
                String profiledLocation = filePath + "-" + profile + "." + extension;
                Resource resource = resourceLoader.getResource(profiledLocation);
                loadPropertySource(profiledLocation, resource, loader, propertySourceList);
            }
        }
        // æœ¬èº«çš„ Resource
        for (PropertyFile propertyFile : sortedPropertyList) {
            String extension = propertyFile.getExtension();
            PropertySourceLoader loader = loaderMap.get(extension);
            String location = propertyFile.getLocation();
            Resource resource = resourceLoader.getResource(location);
            loadPropertySource(location, resource, loader, propertySourceList);
        }
        // è½¬å­˜
        for (PropertySource propertySource : propertySourceList) {
            propertySources.addLast(propertySource);
        }
    }
    private static void loadPropertySource(String location, Resource resource,
                                           PropertySourceLoader loader,
                                           List<PropertySource> sourceList) {
        if (resource.exists()) {
            String name = "bladePropertySource: [" + location + "]";
            try {
                sourceList.addAll(loader.load(name, resource));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("BladePropertySourcePostProcessor init.");
    }
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
    @Getter
    @ToString
    @EqualsAndHashCode
    private static class PropertyFile implements Comparable<PropertyFile> {
        private final int order;
        private final String location;
        private final String extension;
        private final boolean loadActiveProfile;
        PropertyFile(int order, String location, boolean loadActiveProfile) {
            this.order = order;
            this.location = location;
            this.loadActiveProfile = loadActiveProfile;
            this.extension = Objects.requireNonNull(StringUtils.getFilenameExtension(location));
        }
        @Override
        public int compareTo(PropertyFile other) {
            return Integer.compare(this.order, other.order);
        }
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/server/ServerInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.server;
import lombok.Getter;
import org.springblade.core.launch.utils.INetUtil;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
/**
 * æœåŠ¡å™¨ä¿¡æ¯
 *
 * @author Chill
 */
@Getter
@AutoConfiguration
public class ServerInfo implements SmartInitializingSingleton {
    private final ServerProperties serverProperties;
    private String hostName;
    private String ip;
    private Integer port;
    private String ipWithPort;
    @Autowired(required = false)
    public ServerInfo(ServerProperties serverProperties) {
        this.serverProperties = serverProperties;
    }
    @Override
    public void afterSingletonsInstantiated() {
        this.hostName = INetUtil.getHostName();
        this.ip = INetUtil.getHostIp();
        this.port = serverProperties.getPort();
        this.ipWithPort = String.format("%s:%d", ip, port);
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/service/LauncherService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.service;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.Ordered;
/**
 * launcher æ‰©å±• ç”¨äºŽä¸€äº›ç»„件发现
 *
 * @author Chill
 */
public interface LauncherService extends Ordered, Comparable<LauncherService> {
    /**
     * å¯åŠ¨æ—¶ å¤„理 SpringApplicationBuilder
     *
     * @param builder    SpringApplicationBuilder
     * @param appName    SpringApplicationAppName
     * @param profile    SpringApplicationProfile
     * @param isLocalDev SpringApplicationIsLocalDev
     */
    void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev);
    /**
     * èŽ·å–æŽ’åˆ—é¡ºåº
     *
     * @return order
     */
    @Override
    default int getOrder() {
        return 0;
    }
    /**
     * å¯¹æ¯”排序
     *
     * @param o LauncherService
     * @return compare
     */
    @Override
    default int compareTo(LauncherService o) {
        return Integer.compare(this.getOrder(), o.getOrder());
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/utils/INetUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,244 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.launch.utils;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.Enumeration;
/**
 * INet ç›¸å…³å·¥å…·
 *
 * @author L.cm
 */
public class INetUtil {
    public static final String LOCAL_HOST = "127.0.0.1";
    /**
     * èŽ·å– æœåС噍 hostname
     *
     * @return hostname
     */
    public static String getHostName() {
        String hostname;
        try {
            InetAddress address = InetAddress.getLocalHost();
            // force a best effort reverse DNS lookup
            hostname = address.getHostName();
            if (StringUtils.isEmpty(hostname)) {
                hostname = address.toString();
            }
        } catch (UnknownHostException ignore) {
            hostname = LOCAL_HOST;
        }
        return hostname;
    }
    /**
     * èŽ·å– æœåС噍 HostIp
     *
     * @return HostIp
     */
    public static String getHostIp() {
        String hostAddress;
        try {
            InetAddress address = INetUtil.getLocalHostLANAddress();
            // force a best effort reverse DNS lookup
            hostAddress = address.getHostAddress();
            if (StringUtils.isEmpty(hostAddress)) {
                hostAddress = address.toString();
            }
        } catch (UnknownHostException ignore) {
            hostAddress = LOCAL_HOST;
        }
        return hostAddress;
    }
    /**
     * https://stackoverflow.com/questions/9481865/getting-the-ip-address-of-the-current-machine-using-java
     *
     * <p>
     * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's LAN IP address.
     * <p/>
     * This method is intended for use as a replacement of JDK method <code>InetAddress.getLocalHost</code>, because
     * that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same
     * way as regular LAN network interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not
     * specify the algorithm used to select the address returned under such circumstances, and will often return the
     * loopback address, which is not valid for network communication. Details
     * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
     * <p/>
     * This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address
     * most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer
     * a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the
     * first site-local address if the machine has more than one), but if the machine does not hold a site-local
     * address, this method will return simply the first non-loopback address found (IPv4 or IPv6).
     * <p/>
     * If this method cannot find a non-loopback address using this selection algorithm, it will fall back to
     * calling and returning the result of JDK method <code>InetAddress.getLocalHost</code>.
     * <p/>
     *
     * @throws UnknownHostException If the LAN address of the machine cannot be found.
     */
    private static InetAddress getLocalHostLANAddress() throws UnknownHostException {
        try {
            InetAddress candidateAddress = null;
            // Iterate all NICs (network interface cards)...
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // Iterate all IP addresses assigned to each card...
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {
                        if (inetAddr.isSiteLocalAddress()) {
                            // Found non-loopback site-local address. Return it immediately...
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // Found non-loopback address, but not necessarily site-local.
                            // Store it as a candidate to be returned if site-local address is not subsequently found...
                            candidateAddress = inetAddr;
                            // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
                            // only the first. For subsequent iterations, candidate will be non-null.
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                // We did not find a site-local address, but we found some other non-loopback address.
                // Server might have a non-site-local address assigned to its NIC (or it might be running
                // IPv6 which deprecates the "site-local" concept).
                // Return this non-loopback candidate address...
                return candidateAddress;
            }
            // At this point, we did not find a non-loopback address.
            // Fall back to returning whatever InetAddress.getLocalHost() returns...
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            if (jdkSuppliedAddress == null) {
                throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
            }
            return jdkSuppliedAddress;
        } catch (Exception e) {
            UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e);
            unknownHostException.initCause(e);
            throw unknownHostException;
        }
    }
    /**
     * å°è¯•端口时候被占用
     *
     * @param port ç«¯å£å·
     * @return æ²¡æœ‰è¢«å ç”¨ï¼štrue,被占用:false
     */
    public static boolean tryPort(int port) {
        try (ServerSocket ignore = new ServerSocket(port)) {
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * å°† ip è½¬æˆ InetAddress
     *
     * @param ip ip
     * @return InetAddress
     */
    public static InetAddress getInetAddress(String ip) {
        try {
            return InetAddress.getByName(ip);
        } catch (UnknownHostException e) {
            return null;
        }
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å†…网 ip
     *
     * @param ip ip
     * @return boolean
     */
    public static boolean isInternalIp(String ip) {
        return isInternalIp(getInetAddress(ip));
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å†…网 ip
     *
     * @param address InetAddress
     * @return boolean
     */
    public static boolean isInternalIp(InetAddress address) {
        if (isLocalIp(address)) {
            return true;
        }
        return isInternalIp(address.getAddress());
    }
    /**
     * åˆ¤æ–­æ˜¯å¦æœ¬åœ° ip
     *
     * @param address InetAddress
     * @return boolean
     */
    public static boolean isLocalIp(InetAddress address) {
        return address.isAnyLocalAddress()
            || address.isLoopbackAddress()
            || address.isSiteLocalAddress();
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å†…网 ip
     *
     * @param addr ip
     * @return boolean
     */
    public static boolean isInternalIp(byte[] addr) {
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        //10.x.x.x/8
        final byte section1 = 0x0A;
        //172.16.x.x/12
        final byte section2 = (byte) 0xAC;
        final byte section3 = (byte) 0x10;
        final byte section4 = (byte) 0x1F;
        //192.168.x.x/16
        final byte section5 = (byte) 0xC0;
        final byte section6 = (byte) 0xA8;
        switch (b0) {
            case section1:
                return true;
            case section2:
                if (b1 >= section3 && b1 <= section4) {
                    return true;
                }
            case section5:
                if (b1 == section6) {
                    return true;
                }
            default:
                return false;
        }
    }
}
Source/BladeX-Tool/blade-core-launch/src/main/java/org/springblade/core/launch/utils/PropsUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.launch.utils;
import org.springframework.util.StringUtils;
import java.util.Properties;
/**
 * é…ç½®å·¥å…·ç±»
 *
 * @author Chill
 */
public class PropsUtil {
    /**
     * è®¾ç½®é…ç½®å€¼ï¼Œå·²å­˜åœ¨åˆ™è·³è¿‡
     *
     * @param props property
     * @param key   key
     * @param value value
     */
    public static void setProperty(Properties props, String key, String value) {
        if (StringUtils.isEmpty(props.getProperty(key))) {
            props.setProperty(key, value);
        }
    }
}
Source/BladeX-Tool/blade-core-log4j2/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-log4j2</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-launch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-log4j2/src/main/java/org/springblade/core/log4j2/LogLauncherServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.log4j2;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
/**
 * æ—¥å¿—启动器
 *
 * @author L.cm
 */
@AutoService(LauncherService.class)
public class LogLauncherServiceImpl implements LauncherService {
    @Override
    public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
        System.setProperty("logging.config", String.format("classpath:log/log4j2_%s.xml", profile));
        // RocketMQ-Client 4.2.0 Log4j2 é…ç½®æ–‡ä»¶å†²çªé—®é¢˜è§£å†³ï¼šhttps://www.jianshu.com/p/b30ae6dd3811
        System.setProperty("rocketmq.client.log.loadconfig", "false");
        //  RocketMQ-Client 4.3 è®¾ç½®é»˜è®¤ä¸º slf4j
        System.setProperty("rocketmq.client.logUseSlf4j", "true");
        // éžæœ¬åœ° å°† å…¨éƒ¨çš„ System.err å’Œ System.out æ›¿æ¢ä¸ºlog
        if (!isLocalDev) {
            System.setOut(LogPrintStream.out());
            System.setErr(LogPrintStream.err());
        }
    }
}
Source/BladeX-Tool/blade-core-log4j2/src/main/java/org/springblade/core/log4j2/LogPrintStream.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.log4j2;
import lombok.extern.slf4j.Slf4j;
import java.io.PrintStream;
import java.util.Locale;
/**
 * æ›¿æ¢ ç³»ç»Ÿ System.err å’Œ System.out ä¸ºlog
 *
 * @author L.cm
 */
@Slf4j
public class LogPrintStream extends PrintStream {
    private final boolean error;
    private LogPrintStream(boolean error) {
        super(error ? System.err : System.out);
        this.error = error;
    }
    public static LogPrintStream out() {
        return new LogPrintStream(false);
    }
    public static LogPrintStream err() {
        return new LogPrintStream(true);
    }
    @Override
    public void print(String s) {
        if (error) {
            log.error(s);
        } else {
            log.info(s);
        }
    }
    /**
     * é‡å†™æŽ‰å®ƒï¼Œå› ä¸ºå®ƒä¼šæ‰“印很多无用的新行
     */
    @Override
    public void println() {
    }
    @Override
    public void println(String x) {
        if (error) {
            log.error(x);
        } else {
            log.info(x);
        }
    }
    @Override
    public PrintStream printf(String format, Object... args) {
        if (error) {
            log.error(String.format(format, args));
        } else {
            log.info(String.format(format, args));
        }
        return this;
    }
    @Override
    public PrintStream printf(Locale l, String format, Object... args) {
        if (error) {
            log.error(String.format(l, format, args));
        } else {
            log.info(String.format(l, format, args));
        }
        return this;
    }
}
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_appenders.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
<Appenders>
    <Console name="Console" target="SYSTEM_OUT" follow="true">
        <PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}"/>
    </Console>
    <RollingFile name="RollingFile"
                 fileName="${logdir}/${appName}.log"
                 filePattern="${logdir}/${appName}.%d{yyyy-MM-dd}.%i.log.gz">
        <PatternLayout pattern="[%d] [%thread] ${LOG_LEVEL_PATTERN} ${appName} ${sys:PID} %c %m%n"/>
        <Filters>
            <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL" />
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
        </Filters>
        <Policies>
            <SizeBasedTriggeringPolicy size="200MB" />
            <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
        </Policies>
        <DefaultRolloverStrategy max="30"/>
    </RollingFile>
    <!-- åªæ˜¾ç¤ºerror级别的信息 -->
    <RollingFile name="RollingFileError"
                 fileName="${logdir}/${appName}-error.log"
                 filePattern="${logdir}/${appName}-error.%d{yyyy-MM-dd}.%i.log.gz">
        <PatternLayout pattern="[%d] [%thread] ${LOG_LEVEL_PATTERN} ${appName} ${sys:PID} %c %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}"/>
        <Filters>
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
        </Filters>
        <Policies>
            <SizeBasedTriggeringPolicy size="200MB"/>
            <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
        </Policies>
        <DefaultRolloverStrategy max="30"/>
    </RollingFile>
</Appenders>
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_dev.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="off" xmlns:xi="http://www.w3.org/2001/XInclude">
    <Properties>
        <Property name="appName">${sys:spring.application.name}</Property>
        <Property name="logdir">${env:LOG_BASE:-logs}/${appName}</Property>
        <Property name="PID">????</Property>
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%C{36}.%M:%L}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
    </Properties>
    <xi:include href="log4j2_appenders.xml">
        <xi:fallback/>
    </xi:include>
    <Loggers>
        <!-- å‡å°‘部分debug日志 -->
        <AsyncLogger name="org.springframework.context" level="WARN"/>
        <AsyncLogger name="org.springframework.beans" level="WARN"/>
        <AsyncLogger name="springfox.bean.validators" level="ERROR"/>
        <!-- åŸºç¡€ç»„ä»¶ -->
        <AsyncLogger name="RocketmqClient" level="WARN"/>
        <!-- mongo no sql -->
        <AsyncLogger name="org.springframework.data.mongodb.core" level="DEBUG"/>
        <!-- blade日志 -->
        <AsyncLogger name="org.springblade.core" level="INFO"/>
        <Root level="INFO" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="RollingFileError"/>
        </Root>
    </Loggers>
</configuration>
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_ontest.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="off" xmlns:xi="http://www.w3.org/2001/XInclude">
    <Properties>
        <Property name="appName">${sys:spring.application.name}</Property>
        <Property name="logdir">${env:LOG_BASE:-logs}/${appName}</Property>
        <Property name="PID">????</Property>
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
    </Properties>
    <xi:include href="log4j2_appenders.xml">
        <xi:fallback/>
    </xi:include>
    <Loggers>
        <!-- å‡å°‘部分debug日志 -->
        <AsyncLogger name="org.springframework.context" level="WARN"/>
        <AsyncLogger name="org.springframework.beans" level="WARN"/>
        <AsyncLogger name="springfox.bean.validators" level="ERROR"/>
        <!-- åŸºç¡€ç»„ä»¶ -->
        <AsyncLogger name="RocketmqClient" level="WARN"/>
        <!-- blade日志 -->
        <AsyncLogger name="org.springblade.core" level="WARN" />
        <AsyncLogger name="org.springblade.core.http" level="INFO"/>
        <Root level="INFO" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="RollingFileError"/>
        </Root>
    </Loggers>
</configuration>
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_prod.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="off" xmlns:xi="http://www.w3.org/2001/XInclude">
    <Properties>
        <Property name="appName">${sys:spring.application.name}</Property>
        <Property name="logdir">${env:LOG_BASE:-logs}/${appName}</Property>
        <Property name="PID">????</Property>
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
    </Properties>
    <xi:include href="log4j2_appenders.xml">
        <xi:fallback/>
    </xi:include>
    <Loggers>
        <!-- å‡å°‘部分debug日志 -->
        <AsyncLogger name="springfox.bean.validators" level="ERROR"/>
        <!-- åŸºç¡€ç»„ä»¶ -->
        <AsyncLogger name="RocketmqClient" level="ERROR"/>
        <!-- blade日志 -->
        <AsyncLogger name="org.springblade.core" level="ERROR"/>
        <AsyncLogger name="org.springblade.core.http" level="INFO"/>
        <Root level="WARN" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="RollingFile" />
            <AppenderRef ref="RollingFileError" />
        </Root>
    </Loggers>
</configuration>
Source/BladeX-Tool/blade-core-log4j2/src/main/resources/log/log4j2_test.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="off" xmlns:xi="http://www.w3.org/2001/XInclude">
    <Properties>
        <Property name="appName">${sys:spring.application.name}</Property>
        <Property name="logdir">${env:LOG_BASE:-logs}/${appName}</Property>
        <Property name="PID">????</Property>
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%C{36}.%M:%L}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
    </Properties>
    <xi:include href="log4j2_appenders.xml">
        <xi:fallback/>
    </xi:include>
    <Loggers>
        <!-- å‡å°‘部分debug日志 -->
        <AsyncLogger name="org.springframework.context" level="WARN"/>
        <AsyncLogger name="org.springframework.beans" level="WARN"/>
        <AsyncLogger name="springfox.bean.validators" level="ERROR"/>
        <!-- åŸºç¡€ç»„ä»¶ -->
        <AsyncLogger name="RocketmqClient" level="WARN"/>
        <!-- blade日志 -->
        <AsyncLogger name="org.springblade.core" level="INFO"/>
        <Root level="INFO" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="RollingFileError"/>
        </Root>
    </Loggers>
</configuration>
Source/BladeX-Tool/blade-core-secure/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-secure</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!--Blade-->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-auth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-cache</artifactId>
        </dependency>
        <!--Jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>tomcat-jdbc</artifactId>
                    <groupId>org.apache.tomcat</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/annotation/PreAuth.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.annotation;
import java.lang.annotation.*;
/**
 * æƒé™æ³¨è§£ ç”¨äºŽæ£€æŸ¥æƒé™ è§„定访问权限
 *
 * @example @PreAuth("#userVO.id<10")
 * @example @PreAuth("hasRole(#test, #test1)")
 * @example @PreAuth("hasPermission(#test) and @PreAuth.hasPermission(#test)")
 * @author Chill
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PreAuth {
    /**
     * Spring el
     * æ–‡æ¡£åœ°å€ï¼šhttps://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/core.html#expressions
     */
    String value();
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/aspect/AuthAspect.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.auth.AuthFun;
import org.springblade.core.secure.exception.SecureException;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.utils.ClassUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.MethodParameter;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;
import java.lang.reflect.Method;
/**
 * AOP é‰´æƒ
 *
 * @author Chill
 */
@Aspect
public class AuthAspect implements ApplicationContextAware {
    /**
     * è¡¨è¾¾å¼å¤„理
     */
    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
    /**
     * åˆ‡ æ–¹æ³• å’Œ ç±»ä¸Šçš„ @PreAuth æ³¨è§£
     *
     * @param point åˆ‡ç‚¹
     * @return Object
     * @throws Throwable æ²¡æœ‰æƒé™çš„异常
     */
    @Around(
        "@annotation(org.springblade.core.secure.annotation.PreAuth) || " +
            "@within(org.springblade.core.secure.annotation.PreAuth)"
    )
    public Object preAuth(ProceedingJoinPoint point) throws Throwable {
        if (handleAuth(point)) {
            return point.proceed();
        }
        throw new SecureException(ResultCode.UN_AUTHORIZED);
    }
    /**
     * å¤„理权限
     *
     * @param point åˆ‡ç‚¹
     */
    private boolean handleAuth(ProceedingJoinPoint point) {
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod();
        // è¯»å–权限注解,优先方法上,没有则读取类
        PreAuth preAuth = ClassUtil.getAnnotation(method, PreAuth.class);
        // åˆ¤æ–­è¡¨è¾¾å¼
        String condition = preAuth.value();
        if (StringUtil.isNotBlank(condition)) {
            Expression expression = EXPRESSION_PARSER.parseExpression(condition);
            // æ–¹æ³•参数值
            Object[] args = point.getArgs();
            StandardEvaluationContext context = getEvaluationContext(method, args);
            return expression.getValue(context, Boolean.class);
        }
        return false;
    }
    /**
     * èŽ·å–æ–¹æ³•ä¸Šçš„å‚æ•°
     *
     * @param method æ–¹æ³•
     * @param args   å˜é‡
     * @return {SimpleEvaluationContext}
     */
    private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) {
        // åˆå§‹åŒ–Sp el表达式上下文,并设置 AuthFun
        StandardEvaluationContext context = new StandardEvaluationContext(new AuthFun());
        // è®¾ç½®è¡¨è¾¾å¼æ”¯æŒspring bean
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));
        for (int i = 0; i < args.length; i++) {
            // è¯»å–方法参数
            MethodParameter methodParam = ClassUtil.getMethodParameter(method, i);
            // è®¾ç½®æ–¹æ³• å‚数名和值 ä¸ºsp el变量
            context.setVariable(methodParam.getParameterName(), args[i]);
        }
        return context;
    }
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/auth/AuthFun.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,151 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.auth;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.handler.IPermissionHandler;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.*;
/**
 * æƒé™åˆ¤æ–­
 *
 * @author Chill
 */
public class AuthFun {
    /**
     * æƒé™æ ¡éªŒå¤„理器
     */
    private static IPermissionHandler permissionHandler;
    private static IPermissionHandler getPermissionHandler() {
        if (permissionHandler == null) {
            permissionHandler = SpringUtil.getBean(IPermissionHandler.class);
        }
        return permissionHandler;
    }
    /**
     * åˆ¤æ–­è§’色是否具有接口权限
     *
     * @return {boolean}
     */
    public boolean permissionAll() {
        return getPermissionHandler().permissionAll();
    }
    /**
     * åˆ¤æ–­è§’色是否具有接口权限
     *
     * @param permission æƒé™ç¼–号
     * @return {boolean}
     */
    public boolean hasPermission(String permission) {
        return getPermissionHandler().hasPermission(permission);
    }
    /**
     * æ”¾è¡Œæ‰€æœ‰è¯·æ±‚
     *
     * @return {boolean}
     */
    public boolean permitAll() {
        return true;
    }
    /**
     * åªæœ‰è¶…管角色才可访问
     *
     * @return {boolean}
     */
    public boolean denyAll() {
        return hasRole(RoleConstant.ADMIN);
    }
    /**
     * æ˜¯å¦å·²æŽˆæƒ
     *
     * @return {boolean}
     */
    public boolean hasAuth() {
        return Func.isNotEmpty(AuthUtil.getUser());
    }
    /**
     * æ˜¯å¦æœ‰æ—¶é—´æŽˆæƒ
     *
     * @param start å¼€å§‹æ—¶é—´
     * @param end   ç»“束时间
     * @return {boolean}
     */
    public boolean hasTimeAuth(Integer start, Integer end) {
        Integer hour = DateUtil.hour();
        return hour >= start && hour <= end;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦æœ‰è¯¥è§’色权限
     *
     * @param role å•角色
     * @return {boolean}
     */
    public boolean hasRole(String role) {
        return hasAnyRole(role);
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å…·æœ‰æ‰€æœ‰è§’色权限
     *
     * @param role è§’色集合
     * @return {boolean}
     */
    public boolean hasAllRole(String... role) {
        for (String r : role) {
            if (!hasRole(r)) {
                return false;
            }
        }
        return true;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦æœ‰è¯¥è§’色权限
     *
     * @param role è§’色集合
     * @return {boolean}
     */
    public boolean hasAnyRole(String... role) {
        BladeUser user = AuthUtil.getUser();
        if (user == null) {
            return false;
        }
        String userRole = user.getRoleName();
        if (StringUtil.isBlank(userRole)) {
            return false;
        }
        String[] roles = Func.toStrArray(userRole);
        for (String r : role) {
            if (CollectionUtil.contains(roles, r)) {
                return true;
            }
        }
        return false;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.config;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.handler.BladePermissionHandler;
import org.springblade.core.secure.handler.IPermissionHandler;
import org.springblade.core.secure.handler.ISecureHandler;
import org.springblade.core.secure.handler.SecureHandlerHandler;
import org.springblade.core.secure.registry.SecureRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
/**
 * secure注册默认配置
 *
 * @author Chill
 */
@Order
@AutoConfiguration(before = SecureConfiguration.class)
@AllArgsConstructor
public class RegistryConfiguration {
    private final JdbcTemplate jdbcTemplate;
    @Bean
    @ConditionalOnMissingBean(SecureRegistry.class)
    public SecureRegistry secureRegistry() {
        return new SecureRegistry();
    }
    @Bean
    @ConditionalOnMissingBean(ISecureHandler.class)
    public ISecureHandler secureHandler() {
        return new SecureHandlerHandler();
    }
    @Bean
    @ConditionalOnMissingBean(IPermissionHandler.class)
    public IPermissionHandler permissionHandler() {
        return new BladePermissionHandler(jdbcTemplate);
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,118 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.config;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.aspect.AuthAspect;
import org.springblade.core.secure.handler.ISecureHandler;
import org.springblade.core.secure.props.AuthSecure;
import org.springblade.core.secure.props.BasicSecure;
import org.springblade.core.secure.props.BladeSecureProperties;
import org.springblade.core.secure.props.SignSecure;
import org.springblade.core.secure.provider.ClientDetailsServiceImpl;
import org.springblade.core.secure.provider.IClientDetailsService;
import org.springblade.core.secure.registry.SecureRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
import java.util.stream.Collectors;
/**
 * å®‰å…¨é…ç½®ç±»
 *
 * @author Chill
 */
@Order
@AutoConfiguration
@AllArgsConstructor
@EnableConfigurationProperties({BladeSecureProperties.class})
public class SecureConfiguration implements WebMvcConfigurer {
    private final SecureRegistry secureRegistry;
    private final BladeSecureProperties secureProperties;
    private final JdbcTemplate jdbcTemplate;
    private final ISecureHandler secureHandler;
    @Override
    public void addInterceptors(@NonNull InterceptorRegistry registry) {
        // è®¾ç½®è¯·æ±‚授权
        if (secureRegistry.isAuthEnabled() || secureProperties.getAuthEnabled()) {
            List<AuthSecure> authSecures = this.secureRegistry.addAuthPatterns(secureProperties.getAuth()).getAuthSecures();
            if (authSecures.size() > 0) {
                registry.addInterceptor(secureHandler.authInterceptor(authSecures));
                // è®¾ç½®è·¯å¾„放行
                secureRegistry.excludePathPatterns(authSecures.stream().map(AuthSecure::getPattern).collect(Collectors.toList()));
            }
        }
        // è®¾ç½®åŸºç¡€è®¤è¯æŽˆæƒ
        if (secureRegistry.isBasicEnabled() || secureProperties.getBasicEnabled()) {
            List<BasicSecure> basicSecures = this.secureRegistry.addBasicPatterns(secureProperties.getBasic()).getBasicSecures();
            if (basicSecures.size() > 0) {
                registry.addInterceptor(secureHandler.basicInterceptor(basicSecures));
                // è®¾ç½®è·¯å¾„放行
                secureRegistry.excludePathPatterns(basicSecures.stream().map(BasicSecure::getPattern).collect(Collectors.toList()));
            }
        }
        // è®¾ç½®ç­¾åè®¤è¯æŽˆæƒ
        if (secureRegistry.isSignEnabled() || secureProperties.getSignEnabled()) {
            List<SignSecure> signSecures = this.secureRegistry.addSignPatterns(secureProperties.getSign()).getSignSecures();
            if (signSecures.size() > 0) {
                registry.addInterceptor(secureHandler.signInterceptor(signSecures));
                // è®¾ç½®è·¯å¾„放行
                secureRegistry.excludePathPatterns(signSecures.stream().map(SignSecure::getPattern).collect(Collectors.toList()));
            }
        }
        // è®¾ç½®å®¢æˆ·ç«¯æŽˆæƒ
        if (secureRegistry.isClientEnabled() || secureProperties.getClientEnabled()) {
            secureProperties.getClient().forEach(
                clientSecure -> registry.addInterceptor(secureHandler.clientInterceptor(clientSecure.getClientId()))
                    .addPathPatterns(clientSecure.getPathPatterns())
            );
        }
        // è®¾ç½®è·¯å¾„放行
        if (secureRegistry.isEnabled() || secureProperties.getEnabled()) {
            registry.addInterceptor(secureHandler.tokenInterceptor())
                .excludePathPatterns(secureRegistry.getExcludePatterns())
                .excludePathPatterns(secureRegistry.getDefaultExcludePatterns())
                .excludePathPatterns(secureProperties.getSkipUrl());
        }
    }
    @Bean
    public AuthAspect authAspect() {
        return new AuthAspect();
    }
    @Bean
    @ConditionalOnMissingBean(IClientDetailsService.class)
    public IClientDetailsService clientDetailsService() {
        return new ClientDetailsServiceImpl(jdbcTemplate);
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/AuthConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.constant;
/**
 * PreAuth权限表达式
 *
 * @author Chill
 */
public interface AuthConstant {
    /**
     * è¶…管别名
     */
    String ADMINISTRATOR = "administrator";
    /**
     * æ˜¯æœ‰è¶…管角色
     */
    String HAS_ROLE_ADMINISTRATOR = "hasRole('" + ADMINISTRATOR + "')";
    /**
     * ç®¡ç†å‘˜åˆ«å
     */
    String ADMIN = "admin";
    /**
     * æ˜¯å¦æœ‰ç®¡ç†å‘˜è§’色
     */
    String HAS_ROLE_ADMIN = "hasAnyRole('" + ADMINISTRATOR + "', '" + ADMIN + "')";
    /**
     * ç”¨æˆ·åˆ«å
     */
    String USER = "user";
    /**
     * æ˜¯å¦æœ‰ç”¨æˆ·è§’色
     */
    String HAS_ROLE_USER = "hasRole('" + USER + "')";
    /**
     * æµ‹è¯•别名
     */
    String TEST = "test";
    /**
     * æ˜¯å¦æœ‰æµ‹è¯•角色
     */
    String HAS_ROLE_TEST = "hasRole('" + TEST + "')";
    /**
     * æ”¾è¡Œæ‰€æœ‰è¯·æ±‚
     */
    String PERMIT_ALL = "permitAll()";
    /**
     * åªæœ‰è¶…管才能访问
     */
    String DENY_ALL = "denyAll()";
    /**
     * å¯¹æ‰€æœ‰è¯·æ±‚进行接口权限校验
     */
    String PERMISSION_ALL = "permissionAll()";
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/PermissionConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.constant;
import org.springblade.core.tool.utils.StringUtil;
/**
 * æƒé™æ ¡éªŒå¸¸é‡
 *
 * @author Chill
 */
public interface PermissionConstant {
    /**
     * èŽ·å–è§’è‰²æ‰€æœ‰çš„æƒé™ç¼–å·
     *
     * @param size æ•°é‡
     * @return string
     */
    static String permissionAllStatement(int size) {
        return "select scope_path as path from blade_scope_api where id in (select scope_id from blade_role_scope where scope_category = 2 and role_id in (" + buildHolder(size) + "))";
    }
    /**
     * èŽ·å–è§’è‰²æŒ‡å®šçš„æƒé™ç¼–å·
     *
     * @param size æ•°é‡
     * @return string
     */
    static String permissionStatement(int size) {
        return "select resource_code as code from blade_scope_api where resource_code = ? and id in (select scope_id from blade_role_scope where scope_category = 2 and role_id in (" + buildHolder(size) + "))";
    }
    /**
     * èŽ·å–Sql占位符
     *
     * @param size æ•°é‡
     * @return String
     */
    static String buildHolder(int size) {
        StringBuilder builder = StringUtil.builder();
        for (int i = 0; i < size; i++) {
            builder.append("?,");
        }
        return StringUtil.removeSuffix(builder.toString(), ",");
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/constant/SecureConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.constant;
/**
 * æŽˆæƒæ ¡éªŒå¸¸é‡
 *
 * @author Chill
 */
public interface SecureConstant {
    /**
     * è®¤è¯è¯·æ±‚头
     */
    String BASIC_HEADER_KEY = "Authorization";
    /**
     * è®¤è¯è¯·æ±‚头前缀
     */
    String BASIC_HEADER_PREFIX = "Basic ";
    /**
     * è®¤è¯è¯·æ±‚头前缀
     */
    String BASIC_HEADER_PREFIX_EXT = "Basic%20";
    /**
     * è®¤è¯è¯·æ±‚头
     */
    String BASIC_REALM_HEADER_KEY = "WWW-Authenticate";
    /**
     * è®¤è¯è¯·æ±‚值
     */
    String BASIC_REALM_HEADER_VALUE = "basic realm=\"no auth\"";
    /**
     * blade_client表字段
     */
    String CLIENT_FIELDS = "client_id, client_secret, access_token_validity, refresh_token_validity";
    /**
     * blade_client查询语句
     */
    String BASE_STATEMENT = "select " + CLIENT_FIELDS + " from blade_client";
    /**
     * blade_client查询排序
     */
    String DEFAULT_FIND_STATEMENT = BASE_STATEMENT + " order by client_id";
    /**
     * æŸ¥è¯¢client_id
     */
    String DEFAULT_SELECT_STATEMENT = BASE_STATEMENT + " where client_id = ?";
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/BladePermissionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,110 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.handler;
import lombok.AllArgsConstructor;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
import static org.springblade.core.secure.constant.PermissionConstant.permissionAllStatement;
import static org.springblade.core.secure.constant.PermissionConstant.permissionStatement;
/**
 * é»˜è®¤æŽˆæƒæ ¡éªŒç±»
 *
 * @author Chill
 */
@AllArgsConstructor
public class BladePermissionHandler implements IPermissionHandler {
    private static final String SCOPE_CACHE_CODE = "apiScope:code:";
    private final JdbcTemplate jdbcTemplate;
    @Override
    public boolean permissionAll() {
        HttpServletRequest request = WebUtil.getRequest();
        BladeUser user = AuthUtil.getUser();
        if (request == null || user == null) {
            return false;
        }
        String uri = request.getRequestURI();
        List<String> paths = permissionPath(user.getRoleId());
        if (paths.size() == 0) {
            return false;
        }
        return paths.stream().anyMatch(uri::contains);
    }
    @Override
    public boolean hasPermission(String permission) {
        HttpServletRequest request = WebUtil.getRequest();
        BladeUser user = AuthUtil.getUser();
        if (request == null || user == null) {
            return false;
        }
        List<String> codes = permissionCode(permission, user.getRoleId());
        return codes.size() != 0;
    }
    /**
     * èŽ·å–æŽ¥å£æƒé™åœ°å€
     *
     * @param roleId è§’色id
     * @return permissions
     */
    private List<String> permissionPath(String roleId) {
        List<String> permissions = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, roleId, List.class, Boolean.FALSE);
        if (permissions == null) {
            List<Long> roleIds = Func.toLongList(roleId);
            permissions = jdbcTemplate.queryForList(permissionAllStatement(roleIds.size()), roleIds.toArray(), String.class);
            CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, roleId, permissions, Boolean.FALSE);
        }
        return permissions;
    }
    /**
     * èŽ·å–æŽ¥å£æƒé™ä¿¡æ¯
     *
     * @param permission æƒé™ç¼–号
     * @param roleId     è§’色id
     * @return permissions
     */
    private List<String> permissionCode(String permission, String roleId) {
        List<String> permissions = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, permission + StringPool.COLON + roleId, List.class, Boolean.FALSE);
        if (permissions == null) {
            List<Object> args = new ArrayList<>(Collections.singletonList(permission));
            List<Long> roleIds = Func.toLongList(roleId);
            args.addAll(roleIds);
            permissions = jdbcTemplate.queryForList(permissionStatement(roleIds.size()), args.toArray(), String.class);
            CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, permission + StringPool.COLON + roleId, permissions, Boolean.FALSE);
        }
        return permissions;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/IPermissionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.handler;
/**
 * æƒé™æ ¡éªŒé€šç”¨æŽ¥å£
 *
 * @author Chill
 */
public interface IPermissionHandler {
    /**
     * åˆ¤æ–­è§’色是否具有接口权限
     *
     * @return {boolean}
     */
    boolean permissionAll();
    /**
     * åˆ¤æ–­è§’色是否具有接口权限
     *
     * @param permission æƒé™ç¼–号
     * @return {boolean}
     */
    boolean hasPermission(String permission);
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/ISecureHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.handler;
import org.springblade.core.secure.props.AuthSecure;
import org.springblade.core.secure.props.BasicSecure;
import org.springblade.core.secure.props.SignSecure;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import java.util.List;
/**
 * secure æ‹¦æˆªå™¨é›†åˆ
 *
 * @author Chill
 */
public interface ISecureHandler {
    /**
     * token拦截器
     *
     * @return tokenInterceptor
     */
    HandlerInterceptorAdapter tokenInterceptor();
    /**
     * auth拦截器
     *
     * @param authSecures æŽˆæƒé›†åˆ
     * @return HandlerInterceptorAdapter
     */
    HandlerInterceptorAdapter authInterceptor(List<AuthSecure> authSecures);
    /**
     * basic拦截器
     *
     * @param basicSecures åŸºç¡€è®¤è¯é›†åˆ
     * @return HandlerInterceptorAdapter
     */
    HandlerInterceptorAdapter basicInterceptor(List<BasicSecure> basicSecures);
    /**
     * sign拦截器
     *
     * @param signSecures ç­¾åè®¤è¯é›†åˆ
     * @return HandlerInterceptorAdapter
     */
    HandlerInterceptorAdapter signInterceptor(List<SignSecure> signSecures);
    /**
     * client拦截器
     *
     * @param clientId å®¢æˆ·ç«¯id
     * @return clientInterceptor
     */
    HandlerInterceptorAdapter clientInterceptor(String clientId);
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/handler/SecureHandlerHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.handler;
import org.springblade.core.secure.interceptor.*;
import org.springblade.core.secure.props.AuthSecure;
import org.springblade.core.secure.props.BasicSecure;
import org.springblade.core.secure.props.SignSecure;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import java.util.List;
/**
 * Secure处理器
 *
 * @author Chill
 */
public class SecureHandlerHandler implements ISecureHandler {
    @Override
    public HandlerInterceptorAdapter tokenInterceptor() {
        return new TokenInterceptor();
    }
    @Override
    public HandlerInterceptorAdapter authInterceptor(List<AuthSecure> authSecures) {
        return new AuthInterceptor(authSecures);
    }
    @Override
    public HandlerInterceptorAdapter basicInterceptor(List<BasicSecure> basicSecures) {
        return new BasicInterceptor(basicSecures);
    }
    @Override
    public HandlerInterceptorAdapter signInterceptor(List<SignSecure> signSecures) {
        return new SignInterceptor(signSecures);
    }
    @Override
    public HandlerInterceptorAdapter clientInterceptor(String clientId) {
        return new ClientInterceptor(clientId);
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/AuthInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.interceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.auth.AuthFun;
import org.springblade.core.secure.props.AuthSecure;
import org.springblade.core.secure.provider.HttpMethod;
import org.springblade.core.secure.provider.ResponseProvider;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * è‡ªå®šä¹‰æŽˆæƒæ‹¦æˆªå™¨æ ¡éªŒ
 *
 * @author Chill
 */
@Slf4j
@AllArgsConstructor
public class AuthInterceptor extends HandlerInterceptorAdapter {
    /**
     * è¡¨è¾¾å¼å¤„理
     */
    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
    private static final EvaluationContext EVALUATION_CONTEXT = new StandardEvaluationContext(new AuthFun());
    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    /**
     * æŽˆæƒé›†åˆ
     */
    private final List<AuthSecure> authSecures;
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        boolean check = authSecures.stream().filter(authSecure -> checkAuth(request, authSecure)).findFirst().map(
            authSecure -> checkExpression(authSecure.getExpression())
        ).orElse(Boolean.TRUE);
        if (!check) {
            log.warn("授权认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            ResponseProvider.write(response);
            return false;
        }
        return true;
    }
    /**
     * æ£€æµ‹æŽˆæƒ
     */
    private boolean checkAuth(HttpServletRequest request, AuthSecure authSecure) {
        return checkMethod(request, authSecure.getMethod()) && checkPath(request, authSecure.getPattern());
    }
    /**
     * æ£€æµ‹è¯·æ±‚方法
     */
    private boolean checkMethod(HttpServletRequest request, HttpMethod method) {
        return method == HttpMethod.ALL || (
            method != null && method == HttpMethod.of(request.getMethod())
        );
    }
    /**
     * æ£€æµ‹è·¯å¾„匹配
     */
    private boolean checkPath(HttpServletRequest request, String pattern) {
        String servletPath = request.getServletPath();
        String pathInfo = request.getPathInfo();
        if (pathInfo != null && pathInfo.length() > 0) {
            servletPath = servletPath + pathInfo;
        }
        return ANT_PATH_MATCHER.match(pattern, servletPath);
    }
    /**
     * æ£€æµ‹è¡¨è¾¾å¼
     */
    private boolean checkExpression(String expression) {
        Boolean result = EXPRESSION_PARSER.parseExpression(expression).getValue(EVALUATION_CONTEXT, Boolean.class);
        return result != null ? result : false;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/BasicInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.interceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.props.BasicSecure;
import org.springblade.core.secure.provider.HttpMethod;
import org.springblade.core.secure.provider.ResponseProvider;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.lang.NonNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import static org.springblade.core.secure.constant.SecureConstant.BASIC_REALM_HEADER_KEY;
import static org.springblade.core.secure.constant.SecureConstant.BASIC_REALM_HEADER_VALUE;
/**
 * åŸºç¡€è®¤è¯æ‹¦æˆªå™¨æ ¡éªŒ
 *
 * @author Chill
 */
@Slf4j
@AllArgsConstructor
public class BasicInterceptor extends HandlerInterceptorAdapter {
    /**
     * è¡¨è¾¾å¼åŒ¹é…
     */
    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    /**
     * æŽˆæƒé›†åˆ
     */
    private final List<BasicSecure> basicSecures;
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        boolean check = basicSecures.stream().filter(basicSecure -> checkAuth(request, basicSecure)).findFirst().map(
            authSecure -> checkBasic(authSecure.getUsername(), authSecure.getPassword())
        ).orElse(Boolean.TRUE);
        if (!check) {
            log.warn("授权认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            response.setHeader(BASIC_REALM_HEADER_KEY, BASIC_REALM_HEADER_VALUE);
            ResponseProvider.write(response);
            return false;
        }
        return true;
    }
    /**
     * æ£€æµ‹æŽˆæƒ
     */
    private boolean checkAuth(HttpServletRequest request, BasicSecure basicSecure) {
        return checkMethod(request, basicSecure.getMethod()) && checkPath(request, basicSecure.getPattern());
    }
    /**
     * æ£€æµ‹è¯·æ±‚方法
     */
    private boolean checkMethod(HttpServletRequest request, HttpMethod method) {
        return method == HttpMethod.ALL || (
            method != null && method == HttpMethod.of(request.getMethod())
        );
    }
    /**
     * æ£€æµ‹è·¯å¾„匹配
     */
    private boolean checkPath(HttpServletRequest request, String pattern) {
        String servletPath = request.getServletPath();
        String pathInfo = request.getPathInfo();
        if (pathInfo != null && pathInfo.length() > 0) {
            servletPath = servletPath + pathInfo;
        }
        return ANT_PATH_MATCHER.match(pattern, servletPath);
    }
    /**
     * æ£€æµ‹è¡¨è¾¾å¼
     */
    private boolean checkBasic(String username, String password) {
        try {
            String[] tokens = SecureUtil.extractAndDecodeHeader();
            return username.equals(tokens[0]) && password.equals(tokens[1]);
        } catch (Exception e) {
            log.warn("授权认证失败,错误信息:{}", e.getMessage());
            return false;
        }
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/ClientInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.interceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.provider.ResponseProvider;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * å®¢æˆ·ç«¯æ ¡éªŒæ‹¦æˆªå™¨
 *
 * @author Chill
 */
@Slf4j
@AllArgsConstructor
public class ClientInterceptor extends HandlerInterceptorAdapter {
    private final String clientId;
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        BladeUser user = AuthUtil.getUser();
        boolean check = (
            user != null &&
                StringUtil.equals(clientId, SecureUtil.getClientIdFromHeader()) &&
                StringUtil.equals(clientId, user.getClientId())
        );
        if (!check) {
            log.warn("客户端认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            ResponseProvider.write(response);
            return false;
        }
        return true;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/SignInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,170 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.interceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.props.SignSecure;
import org.springblade.core.secure.provider.HttpMethod;
import org.springblade.core.secure.provider.ResponseProvider;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.lang.NonNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Date;
import java.util.List;
/**
 * ç­¾åè®¤è¯æ‹¦æˆªå™¨æ ¡éªŒ
 *
 * @author Chill
 */
@Slf4j
@AllArgsConstructor
public class SignInterceptor extends HandlerInterceptorAdapter {
    /**
     * è¡¨è¾¾å¼åŒ¹é…
     */
    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    /**
     * æŽˆæƒé›†åˆ
     */
    private final List<SignSecure> signSecures;
    /**
     * è¯·æ±‚æ—¶é—´
     */
    private final static String TIMESTAMP = "timestamp";
    /**
     * éšæœºæ•°
     */
    private final static String NONCE = "nonce";
    /**
     * æ—¶é—´éšæœºæ•°ç»„合加密串
     */
    private final static String SIGNATURE = "signature";
    /**
     * sha1加密方式
     */
    private final static String SHA1 = "sha1";
    /**
     * md5加密方式
     */
    private final static String MD5 = "md5";
    /**
     * æ—¶é—´å·®æœ€å°å€¼
     */
    private final static Integer SECOND_MIN = 0;
    /**
     * æ—¶é—´å·®æœ€å¤§å€¼
     */
    private final static Integer SECOND_MAX = 10;
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        boolean check = signSecures.stream().filter(signSecure -> checkAuth(request, signSecure)).findFirst().map(
            authSecure -> checkSign(authSecure.getCrypto())
        ).orElse(Boolean.TRUE);
        if (!check) {
            log.warn("授权认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            ResponseProvider.write(response);
            return false;
        }
        return true;
    }
    /**
     * æ£€æµ‹æŽˆæƒ
     */
    private boolean checkAuth(HttpServletRequest request, SignSecure signSecure) {
        return checkMethod(request, signSecure.getMethod()) && checkPath(request, signSecure.getPattern());
    }
    /**
     * æ£€æµ‹è¯·æ±‚方法
     */
    private boolean checkMethod(HttpServletRequest request, HttpMethod method) {
        return method == HttpMethod.ALL || (
            method != null && method == HttpMethod.of(request.getMethod())
        );
    }
    /**
     * æ£€æµ‹è·¯å¾„匹配
     */
    private boolean checkPath(HttpServletRequest request, String pattern) {
        String servletPath = request.getServletPath();
        String pathInfo = request.getPathInfo();
        if (pathInfo != null && pathInfo.length() > 0) {
            servletPath = servletPath + pathInfo;
        }
        return ANT_PATH_MATCHER.match(pattern, servletPath);
    }
    /**
     * æ£€æµ‹è¡¨è¾¾å¼
     */
    private boolean checkSign(String crypto) {
        try {
            HttpServletRequest request = WebUtil.getRequest();
            if (request == null) {
                return false;
            }
            // èŽ·å–å¤´éƒ¨åŠ¨æ€ç­¾åä¿¡æ¯
            String timestamp = request.getHeader(TIMESTAMP);
            // åˆ¤æ–­æ˜¯å¦åœ¨åˆæ³•时间段
            long seconds = Duration.between(new Date(Func.toLong(timestamp)).toInstant(), DateUtil.now().toInstant()).getSeconds();
            if (seconds < SECOND_MIN || seconds > SECOND_MAX) {
                log.warn("授权认证失败,错误信息:{}", "请求时间戳非法");
                return false;
            }
            String nonce = request.getHeader(NONCE);
            String signature = request.getHeader(SIGNATURE);
            // åŠ å¯†ç­¾åæ¯”å¯¹ï¼Œå¯è‡ªè¡Œæ‹“å±•åŠ å¯†è§„åˆ™
            String sign;
            if (crypto.equals(MD5)) {
                sign = DigestUtil.md5Hex(timestamp + nonce);
            } else if (crypto.equals(SHA1)) {
                sign = DigestUtil.sha1Hex(timestamp + nonce);
            } else {
                sign = DigestUtil.sha1Hex(timestamp + nonce);
            }
            return sign.equalsIgnoreCase(signature);
        } catch (Exception e) {
            log.warn("授权认证失败,错误信息:{}", e.getMessage());
            return false;
        }
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/interceptor/TokenInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.interceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.provider.ResponseProvider;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * ç­¾åè®¤è¯æ‹¦æˆªå™¨
 *
 * @author Chill
 */
@Slf4j
@AllArgsConstructor
public class TokenInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        if (null == AuthUtil.getUser()) {
            log.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            ResponseProvider.write(response);
            return false;
        }
        return true;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/AuthSecure.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.props;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springblade.core.secure.provider.HttpMethod;
/**
 * è‡ªå®šä¹‰æŽˆæƒè§„则
 *
 * @author Chill
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuthSecure {
    /**
     * è¯·æ±‚方法
     */
    private HttpMethod method;
    /**
     * è¯·æ±‚路径
     */
    private String pattern;
    /**
     * è§„则表达式
     */
    private String expression;
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/BasicSecure.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.props;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springblade.core.secure.provider.HttpMethod;
/**
 * åŸºç¡€æŽˆæƒè§„则
 *
 * @author Chill
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BasicSecure {
    /**
     * è¯·æ±‚方法
     */
    private HttpMethod method;
    /**
     * è¯·æ±‚路径
     */
    private String pattern;
    /**
     * å®¢æˆ·ç«¯id
     */
    private String username;
    /**
     * å®¢æˆ·ç«¯å¯†é’¥
     */
    private String password;
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeSecureProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
 * å®¢æˆ·ç«¯æ ¡éªŒé…ç½®
 *
 * @author Chill
 */
@Data
@ConfigurationProperties("blade.secure")
public class BladeSecureProperties {
    /**
     * å¼€å¯é‰´æƒè§„则
     */
    private Boolean enabled = false;
    /**
     * é‰´æƒæ”¾è¡Œè¯·æ±‚
     */
    private final List<String> skipUrl = new ArrayList<>();
    /**
     * å¼€å¯æŽˆæƒè§„则
     */
    private Boolean authEnabled = true;
    /**
     * æŽˆæƒé…ç½®
     */
    private final List<AuthSecure> auth = new ArrayList<>();
    /**
     * å¼€å¯åŸºç¡€è®¤è¯è§„则
     */
    private Boolean basicEnabled = true;
    /**
     * åŸºç¡€è®¤è¯é…ç½®
     */
    private final List<BasicSecure> basic = new ArrayList<>();
    /**
     * å¼€å¯ç­¾åè®¤è¯è§„则
     */
    private Boolean signEnabled = true;
    /**
     * ç­¾åè®¤è¯é…ç½®
     */
    private final List<SignSecure> sign = new ArrayList<>();
    /**
     * å¼€å¯å®¢æˆ·ç«¯è§„则
     */
    private Boolean clientEnabled = true;
    /**
     * å®¢æˆ·ç«¯é…ç½®
     */
    private final List<ClientSecure> client = new ArrayList<>();
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/ClientSecure.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.props;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
 * å®¢æˆ·ç«¯ä»¤ç‰Œè®¤è¯ä¿¡æ¯
 *
 * @author Chill
 */
@Data
public class ClientSecure {
    /**
     * å®¢æˆ·ç«¯ID
     */
    private String clientId;
    /**
     * è·¯å¾„匹配
     */
    private final List<String> pathPatterns = new ArrayList<>();
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/props/SignSecure.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.props;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springblade.core.secure.provider.HttpMethod;
/**
 * ç­¾åæŽˆæƒè§„则
 *
 * @author Chill
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SignSecure {
    /**
     * è¯·æ±‚方法
     */
    private HttpMethod method;
    /**
     * è¯·æ±‚路径
     */
    private String pattern;
    /**
     * åŠ å¯†æ–¹å¼
     */
    private String crypto;
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetails.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * å®¢æˆ·ç«¯è¯¦æƒ…
 *
 * @author Chill
 */
@Data
public class ClientDetails implements IClientDetails {
    /**
     * å®¢æˆ·ç«¯id
     */
    @ApiModelProperty(value = "客户端id")
    private String clientId;
    /**
     * å®¢æˆ·ç«¯å¯†é’¥
     */
    @ApiModelProperty(value = "客户端密钥")
    private String clientSecret;
    /**
     * ä»¤ç‰Œè¿‡æœŸç§’æ•°
     */
    @ApiModelProperty(value = "令牌过期秒数")
    private Integer accessTokenValidity;
    /**
     * åˆ·æ–°ä»¤ç‰Œè¿‡æœŸç§’æ•°
     */
    @ApiModelProperty(value = "刷新令牌过期秒数")
    private Integer refreshTokenValidity;
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ClientDetailsServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.constant.SecureConstant;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
/**
 * èŽ·å–å®¢æˆ·ç«¯è¯¦æƒ…
 *
 * @author Chill
 */
@AllArgsConstructor
public class ClientDetailsServiceImpl implements IClientDetailsService {
    private final JdbcTemplate jdbcTemplate;
    @Override
    public IClientDetails loadClientByClientId(String clientId) {
        try {
            return jdbcTemplate.queryForObject(SecureConstant.DEFAULT_SELECT_STATEMENT, new String[]{clientId}, new BeanPropertyRowMapper<>(ClientDetails.class));
        } catch (Exception ex) {
            return null;
        }
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/HttpMethod.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
/**
 * HttpMethod枚举类
 *
 * @author Chill
 */
public enum HttpMethod {
    /**
     * è¯·æ±‚方法集合
     */
    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE, ALL;
    /**
     * åŒ¹é…æžšä¸¾
     */
    public static HttpMethod of(String method) {
        try {
            return valueOf(method);
        } catch (Exception exception) {
            return null;
        }
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetails.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
import java.io.Serializable;
/**
 * å¤šç»ˆç«¯è¯¦æƒ…接口
 *
 * @author Chill
 */
public interface IClientDetails extends Serializable {
    /**
     * å®¢æˆ·ç«¯id.
     *
     * @return String.
     */
    String getClientId();
    /**
     * å®¢æˆ·ç«¯å¯†é’¥.
     *
     * @return String.
     */
    String getClientSecret();
    /**
     * å®¢æˆ·ç«¯token过期时间
     *
     * @return Integer
     */
    Integer getAccessTokenValidity();
    /**
     * å®¢æˆ·ç«¯åˆ·æ–°token过期时间
     *
     * @return Integer
     */
    Integer getRefreshTokenValidity();
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/IClientDetailsService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
/**
 * å¤šç»ˆç«¯æ³¨å†ŒæŽ¥å£
 *
 * @author Chill
 */
public interface IClientDetailsService {
    /**
     * æ ¹æ®clientId获取Client详情
     *
     * @param clientId å®¢æˆ·ç«¯id
     * @return
     */
    IClientDetails loadClientByClientId(String clientId);
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/provider/ResponseProvider.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.provider;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
/**
 * ResponseProvider
 *
 * @author Chill
 */
@Slf4j
public class ResponseProvider {
    public static void write(HttpServletResponse response) {
        R result = R.fail(ResultCode.UN_AUTHORIZED);
        response.setCharacterEncoding(BladeConstant.UTF_8);
        response.addHeader(BladeConstant.CONTENT_TYPE_NAME, MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        try {
            response.getWriter().write(Objects.requireNonNull(JsonUtil.toJson(result)));
        } catch (IOException ex) {
            log.error(ex.getMessage());
        }
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/registry/SecureRegistry.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,196 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.registry;
import lombok.Data;
import org.springblade.core.secure.props.AuthSecure;
import org.springblade.core.secure.props.BasicSecure;
import org.springblade.core.secure.props.SignSecure;
import org.springblade.core.secure.provider.HttpMethod;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * å®‰å…¨æ¡†æž¶ç»Ÿä¸€é…ç½®
 *
 * @author Chill
 */
@Data
public class SecureRegistry {
    /**
     * æ˜¯å¦å¼€å¯é‰´æƒ
     */
    private boolean enabled = false;
    /**
     * æ˜¯å¦å¼€å¯æŽˆæƒ
     */
    private boolean authEnabled = true;
    /**
     * æ˜¯å¦å¼€å¯åŸºç¡€è®¤è¯
     */
    private boolean basicEnabled = true;
    /**
     * æ˜¯å¦å¼€å¯ç­¾åè®¤è¯
     */
    private boolean signEnabled = true;
    /**
     * æ˜¯å¦å¼€å¯å®¢æˆ·ç«¯è®¤è¯
     */
    private boolean clientEnabled = true;
    /**
     * é»˜è®¤æ”¾è¡Œè§„则
     */
    private final List<String> defaultExcludePatterns = new ArrayList<>();
    /**
     * è‡ªå®šä¹‰æ”¾è¡Œè§„则
     */
    private final List<String> excludePatterns = new ArrayList<>();
    /**
     * è‡ªå®šä¹‰æŽˆæƒé›†åˆ
     */
    private final List<AuthSecure> authSecures = new ArrayList<>();
    /**
     * åŸºç¡€è®¤è¯é›†åˆ
     */
    private final List<BasicSecure> basicSecures = new ArrayList<>();
    /**
     * ç­¾åè®¤è¯é›†åˆ
     */
    private final List<SignSecure> signSecures = new ArrayList<>();
    public SecureRegistry() {
        this.defaultExcludePatterns.add("/actuator/health/**");
        this.defaultExcludePatterns.add("/v2/api-docs/**");
        this.defaultExcludePatterns.add("/auth/**");
        this.defaultExcludePatterns.add("/token/**");
        this.defaultExcludePatterns.add("/log/**");
        this.defaultExcludePatterns.add("/menu/routes");
        this.defaultExcludePatterns.add("/menu/auth-routes");
        this.defaultExcludePatterns.add("/menu/top-menu");
        this.defaultExcludePatterns.add("/process/resource-view");
        this.defaultExcludePatterns.add("/process/diagram-view");
        this.defaultExcludePatterns.add("/manager/check-upload");
        this.defaultExcludePatterns.add("/error/**");
        this.defaultExcludePatterns.add("/assets/**");
    }
    /**
     * è®¾ç½®å•个放行api
     */
    public SecureRegistry excludePathPattern(String pattern) {
        this.excludePatterns.add(pattern);
        return this;
    }
    /**
     * è®¾ç½®æ”¾è¡Œapi集合
     */
    public SecureRegistry excludePathPatterns(String... patterns) {
        this.excludePatterns.addAll(Arrays.asList(patterns));
        return this;
    }
    /**
     * è®¾ç½®æ”¾è¡Œapi集合
     */
    public SecureRegistry excludePathPatterns(List<String> patterns) {
        this.excludePatterns.addAll(patterns);
        return this;
    }
    /**
     * è®¾ç½®å•个自定义授权
     */
    public SecureRegistry addAuthPattern(HttpMethod method, String pattern, String expression) {
        this.authSecures.add(new AuthSecure(method, pattern, expression));
        return this;
    }
    /**
     * è®¾ç½®è‡ªå®šä¹‰æŽˆæƒé›†åˆ
     */
    public SecureRegistry addAuthPatterns(List<AuthSecure> authSecures) {
        this.authSecures.addAll(authSecures);
        return this;
    }
    /**
     * è¿”回自定义授权集合
     */
    public List<AuthSecure> getAuthSecures() {
        return this.authSecures;
    }
    /**
     * è®¾ç½®åŸºç¡€è®¤è¯
     */
    public SecureRegistry addBasicPattern(HttpMethod method, String pattern, String username, String password) {
        this.basicSecures.add(new BasicSecure(method, pattern, username, password));
        return this;
    }
    /**
     * è®¾ç½®åŸºç¡€è®¤è¯é›†åˆ
     */
    public SecureRegistry addBasicPatterns(List<BasicSecure> basicSecures) {
        this.basicSecures.addAll(basicSecures);
        return this;
    }
    /**
     * è¿”回基础认证集合
     */
    public List<BasicSecure> getBasicSecures() {
        return this.basicSecures;
    }
    /**
     * è®¾ç½®ç­¾åè®¤è¯
     */
    public SecureRegistry addSignPattern(HttpMethod method, String pattern, String crypto) {
        this.signSecures.add(new SignSecure(method, pattern, crypto));
        return this;
    }
    /**
     * è®¾ç½®ç­¾åè®¤è¯é›†åˆ
     */
    public SecureRegistry addSignPatterns(List<SignSecure> signSecures) {
        this.signSecures.addAll(signSecures);
        return this;
    }
    /**
     * è¿”回签名认证集合
     */
    public List<SignSecure> getSignSecures() {
        return this.signSecures;
    }
}
Source/BladeX-Tool/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,227 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.secure.utils;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.SneakyThrows;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.secure.TokenInfo;
import org.springblade.core.secure.constant.SecureConstant;
import org.springblade.core.secure.exception.SecureException;
import org.springblade.core.secure.provider.IClientDetails;
import org.springblade.core.secure.provider.IClientDetailsService;
import org.springblade.core.tool.utils.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.*;
/**
 * Secure工具类
 *
 * @author Chill
 */
public class SecureUtil extends AuthUtil {
    private final static String CLIENT_ID = TokenConstant.CLIENT_ID;
    private static IClientDetailsService clientDetailsService;
    private static JwtProperties jwtProperties;
    /**
     * èŽ·å–å®¢æˆ·ç«¯æœåŠ¡ç±»
     *
     * @return clientDetailsService
     */
    private static IClientDetailsService getClientDetailsService() {
        if (clientDetailsService == null) {
            clientDetailsService = SpringUtil.getBean(IClientDetailsService.class);
        }
        return clientDetailsService;
    }
    /**
     * èŽ·å–é…ç½®ç±»
     *
     * @return jwtProperties
     */
    private static JwtProperties getJwtProperties() {
        if (jwtProperties == null) {
            jwtProperties = SpringUtil.getBean(JwtProperties.class);
        }
        return jwtProperties;
    }
    /**
     * åˆ›å»ºä»¤ç‰Œ
     *
     * @param user      user
     * @param audience  audience
     * @param issuer    issuer
     * @param tokenType tokenType
     * @return jwt
     */
    public static TokenInfo createJWT(Map<String, Object> user, String audience, String issuer, String tokenType) {
        String[] tokens = extractAndDecodeHeader();
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        // èŽ·å–å®¢æˆ·ç«¯ä¿¡æ¯
        IClientDetails clientDetails = clientDetails(clientId);
        // æ ¡éªŒå®¢æˆ·ç«¯ä¿¡æ¯
        if (!validateClient(clientDetails, clientId, clientSecret)) {
            throw new SecureException("客户端认证失败, è¯·æ£€æŸ¥è¯·æ±‚头 [Authorization] ä¿¡æ¯");
        }
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        //生成签名密钥
        byte[] apiKeySecretBytes = Base64.getDecoder().decode(JwtUtil.getBase64Security());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        //添加构成JWT的类
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
            .setIssuer(issuer)
            .setAudience(audience)
            .signWith(signingKey);
        //设置JWT参数
        user.forEach(builder::claim);
        //设置应用id
        builder.claim(CLIENT_ID, clientId);
        //添加Token过期时间
        long expireMillis;
        if (tokenType.equals(TokenConstant.ACCESS_TOKEN)) {
            expireMillis = clientDetails.getAccessTokenValidity() * 1000L;
        } else if (tokenType.equals(TokenConstant.REFRESH_TOKEN)) {
            expireMillis = clientDetails.getRefreshTokenValidity() * 1000L;
        } else {
            expireMillis = getExpire();
        }
        long expMillis = nowMillis + expireMillis;
        Date exp = new Date(expMillis);
        builder.setExpiration(exp).setNotBefore(now);
        //组装Token信息
        TokenInfo tokenInfo = new TokenInfo();
        tokenInfo.setToken(builder.compact());
        tokenInfo.setExpire((int) (expireMillis / 1000L));
        //Token状态配置, ä»…在生成AccessToken时候执行
        if (getJwtProperties().getState() && TokenConstant.ACCESS_TOKEN.equals(tokenType)) {
            String tenantId = String.valueOf(user.get(TokenConstant.TENANT_ID));
            String userId = String.valueOf(user.get(TokenConstant.USER_ID));
            JwtUtil.addAccessToken(tenantId, userId, tokenInfo.getToken(), tokenInfo.getExpire());
        }
        //Token状态配置, ä»…在生成RefreshToken时候执行
        if (getJwtProperties().getState() && getJwtProperties().getSingle() && TokenConstant.REFRESH_TOKEN.equals(tokenType)) {
            String tenantId = String.valueOf(user.get(TokenConstant.TENANT_ID));
            String userId = String.valueOf(user.get(TokenConstant.USER_ID));
            JwtUtil.addRefreshToken(tenantId, userId, tokenInfo.getToken(), tokenInfo.getExpire());
        }
        return tokenInfo;
    }
    /**
     * èŽ·å–è¿‡æœŸæ—¶é—´(次日凌晨3点)
     *
     * @return expire
     */
    public static long getExpire() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, 3);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTimeInMillis() - System.currentTimeMillis();
    }
    /**
     * å®¢æˆ·ç«¯ä¿¡æ¯è§£ç 
     */
    @SneakyThrows
    public static String[] extractAndDecodeHeader() {
        // èŽ·å–è¯·æ±‚å¤´å®¢æˆ·ç«¯ä¿¡æ¯
        String header = Objects.requireNonNull(WebUtil.getRequest()).getHeader(SecureConstant.BASIC_HEADER_KEY);
        header = Func.toStr(header).replace(SecureConstant.BASIC_HEADER_PREFIX_EXT, SecureConstant.BASIC_HEADER_PREFIX);
        if (!header.startsWith(SecureConstant.BASIC_HEADER_PREFIX)) {
            throw new SecureException("未获取到请求头[Authorization]的信息");
        }
        byte[] base64Token = header.substring(6).getBytes(Charsets.UTF_8_NAME);
        byte[] decoded;
        try {
            decoded = Base64.getDecoder().decode(base64Token);
        } catch (IllegalArgumentException var7) {
            throw new RuntimeException("客户端令牌解析失败");
        }
        String token = new String(decoded, Charsets.UTF_8_NAME);
        int index = token.indexOf(StringPool.COLON);
        if (index == -1) {
            throw new RuntimeException("客户端令牌不合法");
        } else {
            return new String[]{token.substring(0, index), token.substring(index + 1)};
        }
    }
    /**
     * èŽ·å–è¯·æ±‚å¤´ä¸­çš„å®¢æˆ·ç«¯id
     */
    public static String getClientIdFromHeader() {
        String[] tokens = extractAndDecodeHeader();
        assert tokens.length == 2;
        return tokens[0];
    }
    /**
     * èŽ·å–å®¢æˆ·ç«¯ä¿¡æ¯
     *
     * @param clientId å®¢æˆ·ç«¯id
     * @return clientDetails
     */
    private static IClientDetails clientDetails(String clientId) {
        return getClientDetailsService().loadClientByClientId(clientId);
    }
    /**
     * æ ¡éªŒClient
     *
     * @param clientId     å®¢æˆ·ç«¯id
     * @param clientSecret å®¢æˆ·ç«¯å¯†é’¥
     * @return boolean
     */
    private static boolean validateClient(IClientDetails clientDetails, String clientId, String clientSecret) {
        if (clientDetails != null) {
            return StringUtil.equals(clientId, clientDetails.getClientId()) && StringUtil.equals(clientSecret, clientDetails.getClientSecret());
        }
        return false;
    }
}
Source/BladeX-Tool/blade-core-test/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>BladeX-Tool</artifactId>
        <groupId>org.springblade</groupId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-test</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Blade -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-launch</artifactId>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeBootTest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
 * ç®€åŒ– æµ‹è¯•
 *
 * @author L.cm
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootTest
@ExtendWith(BladeSpringExtension.class)
public @interface BladeBootTest {
    /**
     * æœåŠ¡åï¼šappName
     * @return appName
     */
    @AliasFor("appName")
    String value() default "blade-test";
    /**
     * æœåŠ¡åï¼šappName
     * @return appName
     */
    @AliasFor("value")
    String appName() default "blade-test";
    /**
     * profile
     * @return profile
     */
    String profile() default "dev";
    /**
     * å¯ç”¨ ServiceLoader åŠ è½½ launcherService
     * @return æ˜¯å¦å¯ç”¨
     */
    boolean enableLoader() default false;
}
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeBootTestException.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.test;
/**
 * blade test å¼‚常
 *
 * @author L.cm
 */
class BladeBootTestException extends RuntimeException {
    BladeBootTestException(String message) {
        super(message);
    }
}
Source/BladeX-Tool/blade-core-test/src/main/java/org/springblade/core/test/BladeSpringExtension.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.springblade.core.launch.BladeApplication;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.launch.constant.NacosConstant;
import org.springblade.core.launch.constant.SentinelConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.*;
import java.util.stream.Collectors;
/**
 * è®¾ç½®å¯åŠ¨å‚æ•°
 *
 * @author L.cm
 */
public class BladeSpringExtension extends SpringExtension {
    @Override
    public void beforeAll(@NonNull ExtensionContext context) throws Exception {
        super.beforeAll(context);
        setUpTestClass(context);
    }
    private void setUpTestClass(ExtensionContext context) {
        Class<?> clazz = context.getRequiredTestClass();
        BladeBootTest bladeBootTest = AnnotationUtils.getAnnotation(clazz, BladeBootTest.class);
        if (bladeBootTest == null) {
            throw new BladeBootTestException(String.format("%s must be @BladeBootTest .", clazz));
        }
        String appName = bladeBootTest.appName();
        String profile = bladeBootTest.profile();
        boolean isLocalDev = BladeApplication.isLocalDev();
        Properties props = System.getProperties();
        props.setProperty("blade.env", profile);
        props.setProperty("blade.name", appName);
        props.setProperty("blade.is-local", String.valueOf(isLocalDev));
        props.setProperty("blade.dev-mode", profile.equals(AppConstant.PROD_CODE) ? "false" : "true");
        props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
        props.setProperty("spring.application.name", appName);
        props.setProperty("spring.profiles.active", profile);
        props.setProperty("info.version", AppConstant.APPLICATION_VERSION);
        props.setProperty("info.desc", appName);
        props.setProperty("loadbalancer.client.name", appName);
        props.setProperty("spring.cloud.sentinel.transport.dashboard", SentinelConstant.SENTINEL_ADDR);
        props.setProperty("spring.main.allow-bean-definition-overriding", "true");
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].data-id", NacosConstant.sharedDataId());
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].group", NacosConstant.NACOS_CONFIG_GROUP);
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].refresh", NacosConstant.NACOS_CONFIG_REFRESH);
        props.setProperty("spring.cloud.nacos.config.file-extension", NacosConstant.NACOS_CONFIG_FORMAT);
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].data-id", NacosConstant.sharedDataId(profile));
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].group", NacosConstant.NACOS_CONFIG_GROUP);
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].refresh", NacosConstant.NACOS_CONFIG_REFRESH);
        // åŠ è½½è‡ªå®šä¹‰ç»„ä»¶
        if (bladeBootTest.enableLoader()) {
            SpringApplicationBuilder builder = new SpringApplicationBuilder(clazz);
            List<LauncherService> launcherList = new ArrayList<>();
            ServiceLoader.load(LauncherService.class).forEach(launcherList::add);
            launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList())
                .forEach(launcherService -> launcherService.launcher(builder, appName, profile, isLocalDev));
        }
        System.err.printf("---[junit.test]:[%s]---启动中,读取到的环境变量:[%s]%n", appName, profile);
    }
}
Source/BladeX-Tool/blade-core-tool/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springblade</groupId>
        <artifactId>BladeX-Tool</artifactId>
        <version>3.0.1.RELEASE</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blade-core-tool</artifactId>
    <name>${project.artifactId}</name>
    <version>${project.parent.version}</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Blade -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-launch</artifactId>
        </dependency>
        <!-- Jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>
        <!-- Guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </dependency>
        <!--Swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.swagger</groupId>
                    <artifactId>swagger-models</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
        </dependency>
        <!-- protostuff -->
        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
        </dependency>
        <!-- jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
        </dependency>
        <!-- validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!-- Auto -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-core-auto</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/IResultCode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.api;
import java.io.Serializable;
/**
 * ä¸šåŠ¡ä»£ç æŽ¥å£
 *
 * @author Chill
 */
public interface IResultCode extends Serializable {
    /**
     * èŽ·å–æ¶ˆæ¯
     *
     * @return
     */
    String getMessage();
    /**
     * èŽ·å–çŠ¶æ€ç 
     *
     * @return
     */
    int getCode();
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/R.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,225 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.lang.Nullable;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Optional;
/**
 * ç»Ÿä¸€API响应结果封装
 *
 * @author Chill
 */
@Getter
@Setter
@ToString
@ApiModel(description = "返回信息")
@NoArgsConstructor
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "状态码", required = true)
    private int code;
    @ApiModelProperty(value = "是否成功", required = true)
    private boolean success;
    @ApiModelProperty(value = "承载数据")
    private T data;
    @ApiModelProperty(value = "返回消息", required = true)
    private String msg;
    private R(IResultCode resultCode) {
        this(resultCode, null, resultCode.getMessage());
    }
    private R(IResultCode resultCode, String msg) {
        this(resultCode, null, msg);
    }
    private R(IResultCode resultCode, T data) {
        this(resultCode, data, resultCode.getMessage());
    }
    private R(IResultCode resultCode, T data, String msg) {
        this(resultCode.getCode(), data, msg);
    }
    private R(int code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
        this.success = ResultCode.SUCCESS.code == code;
    }
    /**
     * åˆ¤æ–­è¿”回是否为成功
     *
     * @param result Result
     * @return æ˜¯å¦æˆåŠŸ
     */
    public static boolean isSuccess(@Nullable R<?> result) {
        return Optional.ofNullable(result)
            .map(x -> ObjectUtil.nullSafeEquals(ResultCode.SUCCESS.code, x.code))
            .orElse(Boolean.FALSE);
    }
    /**
     * åˆ¤æ–­è¿”回是否为成功
     *
     * @param result Result
     * @return æ˜¯å¦æˆåŠŸ
     */
    public static boolean isNotSuccess(@Nullable R<?> result) {
        return !R.isSuccess(result);
    }
    /**
     * è¿”回R
     *
     * @param data æ•°æ®
     * @param <T>  T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> data(T data) {
        return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
    }
    /**
     * è¿”回R
     *
     * @param data æ•°æ®
     * @param msg  æ¶ˆæ¯
     * @param <T>  T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> data(T data, String msg) {
        return data(HttpServletResponse.SC_OK, data, msg);
    }
    /**
     * è¿”回R
     *
     * @param code çŠ¶æ€ç 
     * @param data æ•°æ®
     * @param msg  æ¶ˆæ¯
     * @param <T>  T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> data(int code, T data, String msg) {
        return new R<>(code, data, data == null ? BladeConstant.DEFAULT_NULL_MESSAGE : msg);
    }
    /**
     * è¿”回R
     *
     * @param msg æ¶ˆæ¯
     * @param <T> T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> success(String msg) {
        return new R<>(ResultCode.SUCCESS, msg);
    }
    /**
     * è¿”回R
     *
     * @param resultCode ä¸šåŠ¡ä»£ç 
     * @param <T>        T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> success(IResultCode resultCode) {
        return new R<>(resultCode);
    }
    /**
     * è¿”回R
     *
     * @param resultCode ä¸šåŠ¡ä»£ç 
     * @param msg        æ¶ˆæ¯
     * @param <T>        T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> success(IResultCode resultCode, String msg) {
        return new R<>(resultCode, msg);
    }
    /**
     * è¿”回R
     *
     * @param msg æ¶ˆæ¯
     * @param <T> T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> fail(String msg) {
        return new R<>(ResultCode.FAILURE, msg);
    }
    /**
     * è¿”回R
     *
     * @param code çŠ¶æ€ç 
     * @param msg  æ¶ˆæ¯
     * @param <T>  T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> fail(int code, String msg) {
        return new R<>(code, null, msg);
    }
    /**
     * è¿”回R
     *
     * @param resultCode ä¸šåŠ¡ä»£ç 
     * @param <T>        T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> fail(IResultCode resultCode) {
        return new R<>(resultCode);
    }
    /**
     * è¿”回R
     *
     * @param resultCode ä¸šåŠ¡ä»£ç 
     * @param msg        æ¶ˆæ¯
     * @param <T>        T æ³›åž‹æ ‡è®°
     * @return R
     */
    public static <T> R<T> fail(IResultCode resultCode, String msg) {
        return new R<>(resultCode, msg);
    }
    /**
     * è¿”回R
     *
     * @param flag æˆåŠŸçŠ¶æ€
     * @return R
     */
    public static <T> R<T> status(boolean flag) {
        return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : fail(BladeConstant.DEFAULT_FAILURE_MESSAGE);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/api/ResultCode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.api;
import lombok.AllArgsConstructor;
import lombok.Getter;
import javax.servlet.http.HttpServletResponse;
/**
 * ä¸šåŠ¡ä»£ç æžšä¸¾
 *
 * @author Chill
 */
@Getter
@AllArgsConstructor
public enum ResultCode implements IResultCode {
    /**
     * æ“ä½œæˆåŠŸ
     */
    SUCCESS(HttpServletResponse.SC_OK, "操作成功"),
    /**
     * ä¸šåС异叏
     */
    FAILURE(HttpServletResponse.SC_BAD_REQUEST, "业务异常"),
    /**
     * è¯·æ±‚未授权
     */
    UN_AUTHORIZED(HttpServletResponse.SC_UNAUTHORIZED, "请求未授权"),
    /**
     * å®¢æˆ·ç«¯è¯·æ±‚未授权
     */
    CLIENT_UN_AUTHORIZED(HttpServletResponse.SC_UNAUTHORIZED, "客户端请求未授权"),
    /**
     * 404 æ²¡æ‰¾åˆ°è¯·æ±‚
     */
    NOT_FOUND(HttpServletResponse.SC_NOT_FOUND, "404 æ²¡æ‰¾åˆ°è¯·æ±‚"),
    /**
     * æ¶ˆæ¯ä¸èƒ½è¯»å–
     */
    MSG_NOT_READABLE(HttpServletResponse.SC_BAD_REQUEST, "消息不能读取"),
    /**
     * ä¸æ”¯æŒå½“前请求方法
     */
    METHOD_NOT_SUPPORTED(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "不支持当前请求方法"),
    /**
     * ä¸æ”¯æŒå½“前媒体类型
     */
    MEDIA_TYPE_NOT_SUPPORTED(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "不支持当前媒体类型"),
    /**
     * è¯·æ±‚被拒绝
     */
    REQ_REJECT(HttpServletResponse.SC_FORBIDDEN, "请求被拒绝"),
    /**
     * æœåС噍异叏
     */
    INTERNAL_SERVER_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器异常"),
    /**
     * ç¼ºå°‘必要的请求参数
     */
    PARAM_MISS(HttpServletResponse.SC_BAD_REQUEST, "缺少必要的请求参数"),
    /**
     * è¯·æ±‚参数类型错误
     */
    PARAM_TYPE_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数类型错误"),
    /**
     * è¯·æ±‚参数绑定错误
     */
    PARAM_BIND_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数绑定错误"),
    /**
     * å‚数校验失败
     */
    PARAM_VALID_ERROR(HttpServletResponse.SC_BAD_REQUEST, "参数校验失败"),
    ;
    /**
     * code编码
     */
    final int code;
    /**
     * ä¸­æ–‡ä¿¡æ¯æè¿°
     */
    final String message;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BeanProperty.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.springblade.core.tool.beans;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * Bean属性
 *
 * @author Chill
 */
@Getter
@AllArgsConstructor
public class BeanProperty {
    private final String name;
    private final Class<?> type;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,405 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.beans;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.ClassUtil;
import org.springblade.core.tool.utils.ReflectUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.cglib.core.*;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * spring cglib é­”改
 *
 * <p>
 *     1. æ”¯æŒé“¾å¼ bean,支持 map
 *     2. ClassLoader è·Ÿ target ä¿æŒä¸€è‡´
 * </p>
 *
 * @author L.cm
 */
public abstract class BladeBeanCopier {
    private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter");
    private static final Type BEAN_COPIER = TypeUtils.parseType(BladeBeanCopier.class.getName());
    private static final Type BEAN_MAP = TypeUtils.parseType(Map.class.getName());
    private static final Signature COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER});
    private static final Signature CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)");
    private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object)");
    private static final Type CLASS_UTILS = TypeUtils.parseType(ClassUtils.class.getName());
    private static final Signature IS_ASSIGNABLE_VALUE = TypeUtils.parseSignature("boolean isAssignableValue(Class, Object)");
    /**
     * The map to store {@link BladeBeanCopier} of source type and class type for copy.
     */
    private static final ConcurrentMap<BladeBeanCopierKey, BladeBeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();
    public static BladeBeanCopier create(Class source, Class target, boolean useConverter) {
        return BladeBeanCopier.create(source, target, useConverter, false);
    }
    public static BladeBeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) {
        BladeBeanCopierKey copierKey = new BladeBeanCopierKey(source, target, useConverter, nonNull);
        // åˆ©ç”¨ ConcurrentMap ç¼“å­˜ æé«˜æ€§èƒ½ï¼ŒæŽ¥è¿‘ ç›´æŽ¥ get set
        return BEAN_COPIER_MAP.computeIfAbsent(copierKey, key -> {
            Generator gen = new Generator();
            gen.setSource(key.getSource());
            gen.setTarget(key.getTarget());
            gen.setUseConverter(key.isUseConverter());
            gen.setNonNull(key.isNonNull());
            return gen.create(key);
        });
    }
    /**
     * Bean copy
     *
     * @param from from Bean
     * @param to to Bean
     * @param converter Converter
     */
    abstract public void copy(Object from, Object to, @Nullable Converter converter);
    public static class Generator extends AbstractClassGenerator {
        private static final Source SOURCE = new Source(BladeBeanCopier.class.getName());
        private Class source;
        private Class target;
        private boolean useConverter;
        private boolean nonNull;
        Generator() {
            super(SOURCE);
        }
        public void setSource(Class source) {
            if (!Modifier.isPublic(source.getModifiers())) {
                setNamePrefix(source.getName());
            }
            this.source = source;
        }
        public void setTarget(Class target) {
            if (!Modifier.isPublic(target.getModifiers())) {
                setNamePrefix(target.getName());
            }
            this.target = target;
        }
        public void setUseConverter(boolean useConverter) {
            this.useConverter = useConverter;
        }
        public void setNonNull(boolean nonNull) {
            this.nonNull = nonNull;
        }
        @Override
        protected ClassLoader getDefaultClassLoader() {
            // L.cm ä¿è¯ å’Œ è¿”回使用同一个 ClassLoader
            return target.getClassLoader();
        }
        @Override
        protected ProtectionDomain getProtectionDomain() {
            return ReflectUtils.getProtectionDomain(source);
        }
        @Override
        public BladeBeanCopier create(Object key) {
            return (BladeBeanCopier) super.create(key);
        }
        @Override
        public void generateClass(ClassVisitor v) {
            Type sourceType = Type.getType(source);
            Type targetType = Type.getType(target);
            ClassEmitter ce = new ClassEmitter(v);
            ce.begin_class(Constants.V1_2,
                Constants.ACC_PUBLIC,
                getClassName(),
                BEAN_COPIER,
                null,
                Constants.SOURCE_FILE);
            EmitUtils.null_constructor(ce);
            CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
            // map å•独处理
            if (Map.class.isAssignableFrom(source)) {
                generateClassFormMap(ce, e, sourceType, targetType);
                return;
            }
            // 2018.12.27 by L.cm æ”¯æŒé“¾å¼ bean
            // æ³¨æ„ï¼šæ­¤å¤„需兼容链式bean ä½¿ç”¨äº† spring çš„æ–¹æ³•,比较耗时
            PropertyDescriptor[] getters = ReflectUtil.getBeanGetters(source);
            PropertyDescriptor[] setters = ReflectUtil.getBeanSetters(target);
            Map<String, PropertyDescriptor> names = new HashMap<>(16);
            for (PropertyDescriptor getter : getters) {
                names.put(getter.getName(), getter);
            }
            Local targetLocal = e.make_local();
            Local sourceLocal = e.make_local();
            e.load_arg(1);
            e.checkcast(targetType);
            e.store_local(targetLocal);
            e.load_arg(0);
            e.checkcast(sourceType);
            e.store_local(sourceLocal);
            for (PropertyDescriptor setter : setters) {
                String propName = setter.getName();
                CopyProperty targetIgnoreCopy = ReflectUtil.getAnnotation(target, propName, CopyProperty.class);
                // set ä¸Šæœ‰å¿½ç•¥çš„ æ³¨è§£
                if (targetIgnoreCopy != null) {
                    if (targetIgnoreCopy.ignore()) {
                        continue;
                    }
                    // æ³¨è§£ä¸Šçš„别名,如果别名不为空,使用别名
                    String aliasTargetPropName = targetIgnoreCopy.value();
                    if (StringUtil.isNotBlank(aliasTargetPropName)) {
                        propName = aliasTargetPropName;
                    }
                }
                // æ‰¾åˆ°å¯¹åº”çš„ get
                PropertyDescriptor getter = names.get(propName);
                // æ²¡æœ‰ get è·³å‡º
                if (getter == null) {
                    continue;
                }
                MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
                Method writeMethod = setter.getWriteMethod();
                MethodInfo write = ReflectUtils.getMethodInfo(writeMethod);
                Type returnType = read.getSignature().getReturnType();
                Type setterType = write.getSignature().getArgumentTypes()[0];
                Class<?> getterPropertyType = getter.getPropertyType();
                Class<?> setterPropertyType = setter.getPropertyType();
                // L.cm 2019.01.12 ä¼˜åŒ–逻辑,先判断类型,类型一致直接 set,不同再判断 æ˜¯å¦ ç±»åž‹è½¬æ¢
                // nonNull Label
                Label l0 = e.make_label();
                // åˆ¤æ–­ç±»åž‹æ˜¯å¦ä¸€è‡´ï¼ŒåŒ…括 åŒ…装类型
                if (ClassUtil.isAssignable(setterPropertyType, getterPropertyType)) {
                    // 2018.12.27 by L.cm æ”¯æŒé“¾å¼ bean
                    e.load_local(targetLocal);
                    e.load_local(sourceLocal);
                    e.invoke(read);
                    boolean getterIsPrimitive = getterPropertyType.isPrimitive();
                    boolean setterIsPrimitive = setterPropertyType.isPrimitive();
                    if (nonNull) {
                        // éœ€è¦è½æ ˆï¼Œå¼ºåˆ¶è£…ç®±
                        e.box(returnType);
                        Local var = e.make_local();
                        e.store_local(var);
                        e.load_local(var);
                        // nonNull Label
                        e.ifnull(l0);
                        e.load_local(targetLocal);
                        e.load_local(var);
                        // éœ€è¦è½æ ˆï¼Œå¼ºåˆ¶æ‹†ç®±
                        e.unbox_or_zero(setterType);
                    } else {
                        // å¦‚æžœ get ä¸ºåŽŸå§‹ç±»åž‹ï¼Œéœ€è¦è£…ç®±
                        if (getterIsPrimitive && !setterIsPrimitive) {
                            e.box(returnType);
                        }
                        // å¦‚æžœ set ä¸ºåŽŸå§‹ç±»åž‹ï¼Œéœ€è¦æ‹†ç®±
                        if (!getterIsPrimitive && setterIsPrimitive) {
                            e.unbox_or_zero(setterType);
                        }
                    }
                    // æž„造 set æ–¹æ³•
                    invokeWrite(e, write, writeMethod, nonNull, l0);
                } else if (useConverter) {
                    e.load_local(targetLocal);
                    e.load_arg(2);
                    e.load_local(sourceLocal);
                    e.invoke(read);
                    e.box(returnType);
                    if (nonNull) {
                        Local var = e.make_local();
                        e.store_local(var);
                        e.load_local(var);
                        e.ifnull(l0);
                        e.load_local(targetLocal);
                        e.load_arg(2);
                        e.load_local(var);
                    }
                    EmitUtils.load_class(e, setterType);
                    // æ›´æ”¹æˆäº†å±žæ€§åï¼Œä¹‹å‰æ˜¯ set æ–¹æ³•名
                    e.push(propName);
                    e.invoke_interface(CONVERTER, CONVERT);
                    e.unbox_or_zero(setterType);
                    // æž„造 set æ–¹æ³•
                    invokeWrite(e, write, writeMethod, nonNull, l0);
                }
            }
            e.return_value();
            e.end_method();
            ce.end_class();
        }
        private static void invokeWrite(CodeEmitter e, MethodInfo write, Method writeMethod, boolean nonNull, Label l0) {
            // è¿”回值,判断 é“¾å¼ bean
            Class<?> returnType = writeMethod.getReturnType();
            e.invoke(write);
            // é“¾å¼ bean,有返回值需要 pop
            if (!returnType.equals(Void.TYPE)) {
                e.pop();
            }
            if (nonNull) {
                e.visitLabel(l0);
            }
        }
        @Override
        protected Object firstInstance(Class type) {
            return BeanUtil.newInstance(type);
        }
        @Override
        protected Object nextInstance(Object instance) {
            return instance;
        }
        /**
         * å¤„理 map çš„ copy
         * @param ce ClassEmitter
         * @param e CodeEmitter
         * @param sourceType sourceType
         * @param targetType targetType
         */
        public void generateClassFormMap(ClassEmitter ce, CodeEmitter e, Type sourceType, Type targetType) {
            // 2018.12.27 by L.cm æ”¯æŒé“¾å¼ bean
            PropertyDescriptor[] setters = ReflectUtil.getBeanSetters(target);
            // å…¥å£å˜é‡
            Local targetLocal = e.make_local();
            Local sourceLocal = e.make_local();
            e.load_arg(1);
            e.checkcast(targetType);
            e.store_local(targetLocal);
            e.load_arg(0);
            e.checkcast(sourceType);
            e.store_local(sourceLocal);
            Type mapBox = Type.getType(Object.class);
            for (PropertyDescriptor setter : setters) {
                String propName = setter.getName();
                // set ä¸Šæœ‰å¿½ç•¥çš„ æ³¨è§£
                CopyProperty targetIgnoreCopy = ReflectUtil.getAnnotation(target, propName, CopyProperty.class);
                if (targetIgnoreCopy != null) {
                    if (targetIgnoreCopy.ignore()) {
                        continue;
                    }
                    // æ³¨è§£ä¸Šçš„别名
                    String aliasTargetPropName = targetIgnoreCopy.value();
                    if (StringUtil.isNotBlank(aliasTargetPropName)) {
                        propName = aliasTargetPropName;
                    }
                }
                Method writeMethod = setter.getWriteMethod();
                MethodInfo write = ReflectUtils.getMethodInfo(writeMethod);
                Type setterType = write.getSignature().getArgumentTypes()[0];
                e.load_local(targetLocal);
                e.load_local(sourceLocal);
                e.push(propName);
                // æ‰§è¡Œ map get
                e.invoke_interface(BEAN_MAP, BEAN_MAP_GET);
                // box è£…箱,避免 array[] æ•°ç»„问题
                e.box(mapBox);
                // ç”Ÿæˆå˜é‡
                Local var = e.make_local();
                e.store_local(var);
                e.load_local(var);
                // å…ˆåˆ¤æ–­ ä¸ä¸ºnull,然后做类型判断
                Label l0 = e.make_label();
                e.ifnull(l0);
                EmitUtils.load_class(e, setterType);
                e.load_local(var);
                // ClassUtils.isAssignableValue(Integer.class, id)
                e.invoke_static(CLASS_UTILS, IS_ASSIGNABLE_VALUE);
                Label l1 = new Label();
                // è¿”回值,判断 é“¾å¼ bean
                Class<?> returnType = writeMethod.getReturnType();
                if (useConverter) {
                    e.if_jump(Opcodes.IFEQ, l1);
                    e.load_local(targetLocal);
                    e.load_local(var);
                    e.unbox_or_zero(setterType);
                    e.invoke(write);
                    if (!returnType.equals(Void.TYPE)) {
                        e.pop();
                    }
                    e.goTo(l0);
                    e.visitLabel(l1);
                    e.load_local(targetLocal);
                    e.load_arg(2);
                    e.load_local(var);
                    EmitUtils.load_class(e, setterType);
                    e.push(propName);
                    e.invoke_interface(CONVERTER, CONVERT);
                    e.unbox_or_zero(setterType);
                    e.invoke(write);
                } else {
                    e.if_jump(Opcodes.IFEQ, l0);
                    e.load_local(targetLocal);
                    e.load_local(var);
                    e.unbox_or_zero(setterType);
                    e.invoke(write);
                }
                // è¿”回值,判断 é“¾å¼ bean
                if (!returnType.equals(Void.TYPE)) {
                    e.pop();
                }
                e.visitLabel(l0);
            }
            e.return_value();
            e.end_method();
            ce.end_class();
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopierKey.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package org.springblade.core.tool.beans;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
/**
 * copy key
 *
 * @author L.cm
 */
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class BladeBeanCopierKey {
    private final Class<?> source;
    private final Class<?> target;
    private final boolean useConverter;
    private final boolean nonNull;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMap.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
package org.springblade.core.tool.beans;
import org.springframework.asm.ClassVisitor;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.ReflectUtils;
import java.security.ProtectionDomain;
/**
 * é‡å†™ cglib BeanMap,支持链式bean
 *
 * @author L.cm
 */
public abstract class BladeBeanMap extends BeanMap {
    protected BladeBeanMap() {
    }
    protected BladeBeanMap(Object bean) {
        super(bean);
    }
    public static BladeBeanMap create(Object bean) {
        BladeGenerator gen = new BladeGenerator();
        gen.setBean(bean);
        return gen.create();
    }
    /**
     * newInstance
     *
     * @param o Object
     * @return BladeBeanMap
     */
    @Override
    public abstract BladeBeanMap newInstance(Object o);
    public static class BladeGenerator extends AbstractClassGenerator {
        private static final Source SOURCE = new Source(BladeBeanMap.class.getName());
        private Object bean;
        private Class beanClass;
        private int require;
        public BladeGenerator() {
            super(SOURCE);
        }
        /**
         * Set the bean that the generated map should reflect. The bean may be swapped
         * out for another bean of the same type using {@link #setBean}.
         * Calling this method overrides any value previously set using {@link #setBeanClass}.
         * You must call either this method or {@link #setBeanClass} before {@link #create}.
         *
         * @param bean the initial bean
         */
        public void setBean(Object bean) {
            this.bean = bean;
            if (bean != null) {
                beanClass = bean.getClass();
            }
        }
        /**
         * Set the class of the bean that the generated map should support.
         * You must call either this method or {@link #setBeanClass} before {@link #create}.
         *
         * @param beanClass the class of the bean
         */
        public void setBeanClass(Class beanClass) {
            this.beanClass = beanClass;
        }
        /**
         * Limit the properties reflected by the generated map.
         *
         * @param require any combination of {@link #REQUIRE_GETTER} and
         *                {@link #REQUIRE_SETTER}; default is zero (any property allowed)
         */
        public void setRequire(int require) {
            this.require = require;
        }
        @Override
        protected ClassLoader getDefaultClassLoader() {
            return beanClass.getClassLoader();
        }
        @Override
        protected ProtectionDomain getProtectionDomain() {
            return ReflectUtils.getProtectionDomain(beanClass);
        }
        /**
         * Create a new instance of the <code>BeanMap</code>. An existing
         * generated class will be reused if possible.
         *
         * @return {BladeBeanMap}
         */
        public BladeBeanMap create() {
            if (beanClass == null) {
                throw new IllegalArgumentException("Class of bean unknown");
            }
            setNamePrefix(beanClass.getName());
            BladeBeanMapKey key = new BladeBeanMapKey(beanClass, require);
            return (BladeBeanMap) super.create(key);
        }
        @Override
        public void generateClass(ClassVisitor v) throws Exception {
            new BladeBeanMapEmitter(v, getClassName(), beanClass, require);
        }
        @Override
        protected Object firstInstance(Class type) {
            return ((BeanMap) ReflectUtils.newInstance(type)).newInstance(bean);
        }
        @Override
        protected Object nextInstance(Object instance) {
            return ((BeanMap) instance).newInstance(bean);
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMapEmitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,192 @@
package org.springblade.core.tool.beans;
import org.springblade.core.tool.utils.ReflectUtil;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.Type;
import org.springframework.cglib.core.*;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
 * é‡å†™ cglib BeanMap å¤„理器
 *
 * @author L.cm
 */
class BladeBeanMapEmitter extends ClassEmitter {
    private static final Type BEAN_MAP = TypeUtils.parseType(BladeBeanMap.class.getName());
    private static final Type FIXED_KEY_SET = TypeUtils.parseType("org.springframework.cglib.beans.FixedKeySet");
    private static final Signature CSTRUCT_OBJECT = TypeUtils.parseConstructor("Object");
    private static final Signature CSTRUCT_STRING_ARRAY = TypeUtils.parseConstructor("String[]");
    private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object, Object)");
    private static final Signature BEAN_MAP_PUT = TypeUtils.parseSignature("Object put(Object, Object, Object)");
    private static final Signature KEY_SET = TypeUtils.parseSignature("java.util.Set keySet()");
    private static final Signature NEW_INSTANCE = new Signature("newInstance", BEAN_MAP, new Type[]{Constants.TYPE_OBJECT});
    private static final Signature GET_PROPERTY_TYPE = TypeUtils.parseSignature("Class getPropertyType(String)");
    public BladeBeanMapEmitter(ClassVisitor v, String className, Class type, int require) {
        super(v);
        begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
        EmitUtils.null_constructor(this);
        EmitUtils.factory_method(this, NEW_INSTANCE);
        generateConstructor();
        Map<String, PropertyDescriptor> getters = makePropertyMap(ReflectUtil.getBeanGetters(type));
        Map<String, PropertyDescriptor> setters = makePropertyMap(ReflectUtil.getBeanSetters(type));
        Map<String, PropertyDescriptor> allProps = new HashMap<>(32);
        allProps.putAll(getters);
        allProps.putAll(setters);
        if (require != 0) {
            for (Iterator it = allProps.keySet().iterator(); it.hasNext(); ) {
                String name = (String) it.next();
                if ((((require & BladeBeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
                    (((require & BladeBeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) {
                    it.remove();
                    getters.remove(name);
                    setters.remove(name);
                }
            }
        }
        generateGet(type, getters);
        generatePut(type, setters);
        String[] allNames = getNames(allProps);
        generateKeySet(allNames);
        generateGetPropertyType(allProps, allNames);
        end_class();
    }
    private Map<String, PropertyDescriptor> makePropertyMap(PropertyDescriptor[] props) {
        Map<String, PropertyDescriptor> names = new HashMap<>(16);
        for (PropertyDescriptor prop : props) {
            String propName = prop.getName();
            // è¿‡æ»¤ getClass,Spring çš„工具类会拿到该方法
            if (!"class".equals(propName)) {
                names.put(propName, prop);
            }
        }
        return names;
    }
    private String[] getNames(Map<String, PropertyDescriptor> propertyMap) {
        return propertyMap.keySet().toArray(new String[0]);
    }
    private void generateConstructor() {
        CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
        e.load_this();
        e.load_arg(0);
        e.super_invoke_constructor(CSTRUCT_OBJECT);
        e.return_value();
        e.end_method();
    }
    private void generateGet(Class type, final Map<String, PropertyDescriptor> getters) {
        final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null);
        e.load_arg(0);
        e.checkcast(Type.getType(type));
        e.load_arg(1);
        e.checkcast(Constants.TYPE_STRING);
        EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
            @Override
            public void processCase(Object key, Label end) {
                PropertyDescriptor pd = getters.get(key);
                MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
                e.invoke(method);
                e.box(method.getSignature().getReturnType());
                e.return_value();
            }
            @Override
            public void processDefault() {
                e.aconst_null();
                e.return_value();
            }
        });
        e.end_method();
    }
    private void generatePut(Class type, final Map<String, PropertyDescriptor> setters) {
        final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null);
        e.load_arg(0);
        e.checkcast(Type.getType(type));
        e.load_arg(1);
        e.checkcast(Constants.TYPE_STRING);
        EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
            @Override
            public void processCase(Object key, Label end) {
                PropertyDescriptor pd = setters.get(key);
                if (pd.getReadMethod() == null) {
                    e.aconst_null();
                } else {
                    MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod());
                    e.dup();
                    e.invoke(read);
                    e.box(read.getSignature().getReturnType());
                }
                // move old value behind bean
                e.swap();
                // new value
                e.load_arg(2);
                MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod());
                e.unbox(write.getSignature().getArgumentTypes()[0]);
                e.invoke(write);
                e.return_value();
            }
            @Override
            public void processDefault() {
                // fall-through
            }
        });
        e.aconst_null();
        e.return_value();
        e.end_method();
    }
    private void generateKeySet(String[] allNames) {
        // static initializer
        declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null);
        CodeEmitter e = begin_static();
        e.new_instance(FIXED_KEY_SET);
        e.dup();
        EmitUtils.push_array(e, allNames);
        e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
        e.putfield("keys");
        e.return_value();
        e.end_method();
        // keySet
        e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null);
        e.load_this();
        e.getfield("keys");
        e.return_value();
        e.end_method();
    }
    private void generateGetPropertyType(final Map allProps, String[] allNames) {
        final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null);
        e.load_arg(0);
        EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
            @Override
            public void processCase(Object key, Label end) {
                PropertyDescriptor pd = (PropertyDescriptor) allProps.get(key);
                EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
                e.return_value();
            }
            @Override
            public void processDefault() {
                e.aconst_null();
                e.return_value();
            }
        });
        e.end_method();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanMapKey.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.springblade.core.tool.beans;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
/**
 * bean map key,提高性能
 *
 * @author L.cm
 */
@EqualsAndHashCode
@AllArgsConstructor
public class BladeBeanMapKey {
    private final Class type;
    private final int require;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/CopyProperty.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package org.springblade.core.tool.beans;
import java.lang.annotation.*;
/**
 * copy å­—段 é…ç½®
 *
 * @author L.cm
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CopyProperty {
    /**
     * å±žæ€§åï¼Œç”¨äºŽæŒ‡å®šåˆ«åï¼Œé»˜è®¤ä½¿ç”¨ï¼šfield name
     * @return å±žæ€§å
     */
    String value() default "";
    /**
     * å¿½ç•¥ï¼šé»˜è®¤ä¸º false
     * @return æ˜¯å¦å¿½ç•¥
     */
    boolean ignore() default false;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/BladeConverterConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package org.springblade.core.tool.config;
import org.springblade.core.tool.convert.EnumToStringConverter;
import org.springblade.core.tool.convert.StringToEnumConverter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * blade enum ã€Š-》 String è½¬æ¢é…ç½®
 *
 * @author L.cm
 */
@AutoConfiguration
public class BladeConverterConfiguration implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new EnumToStringConverter());
        registry.addConverter(new StringToEnumConverter());
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.config;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.BladeJavaTimeModule;
import org.springblade.core.tool.utils.DateUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
 * Jackson配置类
 *
 * @author Chill
 */
@AutoConfiguration(before = JacksonAutoConfiguration.class)
@ConditionalOnClass(ObjectMapper.class)
@EnableConfigurationProperties(BladeJacksonProperties.class)
public class JacksonConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        builder.simpleDateFormat(DateUtil.PATTERN_DATETIME);
        //创建ObjectMapper
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        //设置地点为中国
        objectMapper.setLocale(Locale.CHINA);
        //去掉默认的时间戳格式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //设置为中国上海时区
        objectMapper.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
        //序列化时,日期的统一格式
        objectMapper.setDateFormat(new SimpleDateFormat(DateUtil.PATTERN_DATETIME, Locale.CHINA));
        //序列化处理
        objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
        objectMapper.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true);
        //失败处理
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //单引号处理
        objectMapper.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
        //反序列化时,属性不存在的兼容处理
        objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        //日期格式化
        objectMapper.configure(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS, false);
        objectMapper.registerModule(BladeJavaTimeModule.INSTANCE);
        objectMapper.configure(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS, true);
        objectMapper.findAndRegisterModules();
        return objectMapper;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.MappingApiJackson2HttpMessageConverter;
import org.springblade.core.tool.utils.DateUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.converter.*;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
 * æ¶ˆæ¯é…ç½®ç±»
 *
 * @author Chill
 */
@AutoConfiguration
@AllArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MessageConfiguration implements WebMvcConfigurer {
    private final ObjectMapper objectMapper;
    private final BladeJacksonProperties properties;
    /**
     * ä½¿ç”¨ JACKSON ä½œä¸ºJSON MessageConverter
     * æ¶ˆæ¯è½¬æ¢ï¼Œå†…置断点续传,下载和字符串
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(x -> x instanceof StringHttpMessageConverter || x instanceof AbstractJackson2HttpMessageConverter);
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new ResourceRegionHttpMessageConverter());
        converters.add(new MappingApiJackson2HttpMessageConverter(objectMapper, properties));
    }
    /**
     * æ—¥æœŸæ ¼å¼åŒ–
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter(DateUtil.PATTERN_DATE));
        registry.addFormatter(new DateFormatter(DateUtil.PATTERN_DATETIME));
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/config/ToolConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.config;
import org.springblade.core.tool.support.BinderSupplier;
import org.springblade.core.tool.utils.SpringUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import java.util.function.Supplier;
/**
 * å·¥å…·é…ç½®ç±»
 *
 * @author Chill
 */
@AutoConfiguration
public class ToolConfiguration {
    /**
     * Spring上下文缓存
     */
    @Bean
    public SpringUtil springUtil() {
        return new SpringUtil();
    }
    /**
     * Binder支持类
     */
    @Bean
    @ConditionalOnMissingBean
    public Supplier<Object> binderSupplier() {
        return new BinderSupplier();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.constant;
/**
 * ç³»ç»Ÿå¸¸é‡
 *
 * @author Chill
 */
public interface BladeConstant {
    /**
     * ç¼–码
     */
    String UTF_8 = "UTF-8";
    /**
     * contentType
     */
    String CONTENT_TYPE_NAME = "Content-type";
    /**
     * JSON èµ„源
     */
    String CONTENT_TYPE = "application/json;charset=utf-8";
    /**
     * ä¸Šä¸‹æ–‡é”®å€¼
     */
    String CONTEXT_KEY = "bladeContext";
    /**
     * mdc request id key
     */
    String MDC_REQUEST_ID_KEY = "requestId";
    /**
     * mdc account id key
     */
    String MDC_ACCOUNT_ID_KEY = "accountId";
    /**
     * mdc tenant id key
     */
    String MDC_TENANT_ID_KEY = "tenantId";
    /**
     * è§’色前缀
     */
    String SECURITY_ROLE_PREFIX = "ROLE_";
    /**
     * ä¸»é”®å­—段名
     */
    String DB_PRIMARY_KEY = "id";
    /**
     * ä¸»é”®å­—段get方法
     */
    String DB_PRIMARY_KEY_METHOD = "getId";
    /**
     * ç§Ÿæˆ·å­—段名
     */
    String DB_TENANT_KEY = "tenantId";
    /**
     * ç§Ÿæˆ·å­—段get方法
     */
    String DB_TENANT_KEY_GET_METHOD = "getTenantId";
    /**
     * ç§Ÿæˆ·å­—段set方法
     */
    String DB_TENANT_KEY_SET_METHOD = "setTenantId";
    /**
     * ä¸šåŠ¡çŠ¶æ€[1:正常]
     */
    int DB_STATUS_NORMAL = 1;
    /**
     * åˆ é™¤çŠ¶æ€[0:正常,1:删除]
     */
    int DB_NOT_DELETED = 0;
    int DB_IS_DELETED = 1;
    /**
     * ç”¨æˆ·é”å®šçŠ¶æ€
     */
    int DB_ADMIN_NON_LOCKED = 0;
    int DB_ADMIN_LOCKED = 1;
    /**
     * é¡¶çº§çˆ¶èŠ‚ç‚¹id
     */
    Long TOP_PARENT_ID = 0L;
    /**
     * é¡¶çº§çˆ¶èŠ‚ç‚¹åç§°
     */
    String TOP_PARENT_NAME = "顶级";
    /**
     * ç®¡ç†å‘˜å¯¹åº”的租户ID
     */
    String ADMIN_TENANT_ID = "000000";
    /**
     * æ—¥å¿—默认状态
     */
    String LOG_NORMAL_TYPE = "1";
    /**
     * é»˜è®¤ä¸ºç©ºæ¶ˆæ¯
     */
    String DEFAULT_NULL_MESSAGE = "暂无承载数据";
    /**
     * é»˜è®¤æˆåŠŸæ¶ˆæ¯
     */
    String DEFAULT_SUCCESS_MESSAGE = "操作成功";
    /**
     * é»˜è®¤å¤±è´¥æ¶ˆæ¯
     */
    String DEFAULT_FAILURE_MESSAGE = "操作失败";
    /**
     * é»˜è®¤æœªæŽˆæƒæ¶ˆæ¯
     */
    String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败";
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/constant/RoleConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.constant;
/**
 * ç³»ç»Ÿé»˜è®¤è§’色
 *
 * @author Chill
 */
public class RoleConstant {
    public static final String ADMINISTRATOR = "administrator";
    public static final String HAS_ROLE_ADMINISTRATOR = "hasRole('" + ADMINISTRATOR + "')";
    public static final String ADMIN = "admin";
    public static final String HAS_ROLE_ADMIN = "hasAnyRole('" + ADMINISTRATOR + "', '" + ADMIN + "')";
    public static final String USER = "user";
    public static final String HAS_ROLE_USER = "hasRole('" + USER + "')";
    public static final String TEST = "test";
    public static final String HAS_ROLE_TEST = "hasRole('" + TEST + "')";
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/BladeConversionService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package org.springblade.core.tool.convert;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
 * ç±»åž‹ è½¬æ¢ æœåŠ¡ï¼Œæ·»åŠ äº† IEnum è½¬æ¢
 *
 * @author L.cm
 */
public class BladeConversionService extends ApplicationConversionService {
    @Nullable
    private static volatile BladeConversionService SHARED_INSTANCE;
    public BladeConversionService() {
        this(null);
    }
    public BladeConversionService(@Nullable StringValueResolver embeddedValueResolver) {
        super(embeddedValueResolver);
        super.addConverter(new EnumToStringConverter());
        super.addConverter(new StringToEnumConverter());
    }
    /**
     * Return a shared default application {@code ConversionService} instance, lazily
     * building it once needed.
     * <p>
     * Note: This method actually returns an {@link BladeConversionService}
     * instance. However, the {@code ConversionService} signature has been preserved for
     * binary compatibility.
     * @return the shared {@code BladeConversionService} instance (never{@code null})
     */
    public static GenericConversionService getInstance() {
        BladeConversionService sharedInstance = BladeConversionService.SHARED_INSTANCE;
        if (sharedInstance == null) {
            synchronized (BladeConversionService.class) {
                sharedInstance = BladeConversionService.SHARED_INSTANCE;
                if (sharedInstance == null) {
                    sharedInstance = new BladeConversionService();
                    BladeConversionService.SHARED_INSTANCE = sharedInstance;
                }
            }
        }
        return sharedInstance;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/BladeConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package org.springblade.core.tool.convert;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.function.CheckedFunction;
import org.springblade.core.tool.utils.ClassUtil;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.ReflectUtil;
import org.springblade.core.tool.utils.Unchecked;
import org.springframework.cglib.core.Converter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * ç»„合 spring cglib Converter å’Œ spring ConversionService
 *
 * @author L.cm
 */
@Slf4j
@AllArgsConstructor
public class BladeConverter implements Converter {
    private static final ConcurrentMap<String, TypeDescriptor> TYPE_CACHE = new ConcurrentHashMap<>();
    private final Class<?> sourceClazz;
    private final Class<?> targetClazz;
    /**
     * cglib convert
     *
     * @param value     æºå¯¹è±¡å±žæ€§
     * @param target    ç›®æ ‡å¯¹è±¡å±žæ€§ç±»
     * @param fieldName ç›®æ ‡çš„field名,原为 set æ–¹æ³•名,BladeBeanCopier é‡Œåšäº†æ›´æ”¹
     * @return {Object}
     */
    @Override
    @Nullable
    public Object convert(Object value, Class target, final Object fieldName) {
        if (value == null) {
            return null;
        }
        // ç±»åž‹ä¸€æ ·ï¼Œä¸éœ€è¦è½¬æ¢
        if (ClassUtil.isAssignableValue(target, value)) {
            return value;
        }
        try {
            TypeDescriptor targetDescriptor = BladeConverter.getTypeDescriptor(targetClazz, (String) fieldName);
            // 1. åˆ¤æ–­ sourceClazz ä¸º Map
            if (Map.class.isAssignableFrom(sourceClazz)) {
                return ConvertUtil.convert(value, targetDescriptor);
            } else {
                TypeDescriptor sourceDescriptor = BladeConverter.getTypeDescriptor(sourceClazz, (String) fieldName);
                return ConvertUtil.convert(value, sourceDescriptor, targetDescriptor);
            }
        } catch (Throwable e) {
            log.warn("BladeConverter error", e);
            return null;
        }
    }
    private static TypeDescriptor getTypeDescriptor(final Class<?> clazz, final String fieldName) {
        String srcCacheKey = clazz.getName() + fieldName;
        // å¿½ç•¥æŠ›å‡ºå¼‚常的函数,定义完整泛型,避免编译问题
        CheckedFunction<String, TypeDescriptor> uncheckedFunction = (key) -> {
            // è¿™é‡Œ property ç†è®ºä¸Šä¸ä¼šä¸º null
            Field field = ReflectUtil.getField(clazz, fieldName);
            if (field == null) {
                throw new NoSuchFieldException(fieldName);
            }
            return new TypeDescriptor(field);
        };
        return TYPE_CACHE.computeIfAbsent(srcCacheKey, Unchecked.function(uncheckedFunction));
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/EnumToStringConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.convert;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * æŽ¥æ”¶å‚æ•° åŒ jackson Enum -》 String è½¬æ¢
 *
 * @author L.cm
 */
@Slf4j
public class EnumToStringConverter implements ConditionalGenericConverter {
    /**
     * ç¼“å­˜ Enum ç±»ä¿¡æ¯ï¼Œæä¾›æ€§èƒ½
     */
    private static final ConcurrentMap<Class<?>, AccessibleObject> ENUM_CACHE_MAP = new ConcurrentHashMap<>(8);
    @Nullable
    private static AccessibleObject getAnnotation(Class<?> clazz) {
        Set<AccessibleObject> accessibleObjects = new HashSet<>();
        // JsonValue METHOD, FIELD
        Field[] fields = clazz.getDeclaredFields();
        Collections.addAll(accessibleObjects, fields);
        // methods
        Method[] methods = clazz.getDeclaredMethods();
        Collections.addAll(accessibleObjects, methods);
        for (AccessibleObject accessibleObject : accessibleObjects) {
            // å¤ç”¨ jackson çš„ JsonValue æ³¨è§£
            JsonValue jsonValue = accessibleObject.getAnnotation(JsonValue.class);
            if (jsonValue != null && jsonValue.value()) {
                accessibleObject.setAccessible(true);
                return accessibleObject;
            }
        }
        return null;
    }
    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return true;
    }
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        Set<ConvertiblePair> pairSet = new HashSet<>(3);
        pairSet.add(new ConvertiblePair(Enum.class, String.class));
        pairSet.add(new ConvertiblePair(Enum.class, Integer.class));
        pairSet.add(new ConvertiblePair(Enum.class, Long.class));
        return Collections.unmodifiableSet(pairSet);
    }
    @Override
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }
        Class<?> sourceClazz = sourceType.getType();
        AccessibleObject accessibleObject = ENUM_CACHE_MAP.computeIfAbsent(sourceClazz, EnumToStringConverter::getAnnotation);
        Class<?> targetClazz = targetType.getType();
        // å¦‚果为null,走默认的转换
        if (accessibleObject == null) {
            if (String.class == targetClazz) {
                return ((Enum) source).name();
            }
            int ordinal = ((Enum) source).ordinal();
            return ConvertUtil.convert(ordinal, targetClazz);
        }
        try {
            return EnumToStringConverter.invoke(sourceClazz, accessibleObject, source, targetClazz);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    @Nullable
    private static Object invoke(Class<?> clazz, AccessibleObject accessibleObject, Object source, Class<?> targetClazz)
        throws IllegalAccessException, InvocationTargetException {
        Object value = null;
        if (accessibleObject instanceof Field) {
            Field field = (Field) accessibleObject;
            value = field.get(source);
        } else if (accessibleObject instanceof Method) {
            Method method = (Method) accessibleObject;
            Class<?> paramType = method.getParameterTypes()[0];
            // ç±»åž‹è½¬æ¢
            Object object = ConvertUtil.convert(source, paramType);
            value = method.invoke(clazz, object);
        }
        if (value == null) {
            return null;
        }
        return ConvertUtil.convert(value, targetClazz);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/StringToEnumConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.convert;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * æŽ¥æ”¶å‚æ•° åŒ jackson String -》 Enum è½¬æ¢
 *
 * @author L.cm
 */
@Slf4j
public class StringToEnumConverter implements ConditionalGenericConverter {
    /**
     * ç¼“å­˜ Enum ç±»ä¿¡æ¯ï¼Œæä¾›æ€§èƒ½
     */
    private static final ConcurrentMap<Class<?>, AccessibleObject> ENUM_CACHE_MAP = new ConcurrentHashMap<>(8);
    @Nullable
    private static AccessibleObject getAnnotation(Class<?> clazz) {
        Set<AccessibleObject> accessibleObjects = new HashSet<>();
        // JsonCreator METHOD, CONSTRUCTOR
        Constructor<?>[] constructors = clazz.getConstructors();
        Collections.addAll(accessibleObjects, constructors);
        // methods
        Method[] methods = clazz.getDeclaredMethods();
        Collections.addAll(accessibleObjects, methods);
        for (AccessibleObject accessibleObject : accessibleObjects) {
            // å¤ç”¨ jackson çš„ JsonCreator注解
            JsonCreator jsonCreator = accessibleObject.getAnnotation(JsonCreator.class);
            if (jsonCreator != null && JsonCreator.Mode.DISABLED != jsonCreator.mode()) {
                accessibleObject.setAccessible(true);
                return accessibleObject;
            }
        }
        return null;
    }
    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return true;
    }
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, Enum.class));
    }
    @Nullable
    @Override
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (StringUtil.isBlank((String) source)) {
            return null;
        }
        Class<?> clazz = targetType.getType();
        AccessibleObject accessibleObject = ENUM_CACHE_MAP.computeIfAbsent(clazz, StringToEnumConverter::getAnnotation);
        String value = ((String) source).trim();
        // å¦‚果为null,走默认的转换
        if (accessibleObject == null) {
            return valueOf(clazz, value);
        }
        try {
            return StringToEnumConverter.invoke(clazz, accessibleObject, value);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    @SuppressWarnings("unchecked")
    private static <T extends Enum<T>> T valueOf(Class<?> clazz, String value){
        return Enum.valueOf((Class<T>) clazz, value);
    }
    @Nullable
    private static Object invoke(Class<?> clazz, AccessibleObject accessibleObject, String value)
        throws IllegalAccessException, InvocationTargetException, InstantiationException {
        if (accessibleObject instanceof Constructor) {
            Constructor constructor = (Constructor) accessibleObject;
            Class<?> paramType = constructor.getParameterTypes()[0];
            // ç±»åž‹è½¬æ¢
            Object object = ConvertUtil.convert(value, paramType);
            return constructor.newInstance(object);
        }
        if (accessibleObject instanceof Method) {
            Method method = (Method) accessibleObject;
            Class<?> paramType = method.getParameterTypes()[0];
            // ç±»åž‹è½¬æ¢
            Object object = ConvertUtil.convert(value, paramType);
            return method.invoke(clazz, object);
        }
        return null;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedCallable.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
/**
 * å—检的 Callable
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedCallable<T> {
    /**
     * Run this callable.
     *
     * @return result
     * @throws Throwable CheckedException
     */
    @Nullable
    T call() throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedComparator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
/**
 * å—检的 Comparator
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedComparator<T> {
    /**
     * Compares its two arguments for order.
     *
     * @param o1 o1
     * @param o2 o2
     * @return int
     * @throws Throwable CheckedException
     */
    int compare(T o1, T o2) throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedConsumer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
/**
 * å—检的 Consumer
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedConsumer<T> {
    /**
     * Run the Consumer
     *
     * @param t T
     * @throws Throwable UncheckedException
     */
    @Nullable
    void accept(@Nullable T t) throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedFunction.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
/**
 * å—检的 function
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedFunction<T, R> {
    /**
     * Run the Function
     *
     * @param t T
     * @return R R
     * @throws Throwable CheckedException
     */
    @Nullable
    R apply(@Nullable T t) throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedRunnable.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
/**
 * å—检的 runnable
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedRunnable {
    /**
     * Run this runnable.
     *
     * @throws Throwable CheckedException
     */
    void run() throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/function/CheckedSupplier.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
/**
 * å—检的 Supplier
 *
 * @author L.cm
 */
@FunctionalInterface
public interface CheckedSupplier<T> {
    /**
     * Run the Supplier
     *
     * @return T
     * @throws Throwable CheckedException
     */
    @Nullable
    T get() throws Throwable;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,127 @@
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import org.springblade.core.tool.utils.Charsets;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.TypeUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
 * åˆ†è¯»å†™çš„ json æ¶ˆæ¯ å¤„理器
 *
 * @author L.cm
 */
public abstract class AbstractReadWriteJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
    private static final java.nio.charset.Charset DEFAULT_CHARSET = Charsets.UTF_8;
    private final ObjectMapper writeObjectMapper;
    @Nullable
    private PrettyPrinter ssePrettyPrinter;
    public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper) {
        super(readObjectMapper);
        this.writeObjectMapper = writeObjectMapper;
        initSsePrettyPrinter();
    }
    public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, MediaType supportedMediaType) {
        this(readObjectMapper, writeObjectMapper);
        setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
        initSsePrettyPrinter();
    }
    public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, List<MediaType> supportedMediaTypes) {
        this(readObjectMapper, writeObjectMapper);
        setSupportedMediaTypes(supportedMediaTypes);
    }
    private void initSsePrettyPrinter() {
        setDefaultCharset(DEFAULT_CHARSET);
        DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
        prettyPrinter.indentObjectsWith(new DefaultIndenter("  ", "\ndata:"));
        this.ssePrettyPrinter = prettyPrinter;
    }
    @Override
    public boolean canWrite(@NonNull Class<?> clazz, @Nullable MediaType mediaType) {
        if (!canWrite(mediaType)) {
            return false;
        }
        AtomicReference<Throwable> causeRef = new AtomicReference<>();
        if (this.defaultObjectMapper.canSerialize(clazz, causeRef)) {
            return true;
        }
        logWarningIfNecessary(clazz, causeRef.get());
        return false;
    }
    @Override
    protected void writeInternal(@NonNull Object object, @Nullable Type type, HttpOutputMessage outputMessage)
        throws IOException, HttpMessageNotWritableException {
        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = getJsonEncoding(contentType);
        JsonGenerator generator = this.writeObjectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
        try {
            writePrefix(generator, object);
            Object value = object;
            Class<?> serializationView = null;
            FilterProvider filters = null;
            JavaType javaType = null;
            if (object instanceof MappingJacksonValue) {
                MappingJacksonValue container = (MappingJacksonValue) object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }
            if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
                javaType = getJavaType(type, null);
            }
            ObjectWriter objectWriter = (serializationView != null ?
                this.writeObjectMapper.writerWithView(serializationView) : this.writeObjectMapper.writer());
            if (filters != null) {
                objectWriter = objectWriter.with(filters);
            }
            if (javaType != null && javaType.isContainerType()) {
                objectWriter = objectWriter.forType(javaType);
            }
            SerializationConfig config = objectWriter.getConfig();
            if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
                config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
                objectWriter = objectWriter.with(this.ssePrettyPrinter);
            }
            objectWriter.writeValue(generator, value);
            writeSuffix(generator, object);
            generator.flush();
        } catch (InvalidDefinitionException ex) {
            throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
        } catch (JsonProcessingException ex) {
            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BigNumberSerializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import java.io.IOException;
/**
 * å¤§æ•°å€¼åºåˆ—化,避免超过js的精度,造成精度丢失
 *
 * @author L.cm
 */
@JacksonStdImpl
public class BigNumberSerializer extends NumberSerializer {
    /**
     * js æœ€å¤§å€¼ä¸º Math.pow(2, 53),十进制为:9007199254740992
     */
    private static final long JS_NUM_MAX = 0x20000000000000L;
    /**
     * js æœ€å°å€¼ä¸º -Math.pow(2, 53),十进制为:-9007199254740992
     */
    private static final long JS_NUM_MIN = -0x20000000000000L;
    /**
     * Static instance that is only to be used for {@link java.lang.Number}.
     */
    public final static BigNumberSerializer instance = new BigNumberSerializer(Number.class);
    public BigNumberSerializer(Class<? extends Number> rawType) {
        super(rawType);
    }
    @Override
    public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        long longValue = value.longValue();
        if (longValue < JS_NUM_MIN || longValue > JS_NUM_MAX) {
            gen.writeString(value.toString());
        } else {
            super.serialize(value, gen, provider);
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeBeanSerializerModifier.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
 * jackson é»˜è®¤å€¼ä¸º null æ—¶çš„处理
 * <p>
 * ä¸»è¦æ˜¯ä¸ºäº†é¿å… app ç«¯å‡ºçްnull导致闪退
 * <p>
 * è§„则:
 * number -1
 * string ""
 * date ""
 * boolean false
 * array []
 * Object {}
 *
 * @author L.cm
 */
public class BladeBeanSerializerModifier extends BeanSerializerModifier {
    @Override
    public List<BeanPropertyWriter> changeProperties(
        SerializationConfig config, BeanDescription beanDesc,
        List<BeanPropertyWriter> beanProperties) {
        // å¾ªçŽ¯æ‰€æœ‰çš„beanPropertyWriter
        beanProperties.forEach(writer -> {
            // å¦‚果已经有 null åºåˆ—化处理如注解:@JsonSerialize(nullsUsing = xxx) è·³è¿‡
            if (writer.hasNullSerializer()) {
                return;
            }
            JavaType type = writer.getType();
            Class<?> clazz = type.getRawClass();
            if (type.isTypeOrSubTypeOf(Number.class)) {
//                writer.assignNullSerializer(NullJsonSerializers.NUMBER_JSON_SERIALIZER);
            } else if (type.isTypeOrSubTypeOf(Boolean.class)) {
                writer.assignNullSerializer(NullJsonSerializers.BOOLEAN_JSON_SERIALIZER);
            } else if (type.isTypeOrSubTypeOf(Character.class)) {
                writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
            } else if (type.isTypeOrSubTypeOf(String.class)) {
                writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
            } else if (type.isArrayType() || clazz.isArray() || type.isTypeOrSubTypeOf(Collection.class)) {
                writer.assignNullSerializer(NullJsonSerializers.ARRAY_JSON_SERIALIZER);
            } else if (type.isTypeOrSubTypeOf(OffsetDateTime.class)) {
                writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
            } else if (type.isTypeOrSubTypeOf(Date.class) || type.isTypeOrSubTypeOf(TemporalAccessor.class)) {
                writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
            } else {
                writer.assignNullSerializer(NullJsonSerializers.OBJECT_JSON_SERIALIZER);
            }
        });
        return super.changeProperties(config, beanDesc, beanProperties);
    }
    public interface NullJsonSerializers {
        JsonSerializer<Object> STRING_JSON_SERIALIZER = new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(StringPool.EMPTY);
            }
        };
        JsonSerializer<Object> NUMBER_JSON_SERIALIZER = new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeNumber(StringUtil.INDEX_NOT_FOUND);
            }
        };
        JsonSerializer<Object> BOOLEAN_JSON_SERIALIZER = new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeObject(Boolean.FALSE);
            }
        };
        JsonSerializer<Object> ARRAY_JSON_SERIALIZER = new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeStartArray();
                gen.writeEndArray();
            }
        };
        JsonSerializer<Object> OBJECT_JSON_SERIALIZER = new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeStartObject();
                gen.writeEndObject();
            }
        };
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJacksonProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.jackson;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * jackson é…ç½®
 *
 * @author L.cm
 */
@Getter
@Setter
@ConfigurationProperties("blade.jackson")
public class BladeJacksonProperties {
    /**
     * null è½¬ä¸º ç©ºï¼Œå­—符串转成"",数组转为[],对象转为{},数字转为-1
     */
    private Boolean nullToEmpty = Boolean.TRUE;
    /**
     * å“åº”到前端,大数值自动写出为 String,避免精度丢失
     */
    private Boolean bigNumToString = Boolean.TRUE;
    /**
     * æ”¯æŒ MediaType text/plain,用于和 blade-api-crypto ä¸€èµ·ä½¿ç”¨
     */
    private Boolean supportTextPlain = Boolean.FALSE;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJavaTimeModule.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springblade.core.tool.utils.DateTimeUtil;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
 * java 8 æ—¶é—´é»˜è®¤åºåˆ—化
 *
 * @author L.cm
 */
public class BladeJavaTimeModule extends SimpleModule {
    public static final BladeJavaTimeModule INSTANCE = new BladeJavaTimeModule();
    public BladeJavaTimeModule() {
        super(PackageVersion.VERSION);
        this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeUtil.DATETIME_FORMAT));
        this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeUtil.DATE_FORMAT));
        this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeUtil.TIME_FORMAT));
        this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeUtil.DATETIME_FORMAT));
        this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeUtil.DATE_FORMAT));
        this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeUtil.TIME_FORMAT));
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeNumberModule.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
 * å¤§æ•´æ•°åºåˆ—化为 String å­—符串,避免浏览器丢失精度
 *
 * <p>
 * å‰ç«¯å»ºè®®é‡‡ç”¨ï¼š
 * bignumber åº“: https://github.com/MikeMcl/bignumber.js
 * decimal.js åº“: https://github.com/MikeMcl/decimal.js
 * </p>
 *
 * @author L.cm
 */
public class BladeNumberModule extends SimpleModule {
    public static final BladeNumberModule INSTANCE = new BladeNumberModule();
    public BladeNumberModule() {
        super(BladeNumberModule.class.getName());
        // Long å’Œ BigInteger é‡‡ç”¨å®šåˆ¶çš„逻辑序列化,避免超过js的精度
        this.addSerializer(Long.class, BigNumberSerializer.instance);
        this.addSerializer(Long.TYPE, BigNumberSerializer.instance);
        this.addSerializer(BigInteger.class, BigNumberSerializer.instance);
        // BigDecimal é‡‡ç”¨ toString é¿å…ç²¾åº¦ä¸¢å¤±ï¼Œå‰ç«¯é‡‡ç”¨ decimal.js æ¥è®¡ç®—。
        this.addSerializer(BigDecimal.class, ToStringSerializer.instance);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,705 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.*;
import org.springframework.lang.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.*;
/**
 * Jackson工具类
 *
 * @author Chill
 */
@Slf4j
public class JsonUtil {
    /**
     * å°†å¯¹è±¡åºåˆ—化成json字符串
     *
     * @param value javaBean
     * @return jsonString json字符串
     */
    public static <T> String toJson(T value) {
        try {
            return getInstance().writeValueAsString(value);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    /**
     * å°†å¯¹è±¡åºåˆ—化成 json byte æ•°ç»„
     *
     * @param object javaBean
     * @return jsonString json字符串
     */
    public static byte[] toJsonAsBytes(Object object) {
        try {
            return getInstance().writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param content   content
     * @param valueType class
     * @param <T>       T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(String content, Class<T> valueType) {
        try {
            return getInstance().readValue(content, valueType);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    /**
     * å°†json反序列化成对象
     *
     * @param content       content
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(String content, TypeReference<T> typeReference) {
        try {
            return getInstance().readValue(content, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json byte æ•°ç»„反序列化成对象
     *
     * @param bytes     json bytes
     * @param valueType class
     * @param <T>       T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(byte[] bytes, Class<T> valueType) {
        try {
            return getInstance().readValue(bytes, valueType);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param bytes         bytes
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(byte[] bytes, TypeReference<T> typeReference) {
        try {
            return getInstance().readValue(bytes, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param in        InputStream
     * @param valueType class
     * @param <T>       T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(InputStream in, Class<T> valueType) {
        try {
            return getInstance().readValue(in, valueType);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param in            InputStream
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    public static <T> T parse(InputStream in, TypeReference<T> typeReference) {
        try {
            return getInstance().readValue(in, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成List对象
     *
     * @param content      content
     * @param valueTypeRef class
     * @param <T>          T æ³›åž‹æ ‡è®°
     * @return List<T>
     */
    public static <T> List<T> parseArray(String content, Class<T> valueTypeRef) {
        try {
            if (!StringUtil.startsWithIgnoreCase(content, StringPool.LEFT_SQ_BRACKET)) {
                content = StringPool.LEFT_SQ_BRACKET + content + StringPool.RIGHT_SQ_BRACKET;
            }
            List<Map<String, Object>> list = getInstance().readValue(content, new TypeReference<List<Map<String, Object>>>() {
            });
            List<T> result = new ArrayList<>();
            for (Map<String, Object> map : list) {
                result.add(toPojo(map, valueTypeRef));
            }
            return result;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    /**
     * å°†json字符串转成 JsonNode
     *
     * @param jsonString jsonString
     * @return jsonString json字符串
     */
    public static JsonNode readTree(String jsonString) {
        Objects.requireNonNull(jsonString, "jsonString is null");
        try {
            return getInstance().readTree(jsonString);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json字符串转成 JsonNode
     *
     * @param in InputStream
     * @return jsonString json字符串
     */
    public static JsonNode readTree(InputStream in) {
        Objects.requireNonNull(in, "InputStream in is null");
        try {
            return getInstance().readTree(in);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json字符串转成 JsonNode
     *
     * @param content content
     * @return jsonString json字符串
     */
    public static JsonNode readTree(byte[] content) {
        Objects.requireNonNull(content, "byte[] content is null");
        try {
            return getInstance().readTree(content);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json字符串转成 JsonNode
     *
     * @param jsonParser JsonParser
     * @return jsonString json字符串
     */
    public static JsonNode readTree(JsonParser jsonParser) {
        Objects.requireNonNull(jsonParser, "jsonParser is null");
        try {
            return getInstance().readTree(jsonParser);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json byte æ•°ç»„反序列化成对象
     *
     * @param content   json bytes
     * @param valueType class
     * @param <T>       T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable byte[] content, Class<T> valueType) {
        if (ObjectUtil.isEmpty(content)) {
            return null;
        }
        try {
            return getInstance().readValue(content, valueType);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param jsonString jsonString
     * @param valueType  class
     * @param <T>        T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable String jsonString, Class<T> valueType) {
        if (StringUtil.isBlank(jsonString)) {
            return null;
        }
        try {
            return getInstance().readValue(jsonString, valueType);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param in        InputStream
     * @param valueType class
     * @param <T>       T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable InputStream in, Class<T> valueType) {
        if (in == null) {
            return null;
        }
        try {
            return getInstance().readValue(in, valueType);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param content       bytes
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable byte[] content, TypeReference<T> typeReference) {
        if (ObjectUtil.isEmpty(content)) {
            return null;
        }
        try {
            return getInstance().readValue(content, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param jsonString    jsonString
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable String jsonString, TypeReference<T> typeReference) {
        if (StringUtil.isBlank(jsonString)) {
            return null;
        }
        try {
            return getInstance().readValue(jsonString, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°†json反序列化成对象
     *
     * @param in            InputStream
     * @param typeReference æ³›åž‹ç±»åž‹
     * @param <T>           T æ³›åž‹æ ‡è®°
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable InputStream in, TypeReference<T> typeReference) {
        if (in == null) {
            return null;
        }
        try {
            return getInstance().readValue(in, typeReference);
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å°è£… map type
     *
     * @param keyClass   key ç±»åž‹
     * @param valueClass value ç±»åž‹
     * @return MapType
     */
    public static MapType getMapType(Class<?> keyClass, Class<?> valueClass) {
        return getInstance().getTypeFactory().constructMapType(Map.class, keyClass, valueClass);
    }
    /**
     * å°è£… map type
     *
     * @param elementClass é›†åˆå€¼ç±»åž‹
     * @return CollectionLikeType
     */
    public static CollectionLikeType getListType(Class<?> elementClass) {
        return getInstance().getTypeFactory().constructCollectionLikeType(List.class, elementClass);
    }
    /**
     * è¯»å–集合
     *
     * @param content      bytes
     * @param elementClass elementClass
     * @param <T>          æ³›åž‹
     * @return é›†åˆ
     */
    public static <T> List<T> readList(@Nullable byte[] content, Class<T> elementClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        try {
            return getInstance().readValue(content, getListType(elementClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content      InputStream
     * @param elementClass elementClass
     * @param <T>          æ³›åž‹
     * @return é›†åˆ
     */
    public static <T> List<T> readList(@Nullable InputStream content, Class<T> elementClass) {
        if (content == null) {
            return Collections.emptyList();
        }
        try {
            return getInstance().readValue(content, getListType(elementClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content      bytes
     * @param elementClass elementClass
     * @param <T>          æ³›åž‹
     * @return é›†åˆ
     */
    public static <T> List<T> readList(@Nullable String content, Class<T> elementClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        try {
            return getInstance().readValue(content, getListType(elementClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content    bytes
     * @param keyClass   key类型
     * @param valueClass å€¼ç±»åž‹
     * @param <K>        æ³›åž‹
     * @param <V>        æ³›åž‹
     * @return é›†åˆ
     */
    public static <K, V> Map<K, V> readMap(@Nullable byte[] content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        try {
            return getInstance().readValue(content, getMapType(keyClass, valueClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content    InputStream
     * @param keyClass   key类型
     * @param valueClass å€¼ç±»åž‹
     * @param <K>        æ³›åž‹
     * @param <V>        æ³›åž‹
     * @return é›†åˆ
     */
    public static <K, V> Map<K, V> readMap(@Nullable InputStream content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        try {
            return getInstance().readValue(content, getMapType(keyClass, valueClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content    bytes
     * @param keyClass   key类型
     * @param valueClass å€¼ç±»åž‹
     * @param <K>        æ³›åž‹
     * @param <V>        æ³›åž‹
     * @return é›†åˆ
     */
    public static <K, V> Map<K, V> readMap(@Nullable String content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        try {
            return getInstance().readValue(content, getMapType(keyClass, valueClass));
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * è¯»å–集合
     *
     * @param content bytes
     * @return é›†åˆ
     */
    public static Map<String, Object> readMap(@Nullable String content) {
        return readMap(content, String.class, Object.class);
    }
    /**
     * è¯»å–集合
     *
     * @param content bytes
     * @return é›†åˆ
     */
    public static List<Map<String, Object>> readListMap(@Nullable String content) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        try {
            return getInstance().readValue(content, new TypeReference<List<Map<String, Object>>>() {
            });
        } catch (IOException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * jackson çš„类型转换
     *
     * @param fromValue   æ¥æºå¯¹è±¡
     * @param toValueType è½¬æ¢çš„类型
     * @param <T>         æ³›åž‹æ ‡è®°
     * @return è½¬æ¢ç»“æžœ
     */
    public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }
    /**
     * jackson çš„类型转换
     *
     * @param fromValue   æ¥æºå¯¹è±¡
     * @param toValueType è½¬æ¢çš„类型
     * @param <T>         æ³›åž‹æ ‡è®°
     * @return è½¬æ¢ç»“æžœ
     */
    public static <T> T convertValue(Object fromValue, JavaType toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }
    /**
     * jackson çš„类型转换
     *
     * @param fromValue      æ¥æºå¯¹è±¡
     * @param toValueTypeRef æ³›åž‹ç±»åž‹
     * @param <T>            æ³›åž‹æ ‡è®°
     * @return è½¬æ¢ç»“æžœ
     */
    public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef) {
        return getInstance().convertValue(fromValue, toValueTypeRef);
    }
    /**
     * tree è½¬å¯¹è±¡
     *
     * @param treeNode  TreeNode
     * @param valueType valueType
     * @param <T>       æ³›åž‹æ ‡è®°
     * @return è½¬æ¢ç»“æžœ
     */
    public static <T> T treeToValue(TreeNode treeNode, Class<T> valueType) {
        try {
            return getInstance().treeToValue(treeNode, valueType);
        } catch (JsonProcessingException e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * å¯¹è±¡è½¬ä¸º json node
     *
     * @param value å¯¹è±¡
     * @return JsonNode
     */
    public static JsonNode valueToTree(@Nullable Object value) {
        return getInstance().valueToTree(value);
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å¯ä»¥åºåˆ—化
     *
     * @param value å¯¹è±¡
     * @return æ˜¯å¦å¯ä»¥åºåˆ—化
     */
    public static boolean canSerialize(@Nullable Object value) {
        if (value == null) {
            return true;
        }
        return getInstance().canSerialize(value.getClass());
    }
    public static Map<String, Object> toMap(String content) {
        try {
            return getInstance().readValue(content, Map.class);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    public static <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) {
        try {
            Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, Map<String, Object>>>() {
            });
            Map<String, T> result = new HashMap<>(16);
            for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
                result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef));
            }
            return result;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    public static <T> T toPojo(Map fromValue, Class<T> toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }
    public static ObjectMapper getInstance() {
        return JacksonHolder.INSTANCE;
    }
    private static class JacksonHolder {
        private static final ObjectMapper INSTANCE = new JacksonObjectMapper();
    }
    private static class JacksonObjectMapper extends ObjectMapper {
        private static final long serialVersionUID = 4288193147502386170L;
        private static final Locale CHINA = Locale.CHINA;
        public JacksonObjectMapper(ObjectMapper src) {
            super(src);
        }
        public JacksonObjectMapper() {
            super();
            //设置地点为中国
            super.setLocale(CHINA);
            //去掉默认的时间戳格式
            super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            //设置为中国上海时区
            super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
            //序列化时,日期的统一格式
            super.setDateFormat(new SimpleDateFormat(DateUtil.PATTERN_DATETIME, Locale.CHINA));
            // å•引号
            super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            // å…è®¸JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)
            super.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
            super.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true);
            super.findAndRegisterModules();
            //失败处理
            super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            //单引号处理
            super.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
            //反序列化时,属性不存在的兼容处理s
            super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            //日期格式化
            super.registerModule(new BladeJavaTimeModule());
            super.findAndRegisterModules();
        }
        @Override
        public ObjectMapper copy() {
            return new JacksonObjectMapper(this);
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
package org.springblade.core.tool.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springblade.core.tool.utils.Charsets;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
 * é’ˆå¯¹ api æœåС坹 android å’Œ ios å¤„理的 åˆ†è¯»å†™çš„ jackson å¤„理
 *
 * <p>
 * 1. app ç«¯ä¸ŠæŠ¥æ•°æ®æ˜¯ ä½¿ç”¨ readObjectMapper
 * 2. è¿”回给 app ç«¯çš„æ•°æ®ä½¿ç”¨ writeObjectMapper
 * 3. å¦‚果是返回字符串,直接相应,不做 json å¤„理
 * </p>
 *
 * @author L.cm
 */
public class MappingApiJackson2HttpMessageConverter extends AbstractReadWriteJackson2HttpMessageConverter {
    @Nullable
    private String jsonPrefix;
    public MappingApiJackson2HttpMessageConverter(ObjectMapper objectMapper, BladeJacksonProperties properties) {
        super(objectMapper, initWriteObjectMapper(objectMapper, properties), initMediaType(properties));
    }
    private static List<MediaType> initMediaType(BladeJacksonProperties properties) {
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(new MediaType("application", "*+json"));
        // æ”¯æŒ text æ–‡æœ¬ï¼Œç”¨äºŽæŠ¥æ–‡ç­¾å
        if (Boolean.TRUE.equals(properties.getSupportTextPlain())) {
            supportedMediaTypes.add(MediaType.TEXT_PLAIN);
        }
        return supportedMediaTypes;
    }
    private static ObjectMapper initWriteObjectMapper(ObjectMapper readObjectMapper, BladeJacksonProperties properties) {
        // æ‹·è´ readObjectMapper
        ObjectMapper writeObjectMapper = readObjectMapper.copy();
        // å¤§æ•°å­— è½¬ å­—符串
        if (Boolean.TRUE.equals(properties.getBigNumToString())) {
            writeObjectMapper.registerModules(BladeNumberModule.INSTANCE);
        }
        // null å¤„理
        if (Boolean.TRUE.equals(properties.getNullToEmpty())) {
            writeObjectMapper.setSerializerFactory(writeObjectMapper.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier()));
            writeObjectMapper.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
        }
        return writeObjectMapper;
    }
    @Override
    protected void writeInternal(@NonNull Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        // å¦‚果是字符串,直接写出
        if (object instanceof String) {
            Charset defaultCharset = this.getDefaultCharset();
            Charset charset = defaultCharset == null ? Charsets.UTF_8 : defaultCharset;
            StreamUtils.copy((String) object, charset, outputMessage.getBody());
        } else {
            super.writeInternal(object, type, outputMessage);
        }
    }
    /**
     * Specify a custom prefix to use for this view's JSON output.
     * Default is none.
     *
     * @param jsonPrefix jsonPrefix
     * @see #setPrefixJson
     */
    public void setJsonPrefix(@Nullable String jsonPrefix) {
        this.jsonPrefix = jsonPrefix;
    }
    /**
     * Indicate whether the JSON output by this view should be prefixed with ")]}', ". Default is false.
     * <p>Prefixing the JSON string in this manner is used to help prevent JSON Hijacking.
     * The prefix renders the string syntactically invalid as a script so that it cannot be hijacked.
     * This prefix should be stripped before parsing the string as JSON.
     *
     * @param prefixJson prefixJson
     * @see #setJsonPrefix
     */
    public void setPrefixJson(boolean prefixJson) {
        this.jsonPrefix = (prefixJson ? ")]}', " : null);
    }
    @Override
    protected void writePrefix(@NonNull JsonGenerator generator, @NonNull Object object) throws IOException {
        if (this.jsonPrefix != null) {
            generator.writeRaw(this.jsonPrefix);
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/BaseNode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,75 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
 * èŠ‚ç‚¹åŸºç±»
 *
 * @author smallchill
 */
@Data
public class BaseNode<T> implements INode<T> {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®ID
     */
    @JsonSerialize(using = ToStringSerializer.class)
    protected Long id;
    /**
     * çˆ¶èŠ‚ç‚¹ID
     */
    @JsonSerialize(using = ToStringSerializer.class)
    protected Long parentId;
    /**
     * å­å­™èŠ‚ç‚¹
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    protected List<T> children = new ArrayList<T>();
    /**
     * æ˜¯å¦æœ‰å­å­™èŠ‚ç‚¹
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private Boolean hasChildren;
    /**
     * æ˜¯å¦æœ‰å­å­™èŠ‚ç‚¹
     *
     * @return Boolean
     */
    @Override
    public Boolean getHasChildren() {
        if (children.size() > 0) {
            return true;
        } else {
            return this.hasChildren;
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * æ£®æž—节点类
 *
 * @author smallchill
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ForestNode extends BaseNode<ForestNode> {
    private static final long serialVersionUID = 1L;
    /**
     * èŠ‚ç‚¹å†…å®¹
     */
    private Object content;
    public ForestNode(Long id, Long parentId, Object content) {
        this.id = id;
        this.parentId = parentId;
        this.content = content;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNodeManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.springblade.core.tool.utils.StringPool;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * æ£®æž—管理类
 *
 * @author smallchill
 */
public class ForestNodeManager<T extends INode<T>> {
    /**
     * æ£®æž—的所有节点
     */
    private final ImmutableMap<Long, T> nodeMap;
    /**
     * æ£®æž—的父节点ID
     */
    private final Map<Long, Object> parentIdMap = Maps.newHashMap();
    public ForestNodeManager(List<T> nodes) {
        nodeMap = Maps.uniqueIndex(nodes, INode::getId);
    }
    /**
     * æ ¹æ®èŠ‚ç‚¹ID获取一个节点
     *
     * @param id èŠ‚ç‚¹ID
     * @return å¯¹åº”的节点对象
     */
    public INode<T> getTreeNodeAt(Long id) {
        if (nodeMap.containsKey(id)) {
            return nodeMap.get(id);
        }
        return null;
    }
    /**
     * å¢žåŠ çˆ¶èŠ‚ç‚¹ID
     *
     * @param parentId çˆ¶èŠ‚ç‚¹ID
     */
    public void addParentId(Long parentId) {
        parentIdMap.put(parentId, StringPool.EMPTY);
    }
    /**
     * èŽ·å–æ ‘çš„æ ¹èŠ‚ç‚¹(一个森林对应多颗树)
     *
     * @return æ ‘的根节点集合
     */
    public List<T> getRoot() {
        List<T> roots = new ArrayList<>();
        nodeMap.forEach((key, node) -> {
            if (node.getParentId() == 0 || parentIdMap.containsKey(node.getId())) {
                roots.add(node);
            }
        });
        return roots;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/ForestNodeMerger.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import java.util.List;
/**
 * æ£®æž—节点归并类
 *
 * @author smallchill
 */
public class ForestNodeMerger {
    /**
     * å°†èŠ‚ç‚¹æ•°ç»„å½’å¹¶ä¸ºä¸€ä¸ªæ£®æž—ï¼ˆå¤šæ£µæ ‘ï¼‰ï¼ˆå¡«å……èŠ‚ç‚¹çš„children域)
     * æ—¶é—´å¤æ‚度为O(n^2)
     *
     * @param items èŠ‚ç‚¹åŸŸ
     * @return å¤šæ£µæ ‘的根节点集合
     */
    public static <T extends INode<T>> List<T> merge(List<T> items) {
        ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
        items.forEach(forestNode -> {
            if (forestNode.getParentId() != 0) {
                INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
                if (node != null) {
                    node.getChildren().add(forestNode);
                } else {
                    forestNodeManager.addParentId(forestNode.getId());
                }
            }
        });
        return forestNodeManager.getRoot();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/INode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import java.io.Serializable;
import java.util.List;
/**
 * Created by Blade.
 *
 * @author smallchill
 */
public interface INode<T> extends Serializable {
    /**
     * ä¸»é”®
     *
     * @return Long
     */
    Long getId();
    /**
     * çˆ¶ä¸»é”®
     *
     * @return Long
     */
    Long getParentId();
    /**
     * å­å­™èŠ‚ç‚¹
     *
     * @return List<T>
     */
    List<T> getChildren();
    /**
     * æ˜¯å¦æœ‰å­å­™èŠ‚ç‚¹
     *
     * @return Boolean
     */
    default Boolean getHasChildren() {
        return false;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/NodeTest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package org.springblade.core.tool.node;
import org.springblade.core.tool.jackson.JsonUtil;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by Blade.
 *
 * @author smallchill
 */
public class NodeTest {
    public static void main(String[] args) {
        List<ForestNode> list = new ArrayList<>();
        list.add(new ForestNode(1L, 0L, "1"));
        list.add(new ForestNode(2L, 0L, "2"));
        list.add(new ForestNode(3L, 1L, "3"));
        list.add(new ForestNode(4L, 2L, "4"));
        list.add(new ForestNode(5L, 3L, "5"));
        list.add(new ForestNode(6L, 4L, "6"));
        list.add(new ForestNode(7L, 3L, "7"));
        list.add(new ForestNode(8L, 5L, "8"));
        list.add(new ForestNode(9L, 6L, "9"));
        list.add(new ForestNode(10L, 9L, "10"));
        List<ForestNode> tns = ForestNodeMerger.merge(list);
        tns.forEach(node ->
            System.out.println(JsonUtil.toJson(node))
        );
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/node/TreeNode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.node;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import org.springblade.core.tool.utils.Func;
import java.util.Objects;
/**
 * æ ‘型节点类
 *
 * @author smallchill
 */
@Data
public class TreeNode extends BaseNode<TreeNode> {
    private static final long serialVersionUID = 1L;
    private String title;
    @JsonSerialize(using = ToStringSerializer.class)
    private Long key;
    @JsonSerialize(using = ToStringSerializer.class)
    private Long value;
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        TreeNode other = (TreeNode) obj;
        return Func.equals(this.getId(), other.getId());
    }
    @Override
    public int hashCode() {
        return Objects.hash(id, parentId);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/spel/BladeExpressionEvaluator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.spel;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * ç¼“å­˜ spEl æé«˜æ€§èƒ½
 *
 * @author L.cm
 */
public class BladeExpressionEvaluator extends CachedExpressionEvaluator {
    private final Map<ExpressionKey, Expression> expressionCache = new ConcurrentHashMap<>(64);
    private final Map<AnnotatedElementKey, Method> methodCache = new ConcurrentHashMap<>(64);
    /**
     * Create an {@link EvaluationContext}.
     *
     * @param method      the method
     * @param args        the method arguments
     * @param target      the target object
     * @param targetClass the target class
     * @return the evaluation context
     */
    public EvaluationContext createContext(Method method, Object[] args, Object target, Class<?> targetClass, @Nullable BeanFactory beanFactory) {
        Method targetMethod = getTargetMethod(targetClass, method);
        BladeExpressionRootObject rootObject = new BladeExpressionRootObject(method, args, target, targetClass, targetMethod);
        MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(rootObject, targetMethod, args, getParameterNameDiscoverer());
        if (beanFactory != null) {
            evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
        }
        return evaluationContext;
    }
    /**
     * Create an {@link EvaluationContext}.
     *
     * @param method      the method
     * @param args        the method arguments
     * @param rootObject  rootObject
     * @param targetClass the target class
     * @return the evaluation context
     */
    public EvaluationContext createContext(Method method, Object[] args, Class<?> targetClass, Object rootObject, @Nullable BeanFactory beanFactory) {
        Method targetMethod = getTargetMethod(targetClass, method);
        MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(rootObject, targetMethod, args, getParameterNameDiscoverer());
        if (beanFactory != null) {
            evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
        }
        return evaluationContext;
    }
    @Nullable
    public Object eval(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
        return eval(expression, methodKey, evalContext, null);
    }
    @Nullable
    public <T> T eval(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext, @Nullable Class<T> valueType) {
        return getExpression(this.expressionCache, methodKey, expression).getValue(evalContext, valueType);
    }
    @Nullable
    public String evalAsText(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
        return eval(expression, methodKey, evalContext, String.class);
    }
    public boolean evalAsBool(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
        return Boolean.TRUE.equals(eval(expression, methodKey, evalContext, Boolean.class));
    }
    private Method getTargetMethod(Class<?> targetClass, Method method) {
        AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
        return methodCache.computeIfAbsent(methodKey, (key) -> AopUtils.getMostSpecificMethod(method, targetClass));
    }
    /**
     * Clear all caches.
     */
    public void clear() {
        this.expressionCache.clear();
        this.methodCache.clear();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/spel/BladeExpressionRootObject.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.spel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.lang.reflect.Method;
/**
 * ExpressionRootObject
 *
 * @author L.cm
 */
@Getter
@AllArgsConstructor
public class BladeExpressionRootObject {
    private final Method method;
    private final Object[] args;
    private final Object target;
    private final Class<?> targetClass;
    private final Method targetMethod;
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/ssl/DisableValidationTrustManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.ssl;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
 * ä¸è¿›è¡Œè¯ä¹¦æ ¡éªŒ
 *
 * @author L.cm
 */
public class DisableValidationTrustManager implements X509TrustManager {
    public static final X509TrustManager INSTANCE = new DisableValidationTrustManager();
    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    }
    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    }
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/ssl/TrustAllHostNames.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.ssl;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
/**
 * ä¿¡ä»»æ‰€æœ‰ host name
 *
 * @author L.cm
 */
public class TrustAllHostNames implements HostnameVerifier {
    public static final TrustAllHostNames INSTANCE = new TrustAllHostNames();
    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/BeanDiff.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package org.springblade.core.tool.support;
import lombok.Getter;
import lombok.ToString;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
 * è·Ÿè¸ªç±»å˜åŠ¨æ¯”è¾ƒ
 *
 * @author L.cm
 */
@Getter
@ToString
public class BeanDiff {
    /**
     * å˜æ›´å­—段
      */
    private final Set<String> fields = new HashSet<>();
    /**
     * æ—§å€¼
     */
    private final Map<String, Object> oldValues = new HashMap<>();
    /**
     * æ–°å€¼
     */
    private final Map<String, Object> newValues = new HashMap<>();
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/BinderSupplier.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.support;
import java.util.function.Supplier;
/**
 * è§£å†³ no binder available é—®é¢˜
 *
 * @author Chill
 */
public class BinderSupplier implements Supplier<Object> {
    @Override
    public Object get() {
        return null;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/CoreMain.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.support;
/**
 * Created by Blade.
 *
 * @author Chill
 */
public class CoreMain {
    public static void main(String[] args) {
        System.out.println("init core module");
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/FastStringWriter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,255 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.StringPool;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
/**
 * FastStringWriter,更改于 jdk CharArrayWriter
 *
 * <p>
 * 1. åŽ»æŽ‰äº†é”
 * 2. åˆå§‹å®¹é‡ç”± 32 æ”¹ä¸º 64
 * </p>
 *
 * @author L.cm
 */
public class FastStringWriter extends Writer {
    /**
     * The buffer where data is stored.
     */
    private char[] buf;
    /**
     * The number of chars in the buffer.
     */
    private int count;
    /**
     * Creates a new CharArrayWriter.
     */
    public FastStringWriter() {
        this(64);
    }
    /**
     * Creates a new CharArrayWriter with the specified initial size.
     *
     * @param initialSize an int specifying the initial buffer size.
     * @throws IllegalArgumentException if initialSize is negative
     */
    public FastStringWriter(int initialSize) {
        if (initialSize < 0) {
            throw new IllegalArgumentException("Negative initial size: " + initialSize);
        }
        buf = new char[initialSize];
    }
    /**
     * Writes a character to the buffer.
     */
    @Override
    public void write(int c) {
        int newCount = count + 1;
        if (newCount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
        }
        buf[count] = (char) c;
        count = newCount;
    }
    /**
     * Writes characters to the buffer.
     *
     * @param c   the data to be written
     * @param off the start offset in the data
     * @param len the number of chars that are written
     */
    @Override
    public void write(char[] c, int off, int len) {
        if ((off < 0) || (off > c.length) || (len < 0) ||
            ((off + len) > c.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        int newCount = count + len;
        if (newCount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
        }
        System.arraycopy(c, off, buf, count, len);
        count = newCount;
    }
    /**
     * Write a portion of a string to the buffer.
     *
     * @param str String to be written from
     * @param off Offset from which to start reading characters
     * @param len Number of characters to be written
     */
    @Override
    public void write(String str, int off, int len) {
        int newCount = count + len;
        if (newCount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
        }
        str.getChars(off, off + len, buf, count);
        count = newCount;
    }
    /**
     * Writes the contents of the buffer to another character stream.
     *
     * @param out the output stream to write to
     * @throws IOException If an I/O error occurs.
     */
    public void writeTo(Writer out) throws IOException {
        out.write(buf, 0, count);
    }
    /**
     * Appends the specified character sequence to this writer.
     *
     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
     * behaves in exactly the same way as the invocation
     *
     * <pre>
     *     out.write(csq.toString()) </pre>
     *
     * <p> Depending on the specification of <tt>toString</tt> for the
     * character sequence <tt>csq</tt>, the entire sequence may not be
     * appended. For instance, invoking the <tt>toString</tt> method of a
     * character buffer will return a subsequence whose content depends upon
     * the buffer's position and limit.
     *
     * @param csq The character sequence to append.  If <tt>csq</tt> is
     *            <tt>null</tt>, then the four characters <tt>"null"</tt> are
     *            appended to this writer.
     * @return This writer
     */
    @Override
    public FastStringWriter append(CharSequence csq) {
        String s = (csq == null ? StringPool.NULL : csq.toString());
        write(s, 0, s.length());
        return this;
    }
    /**
     * Appends a subsequence of the specified character sequence to this writer.
     *
     * <p> An invocation of this method of the form <tt>out.append(csq, start,
     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
     * exactly the same way as the invocation
     *
     * <pre>
     *     out.write(csq.subSequence(start, end).toString()) </pre>
     *
     * @param csq   The character sequence from which a subsequence will be
     *              appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
     *              will be appended as if <tt>csq</tt> contained the four
     *              characters <tt>"null"</tt>.
     * @param start The index of the first character in the subsequence
     * @param end   The index of the character following the last character in the
     *              subsequence
     * @return This writer
     * @throws IndexOutOfBoundsException If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
     *                                   is greater than <tt>end</tt>, or <tt>end</tt> is greater than
     *                                   <tt>csq.length()</tt>
     */
    @Override
    public FastStringWriter append(CharSequence csq, int start, int end) {
        String s = (csq == null ? StringPool.NULL : csq).subSequence(start, end).toString();
        write(s, 0, s.length());
        return this;
    }
    /**
     * Appends the specified character to this writer.
     *
     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
     * behaves in exactly the same way as the invocation
     *
     * <pre>
     *     out.write(c) </pre>
     *
     * @param c The 16-bit character to append
     * @return This writer
     */
    @Override
    public FastStringWriter append(char c) {
        write(c);
        return this;
    }
    /**
     * Resets the buffer so that you can use it again without
     * throwing away the already allocated buffer.
     */
    public void reset() {
        count = 0;
    }
    /**
     * Returns a copy of the input data.
     *
     * @return an array of chars copied from the input data.
     */
    public char[] toCharArray() {
        return Arrays.copyOf(buf, count);
    }
    /**
     * Returns the current size of the buffer.
     *
     * @return an int representing the current size of the buffer.
     */
    public int size() {
        return count;
    }
    /**
     * Converts input data to a string.
     *
     * @return the string.
     */
    @Override
    public String toString() {
        return new String(buf, 0, count);
    }
    /**
     * Flush the stream.
     */
    @Override
    public void flush() {
    }
    /**
     * Close the stream.  This method does not release the buffer, since its
     * contents might still be required. Note: Invoking this method in this class
     * will have no effect.
     */
    @Override
    public void close() {
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/IMultiOutputStream.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.support;
import java.io.OutputStream;
/**
 * A factory for creating MultiOutputStream objects.
 *
 * @author Chill
 */
public interface IMultiOutputStream {
    /**
     * Builds the output stream.
     *
     * @param params the params
     * @return the output stream
     */
    OutputStream buildOutputStream(Integer... params);
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/ImagePosition.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,150 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.support;
/**
 * å›¾ç‰‡æ“ä½œç±»
 *
 * @author Chill
 */
public class ImagePosition {
    /**
     * å›¾ç‰‡é¡¶éƒ¨.
     */
    public static final int TOP = 32;
    /**
     * å›¾ç‰‡ä¸­éƒ¨.
     */
    public static final int MIDDLE = 16;
    /**
     * å›¾ç‰‡åº•部.
     */
    public static final int BOTTOM = 8;
    /**
     * å›¾ç‰‡å·¦ä¾§.
     */
    public static final int LEFT = 4;
    /**
     * å›¾ç‰‡å±…中.
     */
    public static final int CENTER = 2;
    /**
     * å›¾ç‰‡å³ä¾§.
     */
    public static final int RIGHT = 1;
    /**
     * æ¨ªå‘边距,靠左或靠右时和边界的距离.
     */
    private static final int PADDING_HORI = 6;
    /**
     * çºµå‘边距,靠上或靠底时和边界的距离.
     */
    private static final int PADDING_VERT = 6;
    /**
     * å›¾ç‰‡ä¸­ç›’[左上角]的x坐标.
     */
    private int boxPosX;
    /**
     * å›¾ç‰‡ä¸­ç›’[左上角]的y坐标.
     */
    private int boxPosY;
    /**
     * Instantiates a new image position.
     *
     * @param width     the width
     * @param height    the height
     * @param boxWidth  the box width
     * @param boxHeight the box height
     * @param style     the style
     */
    public ImagePosition(int width, int height, int boxWidth, int boxHeight, int style) {
        switch (style & 7) {
            case LEFT:
                boxPosX = PADDING_HORI;
                break;
            case RIGHT:
                boxPosX = width - boxWidth - PADDING_HORI;
                break;
            case CENTER:
            default:
                boxPosX = (width - boxWidth) / 2;
        }
        switch (style >> 3 << 3) {
            case TOP:
                boxPosY = PADDING_VERT;
                break;
            case MIDDLE:
                boxPosY = (height - boxHeight) / 2;
                break;
            case BOTTOM:
            default:
                boxPosY = height - boxHeight - PADDING_VERT;
        }
    }
    /**
     * Gets the x.
     *
     * @return the x
     */
    public int getX() {
        return getX(0);
    }
    /**
     * Gets the x.
     *
     * @param x æ¨ªå‘偏移
     * @return the x
     */
    public int getX(int x) {
        return this.boxPosX + x;
    }
    /**
     * Gets the y.
     *
     * @return the y
     */
    public int getY() {
        return getY(0);
    }
    /**
     * Gets the y.
     *
     * @param y çºµå‘偏移
     * @return the y
     */
    public int getY(int y) {
        return this.boxPosY + y;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,221 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.Func;
import org.springframework.util.LinkedCaseInsensitiveMap;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * é“¾å¼map
 *
 * @author Chill
 */
public class Kv extends LinkedCaseInsensitiveMap<Object> {
    private Kv() {
        super();
    }
    /**
     * åˆ›å»ºKv
     *
     * @return Kv
     */
    public static Kv create() {
        return new Kv();
    }
    public static <K, V> HashMap<K, V> newMap() {
        return new HashMap<>(16);
    }
    /**
     * è®¾ç½®åˆ—
     *
     * @param attr  å±žæ€§
     * @param value å€¼
     * @return æœ¬èº«
     */
    public Kv set(String attr, Object value) {
        this.put(attr, value);
        return this;
    }
    /**
     * è®¾ç½®å…¨éƒ¨
     *
     * @param map å±žæ€§
     * @return æœ¬èº«
     */
    public Kv setAll(Map<? extends String, ?> map) {
        if (map != null) {
            this.putAll(map);
        }
        return this;
    }
    /**
     * è®¾ç½®åˆ—,当键或值为null时忽略
     *
     * @param attr  å±žæ€§
     * @param value å€¼
     * @return æœ¬èº«
     */
    public Kv setIgnoreNull(String attr, Object value) {
        if (attr != null && value != null) {
            set(attr, value);
        }
        return this;
    }
    public Object getObj(String key) {
        return super.get(key);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param <T>          å€¼ç±»åž‹
     * @param attr         å­—段名
     * @param defaultValue é»˜è®¤å€¼
     * @return å­—段值
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String attr, T defaultValue) {
        final Object result = get(attr);
        return (T) (result != null ? result : defaultValue);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public String getStr(String attr) {
        return Func.toStr(get(attr), null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Integer getInt(String attr) {
        return Func.toInt(get(attr), -1);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Long getLong(String attr) {
        return Func.toLong(get(attr), -1L);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Float getFloat(String attr) {
        return Func.toFloat(get(attr), null);
    }
    public Double getDouble(String attr) {
        return Func.toDouble(get(attr), null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Boolean getBool(String attr) {
        return Func.toBoolean(get(attr), null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public byte[] getBytes(String attr) {
        return get(attr, null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Date getDate(String attr) {
        return get(attr, null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Time getTime(String attr) {
        return get(attr, null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Timestamp getTimestamp(String attr) {
        return get(attr, null);
    }
    /**
     * èŽ·å¾—ç‰¹å®šç±»åž‹å€¼
     *
     * @param attr å­—段名
     * @return å­—段值
     */
    public Number getNumber(String attr) {
        return get(attr, null);
    }
    @Override
    public Kv clone() {
        Kv clone = new Kv();
        clone.putAll(this);
        return clone;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/StrSpliter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,501 @@
package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * å­—符串切分器
 *
 * @author Looly
 */
public class StrSpliter {
    //---------------------------------------------------------------------------------------------- Split by char
    /**
     * åˆ‡åˆ†å­—符串路径,仅支持Unix分界符:/
     *
     * @param str è¢«åˆ‡åˆ†çš„字符串
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> splitPath(String str) {
        return splitPath(str, 0);
    }
    /**
     * åˆ‡åˆ†å­—符串路径,仅支持Unix分界符:/
     *
     * @param str è¢«åˆ‡åˆ†çš„字符串
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitPathToArray(String str) {
        return toArray(splitPath(str));
    }
    /**
     * åˆ‡åˆ†å­—符串路径,仅支持Unix分界符:/
     *
     * @param str   è¢«åˆ‡åˆ†çš„字符串
     * @param limit é™åˆ¶åˆ†ç‰‡æ•°
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> splitPath(String str, int limit) {
        return split(str, StringPool.SLASH, limit, true, true);
    }
    /**
     * åˆ‡åˆ†å­—符串路径,仅支持Unix分界符:/
     *
     * @param str   è¢«åˆ‡åˆ†çš„字符串
     * @param limit é™åˆ¶åˆ†ç‰‡æ•°
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitPathToArray(String str, int limit) {
        return toArray(splitPath(str, limit));
    }
    /**
     * åˆ‡åˆ†å­—符串
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitTrim(String str, char separator, boolean ignoreEmpty) {
        return split(str, separator, 0, true, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, char separator, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, 0, isTrim, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串,大小写敏感,去除每个元素两边空白符
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> splitTrim(String str, char separator, int limit, boolean ignoreEmpty) {
        return split(str, separator, limit, true, ignoreEmpty, false);
    }
    /**
     * åˆ‡åˆ†å­—符串,大小写敏感
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, limit, isTrim, ignoreEmpty, false);
    }
    /**
     * åˆ‡åˆ†å­—符串,忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitIgnoreCase(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, limit, isTrim, ignoreEmpty, true);
    }
    /**
     * åˆ‡åˆ†å­—符串
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @param ignoreCase  æ˜¯å¦å¿½ç•¥å¤§å°å†™
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase) {
        if (StringUtil.isEmpty(str)) {
            return new ArrayList<String>(0);
        }
        if (limit == 1) {
            return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
        }
        final ArrayList<String> list = new ArrayList<>(limit > 0 ? limit : 16);
        int len = str.length();
        int start = 0;
        for (int i = 0; i < len; i++) {
            if (Func.equals(separator, str.charAt(i))) {
                addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
                start = i + 1;
                //检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
                if (limit > 0 && list.size() > limit - 2) {
                    break;
                }
            }
        }
        return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串为字符串数组
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitToArray(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
    }
    //---------------------------------------------------------------------------------------------- Split by String
    /**
     * åˆ‡åˆ†å­—符串,不忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, String separator, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, -1, isTrim, ignoreEmpty, false);
    }
    /**
     * åˆ‡åˆ†å­—符串,去除每个元素两边空格,忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitTrim(String str, String separator, boolean ignoreEmpty) {
        return split(str, separator, true, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串,不忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, limit, isTrim, ignoreEmpty, false);
    }
    /**
     * åˆ‡åˆ†å­—符串,去除每个元素两边空格,忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitTrim(String str, String separator, int limit, boolean ignoreEmpty) {
        return split(str, separator, limit, true, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串,忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitIgnoreCase(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return split(str, separator, limit, isTrim, ignoreEmpty, true);
    }
    /**
     * åˆ‡åˆ†å­—符串,去除每个元素两边空格,忽略大小写
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> splitTrimIgnoreCase(String str, String separator, int limit, boolean ignoreEmpty) {
        return split(str, separator, limit, true, ignoreEmpty, true);
    }
    /**
     * åˆ‡åˆ†å­—符串
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符串
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @param ignoreCase  æ˜¯å¦å¿½ç•¥å¤§å°å†™
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.2.1
     */
    public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase) {
        if (StringUtil.isEmpty(str)) {
            return new ArrayList<String>(0);
        }
        if (limit == 1) {
            return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
        }
        if (StringUtil.isEmpty(separator)) {
            return split(str, limit);
        } else if (separator.length() == 1) {
            return split(str, separator.charAt(0), limit, isTrim, ignoreEmpty, ignoreCase);
        }
        final ArrayList<String> list = new ArrayList<>();
        int len = str.length();
        int separatorLen = separator.length();
        int start = 0;
        int i = 0;
        while (i < len) {
            i = StringUtil.indexOf(str, separator, start, ignoreCase);
            if (i > -1) {
                addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
                start = i + separatorLen;
                //检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
                if (limit > 0 && list.size() > limit - 2) {
                    break;
                }
            } else {
                break;
            }
        }
        return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
    }
    /**
     * åˆ‡åˆ†å­—符串为字符串数组
     *
     * @param str         è¢«åˆ‡åˆ†çš„字符串
     * @param separator   åˆ†éš”符字符
     * @param limit       é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitToArray(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
        return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
    }
    //---------------------------------------------------------------------------------------------- Split by Whitespace
    /**
     * ä½¿ç”¨ç©ºç™½ç¬¦åˆ‡åˆ†å­—符串<br>
     * åˆ‡åˆ†åŽçš„字符串两边不包含空白符,空串或空白符串并不做为元素之一
     *
     * @param str   è¢«åˆ‡åˆ†çš„字符串
     * @param limit é™åˆ¶åˆ†ç‰‡æ•°
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, int limit) {
        if (StringUtil.isEmpty(str)) {
            return new ArrayList<String>(0);
        }
        if (limit == 1) {
            return addToList(new ArrayList<String>(1), str, true, true);
        }
        final ArrayList<String> list = new ArrayList<>();
        int len = str.length();
        int start = 0;
        for (int i = 0; i < len; i++) {
            if (Func.isEmpty(str.charAt(i))) {
                addToList(list, str.substring(start, i), true, true);
                start = i + 1;
                if (limit > 0 && list.size() > limit - 2) {
                    break;
                }
            }
        }
        return addToList(list, str.substring(start, len), true, true);
    }
    /**
     * åˆ‡åˆ†å­—符串为字符串数组
     *
     * @param str   è¢«åˆ‡åˆ†çš„字符串
     * @param limit é™åˆ¶åˆ†ç‰‡æ•°
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitToArray(String str, int limit) {
        return toArray(split(str, limit));
    }
    //---------------------------------------------------------------------------------------------- Split by regex
    /**
     * é€šè¿‡æ­£åˆ™åˆ‡åˆ†å­—符串
     *
     * @param str              å­—符串
     * @param separatorPattern åˆ†éš”符正则{@link Pattern}
     * @param limit            é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim           æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty      æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static List<String> split(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty) {
        if (StringUtil.isEmpty(str)) {
            return new ArrayList<String>(0);
        }
        if (limit == 1) {
            return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
        }
        if (null == separatorPattern) {
            return split(str, limit);
        }
        final Matcher matcher = separatorPattern.matcher(str);
        final ArrayList<String> list = new ArrayList<>();
        int len = str.length();
        int start = 0;
        while (matcher.find()) {
            addToList(list, str.substring(start, matcher.start()), isTrim, ignoreEmpty);
            start = matcher.end();
            if (limit > 0 && list.size() > limit - 2) {
                break;
            }
        }
        return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
    }
    /**
     * é€šè¿‡æ­£åˆ™åˆ‡åˆ†å­—符串为字符串数组
     *
     * @param str              è¢«åˆ‡åˆ†çš„字符串
     * @param separatorPattern åˆ†éš”符正则{@link Pattern}
     * @param limit            é™åˆ¶åˆ†ç‰‡æ•°
     * @param isTrim           æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
     * @param ignoreEmpty      æ˜¯å¦å¿½ç•¥ç©ºä¸²
     * @return åˆ‡åˆ†åŽçš„集合
     * @since 3.0.8
     */
    public static String[] splitToArray(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty) {
        return toArray(split(str, separatorPattern, limit, isTrim, ignoreEmpty));
    }
    //---------------------------------------------------------------------------------------------- Split by length
    /**
     * æ ¹æ®ç»™å®šé•¿åº¦ï¼Œå°†ç»™å®šå­—符串截取为多个部分
     *
     * @param str å­—符串
     * @param len æ¯ä¸€ä¸ªå°èŠ‚çš„é•¿åº¦
     * @return æˆªå–后的字符串数组
     */
    public static String[] splitByLength(String str, int len) {
        int partCount = str.length() / len;
        int lastPartCount = str.length() % len;
        int fixPart = 0;
        if (lastPartCount != 0) {
            fixPart = 1;
        }
        final String[] strs = new String[partCount + fixPart];
        for (int i = 0; i < partCount + fixPart; i++) {
            if (i == partCount + fixPart - 1 && lastPartCount != 0) {
                strs[i] = str.substring(i * len, i * len + lastPartCount);
            } else {
                strs[i] = str.substring(i * len, i * len + len);
            }
        }
        return strs;
    }
    //---------------------------------------------------------------------------------------------------------- Private method start
    /**
     * å°†å­—符串加入List中
     *
     * @param list        åˆ—表
     * @param part        è¢«åŠ å…¥çš„éƒ¨åˆ†
     * @param isTrim      æ˜¯å¦åŽ»é™¤ä¸¤ç«¯ç©ºç™½ç¬¦
     * @param ignoreEmpty æ˜¯å¦ç•¥è¿‡ç©ºå­—符串(空字符串不做为一个元素)
     * @return åˆ—表
     */
    private static List<String> addToList(List<String> list, String part, boolean isTrim, boolean ignoreEmpty) {
        part = part.toString();
        if (isTrim) {
            part = part.trim();
        }
        if (false == ignoreEmpty || false == part.isEmpty()) {
            list.add(part);
        }
        return list;
    }
    /**
     * List转Array
     *
     * @param list List
     * @return Array
     */
    private static String[] toArray(List<String> list) {
        return list.toArray(new String[list.size()]);
    }
    //---------------------------------------------------------------------------------------------------------- Private method end
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/support/Try.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.Exceptions;
import org.springframework.lang.Nullable;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * Lambda å—检异常处理
 * https://segmentfault.com/a/1190000007832130
 *
 * @author Chill
 */
public class Try {
    public static <T, R> Function<T, R> of(UncheckedFunction<T, R> mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                return mapper.apply(t);
            } catch (Exception e) {
                throw Exceptions.unchecked(e);
            }
        };
    }
    public static <T> Consumer<T> of(UncheckedConsumer<T> mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                mapper.accept(t);
            } catch (Exception e) {
                throw Exceptions.unchecked(e);
            }
        };
    }
    public static <T> Supplier<T> of(UncheckedSupplier<T> mapper) {
        Objects.requireNonNull(mapper);
        return () -> {
            try {
                return mapper.get();
            } catch (Exception e) {
                throw Exceptions.unchecked(e);
            }
        };
    }
    @FunctionalInterface
    public interface UncheckedFunction<T, R> {
        /**
         * apply
         *
         * @param t
         * @return
         * @throws Exception
         */
        @Nullable
        R apply(@Nullable T t) throws Exception;
    }
    @FunctionalInterface
    public interface UncheckedConsumer<T> {
        /**
         * accept
         *
         * @param t
         * @throws Exception
         */
        @Nullable
        void accept(@Nullable T t) throws Exception;
    }
    @FunctionalInterface
    public interface UncheckedSupplier<T> {
        /**
         * get
         *
         * @return
         * @throws Exception
         */
        @Nullable
        T get() throws Exception;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/tuple/KeyPair.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.tuple;
import lombok.RequiredArgsConstructor;
import org.springblade.core.tool.utils.RsaUtil;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
 * rsa çš„ key pair å°è£…
 *
 * @author L.cm
 */
@RequiredArgsConstructor
public class KeyPair {
    private final java.security.KeyPair keyPair;
    public PublicKey getPublic() {
        return keyPair.getPublic();
    }
    public PrivateKey getPrivate() {
        return keyPair.getPrivate();
    }
    public byte[] getPublicBytes() {
        return this.getPublic().getEncoded();
    }
    public byte[] getPrivateBytes() {
        return this.getPrivate().getEncoded();
    }
    public String getPublicBase64() {
        return RsaUtil.getKeyString(this.getPublic());
    }
    public String getPrivateBase64() {
        return RsaUtil.getKeyString(this.getPrivate());
    }
    @Override
    public String toString() {
        return "PublicKey=" + this.getPublicBase64() + '\n' + "PrivateKey=" + this.getPrivateBase64();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/tuple/Pair.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.tuple;
import lombok.*;
/**
 * tuple Pair
 *
 * @author L.cm
 **/
@Getter
@ToString
@EqualsAndHashCode
public class Pair<L, R> {
    private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);
    private final L left;
    private final R right;
    /**
     * Returns an empty pair.
     */
    @SuppressWarnings("unchecked")
    public static <L, R> Pair<L, R> empty() {
        return (Pair<L, R>) EMPTY;
    }
    /**
     * Constructs a pair with its left value being {@code left}, or returns an empty pair if
     * {@code left} is null.
     *
     * @return the constructed pair or an empty pair if {@code left} is null.
     */
    public static <L, R> Pair<L, R> createLeft(L left) {
        if (left == null) {
            return empty();
        } else {
            return new Pair<>(left, null);
        }
    }
    /**
     * Constructs a pair with its right value being {@code right}, or returns an empty pair if
     * {@code right} is null.
     *
     * @return the constructed pair or an empty pair if {@code right} is null.
     */
    public static <L, R> Pair<L, R> createRight(R right) {
        if (right == null) {
            return empty();
        } else {
            return new Pair<>(null, right);
        }
    }
    public static <L, R> Pair<L, R> create(L left, R right) {
        if (right == null && left == null) {
            return empty();
        } else {
            return new Pair<>(left, right);
        }
    }
    private Pair(L left, R right) {
        this.left = left;
        this.right = right;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,309 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Objects;
/**
 * å®Œå…¨å…¼å®¹å¾®ä¿¡æ‰€ä½¿ç”¨çš„AES加密工具类
 * aes的key必须是256byte长(比如32个字符),可以使用AesKit.genAesKey()来生成一组key
 *
 * @author L.cm
 */
public class AesUtil {
    public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
    /**
     * èŽ·å–å¯†é’¥
     *
     * @return {String}
     */
    public static String genAesKey() {
        return StringUtil.random(32);
    }
    /**
     * åР坆
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] encrypt(String content, String aesTextKey) {
        return encrypt(content.getBytes(DEFAULT_CHARSET), aesTextKey);
    }
    /**
     * åР坆
     *
     * @param content    æ–‡æœ¬å†…容
     * @param charset    ç¼–码
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] encrypt(String content, Charset charset, String aesTextKey) {
        return encrypt(content.getBytes(charset), aesTextKey);
    }
    /**
     * åР坆
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] encrypt(byte[] content, String aesTextKey) {
        return encrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
    }
    /**
     * hex加密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    public static String encryptToHex(String content, String aesTextKey) {
        return HexUtil.encodeToString(encrypt(content, aesTextKey));
    }
    /**
     * hex加密
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    public static String encryptToHex(byte[] content, String aesTextKey) {
        return HexUtil.encodeToString(encrypt(content, aesTextKey));
    }
    /**
     * Base64加密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    public static String encryptToBase64(String content, String aesTextKey) {
        return Base64Util.encodeToString(encrypt(content, aesTextKey));
    }
    /**
     * Base64加密
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    public static String encryptToBase64(byte[] content, String aesTextKey) {
        return Base64Util.encodeToString(encrypt(content, aesTextKey));
    }
    /**
     * hex解密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    @Nullable
    public static String decryptFormHexToString(@Nullable String content, String aesTextKey) {
        byte[] hexBytes = decryptFormHex(content, aesTextKey);
        if (hexBytes == null) {
            return null;
        }
        return new String(hexBytes, DEFAULT_CHARSET);
    }
    /**
     * hex解密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    @Nullable
    public static byte[] decryptFormHex(@Nullable String content, String aesTextKey) {
        if (StringUtil.isBlank(content)) {
            return null;
        }
        return decryptFormHex(content.getBytes(DEFAULT_CHARSET), aesTextKey);
    }
    /**
     * hex解密
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] decryptFormHex(byte[] content, String aesTextKey) {
        return decrypt(HexUtil.decode(content), aesTextKey);
    }
    /**
     * Base64解密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    @Nullable
    public static String decryptFormBase64ToString(@Nullable String content, String aesTextKey) {
        byte[] hexBytes = decryptFormBase64(content, aesTextKey);
        if (hexBytes == null) {
            return null;
        }
        return new String(hexBytes, DEFAULT_CHARSET);
    }
    /**
     * Base64解密
     *
     * @param content    æ–‡æœ¬å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    @Nullable
    public static byte[] decryptFormBase64(@Nullable String content, String aesTextKey) {
        if (StringUtil.isBlank(content)) {
            return null;
        }
        return decryptFormBase64(content.getBytes(DEFAULT_CHARSET), aesTextKey);
    }
    /**
     * Base64解密
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] decryptFormBase64(byte[] content, String aesTextKey) {
        return decrypt(Base64Util.decode(content), aesTextKey);
    }
    /**
     * è§£å¯†
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return {String}
     */
    public static String decryptToString(byte[] content, String aesTextKey) {
        return new String(decrypt(content, aesTextKey), DEFAULT_CHARSET);
    }
    /**
     * è§£å¯†
     *
     * @param content    å†…容
     * @param aesTextKey æ–‡æœ¬å¯†é’¥
     * @return byte[]
     */
    public static byte[] decrypt(byte[] content, String aesTextKey) {
        return decrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
    }
    /**
     * è§£å¯†
     *
     * @param content å†…容
     * @param aesKey  å¯†é’¥
     * @return byte[]
     */
    public static byte[] encrypt(byte[] content, byte[] aesKey) {
        return aes(Pkcs7Encoder.encode(content), aesKey, Cipher.ENCRYPT_MODE);
    }
    /**
     * åР坆
     *
     * @param encrypted å†…容
     * @param aesKey    å¯†é’¥
     * @return byte[]
     */
    public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
        return Pkcs7Encoder.decode(aes(encrypted, aesKey, Cipher.DECRYPT_MODE));
    }
    /**
     * ase加密
     *
     * @param encrypted å†…容
     * @param aesKey    å¯†é’¥
     * @param mode      æ¨¡å¼
     * @return byte[]
     */
    private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
        Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(mode, keySpec, iv);
            return cipher.doFinal(encrypted);
        } catch (Exception e) {
            throw Exceptions.unchecked(e);
        }
    }
    /**
     * æä¾›åŸºäºŽPKCS7算法的加解密接口.
     */
    private static class Pkcs7Encoder {
        private static final int BLOCK_SIZE = 32;
        private static byte[] encode(byte[] src) {
            int count = src.length;
            // è®¡ç®—需要填充的位数
            int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
            // èŽ·å¾—è¡¥ä½æ‰€ç”¨çš„å­—ç¬¦
            byte pad = (byte) (amountToPad & 0xFF);
            byte[] pads = new byte[amountToPad];
            for (int index = 0; index < amountToPad; index++) {
                pads[index] = pad;
            }
            int length = count + amountToPad;
            byte[] dest = new byte[length];
            System.arraycopy(src, 0, dest, 0, count);
            System.arraycopy(pads, 0, dest, count, amountToPad);
            return dest;
        }
        private static byte[] decode(byte[] decrypted) {
            int pad = decrypted[decrypted.length - 1];
            if (pad < 1 || pad > BLOCK_SIZE) {
                pad = 0;
            }
            if (pad > 0) {
                return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
            }
            return decrypted;
        }
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AntPathFilter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import lombok.AllArgsConstructor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;
/**
 * Spring AntPath è§„则文件过滤
 *
 * @author L.cm
 */
@AllArgsConstructor
public class AntPathFilter implements FileFilter, Serializable {
    private static final long serialVersionUID = 812598009067554612L;
    private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
    private final String pattern;
    /**
     * è¿‡æ»¤è§„则
     *
     * @param pathname è·¯å¾„
     * @return boolean
     */
    @Override
    public boolean accept(File pathname) {
        String filePath = pathname.getAbsolutePath();
        return PATH_MATCHER.match(pattern, filePath);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Base64Util.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
/**
 * Base64工具
 *
 * @author L.cm
 */
public class Base64Util extends org.springframework.util.Base64Utils {
    /**
     * ç¼–码
     *
     * @param value å­—符串
     * @return {String}
     */
    public static String encode(String value) {
        return Base64Util.encode(value, Charsets.UTF_8);
    }
    /**
     * ç¼–码
     *
     * @param value   å­—符串
     * @param charset å­—符集
     * @return {String}
     */
    public static String encode(String value, java.nio.charset.Charset charset) {
        byte[] val = value.getBytes(charset);
        return new String(Base64Util.encode(val), charset);
    }
    /**
     * ç¼–码URL安全
     *
     * @param value å­—符串
     * @return {String}
     */
    public static String encodeUrlSafe(String value) {
        return Base64Util.encodeUrlSafe(value, Charsets.UTF_8);
    }
    /**
     * ç¼–码URL安全
     *
     * @param value   å­—符串
     * @param charset å­—符集
     * @return {String}
     */
    public static String encodeUrlSafe(String value, java.nio.charset.Charset charset) {
        byte[] val = value.getBytes(charset);
        return new String(Base64Util.encodeUrlSafe(val), charset);
    }
    /**
     * è§£ç 
     *
     * @param value å­—符串
     * @return {String}
     */
    public static String decode(String value) {
        return Base64Util.decode(value, Charsets.UTF_8);
    }
    /**
     * è§£ç 
     *
     * @param value   å­—符串
     * @param charset å­—符集
     * @return {String}
     */
    public static String decode(String value, java.nio.charset.Charset charset) {
        byte[] val = value.getBytes(charset);
        byte[] decodedValue = Base64Util.decode(val);
        return new String(decodedValue, charset);
    }
    /**
     * è§£ç URL安全
     *
     * @param value å­—符串
     * @return {String}
     */
    public static String decodeUrlSafe(String value) {
        return Base64Util.decodeUrlSafe(value, Charsets.UTF_8);
    }
    /**
     * è§£ç URL安全
     *
     * @param value   å­—符串
     * @param charset å­—符集
     * @return {String}
     */
    public static String decodeUrlSafe(String value, java.nio.charset.Charset charset) {
        byte[] val = value.getBytes(charset);
        byte[] decodedValue = Base64Util.decodeUrlSafe(val);
        return new String(decodedValue, charset);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,424 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import org.springblade.core.tool.beans.BeanProperty;
import org.springblade.core.tool.beans.BladeBeanCopier;
import org.springblade.core.tool.beans.BladeBeanMap;
import org.springblade.core.tool.convert.BladeConverter;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.lang.Nullable;
import java.util.*;
/**
 * å®žä½“工具类
 *
 * @author L.cm
 */
public class BeanUtil extends org.springframework.beans.BeanUtils {
    /**
     * å®žä¾‹åŒ–对象
     *
     * @param clazz ç±»
     * @param <T>   æ³›åž‹æ ‡è®°
     * @return å¯¹è±¡
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<?> clazz) {
        return (T) instantiateClass(clazz);
    }
    /**
     * å®žä¾‹åŒ–对象
     *
     * @param clazzStr ç±»å
     * @param <T>      æ³›åž‹æ ‡è®°
     * @return å¯¹è±¡
     */
    public static <T> T newInstance(String clazzStr) {
        try {
            Class<?> clazz = ClassUtil.forName(clazzStr, null);
            return newInstance(clazz);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * èŽ·å–Bean的属性, æ”¯æŒ propertyName å¤šçº§ ï¼štest.user.name
     *
     * @param bean         bean
     * @param propertyName å±žæ€§å
     * @return å±žæ€§å€¼
     */
    @Nullable
    public static Object getProperty(@Nullable Object bean, String propertyName) {
        if (bean == null) {
            return null;
        }
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
        return beanWrapper.getPropertyValue(propertyName);
    }
    /**
     * è®¾ç½®Bean属性, æ”¯æŒ propertyName å¤šçº§ ï¼štest.user.name
     *
     * @param bean         bean
     * @param propertyName å±žæ€§å
     * @param value        å±žæ€§å€¼
     */
    public static void setProperty(Object bean, String propertyName, Object value) {
        Objects.requireNonNull(bean, "bean Could not null");
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
        beanWrapper.setPropertyValue(propertyName, value);
    }
    /**
     * æ·±å¤åˆ¶
     *
     * <p>
     * æ”¯æŒ map bean
     * </p>
     *
     * @param source æºå¯¹è±¡
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return T
     */
    @SuppressWarnings("unchecked")
    @Nullable
    public static <T> T clone(@Nullable T source) {
        if (source == null) {
            return null;
        }
        return (T) BeanUtil.copy(source, source.getClass());
    }
    /**
     * copy å¯¹è±¡å±žæ€§ï¼Œé»˜è®¤ä¸ä½¿ç”¨Convert
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param source æºå¯¹è±¡
     * @param clazz  ç±»å
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return T
     */
    @Nullable
    public static <T> T copy(@Nullable Object source, Class<T> clazz) {
        if (source == null) {
            return null;
        }
        return BeanUtil.copy(source, source.getClass(), clazz);
    }
    /**
     * copy å¯¹è±¡å±žæ€§ï¼Œé»˜è®¤ä¸ä½¿ç”¨Convert
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param source      æºå¯¹è±¡
     * @param sourceClazz æºç±»åž‹
     * @param targetClazz è½¬æ¢æˆçš„类型
     * @param <T>         æ³›åž‹æ ‡è®°
     * @return T
     */
    @Nullable
    public static <T> T copy(@Nullable Object source, Class sourceClazz, Class<T> targetClazz) {
        if (source == null) {
            return null;
        }
        BladeBeanCopier copier = BladeBeanCopier.create(sourceClazz, targetClazz, false);
        T to = newInstance(targetClazz);
        copier.copy(source, to, null);
        return to;
    }
    /**
     * copy åˆ—表对象,默认不使用Convert
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param sourceList  æºåˆ—表
     * @param targetClazz è½¬æ¢æˆçš„类型
     * @param <T>         æ³›åž‹æ ‡è®°
     * @return T
     */
    public static <T> List<T> copy(@Nullable Collection<?> sourceList, Class<T> targetClazz) {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> outList = new ArrayList<>(sourceList.size());
        Class<?> sourceClazz = null;
        for (Object source : sourceList) {
            if (source == null) {
                continue;
            }
            if (sourceClazz == null) {
                sourceClazz = source.getClass();
            }
            T bean = BeanUtil.copy(source, sourceClazz, targetClazz);
            outList.add(bean);
        }
        return outList;
    }
    /**
     * æ‹·è´å¯¹è±¡
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param source     æºå¯¹è±¡
     * @param targetBean éœ€è¦èµ‹å€¼çš„对象
     */
    public static void copy(@Nullable Object source, @Nullable Object targetBean) {
        if (source == null || targetBean == null) {
            return;
        }
        BladeBeanCopier copier = BladeBeanCopier
            .create(source.getClass(), targetBean.getClass(), false);
        copier.copy(source, targetBean, null);
    }
    /**
     * æ‹·è´å¯¹è±¡ï¼Œsource å±žæ€§åš null åˆ¤æ–­ï¼ŒMap ä¸æ”¯æŒï¼Œmap ä¼šåš instanceof åˆ¤æ–­ï¼Œä¸ä¼š
     *
     * <p>
     * æ”¯æŒ bean copy
     * </p>
     *
     * @param source     æºå¯¹è±¡
     * @param targetBean éœ€è¦èµ‹å€¼çš„对象
     */
    public static void copyNonNull(@Nullable Object source, @Nullable Object targetBean) {
        if (source == null || targetBean == null) {
            return;
        }
        BladeBeanCopier copier = BladeBeanCopier
            .create(source.getClass(), targetBean.getClass(), false, true);
        copier.copy(source, targetBean, null);
    }
    /**
     * æ‹·è´å¯¹è±¡å¹¶å¯¹ä¸åŒç±»åž‹å±žæ€§è¿›è¡Œè½¬æ¢
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param source æºå¯¹è±¡
     * @param targetClazz è½¬æ¢æˆçš„ç±»
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return T
     */
    @Nullable
    public static <T> T copyWithConvert(@Nullable Object source, Class<T> targetClazz) {
        if (source == null) {
            return null;
        }
        return BeanUtil.copyWithConvert(source, source.getClass(), targetClazz);
    }
    /**
     * æ‹·è´å¯¹è±¡å¹¶å¯¹ä¸åŒç±»åž‹å±žæ€§è¿›è¡Œè½¬æ¢
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param source æºå¯¹è±¡
     * @param sourceClazz æºç±»
     * @param targetClazz è½¬æ¢æˆçš„ç±»
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return T
     */
    @Nullable
    public static <T> T copyWithConvert(@Nullable Object source, Class<?> sourceClazz, Class<T> targetClazz) {
        if (source == null) {
            return null;
        }
        BladeBeanCopier copier = BladeBeanCopier.create(sourceClazz, targetClazz, true);
        T to = newInstance(targetClazz);
        copier.copy(source, to, new BladeConverter(sourceClazz, targetClazz));
        return to;
    }
    /**
     * æ‹·è´åˆ—表并对不同类型属性进行转换
     *
     * <p>
     * æ”¯æŒ map bean copy
     * </p>
     *
     * @param sourceList æºå¯¹è±¡åˆ—表
     * @param targetClazz è½¬æ¢æˆçš„ç±»
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return List
     */
    public static <T> List<T> copyWithConvert(@Nullable Collection<?> sourceList, Class<T> targetClazz) {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> outList = new ArrayList<>(sourceList.size());
        Class<?> sourceClazz = null;
        for (Object source : sourceList) {
            if (source == null) {
                continue;
            }
            if (sourceClazz == null) {
                sourceClazz = source.getClass();
            }
            T bean = BeanUtil.copyWithConvert(source, sourceClazz, targetClazz);
            outList.add(bean);
        }
        return outList;
    }
    /**
     * Copy the property values of the given source bean into the target class.
     * <p>Note: The source and target classes do not have to match or even be derived
     * from each other, as long as the properties match. Any bean properties that the
     * source bean exposes but the target bean does not will silently be ignored.
     * <p>This is just a convenience method. For more complex transfer needs,
     *
     * @param source the source bean
     * @param targetClazz the target bean class
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return T
     * @throws BeansException if the copying failed
     */
    @Nullable
    public static <T> T copyProperties(@Nullable Object source, Class<T> targetClazz) throws BeansException {
        if (source == null) {
            return null;
        }
        T to = newInstance(targetClazz);
        BeanUtil.copyProperties(source, to);
        return to;
    }
    /**
     * Copy the property values of the given source bean into the target class.
     * <p>Note: The source and target classes do not have to match or even be derived
     * from each other, as long as the properties match. Any bean properties that the
     * source bean exposes but the target bean does not will silently be ignored.
     * <p>This is just a convenience method. For more complex transfer needs,
     *
     * @param sourceList the source list bean
     * @param targetClazz the target bean class
     * @param <T>    æ³›åž‹æ ‡è®°
     * @return List
     * @throws BeansException if the copying failed
     */
    public static <T> List<T> copyProperties(@Nullable Collection<?> sourceList, Class<T> targetClazz) throws BeansException {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> outList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            if (source == null) {
                continue;
            }
            T bean = BeanUtil.copyProperties(source, targetClazz);
            outList.add(bean);
        }
        return outList;
    }
    /**
     * å°†å¯¹è±¡è£…成map形式
     *
     * @param bean æºå¯¹è±¡
     * @return {Map}
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> toMap(@Nullable Object bean) {
        if (bean == null) {
            return new HashMap<>(0);
        }
        return BladeBeanMap.create(bean);
    }
    /**
     * å°†map è½¬ä¸º bean
     *
     * @param beanMap   map
     * @param valueType å¯¹è±¡ç±»åž‹
     * @param <T>       æ³›åž‹æ ‡è®°
     * @return {T}
     */
    public static <T> T toBean(Map<String, Object> beanMap, Class<T> valueType) {
        Objects.requireNonNull(beanMap, "beanMap Could not null");
        T to = newInstance(valueType);
        if (beanMap.isEmpty()) {
            return to;
        }
        BeanUtil.copy(beanMap, to);
        return to;
    }
    /**
     * ç»™ä¸€ä¸ªBean添加字段
     *
     * @param superBean çˆ¶çº§Bean
     * @param props     æ–°å¢žå±žæ€§
     * @return {Object}
     */
    @Nullable
    public static Object generator(@Nullable Object superBean, BeanProperty... props) {
        if (superBean == null) {
            return null;
        }
        Class<?> superclass = superBean.getClass();
        Object genBean = generator(superclass, props);
        BeanUtil.copy(superBean, genBean);
        return genBean;
    }
    /**
     * ç»™ä¸€ä¸ªclass添加字段
     *
     * @param superclass çˆ¶çº§
     * @param props      æ–°å¢žå±žæ€§
     * @return {Object}
     */
    public static Object generator(Class<?> superclass, BeanProperty... props) {
        BeanGenerator generator = new BeanGenerator();
        generator.setSuperclass(superclass);
        generator.setUseCache(true);
        for (BeanProperty prop : props) {
            generator.addProperty(prop.getName(), prop.getType());
        }
        return generator.create();
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CharPool.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
/**
 * char å¸¸é‡æ± 
 *
 * @author L.cm
 */
public interface CharPool {
    // @formatter:off
    char UPPER_A          = 'A';
    char LOWER_A          = 'a';
    char UPPER_Z          = 'Z';
    char LOWER_Z          = 'z';
    char DOT              = '.';
    char AT               = '@';
    char LEFT_BRACE       = '{';
    char RIGHT_BRACE      = '}';
    char LEFT_BRACKET     = '(';
    char RIGHT_BRACKET    = ')';
    char DASH             = '-';
    char PERCENT          = '%';
    char PIPE             = '|';
    char PLUS             = '+';
    char QUESTION_MARK    = '?';
    char EXCLAMATION_MARK = '!';
    char EQUALS           = '=';
    char AMPERSAND        = '&';
    char ASTERISK         = '*';
    char STAR             = ASTERISK;
    char BACK_SLASH       = '\\';
    char COLON            = ':';
    char COMMA            = ',';
    char DOLLAR           = '$';
    char SLASH            = '/';
    char HASH             = '#';
    char HAT              = '^';
    char LEFT_CHEV        = '<';
    char NEWLINE          = '\n';
    char N                = 'n';
    char Y                = 'y';
    char QUOTE            = '\"';
    char RETURN           = '\r';
    char TAB              = '\t';
    char RIGHT_CHEV       = '>';
    char SEMICOLON        = ';';
    char SINGLE_QUOTE     = '\'';
    char BACKTICK         = '`';
    char SPACE            = ' ';
    char TILDA            = '~';
    char LEFT_SQ_BRACKET  = '[';
    char RIGHT_SQ_BRACKET = ']';
    char UNDERSCORE       = '_';
    char ONE              = '1';
    char ZERO             = '0';
    // @formatter:on
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Charsets.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
/**
 * å­—符集工具类
 *
 * @author L.cm
 */
public class Charsets {
    /**
     * å­—符集ISO-8859-1
     */
    public static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
    public static final String ISO_8859_1_NAME = ISO_8859_1.name();
    /**
     * å­—符集GBK
     */
    public static final Charset GBK = Charset.forName(StringPool.GBK);
    public static final String GBK_NAME = GBK.name();
    /**
     * å­—符集utf-8
     */
    public static final Charset UTF_8 = StandardCharsets.UTF_8;
    public static final String UTF_8_NAME = UTF_8.name();
    /**
     * è½¬æ¢ä¸ºCharset对象
     *
     * @param charsetName å­—符集,为空则返回默认字符集
     * @return Charsets
     * @throws UnsupportedCharsetException ç¼–码不支持
     */
    public static Charset charset(String charsetName) throws UnsupportedCharsetException {
        return StringUtil.isBlank(charsetName) ? Charset.defaultCharset() : Charset.forName(charsetName);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.web.method.HandlerMethod;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
 * ç±»æ“ä½œå·¥å…·
 *
 * @author L.cm
 */
public class ClassUtil extends org.springframework.util.ClassUtils {
    private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    /**
     * èŽ·å–æ–¹æ³•å‚æ•°ä¿¡æ¯
     *
     * @param constructor    æž„造器
     * @param parameterIndex å‚数序号
     * @return {MethodParameter}
     */
    public static MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) {
        MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);
        methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
        return methodParameter;
    }
    /**
     * èŽ·å–æ–¹æ³•å‚æ•°ä¿¡æ¯
     *
     * @param method         æ–¹æ³•
     * @param parameterIndex å‚数序号
     * @return {MethodParameter}
     */
    public static MethodParameter getMethodParameter(Method method, int parameterIndex) {
        MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
        methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
        return methodParameter;
    }
    /**
     * èŽ·å–Annotation
     *
     * @param method         Method
     * @param annotationType æ³¨è§£ç±»
     * @param <A>            æ³›åž‹æ ‡è®°
     * @return {Annotation}
     */
    public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
        Class<?> targetClass = method.getDeclaringClass();
        // The method may be on an interface, but we need attributes from the target class.
        // If the target class is null, the method will be unchanged.
        Method specificMethod = ClassUtil.getMostSpecificMethod(method, targetClass);
        // If we are dealing with method with generic parameters, find the original method.
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
        // å…ˆæ‰¾æ–¹æ³•,再找方法上的类
        A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType);
        ;
        if (null != annotation) {
            return annotation;
        }
        // èŽ·å–ç±»ä¸Šé¢çš„Annotation,可能包含组合注解,故采用spring的工具类
        return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType);
    }
    /**
     * èŽ·å–Annotation
     *
     * @param handlerMethod  HandlerMethod
     * @param annotationType æ³¨è§£ç±»
     * @param <A>            æ³›åž‹æ ‡è®°
     * @return {Annotation}
     */
    public static <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {
        // å…ˆæ‰¾æ–¹æ³•,再找方法上的类
        A annotation = handlerMethod.getMethodAnnotation(annotationType);
        if (null != annotation) {
            return annotation;
        }
        // èŽ·å–ç±»ä¸Šé¢çš„Annotation,可能包含组合注解,故采用spring的工具类
        Class<?> beanType = handlerMethod.getBeanType();
        return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
    }
    /**
     * åˆ¤æ–­æ˜¯å¦æœ‰æ³¨è§£ Annotation
     *
     * @param method         Method
     * @param annotationType æ³¨è§£ç±»
     * @param <A>            æ³›åž‹æ ‡è®°
     * @return {boolean}
     */
    public static <A extends Annotation> boolean isAnnotated(Method method, Class<A> annotationType) {
        // å…ˆæ‰¾æ–¹æ³•,再找方法上的类
        boolean isMethodAnnotated = AnnotatedElementUtils.isAnnotated(method, annotationType);
        if (isMethodAnnotated) {
            return true;
        }
        // èŽ·å–ç±»ä¸Šé¢çš„Annotation,可能包含组合注解,故采用spring的工具类
        Class<?> targetClass = method.getDeclaringClass();
        return AnnotatedElementUtils.isAnnotated(targetClass, annotationType);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CollectionUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,177 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;
/**
 * é›†åˆå·¥å…·ç±»
 *
 * @author L.cm
 */
public class CollectionUtil extends CollectionUtils {
    /**
     * Return {@code true} if the supplied Collection is not {@code null} or empty.
     * Otherwise, return {@code false}.
     *
     * @param collection the Collection to check
     * @return whether the given Collection is not empty
     */
    public static boolean isNotEmpty(@Nullable Collection<?> collection) {
        return !CollectionUtil.isEmpty(collection);
    }
    /**
     * Return {@code true} if the supplied Map is not {@code null} or empty.
     * Otherwise, return {@code false}.
     *
     * @param map the Map to check
     * @return whether the given Map is not empty
     */
    public static boolean isNotEmpty(@Nullable Map<?, ?> map) {
        return !CollectionUtil.isEmpty(map);
    }
    /**
     * Check whether the given Array contains the given element.
     *
     * @param array   the Array to check
     * @param element the element to look for
     * @param <T>     The generic tag
     * @return {@code true} if found, {@code false} else
     */
    public static <T> boolean contains(@Nullable T[] array, final T element) {
        if (array == null) {
            return false;
        }
        return Arrays.stream(array).anyMatch(x -> ObjectUtil.nullSafeEquals(x, element));
    }
    /**
     * Concatenates 2 arrays
     *
     * @param one   æ•°ç»„1
     * @param other æ•°ç»„2
     * @return æ–°æ•°ç»„
     */
    public static String[] concat(String[] one, String[] other) {
        return concat(one, other, String.class);
    }
    /**
     * Concatenates 2 arrays
     *
     * @param one   æ•°ç»„1
     * @param other æ•°ç»„2
     * @param clazz æ•°ç»„ç±»
     * @return æ–°æ•°ç»„
     */
    public static <T> T[] concat(T[] one, T[] other, Class<T> clazz) {
        T[] target = (T[]) Array.newInstance(clazz, one.length + other.length);
        System.arraycopy(one, 0, target, 0, one.length);
        System.arraycopy(other, 0, target, one.length, other.length);
        return target;
    }
    /**
     * å¯¹è±¡æ˜¯å¦ä¸ºæ•°ç»„对象
     *
     * @param obj å¯¹è±¡
     * @return æ˜¯å¦ä¸ºæ•°ç»„对象,如果为{@code null} è¿”回false
     */
    public static boolean isArray(Object obj) {
        if (null == obj) {
            return false;
        }
        return obj.getClass().isArray();
    }
    /**
     * ä¸å¯å˜ Set
     *
     * @param es  å¯¹è±¡
     * @param <E> æ³›åž‹
     * @return é›†åˆ
     */
    @SafeVarargs
    public static <E> Set<E> ofImmutableSet(E... es) {
        Objects.requireNonNull(es, "args es is null.");
        return Arrays.stream(es).collect(Collectors.toSet());
    }
    /**
     * ä¸å¯å˜ List
     *
     * @param es  å¯¹è±¡
     * @param <E> æ³›åž‹
     * @return é›†åˆ
     */
    @SafeVarargs
    public static <E> List<E> ofImmutableList(E... es) {
        Objects.requireNonNull(es, "args es is null.");
        return Arrays.stream(es).collect(Collectors.toList());
    }
    /**
     * Iterable è½¬æ¢ä¸ºList集合
     *
     * @param elements Iterable
     * @param <E>      æ³›åž‹
     * @return é›†åˆ
     */
    public static <E> List<E> toList(Iterable<E> elements) {
        Objects.requireNonNull(elements, "elements es is null.");
        if (elements instanceof Collection) {
            return new ArrayList((Collection) elements);
        }
        Iterator<E> iterator = elements.iterator();
        List<E> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }
    /**
     * å°†key value æ•°ç»„转为 map
     *
     * @param keysValues key value æ•°ç»„
     * @param <K>        key
     * @param <V>        value
     * @return map é›†åˆ
     */
    public static <K, V> Map<K, V> toMap(Object... keysValues) {
        int kvLength = keysValues.length;
        if (kvLength % 2 != 0) {
            throw new IllegalArgumentException("wrong number of arguments for met, keysValues length can not be odd");
        }
        Map<K, V> keyValueMap = new HashMap<>(kvLength);
        for (int i = kvLength - 2; i >= 0; i -= 2) {
            Object key = keysValues[i];
            Object value = keysValues[i + 1];
            keyValueMap.put((K) key, (V) value);
        }
        return keyValueMap;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ConcurrentDateFormat.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Queue;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
 * å‚考tomcat8中的并发DateFormat
 * <p>
 * {@link SimpleDateFormat}的线程安全包装器。
 * ä¸ä½¿ç”¨ThreadLocal,创建足够的SimpleDateFormat对象来满足并发性要求。
 * </p>
 *
 * @author L.cm
 */
public class ConcurrentDateFormat {
    private final String format;
    private final Locale locale;
    private final TimeZone timezone;
    private final Queue<SimpleDateFormat> queue = new ConcurrentLinkedQueue<>();
    private ConcurrentDateFormat(String format, Locale locale, TimeZone timezone) {
        this.format = format;
        this.locale = locale;
        this.timezone = timezone;
        SimpleDateFormat initial = createInstance();
        queue.add(initial);
    }
    public static ConcurrentDateFormat of(String format) {
        return new ConcurrentDateFormat(format, Locale.getDefault(), TimeZone.getDefault());
    }
    public static ConcurrentDateFormat of(String format, TimeZone timezone) {
        return new ConcurrentDateFormat(format, Locale.getDefault(), timezone);
    }
    public static ConcurrentDateFormat of(String format, Locale locale, TimeZone timezone) {
        return new ConcurrentDateFormat(format, locale, timezone);
    }
    public String format(Date date) {
        SimpleDateFormat sdf = queue.poll();
        if (sdf == null) {
            sdf = createInstance();
        }
        String result = sdf.format(date);
        queue.add(sdf);
        return result;
    }
    public Date parse(String source) throws ParseException {
        SimpleDateFormat sdf = queue.poll();
        if (sdf == null) {
            sdf = createInstance();
        }
        Date result = sdf.parse(source);
        queue.add(sdf);
        return result;
    }
    private SimpleDateFormat createInstance() {
        SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
        sdf.setTimeZone(timezone);
        return sdf;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ConvertUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
package org.springblade.core.tool.utils;
import org.springblade.core.tool.convert.BladeConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
/**
 * åŸºäºŽ spring ConversionService ç±»åž‹è½¬æ¢
 *
 * @author L.cm
 */
@SuppressWarnings("unchecked")
public class ConvertUtil {
    /**
     * Convenience operation for converting a source object to the specified targetType.
     * {@link TypeDescriptor#forObject(Object)}.
     * @param source the source object
     * @param targetType the target type
     * @param <T> æ³›åž‹æ ‡è®°
     * @return the converted value
     * @throws IllegalArgumentException if targetType is {@code null},
     * or sourceType is {@code null} but source is not {@code null}
     */
    @Nullable
    public static <T> T convert(@Nullable Object source, Class<T> targetType) {
        if (source == null) {
            return null;
        }
        if (ClassUtil.isAssignableValue(targetType, source)) {
            return (T) source;
        }
        GenericConversionService conversionService = BladeConversionService.getInstance();
        return conversionService.convert(source, targetType);
    }
    /**
     * Convenience operation for converting a source object to the specified targetType,
     * where the target type is a descriptor that provides additional conversion context.
     * {@link TypeDescriptor#forObject(Object)}.
     * @param source the source object
     * @param sourceType the source type
     * @param targetType the target type
     * @param <T> æ³›åž‹æ ‡è®°
     * @return the converted value
     * @throws IllegalArgumentException if targetType is {@code null},
     * or sourceType is {@code null} but source is not {@code null}
     */
    @Nullable
    public static <T> T convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }
        GenericConversionService conversionService = BladeConversionService.getInstance();
        return (T) conversionService.convert(source, sourceType, targetType);
    }
    /**
     * Convenience operation for converting a source object to the specified targetType,
     * where the target type is a descriptor that provides additional conversion context.
     * Simply delegates to {@link #convert(Object, TypeDescriptor, TypeDescriptor)} and
     * encapsulates the construction of the source type descriptor using
     * {@link TypeDescriptor#forObject(Object)}.
     * @param source the source object
     * @param targetType the target type
     * @param <T> æ³›åž‹æ ‡è®°
     * @return the converted value
     * @throws IllegalArgumentException if targetType is {@code null},
     * or sourceType is {@code null} but source is not {@code null}
     */
    @Nullable
    public static <T> T convert(@Nullable Object source, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }
        GenericConversionService conversionService = BladeConversionService.getInstance();
        return (T) conversionService.convert(source, targetType);
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DatatypeConverterUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package org.springblade.core.tool.utils;
/**
 * æ•°æ®ç±»åž‹è½¬æ¢å·¥å…·ç±»
 *
 * @author Chill
 */
public class DatatypeConverterUtil {
    /**
     * hex文本转换为二进制
     *
     * @param hexStr hex文本
     * @return byte[]
     */
    public static byte[] parseHexBinary(String hexStr) {
        final int len = hexStr.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("hexBinary needs to be even-length: " + hexStr);
        }
        byte[] out = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            int h = hexToBin(hexStr.charAt(i));
            int l = hexToBin(hexStr.charAt(i + 1));
            if (h == -1 || l == -1) {
                throw new IllegalArgumentException("contains illegal character for hexBinary: " + hexStr);
            }
            out[i / 2] = (byte) (h * 16 + l);
        }
        return out;
    }
    /**
     * hex文本转换为int
     *
     * @param ch hex文本
     * @return int
     */
    private static int hexToBin(char ch) {
        if ('0' <= ch && ch <= '9') {
            return ch - '0';
        }
        if ('A' <= ch && ch <= 'F') {
            return ch - 'A' + 10;
        }
        if ('a' <= ch && ch <= 'f') {
            return ch - 'a' + 10;
        }
        return -1;
    }
}
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateTimeUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,226 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
/**
 * DateTime å·¥å…·ç±»
 *
 * @author L.cm
 */
public class DateTimeUtil {
    public static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern(DateUtil.PATTERN_DATETIME);
    public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(DateUtil.PATTERN_DATE);
    public static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern(DateUtil.PATTERN_TIME);
    /**
     * æ—¥æœŸæ—¶é—´æ ¼å¼åŒ–
     *
     * @param temporal æ—¶é—´
     * @return æ ¼å¼åŒ–后的时间
     */
    public static String formatDateTime(TemporalAccessor temporal) {
        return DATETIME_FORMAT.format(temporal);
    }
    /**
     * æ—¥æœŸæ—¶é—´æ ¼å¼åŒ–
     *
     * @param temporal æ—¶é—´
     * @return æ ¼å¼åŒ–后的时间
     */
    public static String formatDate(TemporalAccessor temporal) {
        return DATE_FORMAT.format(temporal);
    }
    /**
     * æ—¶é—´æ ¼å¼åŒ–
     *
     * @param temporal æ—¶é—´
     * @return æ ¼å¼åŒ–后的时间
     */
    public static String formatTime(TemporalAccessor temporal) {
        return TIME_FORMAT.format(temporal);
    }
    /**
     * æ—¥æœŸæ ¼å¼åŒ–
     *
     * @param temporal æ—¶é—´
     * @param pattern  è¡¨è¾¾å¼
     * @return æ ¼å¼åŒ–后的时间
     */
    public static String format(TemporalAccessor temporal, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(temporal);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr æ—¶é—´å­—符串
     * @param pattern è¡¨è¾¾å¼
     * @return æ—¶é—´
     */
    public static LocalDateTime parseDateTime(String dateStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return DateTimeUtil.parseDateTime(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr   æ—¶é—´å­—符串
     * @param formatter DateTimeFormatter
     * @return æ—¶é—´
     */
    public static LocalDateTime parseDateTime(String dateStr, DateTimeFormatter formatter) {
        return LocalDateTime.parse(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr æ—¶é—´å­—符串
     * @return æ—¶é—´
     */
    public static LocalDateTime parseDateTime(String dateStr) {
        return DateTimeUtil.parseDateTime(dateStr, DateTimeUtil.DATETIME_FORMAT);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr æ—¶é—´å­—符串
     * @param pattern è¡¨è¾¾å¼
     * @return æ—¶é—´
     */
    public static LocalDate parseDate(String dateStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return DateTimeUtil.parseDate(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr   æ—¶é—´å­—符串
     * @param formatter DateTimeFormatter
     * @return æ—¶é—´
     */
    public static LocalDate parseDate(String dateStr, DateTimeFormatter formatter) {
        return LocalDate.parse(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为日期
     *
     * @param dateStr æ—¶é—´å­—符串
     * @return æ—¶é—´
     */
    public static LocalDate parseDate(String dateStr) {
        return DateTimeUtil.parseDate(dateStr, DateTimeUtil.DATE_FORMAT);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr æ—¶é—´å­—符串
     * @param pattern æ—¶é—´æ­£åˆ™
     * @return æ—¶é—´
     */
    public static LocalTime parseTime(String dateStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return DateTimeUtil.parseTime(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr   æ—¶é—´å­—符串
     * @param formatter DateTimeFormatter
     * @return æ—¶é—´
     */
    public static LocalTime parseTime(String dateStr, DateTimeFormatter formatter) {
        return LocalTime.parse(dateStr, formatter);
    }
    /**
     * å°†å­—符串转换为时间
     *
     * @param dateStr æ—¶é—´å­—符串
     * @return æ—¶é—´
     */
    public static LocalTime parseTime(String dateStr) {
        return DateTimeUtil.parseTime(dateStr, DateTimeUtil.TIME_FORMAT);
    }
    /**
     * æ—¶é—´è½¬ Instant
     *
     * @param dateTime æ—¶é—´
     * @return Instant
     */
    public static Instant toInstant(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant();
    }
    /**
     * Instant è½¬ æ—¶é—´
     *
     * @param instant Instant
     * @return Instant
     */
    public static LocalDateTime toDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
    /**
     * è½¬æ¢æˆ date
     *
     * @param dateTime LocalDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime dateTime) {
        return Date.from(DateTimeUtil.toInstant(dateTime));
    }
    /**
     * æ¯”较2个时间差,跨度比较小
     *
     * @param startInclusive å¼€å§‹æ—¶é—´
     * @param endExclusive   ç»“束时间
     * @return æ—¶é—´é—´éš”
     */
    public static Duration between(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive);
    }
    /**
     * æ¯”较2个时间差,跨度比较大,年月日为单位
     *
     * @param startDate å¼€å§‹æ—¶é—´
     * @param endDate   ç»“束时间
     * @return æ—¶é—´é—´éš”
     */
    public static Period between(LocalDate startDate, LocalDate endDate) {
        return Period.between(startDate, endDate);
    }
}
在上述文件截断后对比
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DesUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DigestUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Exceptions.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/FileUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Func.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/HexUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Holder.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ImageUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/IntegerPool.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/IoUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Lazy.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/NumberUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ObjectUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PathUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PlaceholderUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ProtostuffUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RandomType.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ReflectUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RegexUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ResourceUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RsaUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/RuntimeUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SpringUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringPool.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SuffixFileFilter.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ThreadLocalUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ThreadUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Unchecked.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/UrlUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Version.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/XmlUtil.java Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/yml/YmlPropertyLoaderFactory.java Source/BladeX-Tool/blade-starter-actuate/README.md Source/BladeX-Tool/blade-starter-actuate/pom.xml Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/BladeHttpCacheProperties.java Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheAble.java Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheConfiguration.java Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheInterceptor.java Source/BladeX-Tool/blade-starter-actuate/src/main/java/org/springblade/core/http/cache/HttpCacheService.java Source/BladeX-Tool/blade-starter-api-crypto/README.md Source/BladeX-Tool/blade-starter-api-crypto/pom.xml Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCrypto.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoAes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoDes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/crypto/ApiCryptoRsa.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecrypt.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptAes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptDes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptRsa.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncrypt.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptAes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptDes.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptRsa.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/bean/CryptoInfoBean.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/bean/DecryptHttpInputMessage.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoConfiguration.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoProperties.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptParamResolver.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptRequestBodyAdvice.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiEncryptResponseBodyAdvice.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/enums/CryptoType.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/DecryptBodyFailException.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptBodyFailException.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptMethodNotFoundException.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/exception/KeyNotConfiguredException.java Source/BladeX-Tool/blade-starter-api-crypto/src/main/java/org/springblade/core/api/crypto/util/ApiCryptoUtil.java Source/BladeX-Tool/blade-starter-auth/pom.xml Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/AuthInfo.java Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/BladeUser.java Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/TokenInfo.java Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/exception/SecureException.java Source/BladeX-Tool/blade-starter-auth/src/main/java/org/springblade/core/secure/utils/AuthUtil.java Source/BladeX-Tool/blade-starter-cache/pom.xml Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/config/CacheConfiguration.java Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/constant/CacheConstant.java Source/BladeX-Tool/blade-starter-cache/src/main/java/org/springblade/core/cache/utils/CacheUtil.java Source/BladeX-Tool/blade-starter-datascope/pom.xml Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/annotation/DataAuth.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/config/DataScopeConfiguration.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/constant/DataScopeConstant.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/enums/DataScopeEnum.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/exception/DataScopeException.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/BladeDataScopeHandler.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/BladeScopeModelHandler.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/DataScopeHandler.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/handler/ScopeModelHandler.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/interceptor/DataScopeInterceptor.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java Source/BladeX-Tool/blade-starter-datascope/src/main/java/org/springblade/core/datascope/props/DataScopeProperties.java Source/BladeX-Tool/blade-starter-develop/pom.xml Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/CodeGenerator.java Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/support/BladeTemplateEngine.java Source/BladeX-Tool/blade-starter-develop/src/main/resources/beetl.properties Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/controller.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entity.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entityDTO.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/entityVO.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/feign.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/feignclient.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/mapper.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/mapper.xml.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/service.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/serviceImpl.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/api/wrapper.java.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/code.properties Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/crud/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/sub/sub.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/element/tree/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/Modal.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/data.data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/crud/index.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/Modal.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/data.data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/index.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/sub/sub.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/Modal.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/data.data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/data.ts.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/lemon/tree/index.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/crud/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/sub/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/api.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/const.js.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/saber/tree/crud.vue.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sql/menu.sql.btl Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/action.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/add.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/edit.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/list.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/model.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/service.js.vm Source/BladeX-Tool/blade-starter-develop/src/main/resources/templates/sword/view.js.vm Source/BladeX-Tool/blade-starter-ehcache/pom.xml Source/BladeX-Tool/blade-starter-ehcache/src/main/java/org/springblade/core/ehcache/EhcacheConfiguration.java Source/BladeX-Tool/blade-starter-ehcache/src/main/resources/ehcache.xml Source/BladeX-Tool/blade-starter-excel/pom.xml Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/listener/DataListener.java Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/listener/ImportListener.java Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/support/ExcelException.java Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/support/ExcelImporter.java Source/BladeX-Tool/blade-starter-excel/src/main/java/org/springblade/core/excel/util/ExcelUtil.java Source/BladeX-Tool/blade-starter-flowable/pom.xml Source/BladeX-Tool/blade-starter-flowable/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java Source/BladeX-Tool/blade-starter-flowable/src/main/java/org/flowable/common/engine/impl/db/LiquibaseBasedSchemaManager.java Source/BladeX-Tool/blade-starter-flowable/src/main/resources/processes/LeaveProcess.bpmn20.xml Source/BladeX-Tool/blade-starter-http/pom.xml Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/AsyncCall.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/AsyncCallback.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/BaseAuthenticator.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/CssQuery.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/CssQueryMethodInterceptor.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/DomMapper.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Exchange.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/FormBuilder.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/HttpRequest.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/HttpResponse.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/LogLevel.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Method.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/MultipartFormBuilder.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/ResponseSpec.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/RetryInterceptor.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/RetryPolicy.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/Slf4jLogger.java Source/BladeX-Tool/blade-starter-http/src/main/java/org/springblade/core/http/util/HttpUtil.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/BladeProxySelector.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/HttpRequestDemo.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/HttpRequestProxyTest.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/OsChina.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/OsChinaTest.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/VBlog.java Source/BladeX-Tool/blade-starter-http/src/test/java/org/springblade/core/http/test/VNews.java Source/BladeX-Tool/blade-starter-jwt/pom.xml Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/JwtUtil.java Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/config/JwtConfiguration.java Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/config/JwtRedisConfiguration.java Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/constant/JwtConstant.java Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/props/JwtProperties.java Source/BladeX-Tool/blade-starter-jwt/src/main/java/org/springblade/core/jwt/serializer/JwtRedisKeySerializer.java Source/BladeX-Tool/blade-starter-loadbalancer/pom.xml Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/config/BladeLoadBalancerConfiguration.java Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/constant/LoadBalancerConstant.java Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/rule/GrayscaleEnvPostProcessor.java Source/BladeX-Tool/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/rule/GrayscaleLoadBalancer.java Source/BladeX-Tool/blade-starter-log/pom.xml Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/annotation/ApiLog.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/ApiLogAspect.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/LogTraceAspect.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/aspect/RequestLogAspect.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/constant/EventConstant.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/error/RestExceptionTranslator.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ApiLogEvent.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ApiLogListener.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ErrorLogEvent.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/UsualLogEvent.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/event/UsualLogListener.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/exception/ServiceException.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/feign/ILogClient.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/feign/LogClientFallback.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/filter/LogTraceFilter.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/launch/LogLauncherServiceImpl.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/listener/LoggerStartupListener.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/logger/BladeLogger.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogAbstract.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogApi.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogError.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/model/LogUsual.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/props/BladeRequestLogProperties.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/ElkPropsUtil.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java Source/BladeX-Tool/blade-starter-log/src/main/java/org/springblade/core/log/utils/LogTraceUtil.java Source/BladeX-Tool/blade-starter-log/src/main/resources/blade-log.yml Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-dev.xml Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-prod.xml Source/BladeX-Tool/blade-starter-log/src/main/resources/log/logback-test.xml Source/BladeX-Tool/blade-starter-metrics/pom.xml Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/druid/DruidDataSourceMetadataProviderConfiguration.java Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/druid/DruidDataSourcePoolMetadata.java Source/BladeX-Tool/blade-starter-metrics/src/main/java/org/springblade/core/metrics/sentinel/SentinelMetricsExtension.java Source/BladeX-Tool/blade-starter-mongo/pom.xml Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/config/MongoConfiguration.java Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/converter/DBObjectToJsonNodeConverter.java Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/converter/JsonNodeToDocumentConverter.java Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/utils/JsonNodeInfo.java Source/BladeX-Tool/blade-starter-mongo/src/main/java/org/springblade/core/mongo/utils/MongoJsonUtils.java Source/BladeX-Tool/blade-starter-mybatis/pom.xml Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/BladeMetaObjectHandler.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/config/MybatisPlusConfiguration.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/BladeSqlInjector.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/BladeSqlMethod.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/AbstractInsertMethod.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/InsertIgnore.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/injector/methods/Replace.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/mapper/BladeMapper.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/BladePaginationInterceptor.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/QueryInterceptorExecutor.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/plugins/SqlLogInterceptor.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/props/MybatisPlusProperties.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/resolver/PageArgumentResolver.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/service/BladeService.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/service/impl/BladeServiceImpl.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/BaseEntityWrapper.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/BladePage.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/Condition.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/Query.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/support/SqlKeyword.java Source/BladeX-Tool/blade-starter-mybatis/src/main/java/org/springblade/core/mp/utils/PageUtil.java Source/BladeX-Tool/blade-starter-mybatis/src/main/resources/blade-mybatis.yml Source/BladeX-Tool/blade-starter-oss/pom.xml Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/HuaweiObsTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/MinioTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/OssTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/TencentCosTemplate.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/HuaweiObsConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/MinioConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/OssConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/config/TencentCosConfiguration.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/OssEnum.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/OssStatusEnum.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/enums/PolicyType.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/MinioItem.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/model/OssFile.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/rule/BladeOssRule.java Source/BladeX-Tool/blade-starter-oss/src/main/java/org/springblade/core/oss/rule/OssRule.java Source/BladeX-Tool/blade-starter-prometheus/pom.xml Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/config/PrometheusConfiguration.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Agent.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/ChangeItem.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Config.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/Service.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/data/ServiceHealth.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/endpoint/AgentEndpoint.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/endpoint/ServiceEndpoint.java Source/BladeX-Tool/blade-starter-prometheus/src/main/java/org/springblade/core/prometheus/service/RegistrationService.java Source/BladeX-Tool/blade-starter-prometheus/src/main/resources/blade-prometheus.yml Source/BladeX-Tool/blade-starter-redis/pom.xml Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/BladeRedis.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/CacheKey.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/ICacheKey.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisCacheAutoConfiguration.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisProperties.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/BladeRedisSerializerConfigAble.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/ProtoStuffSerializerConfiguration.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RateLimiterAutoConfiguration.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisAutoCacheManager.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisCacheManagerConfig.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/config/RedisTemplateConfiguration.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/BladeLockAutoConfiguration.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/BladeLockProperties.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/LockType.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLock.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockAspect.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockClient.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/lock/RedisLockClientImpl.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiter.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiterClient.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RateLimiterException.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RedisRateLimiterAspect.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/ratelimiter/RedisRateLimiterClient.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/BytesWrapper.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/ProtoStuffSerializer.java Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/serializer/RedisKeySerializer.java Source/BladeX-Tool/blade-starter-redis/src/main/resources/META-INF/scripts/blade_rate_limiter.lua Source/BladeX-Tool/blade-starter-redis/src/main/resources/additional-spring-configuration-metadata.json Source/BladeX-Tool/blade-starter-report/pom.xml Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/datasource/ReportDataSource.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/endpoint/ReportBootEndpoint.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/endpoint/ReportEndpoint.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/entity/ReportFileEntity.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/mapper/ReportFileMapper.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportDatabaseProperties.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/provider/DatabaseProvider.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/provider/ReportPlaceholderProvider.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/service/IReportFileService.java Source/BladeX-Tool/blade-starter-report/src/main/java/org/springblade/core/report/service/impl/ReportFileServiceImpl.java Source/BladeX-Tool/blade-starter-sms/pom.xml Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/AliSmsTemplate.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/QiniuSmsTemplate.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/SmsTemplate.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/TencentSmsTemplate.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/YunpianSmsTemplate.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/AliSmsConfiguration.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/QiniuSmsConfiguration.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/SmsConfiguration.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/TencentSmsConfiguration.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/config/YunpianSmsConfiguration.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/constant/SmsConstant.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/enums/SmsEnum.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/enums/SmsStatusEnum.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsCode.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsData.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsInfo.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/model/SmsResponse.java Source/BladeX-Tool/blade-starter-sms/src/main/java/org/springblade/core/sms/props/SmsProperties.java Source/BladeX-Tool/blade-starter-social/pom.xml Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/cache/AuthStateRedisCache.java Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/config/SocialConfiguration.java Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/props/SocialProperties.java Source/BladeX-Tool/blade-starter-social/src/main/java/org/springblade/core/social/utils/SocialUtil.java Source/BladeX-Tool/blade-starter-social/src/main/resources/blade-social.yml Source/BladeX-Tool/blade-starter-swagger/pom.xml Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/EnableSwagger.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerAutoConfiguration.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerHandlerConfiguration.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerUtil.java Source/BladeX-Tool/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerWebConfiguration.java Source/BladeX-Tool/blade-starter-swagger/src/main/resources/blade-swagger.yml Source/BladeX-Tool/blade-starter-tenant/pom.xml Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantHandler.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantHolder.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantId.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantInterceptor.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/BladeTenantProperties.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/TenantId.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/NonDS.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TableExclude.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantDS.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantIgnore.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/annotation/TenantParamDS.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/aspect/BladeTenantAspect.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/config/TenantConfiguration.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/config/TenantDataSourceConfiguration.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/constant/TenantBaseConstant.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/DsTenantIdProcessor.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSource.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceAnnotationInterceptor.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceGlobalAdvisor.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceGlobalInterceptor.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceHolder.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/dynamic/TenantDataSourceJdbcProvider.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/exception/TenantDataSourceException.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/launcher/TenantLauncherServiceImpl.java Source/BladeX-Tool/blade-starter-tenant/src/main/java/org/springblade/core/tenant/mp/TenantEntity.java Source/BladeX-Tool/blade-starter-trace/pom.xml Source/BladeX-Tool/blade-starter-trace/src/main/java/org/springblade/core/trace/TraceAutoConfiguration.java Source/BladeX-Tool/blade-starter-trace/src/main/resources/blade-trace.yml Source/BladeX-Tool/blade-starter-transaction/pom.xml Source/BladeX-Tool/blade-starter-transaction/src/main/java/org/springblade/core/transaction/annotation/SeataCloudApplication.java Source/BladeX-Tool/blade-starter-transaction/src/main/java/org/springblade/core/transaction/config/TransactionConfiguration.java Source/BladeX-Tool/blade-starter-transaction/src/main/resources/blade-transaction.yml Source/BladeX-Tool/blade-starter-transaction/src/main/resources/file.conf Source/BladeX-Tool/doc/mvn/mvn命令.md Source/BladeX-Tool/pom.xml Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MDMData.java (已删除) Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MDMParamData.java (已删除) Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/MdmResultData.java (已删除) Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/webserviceModel/mdm/data.json (已删除) Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/CodeSyncUniversalController.java Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/RedirectViewController.java (已删除) Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/CodeMdmInfaceI.java (已删除) Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeMdmInfaceImpl.java (已删除) Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/webService/config/ClassifyConfig.java (已删除) Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/webService/config/MDMInterFaceConfig.java (已删除)