0. Swagger
- Swagger 는 Java, Spring 전용 프레임워크가 아닌 OAS(OpenAPI Specification)를 위한 프레임워크
- Spring 환경에서 Swagger 를 사용하려면 Swagger UI의 설정, Swagger 어노테이션으로 API 메타데이터를 읽는 과정 등을 직접 구현해줘야 함
- 이런 작업을 대신해주는 라이브러리, SpringDoc 또는 SpringFox 를 사용
- SpringDoc과 SpringFox : Swagger UI를 만들고, Swagger 어노테이션을 유저가 쓰기 쉽게 제공하는 라이브러리
- SpringFox는 2020년 이후로 업데이트를 멈춘 반면, SpringDoc은 최근까지도 계속 업데이트를 진행
- 1-2. 번 + 1-2-2. 번 Swagger Springfox 세팅으로 진행하였음
1. pom.xml
- pom.xml 파일을 계속 수정하므로, 아래 절차를 모두 수행하고 나는 오류를 확인해야 함
Maven Clean
> Maven Install
> Update Project
> Project Clean
> Build
1-1. Swagger Springdoc 세팅
- Springdoc 사용을 위해 아래 의존성 추가
implementation("org.springdoc:springdoc-openapi-ui:1.6.11")
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.11</version>
</dependency>
- Spring Boot 3부터는 위의 의존성 라이브러리 추가 후 Swagger UI 접속 시, 404 에러가 발생하기 때문에 다음 코드를 추가해야 함
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2")
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
1-2. Swagger Springfox 세팅
- Springfox 사용을 위해 아래 의존성 추가
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
1-2-1. Swagger Springfox 세팅
- 위의 의존성으로 되지 않으면 아래 의존성으로 변경
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
1-2-2. java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ObjectMapper
pom.xml
에 아래 내용 추가 (오류 발생 시에만 진행)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.5.1</version>
<scope>compile</scope>
</dependency>
- 5-1. 5-2. 7-3. 등의 오류가 발생하면 버전 문제일 가능성이 큼
<version>2.9.9</version>
-> <version>2.0.0</version>
으로 변경
- Swagger 버전도
2.9.2
> 2.5.0
로 변경!!
1-2-3. Caused by: java.lang.ClassNotFoundException
2. SwaggerConfig.java 설정
2-1. springfox 2.9.2 버전용
package egovframework.com.cmm;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableWebMvc
public class SwaggerConfig {
@Bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.POST, getArrayList())
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("egovframework.bmigsvr.controller"))
.paths(PathSelectors.any())
.build();
}
public ApiInfo getApiInfo() {
return new ApiInfo("Service REST API Documentation",
"REST Api Documentation",
"1.0",
"localhost:8080",
new Contact("kang-min-kyu","","aaa@gmail.com"),
"Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<VendorExtension>());
}
private ArrayList<ResponseMessage> getArrayList() {
ArrayList<ResponseMessage> lists = new ArrayList<ResponseMessage>();
lists.add(new ResponseMessageBuilder().code(500).message("이상한요청").build());
lists.add(new ResponseMessageBuilder().code(403).message("황당한요청").build());
lists.add(new ResponseMessageBuilder().code(401).message("비인증된접근").build());
return lists;
}
}
2-2. springfox 3.0.0 버전용
- 설정 후에도 오류가 나면 springfox 2.9.2 버전을 3.0.0 버전으로 변경해주어야 함 (오류 발생 시에만 진행)
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
return new Docket(DocumentationType.SWAGGER_2)
의 SWAGGER_2
부분 클릭하여 2.9.2 버전을 아직 사용 중이진 않은지 확인 (OAS_30
필요)
- 계속 2.9.2 버전을 유지하고 있어서 .m2 리포지토리에서 직접 삭제함
- springfox 3.0.0 버전용
@EnableWebMvc
@Configuration
public class SwaggerConfig {
@Bean
public Docket customImplementation() {
return new Docket(DocumentationType.OAS_30)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("egovframework.bmigsvr.controller"))
.paths(PathSelectors.any())
.build();
}
(globalResponseMessage, apiInfo 는 각자 용도에 맞게 수정해서 사용)
}
- 이후 절차도 springfox 3.0.0 버전에 맞게 수정해야 함
2-3. springfox 2.5.0 버전용
package egovframework.com.cmm.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2
@EnableWebMvc
public class SwaggerConfig extends WebMvcConfigurationSupport {
@Bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("egovframework.bmigsvr.controller"))
.paths(PathSelectors.any())
.build();
}
public ApiInfo getApiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("API Documentation")
.version("1.0")
.build();
}
}
- 전자정부프레임워크에 swagger 2.9.2 적용하기
/src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml
에 <bean>
, <mvc:resources>
추가
- 직접 정의한
egovframework.com.cmm.config.SwaggerConfig
를 연결하거나,
- 기본값인
springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration
로 설정해도 무방
<context:component-scan base-package="egovframework">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<bean id="swaggerConfig" class="egovframework.com.cmm.config.SwaggerConfig"/>
<mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html" />
<mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/cop/com/*.do"/>
<mvc:mapping path="/cop/bbs/*Master*.do"/>
<mvc:mapping path="/uat/uia/*.do"/>
<mvc:exclude-mapping path="/uat/uia/actionLogin.do"/>
<mvc:exclude-mapping path="/uat/uia/egovLoginUsr.do"/>
<mvc:exclude-mapping path="/swagger-ui.html"/>
<mvc:exclude-mapping path="/swagger-ui.html/**"/>
<mvc:exclude-mapping path="/swagger-ui/**"/>
<mvc:exclude-mapping path="/configuration/**"/>
<mvc:exclude-mapping path="/swagger-resources/**"/>
<mvc:exclude-mapping path="/swagger-resources/configuration/**"/>
<mvc:exclude-mapping path="/swagger-resources/configuration/ui"/>
<mvc:exclude-mapping path="/v2/api-docs"/>
<mvc:exclude-mapping path="/webjars/**"/>
<mvc:exclude-mapping path="/webjars/springfox-swagger-ui/*.{js,css}"/>
<bean class="egovframework.com.cmm.interceptor.AuthenticInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
4. web.xml
- (다시 세팅했을 때, 생략해도 실행된 것으로 보아 생략해도 무방)
web.xml
에 아래 내용 추가
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/egovframework/springmvc/*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>swagger</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/egovframework/springmvc/*.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>swagger</servlet-name>
<url-pattern>/swagger-ui.html</url-pattern>
<url-pattern>/webjars/**</url-pattern>
<url-pattern>/</url-pattern>
</servlet-mapping>
4-1. Error creating bean with name 'documentationPluginsBootstrapper' defined in URL
SwaggerConfig.java
에 @EnableSwagger2
, @EnableWebMvc
를 추가해주면 됨
Error creating bean with name 'documentationPluginsBootstrapper' defined in URL
Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<scope>compile</scope>
</dependency>
5. globals.properties 설정
globals.properties
에 아래 내용 추가
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
5-1. Failed to start bean 'documentationPluginsBootstrapper'
globals.properties
> spring.mvc.pathmatch.matching-strategy=ant_path_matcher
를 추가하면 해결됨
- 대부분 spring boot 2.6.0부터 요청 경로를 ControllerHandler에 매칭시키기 위한 전략의 기본값이 ant_path_matcher 전략 -> path_pattern_parser 전략으로 변경되었기 때문
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NoSuchMethodError: org.springframework.web.bind.annotation.RequestMapping.path()[Ljava/lang/String;
5-2. java.lang.IllegalStateException: 불허되는 접근
mysql-connector-java-8.0.28.jar
파일을 C:\server\apache-tomcat-8.5.98\lib
경로에 추가
org.apache.catalina.loader.WebappClassLoaderBase checkStateForResourceLoading
정보: 불허되는 접근: 이 웹 애플리케이션 인스턴스는 이미 중지되었습니다. []을(를) 로드할 수 없습니다. 디버그 목적 및 불허되는 접근을 발생시킨 해당 쓰레드를 종료시키기 위한 시도로서, 다음 스택 트레이스가 생성됩니다.
java.lang.IllegalStateException: 불허되는 접근: 이 웹 애플리케이션 인스턴스는 이미 중지되었습니다. []을(를) 로드할 수 없습니다. 디버그 목적 및 불허되는 접근을 발생시킨 해당 쓰레드를 종료시키기 위한 시도로서, 다음 스택 트레이스가 생성됩니다.
6. Swagger 접속
- Tomcat 실행 후 아래 url 로 접속
- Swagger 2 : http://://swagger-ui.html
- Swagger 3 : http://://swagger-ui/index.html
6-1. Failed to load API definition
No mapping found for HTTP request with URI [/swagger-ui/index.html]
No mapping found for HTTP request with URI [/null/swagger-resources/configuration/ui] in DispatcherServlet with name 'swagger'
Failed to load API definition.
Fetch error > undefined http://192.168.1.217:8060/v2/api-docs
6-1-1. No mapping found for HTTP request with URI [/csrf] in DispatcherServlet with name 'swagger'
WARN [org.springframework.web.servlet.PageNotFound] No mapping found for HTTP request with URI [/csrf] in DispatcherServlet with name 'swagger'
egov-com-servlet.xml
에 <mvc:annotation-driven />
, mvc:default-servlet-handler />
가 있는지 확인
6-1-2. java.lang.NoSuchMethodError: org.springframework.web.util.UriComponentsBuilder
java.lang.NoSuchMethodError: org.springframework.web.util.UriComponentsBuilder.fromHttpRequest(Lorg/springframework/http/HttpRequest;)Lorg/springframework/web/util/UriComponentsBuilder;
6-1-3. Spring 버전 차이로 발생되는 오류
- Spring 버전 차이로 발생할 수 있음
- maven dependency 버전 수정 필요
java.lang.NoSuchMethodError: org.springframework.beans.factory.support.RootBeanDefinition.setTargetType
java.lang.IllegalStateException: LifecycleProcessor not initialized
또는
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.findAnnotation
6-2. 빈 화면이 뜨는 경우
- F12 개발자 도구 확인 >
Failed to load resource: the server responded with a status of 404 ()
- swagger-ui 화면을 구성하는 css, js, png 등의 파일을 불러오지 못한 것
7. 관련 링크
7-1. 접속 경로
7-2. Spring-Boot 및 Spring 에 Swagger 연동
7-3. 전자정부프레임워크에 Swagger 연동