이 글에 나오는
Spring Legacy
라는 표현은Spring Boot
를 사용하지 않는 환경을
의미합니다. 이 점 유의하여 읽어주시기 바랍니다.
이 글은 읽는 분들께서 어느정도 web.xml 작성법 및 spring xml 설정법을
할 줄 안다는 가정하에서 작성된 글입니다.
혹시 잘 모르겠는 부분 있으면 EMAIL 또는 댓글로 질문해주시기 바랍니다.
이번에 회사의 동기 분께서 Spring Legacy
환경으로 구축된 프로젝트가 있는데,
해당 프로젝트에 Swagger 를 추가하고 싶은데 잘 안 풀린다고 하셔서
도와드리게 되었습니다. 이 과정에서 제가 사용한 프로젝트 세팅법을 공유합니다.
swagger 를 사용하기 위한 dependency 2개를 추가합니다.
참고로 springframework 버전 4, 5 에서 전반적으로 다 되는 것을 확인했습니다.
<dependencies>
<!-- .. 나머지 dependency 들은 생략! .. -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
참고로 톰캣 버전은 9 입니다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 나머지 다 생략 -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- contextConfigLocation 의 파일 경로가 중요! -->
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
contextConfigLocation
를 사용하는지 꼭 확인!
주의사항
: 만약에servlet
<url-pattern>
에*.do
를 쓰신다면...?요즘은 흔치 않지만, 여전히 Legacy Project 와 공공사업 프로젝트에서는
*.do
라는 url 체계를 쓰는 곳이 많습니다.
그런데 이러한 url 방식을 쓸 대는 servlet url pattern 에 추가 적으로
작성해야되는 4가지 url 이 있습니다.<servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>*.do</url-pattern> <!-- 아래 4줄 추가!!! --> <url-pattern>/swagger-resources/configuration/ui</url-pattern> <url-pattern>/swagger-resources/configuration/security</url-pattern> <url-pattern>/swagger-resources</url-pattern> <url-pattern>/v2/api-docs</url-pattern> </servlet-mapping>
- 이렇게 하는 이유는 swagger 를 dispatcherServlet 내부에서
Spring 설정을 하게 되면,Swagger
자체가DispatcherServlet
의application context
에 어떤 방법을 통해서 자신만의endpoint
를 등록합니다.
- 해당
endpoint
는 4가지입니다.
- /swagger-resources/configuration/ui
- /swagger-resources/configuration/security
- /swagger-resources
- /v2/api-docs
- 하지만
dispatcher servlet
의url-pattern
이 단순히*.do
만 있으면
Swagger 가 만든url
에 접근할 수가 없게 됩니다!
- 이런 이유로 위와 같은 작업을 해주는 겁니다.
web.xml
에서 DispatcherServlet -> contextConfigLocation
로 설정한
servlet-context.xml
에서 swagger
설정을 추가해줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- ...생략... -->
<!-- THIS IS FOR SWAGGER [START] -->
<bean name="applicationSwaggerConfig" class="me.dailycode.spring.legacy.config.SwaggerConfig"/>
<mvc:resources mapping="/swagger-ui.html" location="classpath:/META-INF/resources/"/>
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<!-- THIS IS FOR SWAGGER [END] -->
<!-- ...생략... -->
</beans>
THIS IS FOR SWAGGER [START] ~ [END]
영역에 있는 코드만 복사하시면 됩니다.앞서 applicationSwaggerConfig
의 class 로 지정한
SwaggerConfig 클래스를 작성해보겠습니다.
package me.dailycode.spring.legacy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/*@Configuration*/ // 굳이 Configuration 안해도 됩니다.
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
// 자기 프로젝트에 맞게 설정!
.apis(RequestHandlerSelectors.basePackage("me.dailycode.spring"))
.paths(PathSelectors.any())
// .paths(PathSelectors.regex("(?!/error.*).*"))
.build()
.pathMapping("/")
.useDefaultResponseMessages(false)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SAMPLE-API")
.description("샘플 API 입니다.")
.termsOfServiceUrl("coding.toast.co.kr/api/")
.version("1.0.0")
.build();
}
@Bean
public UiConfiguration uiconfig() {
return UiConfigurationBuilder
.builder().operationsSorter(OperationsSorter.ALPHA)
.build();
}
}
RequestHandlerSelectors.basePackage("me.dailycode.spring")
입니다.RequestHandlerSelectors.basePackage
는 자신의 @Controller
, @RestController
클래스가 위치한 packge
, 또는 그보다 상위 package
를 작성합니다.
참고
여러 Controller 클래스 패키지를 지정하고 싶은 경우import com.google.common.base.Predicate; import com.google.common.base.Predicates; import springfox.documentation.RequestHandler; import java.util.ArrayList; import java.util.List; // 나머지 import 생략... @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api(){ List<Predicate<RequestHandler>> predicateList = new ArrayList<>(); predicateList.add(RequestHandlerSelectors.basePackage("controller.package1")); predicateList.add(RequestHandlerSelectors.basePackage("controller.package2")); return new Docket(DocumentationType.SWAGGER_2) .select() .apis(Predicates.or(predicateList)) //** 핵심 ** .paths(PathSelectors.any()) .build() .pathMapping("/") .useDefaultResponseMessages(false) .apiInfo(apiInfo()); } // 생략 ... }
끝입니다
이러고 나서 자신의 브라우저에 localhost:8080/swagger-ui.html
로 접속하면
정상적으로 Swagger 화면이 나오는 것을 확인할 수 있습니다.
(contextPath 를 지정했다면 localhost:8080/{contextPath}/swagger-ui.html
로
접속하면 됩니다!)
혹시 완성된 프로젝트 형태로 보고 싶다면 저의 github repo 를 참고하시기 바랍니다.
제가 깃헙에 올린건 spring security 처리가 안된 프로젝트입니다.
만약 자신이 spring security 를 사용하는 환경이면
security 관련 xml config 파일에서 아래처럼 작성해주면 됩니다.
<sec:intercept-url pattern="/swagger-ui.html/**" access="isAnonymous()" />
<sec:intercept-url pattern="/swagger-resources/**" access="isAnonymous()" />
<sec:intercept-url pattern="/v2/api-docs" access="isAnonymous()" />
<sec:intercept-url pattern="/webjars/**" access="isAnonymous()" />
<sec:intercept-url pattern="/webjars/springfox-swagger-ui/*.{js,css}" access="isAnonymous()" />
감사합니다. 매우 매우 큰 도움이 되었어요.