1. 引入swagger

2. swagger Admin 聚合
This commit is contained in:
b2baccline
2019-11-17 17:53:03 +08:00
parent 83eb5159e4
commit 30688e3c8c
23 changed files with 549 additions and 22 deletions

View File

@@ -29,7 +29,17 @@
<groupId>com.hccake</groupId> <groupId>com.hccake</groupId>
<artifactId>ballcat-common-log</artifactId> <artifactId>ballcat-common-log</artifactId>
</dependency> </dependency>
<!-- swagger 文档聚合 -->
<dependency>
<groupId>com.hccake</groupId>
<artifactId>ballcat-common-swagger</artifactId>
</dependency>
<!-- swagger 增强版 ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!--mybatis plus--> <!--mybatis plus-->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
@@ -60,11 +70,7 @@
<groupId>org.springframework.security.oauth</groupId> <groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId> <artifactId>spring-security-oauth2</artifactId>
</dependency> </dependency>
<!--swagger-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
</dependency>
<!--监控Client--> <!--监控Client-->
<dependency> <dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>

View File

@@ -9,6 +9,7 @@ import org.springframework.boot.web.servlet.ServletComponentScan;
* @author Hccake * @author Hccake
*/ */
/*@EnableXxlJob*/ /*@EnableXxlJob*/
/*@EnableSwagger2Aggregator*/
@EnableAccessLog @EnableAccessLog
@ServletComponentScan("com.hccake.ballcat.admin.oauth.filter") @ServletComponentScan("com.hccake.ballcat.admin.oauth.filter")
@SpringBootApplication @SpringBootApplication

View File

@@ -49,8 +49,13 @@ public class CustomResourceServerConfigurer extends ResourceServerConfigurerAdap
http http
// 拦截 url 配置 // 拦截 url 配置
.authorizeRequests() .authorizeRequests()
// TODO Actuator权限控制
.antMatchers("/actuator/**").permitAll() .antMatchers("/actuator/**").permitAll()
.antMatchers("/doc.html").permitAll()
.antMatchers("/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**",
"favicon.ico").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()

View File

@@ -6,4 +6,8 @@ spring:
redis: redis:
host: ballcat-redis host: ballcat-redis
password: '' password: ''
port: 6379 port: 6379
# 生产环境关闭文档
swagger:
enabled: false

View File

@@ -6,12 +6,12 @@ spring:
name: @artifactId@ name: @artifactId@
profiles: profiles:
active: @profiles.active@ # 当前激活配置默认dev active: @profiles.active@ # 当前激活配置默认dev
boot: # boot:
admin: # admin:
client: # client:
url: http://ballcat-monitor:9999 # url: http://ballcat-monitor:9999
username: admin # username: admin
password: 123456 # password: 123456
# 暴露监控端口 # 暴露监控端口
management: management:
@@ -48,3 +48,20 @@ monitor:
# port: 7888 #通讯端口 # port: 7888 #通讯端口
# appName: ballcat-admin-job # appName: ballcat-admin-job
swagger:
title: BallCat-Admin Docs
group-name: ballcat-admin
description: BallCat 后台管理服务Api文档
version: 0.0.1
license: Powered By BallCat
licenseUrl: http://www.ballcat.cn/
terms-of-service-url: http://www.ballcat.cn/
contact:
name: Hccake
email: chengbohua@foxmail.com
url: https://github.com/Hccake
provider:
resources:
- {name: ballcat-api, url: http://ballcat-api:9090/v2/api-docs, swagger-version: 2.0}

View File

@@ -33,6 +33,10 @@
<groupId>com.hccake</groupId> <groupId>com.hccake</groupId>
<artifactId>ballcat-common-log</artifactId> <artifactId>ballcat-common-log</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.hccake</groupId>
<artifactId>ballcat-common-swagger</artifactId>
</dependency>
<!--webmvc--> <!--webmvc-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -59,6 +63,8 @@
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency> </dependency>
<!-- spring-security oauth --> <!-- spring-security oauth -->
<!-- <dependency> <!-- <dependency>
<groupId>org.springframework.security.oauth</groupId> <groupId>org.springframework.security.oauth</groupId>

View File

@@ -1,11 +1,14 @@
package com.hccake.ballcat.api; package com.hccake.ballcat.api;
import com.hccake.ballcat.commom.log.access.annotation.EnableAccessLog; import com.hccake.ballcat.commom.log.access.annotation.EnableAccessLog;
import com.hccake.ballcat.common.job.annotation.EnableXxlJob; import com.hccake.ballcat.common.swagger.annotation.EnableSwagger2Provider;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
/*
@EnableXxlJob @EnableXxlJob
*/
@EnableSwagger2Provider
@EnableAccessLog @EnableAccessLog
@SpringBootApplication @SpringBootApplication
public class ApiApplication { public class ApiApplication {

View File

@@ -1,6 +1,7 @@
package com.hccake.ballcat.api.modules.api.controller; package com.hccake.ballcat.api.modules.api.controller;
import com.hccake.ballcat.common.core.exception.BallCatException; import com.hccake.ballcat.common.core.exception.BallCatException;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.time.LocalDate; import java.time.LocalDate;
@@ -16,6 +17,7 @@ import java.time.LocalDateTime;
public class TestController { public class TestController {
@ApiOperation("测试地址")
@PostMapping("/test") @PostMapping("/test")
public String test(){ public String test(){
return "Hello word!"; return "Hello word!";

View File

@@ -8,3 +8,6 @@ spring:
password: '' password: ''
port: 6379 port: 6379
# 生产环境关闭文档
swagger:
enabled: false

View File

@@ -45,3 +45,19 @@ password:
# executor: # executor:
# port: 6888 #通讯端口 # port: 6888 #通讯端口
# appName: ballcat-api-job # appName: ballcat-api-job
swagger:
title: BallCat-Api Docs
description: BallCat 业务接口服务Api文档
version: 0.0.1
license: Powered By BallCat
licenseUrl: http://www.ballcat.cn/
terms-of-service-url: http://www.ballcat.cn/
host: http://localhost:9090
contact:
name: Hccake
email: chengbohua@foxmail.com
url: https://github.com/Hccake
aggregator:
origin: http://ballcat-admin:8080

View File

@@ -3,7 +3,6 @@ package com.hccake.ballcat.common.job;
import com.hccake.ballcat.common.job.properties.XxlJobProperties; import com.hccake.ballcat.common.job.properties.XxlJobProperties;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -17,7 +16,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@EnableAutoConfiguration @EnableAutoConfiguration
@ComponentScan("com.hccake.ballcat.common.job.properties") @ComponentScan("com.hccake.ballcat.common.job.properties")
@EnableConfigurationProperties(XxlJobAutoConfiguration.class)
public class XxlJobAutoConfiguration { public class XxlJobAutoConfiguration {
@Bean(initMethod = "start", destroyMethod = "destroy") @Bean(initMethod = "start", destroyMethod = "destroy")

View File

@@ -0,0 +1,34 @@
<?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>ballcat-common</artifactId>
<groupId>com.hccake</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ballcat-common-swagger</artifactId>
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,63 @@
package com.hccake.ballcat.common.swagger;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
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.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.util.CollectionUtils;
import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 20:03
*/
@Configuration
@EnableAutoConfiguration
@Import(SwaggerConfiguration.class)
@ConditionalOnProperty(name = "swagger.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerAggregatorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SwaggerProviderProperties swaggerProviderProperties() {
return new SwaggerProviderProperties();
}
/**
* 聚合文档
*
* @param defaultResourcesProvider
* @return
*/
@Primary
@Bean
public SwaggerResourcesProvider swaggerResourcesProvider(
InMemorySwaggerResourcesProvider defaultResourcesProvider,
SwaggerProviderProperties swaggerProviderProperties) {
return () -> {
// 聚合者自己的 Resources
List<SwaggerResource> resources = new ArrayList<>(defaultResourcesProvider.get());
// 提供者的 Resources
List<SwaggerResource> providerResources = swaggerProviderProperties.getResources();
if (!CollectionUtils.isEmpty(providerResources)){
resources.addAll(providerResources);
}
return resources;
};
}
}

View File

@@ -0,0 +1,94 @@
package com.hccake.ballcat.common.swagger;
import io.swagger.annotations.ApiOperation;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 19:43
*/
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
@ConditionalOnMissingBean
public SwaggerProperties swaggerProperties() {
return new SwaggerProperties();
}
@Bean
public Docket api(SwaggerProperties swaggerProperties) {
return new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost())
.apiInfo(apiInfo(swaggerProperties))
.groupName(swaggerProperties.getGroupName())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.build()
.securitySchemes(Collections.singletonList(securitySchema()))
.securityContexts(Collections.singletonList(securityContext()))
.pathMapping("/");
}
/**
* 配置默认的全局鉴权策略的开关通过正则表达式进行匹配默认匹配所有URL
*
* @return
*/
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
.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();
}
}

View File

@@ -0,0 +1,27 @@
package com.hccake.ballcat.common.swagger;
import java.util.Arrays;
import java.util.List;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 20:03
*/
public final class SwaggerConstants {
private SwaggerConstants(){}
/**
* 默认的排除路径排除Spring Boot默认的错误处理路径和端点
*/
public static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
/**
* 默认扫描路径
*/
public static final String BASE_PATH = "/**";
/**
* 默认的文档提供路径
*/
public static final String API_URI = "/v2/api-docs";
}

View File

@@ -0,0 +1,131 @@
package com.hccake.ballcat.common.swagger;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 19:37
*/
@Data
@ConfigurationProperties("swagger")
public class SwaggerProperties {
/**
* 是否开启swagger
*/
private Boolean enabled;
/**
* 分组名称
*/
private String groupName;
/**
* swagger会解析的包路径
**/
private String basePackage = "";
/**
* swagger会解析的url规则
**/
private List<String> basePath = new ArrayList<>();
/**
* 在basePath基础上需要排除的url规则
**/
private List<String> excludePath = new ArrayList<>();
/**
* 标题
**/
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 Authorization authorization = new Authorization();
@Data
@NoArgsConstructor
public static class Contact {
/**
* 联系人
**/
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 = "";
}
}

View File

@@ -0,0 +1,48 @@
package com.hccake.ballcat.common.swagger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 20:03
*/
@Configuration
@EnableAutoConfiguration
@Import(SwaggerConfiguration.class)
@ConditionalOnProperty(name = "swagger.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerProviderAutoConfiguration {
@Value("${swagger.aggregator.origin: http://localhost:8080}")
private String aggregatorOrigin;
/**
* 允许swagger文档跨域访问
* 解决聚合文档导致的跨域问题
* @return
*/
@Bean
@ConditionalOnMissingBean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedOrigin(aggregatorOrigin);
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}

View File

@@ -0,0 +1,23 @@
package com.hccake.ballcat.common.swagger;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import springfox.documentation.swagger.web.SwaggerResource;
import java.util.ArrayList;
import java.util.List;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 20:05
*/
@Data
@ConfigurationProperties("swagger.provider")
public class SwaggerProviderProperties {
/**
* 聚合文档源信息
*/
private List<SwaggerResource> resources = new ArrayList<>();
}

View File

@@ -0,0 +1,20 @@
package com.hccake.ballcat.common.swagger.annotation;
import com.hccake.ballcat.common.swagger.SwaggerAggregatorAutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 19:43
* 聚合者的swagger开启注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({SwaggerAggregatorAutoConfiguration.class})
public @interface EnableSwagger2Aggregator {
}

View File

@@ -0,0 +1,20 @@
package com.hccake.ballcat.common.swagger.annotation;
import com.hccake.ballcat.common.swagger.SwaggerProviderAutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @author Hccake
* @version 1.0
* @date 2019/11/1 19:43
* 聚合者的swagger开启注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({SwaggerProviderAutoConfiguration.class})
public @interface EnableSwagger2Provider {
}

View File

@@ -19,6 +19,7 @@
<module>ballcat-common-log</module> <module>ballcat-common-log</module>
<module>ballcat-common-conf</module> <module>ballcat-common-conf</module>
<module>ballcat-common-job</module> <module>ballcat-common-job</module>
<module>ballcat-common-swagger</module>
</modules> </modules>

View File

@@ -22,6 +22,13 @@ public class AuthHeaderProvider implements HttpHeadersProvider {
private String secretKey; private String secretKey;
/**
* 当授权中心剥离时目前BallCat的设计是简单启动
* 所以不做独立的授权中心,在此记录下拓展使用方式
* 可以考虑 client_credentials 客户端授权模式
* @param instance
* @return
*/
@Override @Override
public HttpHeaders getHeaders(Instance instance) { public HttpHeaders getHeaders(Instance instance) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();

View File

@@ -32,7 +32,6 @@
<hutool.version>5.0.1</hutool.version> <hutool.version>5.0.1</hutool.version>
<mybatis-plus.version>3.2.0</mybatis-plus.version> <mybatis-plus.version>3.2.0</mybatis-plus.version>
<simple-cache.version>0.0.4</simple-cache.version> <simple-cache.version>0.0.4</simple-cache.version>
<swagger-start.version>1.9.0.RELEASE</swagger-start.version>
<swagger.core.version>1.5.2</swagger.core.version> <swagger.core.version>1.5.2</swagger.core.version>
<xxl-job.version>2.1.0</xxl-job.version> <xxl-job.version>2.1.0</xxl-job.version>
<spring-security.version>5.1.6.RELEASE</spring-security.version> <spring-security.version>5.1.6.RELEASE</spring-security.version>
@@ -98,11 +97,10 @@
<artifactId>ballcat-common-modules</artifactId> <artifactId>ballcat-common-modules</artifactId>
<version>${ballcat.version}</version> <version>${ballcat.version}</version>
</dependency> </dependency>
<!--swagger封装-->
<dependency> <dependency>
<groupId>com.spring4all</groupId> <groupId>com.hccake</groupId>
<artifactId>swagger-spring-boot-starter</artifactId> <artifactId>ballcat-common-swagger</artifactId>
<version>${swagger-start.version}</version> <version>${ballcat.version}</version>
</dependency> </dependency>
<!--swagger注解--> <!--swagger注解-->
<dependency> <dependency>