📝 swagger ui -> springdoc openapi ui 변경

This commit is contained in:
shinmj
2021-11-08 09:48:36 +09:00
parent c50df972e9
commit 043bfb8ef6
21 changed files with 279 additions and 446 deletions

View File

@@ -29,8 +29,7 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.8'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

View File

@@ -1,70 +0,0 @@
package org.egovframe.cloud.apigateway.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
/**
* org.egovframe.cloud.apigateway.api.SwaggerResourcesController
*
* Swagger resource 들을 모으는 controller class
*
* @author 표준프레임워크센터 shinmj
* @version 1.0
* @since 2021/07/07
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/07/07 shinmj 최초 생성
* </pre>
*/
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerResourcesController {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerResourcesController(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
HttpStatus.OK
));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()),
HttpStatus.OK
));
}
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just(new ResponseEntity(
swaggerResources.get(), HttpStatus.OK
));
}
}

View File

@@ -36,7 +36,7 @@ import java.nio.file.Paths;
@Configuration
public class MessageSourceConfig {
@Value("${messages.directory:${user.home}/msa-attach-volume/messages}")
@Value("${messages.directory}")
private String messagesDirectory;
@Value("${spring.profiles.active:default}")

View File

@@ -0,0 +1,30 @@
package org.egovframe.cloud.apigateway.config;
import java.util.ArrayList;
import java.util.List;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SwaggerUiConfigParameters;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Configuration
public class OpenApiDocConfig {
@Bean
@Lazy(false)
public List<GroupedOpenApi> apis(SwaggerUiConfigParameters swaggerUiConfigParameters, RouteDefinitionLocator locator) {
List<GroupedOpenApi> groups = new ArrayList<>();
List<RouteDefinition> definitions = locator.getRouteDefinitions().log("OpenApiDocConfig").collectList().block();
definitions.stream().filter(routeDefinition -> routeDefinition.getId().matches(".*-service")).forEach(routeDefinition -> {
String name = routeDefinition.getId();
swaggerUiConfigParameters.addGroup(name);
GroupedOpenApi.builder().pathsToMatch("/" + name + "/**").group(name).build();
});
return groups;
}
}

View File

@@ -1,78 +0,0 @@
package org.egovframe.cloud.apigateway.config;
import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* org.egovframe.cloud.apigateway.config.SwaggerProvider
*
* Swagger API Doc aggregator class
* Swagger Resource인 api-docs를 가져오는 provider
*
* @author 표준프레임워크센터 shinmj
* @version 1.0
* @since 2021/07/07
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/07/07 shinmj 최초 생성
* </pre>
*/
@AllArgsConstructor
@Component
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider {
public static final String API_URL = "/v2/api-docs";
public static final String WEBFLUX_API_URL = "/v3/api-docs";
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream()
.filter(routeDefinition -> routes.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition ->
resources.add(
swaggerResource(routeDefinition.getId(),
predicateDefinition.
getArgs().
get(NameUtils.GENERATED_NAME_PREFIX+"0").
replace("/**", API_URL))))
);
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
if (name.contains("reserve")) {
swaggerResource.setLocation(location.replace(API_URL, WEBFLUX_API_URL));
}else {
swaggerResource.setLocation(location);
}
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}

View File

@@ -35,7 +35,7 @@ public class WebFluxSecurityConfig {
ReactiveAuthorization.AUTHORIZATION_URI, "/", "/csrf",
"/user-service/login", "/?*-service/api/v1/messages/**", "/api/v1/messages/**",
"/?*-service/actuator/?*", "/actuator/?*",
"/?*-service/v2/api-docs", "/?*-service/v3/api-docs", "**/configuration/*", "/swagger*/**", "/webjars/**"
"/v3/api-docs/**", "/?*-service/v3/api-docs", "**/configuration/*", "/swagger*/**", "/webjars/**"
};
private final static String USER_JOIN_ANTPATTERNS = "/user-service/api/v1/users";

View File

@@ -1,49 +0,0 @@
package org.egovframe.cloud.apigateway.filter;
import org.egovframe.cloud.apigateway.config.SwaggerProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
/**
* org.egovframe.cloud.apigateway.filter.SwaggerHeaderFilter
*
* Swagger header filter class
* 각 서비스 명을 붙여서 호출 할 수 있도록 filter를 추가 한다.
*
* @author 표준프레임워크센터 shinmj
* @version 1.0
* @since 2021/07/07
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/07/07 shinmj 최초 생성
* </pre>
*/
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URL)) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URL));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}

View File

@@ -14,42 +14,42 @@ spring:
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: portal-service
uri: lb://PORTAL-SERVICE
predicates:
- Path=/portal-service/**
filters:
- RewritePath=/portal-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: board-service
uri: lb://BOARD-SERVICE
predicates:
- Path=/board-service/**
filters:
- RewritePath=/board-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: reserve-item-service
uri: lb://RESERVE-ITEM-SERVICE
predicates:
- Path=/reserve-item-service/**
filters:
- RewritePath=/reserve-item-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: reserve-check-service
uri: lb://RESERVE-CHECK-SERVICE
predicates:
- Path=/reserve-check-service/**
filters:
- RewritePath=/reserve-check-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: reserve-request-service
uri: lb://RESERVE-REQUEST-SERVICE
predicates:
- Path=/reserve-request-service/**
filters:
- RewritePath=/reserve-request-service/(?<segment>.*), /$\{segment}
- SwaggerHeaderFilter
- id: openapi
uri: http://localhost:${server.port}
predicates:
- Path=/v3/api-docs/**
filters:
- RewritePath=/v3/api-docs/(?<segment>.*), /$\{segment}/v3/api-docs
default-filters:
- name: GlobalFilter
args:

View File

@@ -54,9 +54,8 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-stream'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
// swagger
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webmvc-core:1.5.8'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
// lombok

View File

@@ -11,7 +11,7 @@ spring:
server:
native:
search-locations: ${search.location:file:///${user.home}/workspace.edu/egovframe-msa-edu/config} # Windows
# search-locations: file://${user.home}/workspace.edu/egovframe-msa-edu/config # MacOS
# search-locations: file://${user.home}/workspace.edu/egovframe-msa-edu/config # MacOS
rabbitmq:
host: localhost
port: 5672

View File

@@ -38,6 +38,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/actuator/?*").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();

View File

@@ -56,9 +56,8 @@ dependencies {
// querydsl
implementation 'com.querydsl:querydsl-jpa'
// swagger
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webmvc-core:1.5.8'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
// lombok

View File

@@ -37,6 +37,7 @@ import org.springframework.test.context.TestPropertySource;
@ActiveProfiles(profiles = "test")
class MenuApiControllerTest {
@Autowired
private TestRestTemplate restTemplate;

View File

@@ -30,6 +30,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableConfigurationProperties
@@ -37,6 +38,7 @@ import org.springframework.test.context.TestPropertySource;
@ActiveProfiles(profiles = "test")
class MenuRoleApiControllerTest {
@Autowired
private TestRestTemplate restTemplate;

View File

@@ -5,12 +5,15 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.egovframe.cloud.portalservice.api.statistics.dto.StatisticsResponseDto;
import org.egovframe.cloud.portalservice.domain.statistics.Statistics;
import org.egovframe.cloud.portalservice.domain.statistics.StatisticsRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
@@ -85,5 +88,4 @@ class StatisticsApiControllerTest {
assertThat(responseEntity.getBody().get(0).getY()).isEqualTo(10);
}
}

View File

@@ -48,19 +48,18 @@ dependencies {
//messaging
implementation 'org.springframework.cloud:spring-cloud-stream'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
// implementation 'net.java.dev.jna:jna:5.9.0' // byte-buddy (No compatible attachment provider is available.)
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE'
implementation 'mysql:mysql-connector-java'
// swagger api docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.10'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.8'
// bolcking 호출 감지
// implementation 'io.projectreactor:reactor-tools:3.4.9'
// implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
implementation 'io.projectreactor:reactor-tools:3.4.9'
implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
//lombok
implementation 'org.projectlombok:lombok'

View File

@@ -41,26 +41,25 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j'
implementation 'com.playtika.reactivefeign:feign-reactor-spring-cloud-starter:3.1.0'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation 'org.springframework.cloud:spring-cloud-sleuth-zipkin'
implementation 'net.logstash.logback:logstash-logback-encoder:6.6' // logstash logback
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE'
implementation 'mysql:mysql-connector-java'
// swagger api docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.10'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.8'
// bolcking 호출 감지
// implementation 'io.projectreactor:reactor-tools:3.4.9'
// implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
implementation 'io.projectreactor:reactor-tools:3.4.9'
implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
//messaging
implementation 'org.springframework.cloud:spring-cloud-stream'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
// implementation 'net.java.dev.jna:jna:5.9.0' // byte-buddy (No compatible attachment provider is available.)
//lombok
implementation 'org.projectlombok:lombok'

View File

@@ -50,7 +50,6 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-stream'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
// implementation 'net.java.dev.jna:jna:5.9.0' // byte-buddy (No compatible attachment provider is available.)
implementation 'io.jsonwebtoken:jjwt:0.9.1'
@@ -58,12 +57,12 @@ dependencies {
implementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE'
implementation 'mysql:mysql-connector-java'
// swagger api docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.10'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.5.8'
// bolcking 호출 감지
// implementation 'io.projectreactor:reactor-tools:3.4.9'
// implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
implementation 'io.projectreactor:reactor-tools:3.4.9'
implementation 'io.projectreactor.tools:blockhound:1.0.6.RELEASE'
//lombok
implementation 'org.projectlombok:lombok'

View File

@@ -56,9 +56,8 @@ dependencies {
implementation 'com.google.api-client:google-api-client:1.32.1'
// swagger
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
// openapi docs
implementation 'org.springdoc:springdoc-openapi-webmvc-core:1.5.8'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
// lombok

View File

@@ -14,6 +14,7 @@ services:
- --collation-server=utf8mb4_unicode_ci
volumes:
- "./init/:/docker-entrypoint-initdb.d/"
platform: linux/x86_64 #m1에서 플랫폼을 명시해주지 않으면 에러남
ports:
- "3306:3306"
container_name: mysql