Merge remote-tracking branch 'origin/openapi' into leng_dev

# Conflicts:
#	pigx-visual/pigx-codegen/src/main/resources/template/Entity.java.vm
This commit is contained in:
lbw committed 2023-01-04 21:50:44 +08:00
commit d1c33d001b
174 files changed
+1288 -1714

No files matched your search

+24 -12
View File
@@ -26,7 +26,9 @@
<oracle.version>21.3.0.0</oracle.version>
<sqlserver.version>8.4.1.jre8</sqlserver.version>
<dm.version>8.1.2.79</dm.version>
<swagger.core.version>1.5.22</swagger.core.version>
<knife4j.version>3.0.3</knife4j.version>
<swagger.core.version>2.2.0</swagger.core.version>
<springdoc.version>1.6.9</springdoc.version>
<mp.weixin.version>4.4.0</mp.weixin.version>
<ijpay.version>2.8.0</ijpay.version>
<groovy.version>3.0.3</groovy.version>
@@ -122,11 +124,6 @@
<artifactId>pigx-common-seata</artifactId>
<version>${pigx.version}</version>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-test</artifactId>
<version>${pigx.version}</version>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-xss</artifactId>
@@ -228,16 +225,31 @@
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--swagger 最新依赖内置版本-->
<!--springdoc -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.springboot</groupId>
<artifactId>knife4j-openapi3-ui</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.core.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.core.version}</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-security</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!--微信依赖-->
<dependency>
+1 -1
View File
@@ -68,7 +68,7 @@
</dependency>
<!--swagger 依赖-->
<dependency>
<groupId>io.swagger</groupId>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
</dependencies>
@@ -32,7 +32,7 @@ import org.springframework.context.support.ReloadableResourceBundleMessageSource
public class MessageSourceConfiguration {
@Bean
public MessageSource messageSource() {
public MessageSource pigxMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages");
return messageSource;
@@ -20,7 +20,7 @@ public class MsgUtils {
* @return
*/
public String getMessage(String code) {
MessageSource messageSource = SpringContextHolder.getBean("messageSource");
MessageSource messageSource = SpringContextHolder.getBean("pigxMessageSource");
return messageSource.getMessage(code, null, Locale.CHINA);
}
@@ -30,7 +30,7 @@ public class MsgUtils {
* @return
*/
public String getMessage(String code, Object... objects) {
MessageSource messageSource = SpringContextHolder.getBean("messageSource");
MessageSource messageSource = SpringContextHolder.getBean("pigxMessageSource");
return messageSource.getMessage(code, objects, Locale.CHINA);
}
@@ -20,8 +20,7 @@
package com.pig4cloud.pigx.common.core.util;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
@@ -38,24 +37,24 @@ import java.io.Serializable;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "响应信息主体")
@Schema(description = "响应信息主体")
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
@ApiModelProperty(value = "返回标记:成功标记=0,失败标记=1")
@Schema(description = "返回标记:成功标记=0,失败标记=1")
private int code;
@Getter
@Setter
@ApiModelProperty(value = "返回信息")
@Schema(description = "返回信息")
private String msg;
@Getter
@Setter
@ApiModelProperty(value = "数据")
@Schema(description = "数据")
private T data;
public static <T> R<T> ok() {
@@ -210,7 +210,7 @@ public class RetOps<T> {
* @throws Ex 断言失败时抛出
*/
public <Ex extends Exception> RetOps<T> assertDataNotEmpty(Function<? super R<T>, ? extends Ex> func) throws Ex {
if (ObjectUtil.isNotEmpty(original.getData())) {
if (ObjectUtil.isEmpty(original.getData())) {
throw func.apply(original);
}
return this;
@@ -2,7 +2,6 @@ package com.pig4cloud.pigx.common.datasource.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lengleng
@@ -11,7 +10,6 @@ import org.springframework.stereotype.Component;
* 参考DruidDataSourceWrapper
*/
@Data
@Component
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceProperties {
@@ -23,8 +23,6 @@ import com.pig4cloud.pigx.common.gateway.support.DynamicRouteHealthIndicator;
import com.pig4cloud.pigx.common.gateway.support.RouteCacheHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -47,15 +45,6 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class DynamicRouteAutoConfiguration {
/**
* 配置文件设置为空 redis 加载为准
* @return
*/
@Bean
public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator() {
return new PropertiesRouteDefinitionLocator(new GatewayProperties());
}
/**
* redis 监听配置
* @param redisConnectionFactory redis 配置
@@ -1,54 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.gateway.support;
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;
/**
* Ribbon 配置
*
* @author L.cm
*/
@Getter
@Setter
@RefreshScope
@ConfigurationProperties("ribbon.rule")
public class PigxRibbonRuleProperties {
/**
* 是否开启,默认:true
*/
private boolean enabled = Boolean.TRUE;
/**
* 是否开启灰度路由,默认:false
*/
private boolean grayEnabled;
/**
* 优先的ip列表,支持通配符,例如:10.20.0.8*、10.20.0.*
*/
private List<String> priorIpPattern = new ArrayList<>();
}
+51 -62
View File
@@ -19,70 +19,59 @@
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>com.pig4cloud</groupId>
<artifactId>pigx-common</artifactId>
<version>4.6.0</version>
</parent>
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>com.pig4cloud</groupId>
<artifactId>pigx-common</artifactId>
<version>4.6.0</version>
</parent>
<artifactId>pigx-common-swagger</artifactId>
<packaging>jar</packaging>
<artifactId>pigx-common-swagger</artifactId>
<packaging>jar</packaging>
<description>pigx 接口文档</description>
<description>pigx 接口文档</description>
<dependencies>
<!--接口文档-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-oas</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!--knife4j spring ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!--knife4j是为Java MVC框架集成Swagger生成Api文档的增强-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!--webflux 相关包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>provided</scope>
</dependency>
<!--网关 swagger 聚合依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencies>
<!--接口文档-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-security</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!--webflux 相关包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>provided</scope>
</dependency>
<!--网关 swagger 聚合依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-core</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
*
* 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.pig4cloud.pigx.common.swagger.annotation;
import com.pig4cloud.pigx.common.core.factory.YamlPropertySourceFactory;
import com.pig4cloud.pigx.common.swagger.config.OpenAPIDefinitionImportSelector;
import com.pig4cloud.pigx.common.swagger.support.SwaggerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import java.lang.annotation.*;
/**
* 开启 pig spring doc
*
* @author lengleng
* @date 2022-03-26
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableConfigurationProperties(SwaggerProperties.class)
@Import({ OpenAPIDefinitionImportSelector.class })
@PropertySource(value = "classpath:openapi-config.yaml", factory = YamlPropertySourceFactory.class)
public @interface EnableOpenApi {
String value() default "";
}
@@ -1,41 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.annotation;
import com.pig4cloud.pigx.common.swagger.support.SwaggerBeanDefinitionRegistrar;
import com.pig4cloud.pigx.common.swagger.support.SwaggerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.lang.annotation.*;
/**
* @author lengleng
* @date 2020/10/2 开启pigx swagger
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
@Import({ SwaggerBeanDefinitionRegistrar.class })
public @interface EnablePigxSwagger2 {
}
@@ -1,88 +0,0 @@
package com.pig4cloud.pigx.common.swagger.config;
import com.pig4cloud.pigx.common.swagger.support.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
/**
* @author lengleng
* @date 2020/10/2
* <p>
* 网关swagger 配置类,仅在webflux 环境生效哦
*/
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GatewaySwaggerAutoConfiguration {
@Bean
@Primary
public SwaggerProvider swaggerProvider(RouteDefinitionRepository repository, SwaggerProperties swaggerProperties,
DiscoveryClient discoveryClient) {
return new SwaggerProvider(repository, swaggerProperties, discoveryClient);
}
@Bean
public SwaggerResourceHandler swaggerResourceHandler(SwaggerProvider swaggerProvider) {
return new SwaggerResourceHandler(swaggerProvider);
}
@Bean
public WebFluxSwaggerConfiguration fluxSwaggerConfiguration() {
return new WebFluxSwaggerConfiguration();
}
@Bean
public SwaggerSecurityHandler swaggerSecurityHandler(
ObjectProvider<SecurityConfiguration> securityConfigurationObjectProvider) {
SecurityConfiguration securityConfiguration = securityConfigurationObjectProvider
.getIfAvailable(() -> SecurityConfigurationBuilder.builder().build());
return new SwaggerSecurityHandler(securityConfiguration);
}
@Bean
public SwaggerUiHandler swaggerUiHandler(ObjectProvider<UiConfiguration> uiConfigurationObjectProvider) {
UiConfiguration uiConfiguration = uiConfigurationObjectProvider
.getIfAvailable(() -> UiConfigurationBuilder.builder().build());
return new SwaggerUiHandler(uiConfiguration);
}
@Bean
public RouterFunction swaggerRouterFunction(SwaggerProperties swaggerProperties, SwaggerUiHandler swaggerUiHandler,
SwaggerSecurityHandler swaggerSecurityHandler, SwaggerResourceHandler swaggerResourceHandler) {
// 开启swagger 正常执行路由
if (swaggerProperties.getEnabled()) {
return RouterFunctions
.route(RequestPredicates.GET("/swagger-resources").and(RequestPredicates.accept(MediaType.ALL)),
swaggerResourceHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
}
else {
// 关闭时,返回404
return RouterFunctions
.route(RequestPredicates.GET("/*/v2/api-docs").and(RequestPredicates.accept(MediaType.ALL)),
serverRequest -> ServerResponse.notFound().build())
.andRoute(RequestPredicates.GET("/swagger-ui/**").and(RequestPredicates.accept(MediaType.ALL)),
serverRequest -> ServerResponse.notFound().build())
.andRoute(RequestPredicates.GET("/doc.html").and(RequestPredicates.accept(MediaType.ALL)),
serverRequest -> ServerResponse.notFound().build());
}
}
}
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.config;
import com.pig4cloud.pigx.common.swagger.support.SwaggerProperties;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.Scopes;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpHeaders;
import java.util.ArrayList;
import java.util.List;
/**
* swagger配置
*
* <p>
* 禁用方法1:使用注解@Profile({"dev","test"})
*
* 表示在开发或测试环境开启,而在生产关闭。(推荐使用) 禁用方法2:使用注解@ConditionalOnProperty(name = "swagger.enable",
*
* havingValue = "true") 然后在测试配置或者开发配置中添加swagger.enable=true即可开启,生产环境不填则默认关闭Swagger.
* </p>
*
* @author lengleng
*/
@RequiredArgsConstructor
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public class OpenAPIDefinition extends OpenAPI implements InitializingBean, ApplicationContextAware {
@Setter
private String path;
private ApplicationContext applicationContext;
private SecurityScheme securityScheme(SwaggerProperties swaggerProperties) {
OAuthFlow clientCredential = new OAuthFlow();
clientCredential.setTokenUrl(swaggerProperties.getTokenUrl());
clientCredential.setScopes(new Scopes().addString(swaggerProperties.getScope(), swaggerProperties.getScope()));
OAuthFlows oauthFlows = new OAuthFlows();
oauthFlows.password(clientCredential);
SecurityScheme securityScheme = new SecurityScheme();
securityScheme.setType(SecurityScheme.Type.OAUTH2);
securityScheme.setFlows(oauthFlows);
return securityScheme;
}
@Override
public void afterPropertiesSet() throws Exception {
SwaggerProperties swaggerProperties = applicationContext.getBean(SwaggerProperties.class);
this.info(new Info().title(swaggerProperties.getTitle()));
// oauth2.0 password
this.schemaRequirement(HttpHeaders.AUTHORIZATION, this.securityScheme(swaggerProperties));
// servers
List<Server> serverList = new ArrayList<>();
serverList.add(new Server().url(swaggerProperties.getGateway() + "/" + path));
this.servers(serverList);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
@@ -0,0 +1,45 @@
package com.pig4cloud.pigx.common.swagger.config;
import com.pig4cloud.pigx.common.swagger.annotation.EnableOpenApi;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import java.util.Objects;
/**
* openapi 配置类
*
* @author lengleng
* @date 2023/1/1
*/
public class OpenAPIDefinitionImportSelector implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableOpenApi.class.getName(),
true);
Object value = annotationAttributes.get("value");
if (Objects.isNull(value)) {
return;
}
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(OpenAPIDefinition.class);
definition.addPropertyValue("path", value);
registry.registerBeanDefinition("openAPIDefinition", definition.getBeanDefinition());
// 如果是微服务架构则,引入了服务发现声明相关的元数据配置
boolean isMicro = registry.containsBeanDefinition("serviceInstance");
if (isMicro) {
BeanDefinitionBuilder openAPIMetadata = BeanDefinitionBuilder
.genericBeanDefinition(OpenAPIMetadataConfiguration.class);
openAPIMetadata.addPropertyValue("path", value);
registry.registerBeanDefinition("openAPIMetadata", openAPIMetadata.getBeanDefinition());
}
}
}
@@ -0,0 +1,32 @@
package com.pig4cloud.pigx.common.swagger.config;
import lombok.Setter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @author lengleng
* @date 2023/1/4
*/
public class OpenAPIMetadataConfiguration implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
@Setter
private String path;
@Override
public void afterPropertiesSet() throws Exception {
ServiceInstance serviceInstance = applicationContext.getBean(ServiceInstance.class);
serviceInstance.getMetadata().put("spring-doc", path);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
@@ -1,182 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.config;
import com.pig4cloud.pigx.common.swagger.support.SwaggerProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author lengleng swagger配置 禁用方法1:使用注解@Profile({"dev","test"})
* 表示在开发或测试环境开启,而在生产关闭。(推荐使用) 禁用方法2:使用注解@ConditionalOnProperty(name = "swagger.enable",
* havingValue = "true") 然后在测试配置或者开发配置中添加swagger.enable=true即可开启,生产环境不填则默认关闭Swagger.
*/
@Configuration
@EnableAutoConfiguration
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class SwaggerAutoConfiguration {
/**
* 默认的排除路径,排除Spring Boot默认的错误处理路径和端点
*/
private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
private static final String BASE_PATH = "/**";
private final SwaggerProperties swaggerProperties;
@Bean
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public Docket api() {
// base-path处理
if (swaggerProperties.getBasePath().isEmpty()) {
swaggerProperties.getBasePath().add(BASE_PATH);
}
// exclude-path处理
if (swaggerProperties.getExcludePath().isEmpty()) {
swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
}
List<Predicate<String>> excludePath = new ArrayList<>();
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
// 版本请求头处理
List<RequestParameter> pars = new ArrayList<>();
RequestParameterBuilder versionPar = new RequestParameterBuilder().description("灰度路由版本信息")
.in(ParameterType.HEADER).name("VERSION").required(false)
.query(param -> param.model(model -> model.scalarModel(ScalarType.STRING)));
pars.add(versionPar.build());
ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost())
.apiInfo(apiInfo(swaggerProperties)).globalRequestParameters(pars).select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));
swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
return builder.build().securitySchemes(Collections.singletonList(securitySchema()))
.securityContexts(Collections.singletonList(securityContext())).pathMapping("/");
}
/**
* 配置默认的全局鉴权策略的开关,通过正则表达式进行匹配;默认匹配所有URL
* @return
*/
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(defaultAuth()).build();
}
/**
* 默认的全局鉴权策略
* @return
*/
private List<SecurityReference> defaultAuth() {
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
swaggerProperties.getAuthorization().getAuthorizationScopeList()
.forEach(authorizationScope -> authorizationScopeList.add(
new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
return Collections
.singletonList(SecurityReference.builder().reference(swaggerProperties.getAuthorization().getName())
.scopes(authorizationScopeList.toArray(authorizationScopes)).build());
}
private OAuth securitySchema() {
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
swaggerProperties.getAuthorization().getAuthorizationScopeList()
.forEach(authorizationScope -> authorizationScopeList.add(
new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
ArrayList<GrantType> grantTypes = new ArrayList<>();
swaggerProperties.getAuthorization().getTokenUrlList()
.forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
return new OAuth(swaggerProperties.getAuthorization().getName(), authorizationScopeList, grantTypes);
}
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
return new ApiInfoBuilder().title(swaggerProperties.getTitle()).description(swaggerProperties.getDescription())
.license(swaggerProperties.getLicense()).licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(),
swaggerProperties.getContact().getEmail()))
.version(swaggerProperties.getVersion()).build();
}
@Bean
public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(
List<T> mappings) {
List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
}
@@ -1,21 +0,0 @@
package com.pig4cloud.pigx.common.swagger.config;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
/**
* @author lengleng
* @date 2020/10/2
* <p>
* webflux 网关 swagger 资源路径配置
*/
public class WebFluxSwaggerConfiguration implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
}
@@ -1,37 +0,0 @@
package com.pig4cloud.pigx.common.swagger.support;
import com.pig4cloud.pigx.common.swagger.config.GatewaySwaggerAutoConfiguration;
import com.pig4cloud.pigx.common.swagger.config.SwaggerAutoConfiguration;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* @author lengleng
* @date 2022/6/28
*/
public class SwaggerBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 根据注解值动态注入资源服务器的相关属性
* @param metadata 注解信息
* @param registry 注册器
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// swagger 功能依赖系统的动态路由,需要读取路由表中的参数
if (registry.isBeanNameInUse("com.pig4cloud.pigx.common.gateway.configuration.DynamicRouteAutoConfiguration")) {
GenericBeanDefinition gatewaySwagger = new GenericBeanDefinition();
gatewaySwagger.setBeanClass(GatewaySwaggerAutoConfiguration.class);
registry.registerBeanDefinition(GatewaySwaggerAutoConfiguration.class.getSimpleName(), gatewaySwagger);
}
else {
GenericBeanDefinition swaggerAutoConfiguration = new GenericBeanDefinition();
swaggerAutoConfiguration.setBeanClass(SwaggerAutoConfiguration.class);
registry.registerBeanDefinition(SwaggerAutoConfiguration.class.getSimpleName(), swaggerAutoConfiguration);
}
}
}
@@ -17,21 +17,19 @@
package com.pig4cloud.pigx.common.swagger.support;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* SwaggerProperties
*
* @author: lengleng
* @date: 2018/7/25 14:00
* @author lengleng
* @date 2018/7/25 14:00
*/
@Data
@Component
@ConfigurationProperties("swagger")
public class SwaggerProperties {
@@ -66,103 +64,23 @@ public class SwaggerProperties {
private String title = "";
/**
* 描述
**/
private String description = "";
/**
* 版本
**/
private String version = "";
/**
* 许可证
**/
private String license = "";
/**
* 许可证URL
**/
private String licenseUrl = "";
/**
* 服务条款URL
**/
private String termsOfServiceUrl = "";
/**
* host信息
**/
private String host = "";
/**
* 联系人信息
* 网关
*/
private Contact contact = new Contact();
private String gateway;
/**
* 全局统一鉴权配置
**/
private Authorization authorization = new Authorization();
* 获取token
*/
private String tokenUrl;
@Data
@NoArgsConstructor
public static class Contact {
/**
* 作用域
*/
private String scope;
/**
* 联系人
**/
private String name = "";
/**
* 联系人url
**/
private String url = "";
/**
* 联系人email
**/
private String email = "";
}
@Data
@NoArgsConstructor
public static class Authorization {
/**
* 鉴权策略ID,需要和SecurityReferences ID保持一致
*/
private String name = "";
/**
* 需要开启鉴权URL的正则
*/
private String authRegex = "^.*$";
/**
* 鉴权作用域列表
*/
private List<AuthorizationScope> authorizationScopeList = new ArrayList<>();
private List<String> tokenUrlList = new ArrayList<>();
}
@Data
@NoArgsConstructor
public static class AuthorizationScope {
/**
* 作用域名称
*/
private String scope = "";
/**
* 作用域描述
*/
private String description = "";
}
/**
* 服务转发配置
*/
private Map<String, String> services;
}
@@ -1,76 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.support;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NameUtils;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Sywd 聚合接口文档注册,和zuul实现类似
*/
@RequiredArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
private static final String API_URI = "/v2/api-docs";
private final RouteDefinitionRepository routeDefinitionRepository;
private final SwaggerProperties swaggerProperties;
private final DiscoveryClient discoveryClient;
@Override
public List<SwaggerResource> get() {
List<RouteDefinition> routes = new ArrayList<>();
routeDefinitionRepository.getRouteDefinitions()
// swagger 显示服务名称根据 路由的order 字段进行升序排列
.sort(Comparator.comparingInt(RouteDefinition::getOrder)).subscribe(routes::add);
return routes.stream()
.flatMap(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
.filter(predicateDefinition -> !swaggerProperties.getIgnoreProviders()
.contains(routeDefinition.getId()))
.map(predicateDefinition -> swaggerResource(routeDefinition.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**",
API_URI))))
// 只显示注册中心 内已经正确启动的服务
.filter(swaggerResource -> discoveryClient.getServices().stream()
.anyMatch(s -> s.equals(swaggerResource.getName())))
.collect(Collectors.toList());
}
private static SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.support;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
/**
* @author lengleng
* @date 2018-07-19 SwaggerResourceHandler
*/
@Slf4j
@AllArgsConstructor
public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {
private final SwaggerResourcesProvider swaggerResources;
/**
* Handle the given request.
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(swaggerResources.get()));
}
}
@@ -1,54 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.support;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import java.util.Optional;
/**
* @author lengleng
* @date 2018-07-19 SwaggerSecurityHandler
*/
@RequiredArgsConstructor
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {
private final SecurityConfiguration securityConfiguration;
/**
* Handle the given request.
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(Optional.ofNullable(securityConfiguration)
.orElse(SecurityConfigurationBuilder.builder().build())));
}
}
@@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng 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 pig4cloud.com 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: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.swagger.support;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import java.util.Optional;
/**
* @author lengleng
* @date 2018-07-19 SwaggerUiHandler
*/
@Slf4j
@RequiredArgsConstructor
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {
private final UiConfiguration uiConfiguration;
/**
* Handle the given request.
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters
.fromValue(Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build())));
}
}
@@ -0,0 +1,7 @@
# swagger 配置
swagger:
enabled: true
title: PigX Swagger API
gateway: http://${GATEWAY-HOST:pigx-gateway}:${GATEWAY-PORT:9999}
token-url: ${swagger.gateway}/auth/oauth2/token
scope: server