diff --git a/blade-core-boot/src/main/resources/static/favicon.ico b/blade-core-boot/src/main/resources/static/favicon.ico index 5e2aec9..cb67ccb 100644 Binary files a/blade-core-boot/src/main/resources/static/favicon.ico and b/blade-core-boot/src/main/resources/static/favicon.ico differ diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java b/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java index 4da56e0..ebd77d0 100644 --- a/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java +++ b/blade-core-launch/src/main/java/org/springblade/core/launch/BladeApplication.java @@ -27,7 +27,6 @@ import org.springframework.util.StringUtils; import java.util.*; import java.util.function.Function; -import java.util.stream.Collectors; /** * 项目启动器,搞定环境变量问题 @@ -88,9 +87,9 @@ public class BladeApplication { // 同时存在dev、test、prod环境时 throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]"); } - String startJarPath = BladeApplication.class.getResource("/").getPath().split("!")[0]; + String startJarPath = Objects.requireNonNull(BladeApplication.class.getResource("/")).getPath().split("!")[0]; String activePros = joinFun.apply(activeProfileList.toArray()); - System.out.println(String.format("----启动中,读取到的环境变量:[%s],jar地址:[%s]----", activePros, startJarPath)); + 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); @@ -102,15 +101,15 @@ public class BladeApplication { props.setProperty("blade.dev-mode", profile.equals(AppConstant.PROD_CODE) ? "false" : "true"); props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION); props.setProperty("spring.main.allow-bean-definition-overriding", "true"); - props.setProperty("spring.cloud.nacos.config.prefix", NacosConstant.NACOS_CONFIG_PREFIX); - props.setProperty("spring.cloud.nacos.config.file-extension", NacosConstant.NACOS_CONFIG_FORMAT); props.setProperty("spring.cloud.sentinel.transport.dashboard", SentinelConstant.SENTINEL_ADDR); props.setProperty("spring.cloud.alibaba.seata.tx-service-group", appName.concat(NacosConstant.NACOS_GROUP_SUFFIX)); + props.setProperty("spring.config.import", String.join(",", NacosConstant.dataId(), NacosConstant.dataId(profile), NacosConstant.dataId(appName, profile))); + props.setProperty("nacos.logging.default.config.enabled", "false"); // 加载自定义组件 List launcherList = new ArrayList<>(); ServiceLoader.load(LauncherService.class).forEach(launcherList::add); SpringApplicationBuilder finalBuilder = builder; - launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList()) + launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).toList() .forEach(launcherService -> launcherService.launcher(finalBuilder, appName, profile)); return finalBuilder; } @@ -122,7 +121,7 @@ public class BladeApplication { */ public static boolean isLocalDev() { String osName = System.getProperty("os.name"); - return StringUtils.hasText(osName) && !(AppConstant.OS_NAME_LINUX.equals(osName.toUpperCase())); + return StringUtils.hasText(osName) && !(AppConstant.OS_NAME_LINUX.equalsIgnoreCase(osName)); } } diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java index 98191ae..05af223 100644 --- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java +++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/NacosConstant.java @@ -22,6 +22,16 @@ package org.springblade.core.launch.constant; */ public interface NacosConstant { + /** + * optional + */ + String OPTIONAL = "optional"; + + /** + * nacos + */ + String NACOS = "nacos"; + /** * nacos 地址 */ @@ -57,6 +67,25 @@ public interface NacosConstant { */ String NACOS_CONFIG_GROUP = "DEFAULT_GROUP"; + /** + * 服务默认加载的配置 + * + * @return dataId + */ + static String dataId() { + return OPTIONAL + ":" + NACOS + ":" + NACOS_CONFIG_PREFIX + "." + NACOS_CONFIG_FORMAT; + } + + /** + * 服务默认加载的配置 + * + * @param profile 环境变量 + * @return dataId + */ + static String dataId(String profile) { + return OPTIONAL + ":" + NACOS + ":" + NACOS_CONFIG_PREFIX + "-" + profile + "." + NACOS_CONFIG_FORMAT; + } + /** * 构建服务对应的 dataId * @@ -77,7 +106,7 @@ public interface NacosConstant { * @return dataId */ static String dataId(String appName, String profile, String format) { - return appName + "-" + profile + "." + format; + return OPTIONAL + ":" + NACOS + ":" + appName + "-" + profile + "." + format; } } diff --git a/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java b/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java index c40cc4c..3ca1567 100644 --- a/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java +++ b/blade-starter-loadbalancer/src/main/java/org/springblade/core/loadbalancer/props/BladeLoadBalancerProperties.java @@ -18,7 +18,6 @@ package org.springblade.core.loadbalancer.props; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.context.config.annotation.RefreshScope; import java.util.ArrayList; import java.util.List; @@ -30,7 +29,6 @@ import java.util.List; */ @Getter @Setter -@RefreshScope @ConfigurationProperties(BladeLoadBalancerProperties.PROPERTIES_PREFIX) public class BladeLoadBalancerProperties { public static final String PROPERTIES_PREFIX = "blade.loadbalancer"; diff --git a/blade-starter-swagger/src/main/java/com/github/xiaoymin/knife4j/spring/extension/Knife4jOpenApiCustomizer.java b/blade-starter-swagger/src/main/java/com/github/xiaoymin/knife4j/spring/extension/Knife4jOpenApiCustomizer.java new file mode 100644 index 0000000..621788c --- /dev/null +++ b/blade-starter-swagger/src/main/java/com/github/xiaoymin/knife4j/spring/extension/Knife4jOpenApiCustomizer.java @@ -0,0 +1,159 @@ +/* + * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com) + * + * 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 + * + * http://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 com.github.xiaoymin.knife4j.spring.extension; + +import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import com.github.xiaoymin.knife4j.core.conf.ExtensionsConstants; +import com.github.xiaoymin.knife4j.core.conf.GlobalConstants; +import com.github.xiaoymin.knife4j.spring.configuration.Knife4jProperties; +import com.github.xiaoymin.knife4j.spring.configuration.Knife4jSetting; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.models.OpenAPI; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; +import org.springdoc.core.customizers.GlobalOpenApiCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.RestController; + +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 增强扩展属性支持 + * + * @author xiaoymin@foxmail.com + * 2022/12/11 22:40 + * @since 4.1.0 + */ +@Slf4j +@AllArgsConstructor +public class Knife4jOpenApiCustomizer implements GlobalOpenApiCustomizer { + + final Knife4jProperties knife4jProperties; + final SpringDocConfigProperties properties; + + @Override + public void customise(OpenAPI openApi) { + log.debug("Knife4j OpenApiCustomizer"); + if (knife4jProperties.isEnable()) { + Knife4jSetting setting = knife4jProperties.getSetting(); + OpenApiExtensionResolver openApiExtensionResolver = new OpenApiExtensionResolver(setting, knife4jProperties.getDocuments()); + // 解析初始化 + openApiExtensionResolver.start(); + Map objectMap = new HashMap<>(); + objectMap.put(GlobalConstants.EXTENSION_OPEN_SETTING_NAME, setting); + objectMap.put(GlobalConstants.EXTENSION_OPEN_MARKDOWN_NAME, openApiExtensionResolver.getMarkdownFiles()); + openApi.addExtension(GlobalConstants.EXTENSION_OPEN_API_NAME, objectMap); + addOrderExtension(openApi); + } + } + + /** + * 往OpenAPI内tags字段添加x-order属性 + * + * @param openApi openApi + */ + private void addOrderExtension(OpenAPI openApi) { + if (CollectionUtils.isEmpty(properties.getGroupConfigs())) { + return; + } + // 获取包扫描路径 + Set packagesToScan = + properties.getGroupConfigs().stream() + .map(SpringDocConfigProperties.GroupConfig::getPackagesToScan) + .filter(toScan -> !CollectionUtils.isEmpty(toScan)) + .flatMap(List::stream) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(packagesToScan)) { + return; + } + // 扫描包下被ApiSupport注解的RestController Class + Set> classes = + packagesToScan.stream() + .map(packageToScan -> scanPackageByAnnotation(packageToScan, RestController.class)) + .flatMap(Set::stream) + .filter(clazz -> clazz.isAnnotationPresent(ApiSupport.class)) + .collect(Collectors.toSet()); + if (!CollectionUtils.isEmpty(classes)) { + // ApiSupport oder值存入tagSortMap + Map tagOrderMap = new HashMap<>(); + classes.forEach( + clazz -> { + Tag tag = getTag(clazz); + if (Objects.nonNull(tag)) { + ApiSupport apiSupport = clazz.getAnnotation(ApiSupport.class); + tagOrderMap.putIfAbsent(tag.name(), apiSupport.order()); + } + }); + // 往openApi tags字段添加x-order增强属性 + if (openApi.getTags() != null) { + openApi + .getTags() + .forEach( + tag -> { + if (tagOrderMap.containsKey(tag.getName())) { + tag.addExtension( + ExtensionsConstants.EXTENSION_ORDER, tagOrderMap.get(tag.getName())); + } + }); + } + } + } + + private Tag getTag(Class clazz) { + // 从类上获取 + Tag tag = clazz.getAnnotation(Tag.class); + if (Objects.isNull(tag)) { + // 从接口上获取 + Class[] interfaces = clazz.getInterfaces(); + if (ArrayUtils.isNotEmpty(interfaces)) { + for (Class interfaceClazz : interfaces) { + Tag anno = interfaceClazz.getAnnotation(Tag.class); + if (Objects.nonNull(anno)) { + tag = anno; + break; + } + } + } + } + return tag; + } + + private Set> scanPackageByAnnotation( + String packageName, final Class annotationClass) { + ClassPathScanningCandidateComponentProvider scanner = + new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass)); + Set> classes = new HashSet<>(); + for (BeanDefinition beanDefinition : scanner.findCandidateComponents(packageName)) { + try { + Class clazz = Class.forName(beanDefinition.getBeanClassName()); + classes.add(clazz); + } catch (ClassNotFoundException ignore) { + + } + } + return classes; + } +} diff --git a/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java b/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java index 1269003..3da0b2d 100644 --- a/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java +++ b/blade-starter-swagger/src/main/java/org/springblade/core/swagger/SwaggerLauncherServiceImpl.java @@ -15,7 +15,6 @@ */ package org.springblade.core.swagger; -import net.dreamlu.mica.auto.annotation.AutoService; import org.springblade.core.launch.constant.AppConstant; import org.springblade.core.launch.service.LauncherService; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -28,7 +27,6 @@ import java.util.Properties; * * @author Chill */ -@AutoService(LauncherService.class) public class SwaggerLauncherServiceImpl implements LauncherService { @Override public void launcher(SpringApplicationBuilder builder, String appName, String profile) { diff --git a/blade-starter-swagger/src/main/resources/META-INF/services/org.springblade.core.launch.service.LauncherService b/blade-starter-swagger/src/main/resources/META-INF/services/org.springblade.core.launch.service.LauncherService new file mode 100644 index 0000000..03ce0b3 --- /dev/null +++ b/blade-starter-swagger/src/main/resources/META-INF/services/org.springblade.core.launch.service.LauncherService @@ -0,0 +1 @@ +org.springblade.core.swagger.SwaggerLauncherServiceImpl diff --git a/pom.xml b/pom.xml index 8706569..826c257 100644 --- a/pom.xml +++ b/pom.xml @@ -390,6 +390,11 @@ springdoc-openapi-starter-webflux-ui 2.8.9 + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.9 + io.protostuff