ふたりで

springboot+swagger+config 본문

Spring

springboot+swagger+config

graykang 2022. 4. 18. 15:17
728x90
반응형
SMALL

springboot 후로잭트에 swagger를 설정 하는 방법에 대해 정리 해본다...

먼저 아래와 같이 Maven 설정.

		<dependency>
		    <groupId>io.springfox</groupId>
		    <artifactId>springfox-swagger2</artifactId>
		    <version>2.9.2</version>
		</dependency>

1. SwaggerConfig.java 작성.

swagger를 사용하기 위해 springboot 프로잭트에 설정을 한다.

package com.graykang.test.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.RequestMethod;

import com.graykang.test.supplierorder.common.model.RestException;

import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
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.swagger.web.DocExpansion;
import springfox.documentation.swagger.web.ModelRendering;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.TagsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Profile({"local","dev"})//개발과 로컬에서만 API UI가 보여 지게 설정.
@Configuration 
@EnableSwagger2
public class SwaggerConfig {
    private String version;
    private String title;
    
    @SuppressWarnings("unchecked")
	@Bean
    public Docket apiDefault() {//기본 설정.
        version = "Default";
        title = "API " + version;
        
        
		@SuppressWarnings("rawtypes")
		List global = new ArrayList();
		global.add(new ParameterBuilder().name("Authorization").
								  description("AccessToken").parameterType("header").
								  required(false).modelRef(new ModelRef("string")).build());


        return new Docket(DocumentationType.SWAGGER_2)
        		.globalOperationParameters(global)/*Authentication header 처리를 api-version별 사용하기 위해 global 사용*/
                .useDefaultResponseMessages(false)
                .groupName(version)
                .select()
                .apis(RequestHandlerSelectors.basePackage(""))
                .paths(PathSelectors.ant("/Default/api/**"))
                .build()
                .apiInfo(apiDefaultInfo(title, version));

    }
    
    @SuppressWarnings("unchecked")
	@Bean
    public Docket apiV1() {
        version = "V1";
        title = "API " + version;
        
		@SuppressWarnings("rawtypes")
		List global = new ArrayList();
		global.add(new ParameterBuilder().name("Authorization").
								  description("AccessToken").parameterType("header").
								  required(false).modelRef(new ModelRef("string")).build());


        return new Docket(DocumentationType.SWAGGER_2)
        		.globalOperationParameters(global)/*Authentication header 처리를 api-version별 사용하기 위해 global 사용*/
                .useDefaultResponseMessages(false)
                .groupName(version)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.graykang.test"))
                .paths(PathSelectors.ant("/v1/api/**"))
                .build()
                .apiInfo(apiInfoV1(title, version));

    }
    
    /**
     * v2용 API는 토큰 인증대신 파라메터값으로 자체 인증 함으로 Authentication 로직 주석 처리.
     * @return
     */
    @Bean
    public Docket apiV2() {
        version = "V2";
        title = "API " + version;
        
//		@SuppressWarnings("rawtypes")
//		List global = new ArrayList();
//		global.add(new ParameterBuilder().name("Authorization").
//								  description("AccessToken").parameterType("header").
//								  required(false).modelRef(new ModelRef("string")).build());

        return new Docket(DocumentationType.SWAGGER_2)
//        		.globalOperationParameters(global)/*Authentication header 처리를 api-version별 사용하기 위해 global 사용*/
                .useDefaultResponseMessages(false)
                .groupName(version)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.graykang.test.v2api"))
                .paths(PathSelectors.ant("/v2/api/**"))
                .build()
                .apiInfo(apiInfoMgr(title, version));

    }


    private ApiInfo apiDefaultInfo(String title, String version) {
        return new ApiInfo(
                title,
                "Swagger-Default",
                version,
                "",
                new Contact("", "", "tenpest@naver.com"),
                "",

                "",

                new ArrayList<>());
    }
    
    private ApiInfo apiInfoV1(String title, String version) {
        return new ApiInfo(
                title,
                "Swagger로 생성한 API Docs\n 1.cryptoTest서비스는 authenticate를 테스트할때 userid/password암호화를 위해 사용한다.\n  2.authenticate를 호출해 Token발급\n 3.발급받은 Token을  Header값[Authorization]에 입력하여 조회용API를 호출 한다.",
                version,
                "",
                new Contact("", "", "graykang@naver.com"),
                "",
                "graykang.tistory.com",
                new ArrayList<>()
                );
    }
    
    private ApiInfo apiInfoV2(String title, String version) {
//        return new ApiInfo(
//                title,
//                "Swagger로 생성한 API Docs\n MGR에서 상품발주서 전송시 사용.",
//                version,
//                "www.graykang.kr",
//                new Contact("Contact Me", "www.graykang.kr", "tenpest@naver.com"),
//                "Licenses",
//
//                "graykang.tistory.com",
//
//                new ArrayList<>());
    	
      return new ApiInfo(
      title,
      "Swagger로 생성한 API Docs\n V2 데이터 전송시 사용.",
      version,
      "",
      new Contact("", "", "graykang@naver.com"),
      "",
      "",
      new ArrayList<>()
      );

    }
    
    @Bean
    UiConfiguration uiConfig() {
      return UiConfigurationBuilder.builder()
        .deepLinking(false)
        .displayOperationId(false)
        .defaultModelsExpandDepth(-1)
        .defaultModelExpandDepth(1)
        .defaultModelRendering(ModelRendering.EXAMPLE)
        .displayRequestDuration(false)
        .docExpansion(DocExpansion.NONE)
        .filter(false)
        .maxDisplayedTags(null)
        .operationsSorter(OperationsSorter.METHOD)
        .showExtensions(false)
        .tagsSorter(TagsSorter.ALPHA)
        .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
        .validatorUrl(null)
        .build();
    }
}

2. SwaggerController.java 작성

swagger API document UI 용 페이지 전환용 컨트롤러...

package com.graykang.test.common.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
public class SwaggerController {
	
	@RequestMapping(value = "/swaggerV1", method = RequestMethod.GET)
	public String swaggerCallV1(Model model) {
		System.out.println("swaggerv1");
		return "api-v1";
		
	}
	
	@RequestMapping(value = "/swaggerapilocalV2", method = RequestMethod.GET)
	public String swaggerCallLocalV2(Model model) {
		System.out.println("swaggerv2");
		return "api-localv2";
		
	}

}

3. 컨트롤러에서 전환해줄 jsp 작성

3-1. api-v1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Biz Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/swagger/css/swagger-ui.css" >
    <link rel="icon" type="image/png" href="${pageContext.request.contextPath}/swagger/img/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="${pageContext.request.contextPath}/swagger/img/favicon-16x16.png" sizes="16x16" />
    <script src="${pageContext.request.contextPath}/swagger/js/swagger-ui-bundle.js"> </script>
    <script src="${pageContext.request.contextPath}/swagger/js/swagger-ui-standalone-preset.js"> </script>
    <style>
      html
      {
        box-sizing: border-box;
        overflow: -moz-scrollbars-vertical;
        overflow-y: scroll;
      }

      *,
      *:before,
      *:after
      {
        box-sizing: inherit;
      }

      body
      {
        margin:0;
        background: #fafafa;
      }
    </style>
  </head>

  <body>
    <div id="swagger-ui"></div>
    <script>
    function getContextPath() {
        var hostIndex = location.href.indexOf( location.host ) + location.host.length;
        return location.href.substring( hostIndex, location.href.indexOf('/', hostIndex + 1) );
    }
    
    window.onload = function() {
    	const hostIndex = location.href.indexOf( location.host ) + location.host.length;
		const path = location.href.substring( hostIndex, location.href.indexOf('/', hostIndex + 1) );
     // Begin Swagger UI call region
      const ui = SwaggerUIBundle({
        url: "${pageContext.request.contextPath}/v2/api-docs?group=V1",
        dom_id: '#swagger-ui',
        deepLinking: true,
        defaultModelsExpandDepth: -1,   // <-------
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset.slice(1)
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      window.ui = ui
    }
  </script>
  </body>
</html>

3-2. api-localv2.jap

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>MGR Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/swagger/css/swagger-ui.css" >
    <link rel="icon" type="image/png" href="${pageContext.request.contextPath}/swagger/img/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="${pageContext.request.contextPath}/swagger/img/favicon-16x16.png" sizes="16x16" />
    <script src="${pageContext.request.contextPath}/swagger/js/swagger-ui-bundle.js"> </script>
    <script src="${pageContext.request.contextPath}/swagger/js/swagger-ui-standalone-preset.js"> </script>
    <script src="${pageContext.request.contextPath}/swagger/js/jquery-3.3.1.min.js"> </script>
    <style>
      html
      {
        box-sizing: border-box;
        overflow: -moz-scrollbars-vertical;
        overflow-y: scroll;
      }

      *,
      *:before,
      *:after
      {
        box-sizing: inherit;
      }

      body
      {
        margin:0;
        background: #fafafa;
      }
    </style>
  </head>

  <body>
    <div id="swagger-ui"></div>

    <script>
    function getContextPath() {
        var hostIndex = location.href.indexOf( location.host ) + location.host.length;
        return location.href.substring( hostIndex, location.href.indexOf('/', hostIndex + 1) );
    }
    
    window.onload = function() {
      //const hostIndex = location.href.indexOf( location.host ) + location.host.length;
	  //const path = location.href.substring( hostIndex, location.href.indexOf('/', hostIndex + 1) );
      // Begin Swagger UI call region
      const ui = SwaggerUIBundle({
        url: "${pageContext.request.contextPath}/v2/api-docs?group=mgr",
        dom_id: '#swagger-ui',
        deepLinking: true,
        defaultModelsExpandDepth: -1,   // <-------
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      window.ui = ui
    }
  </script>
  </body>
</html>

4. 실사용되는 컨트롤러 예시

아래의 컨트롤러 소스 코드는 분기시킨 V2 기준 이다.

package com.graykang.test.v2api.controller;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.graykang.test.common.model.JwtRequest;
import com.graykang.test.common.model.PmTestRequestVO;
import com.graykang.test.common.model.PmVO;
import com.graykang.test.common.model.RestException;
import com.graykang.test.common.util.CustomCollectionValidator;
import com.graykang.test.common.util.SecureUtil;
import com.graykang.test.v2api.model.MartCouncilInfoVO;
import com.graykang.test.v2api.model.OrderListByMartCouncilVO;
import com.graykang.test.v2api.model.OrderListMartCouncilResultVO;
import com.graykang.test.v2api.model.ResultVO;
import com.graykang.test.v2api.model.SupplierOrderListPutVO;
import com.graykang.test.v2api.model.SupplierOrderListPutVO2;
import com.graykang.test.v2api.service.V2ApitService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@Api(tags = {"1. MGR API Service"})
@CrossOrigin
@RestController
@RequestMapping(value = "/v2/api")
public class V2APIController {
	
	private static Logger logger = LoggerFactory.getLogger(V2APIController.class);
	
	@Autowired
	CustomCollectionValidator customCollectionValidator;
	
	@Autowired
	V2ApiService v2ApiService;
	
	/**
	 * @param securityKey
	 * @return
	 * @throws Exception
	 */
	@ApiOperation(value = "4.테스트 데이터 리스트 반환")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "securityKey", value="", required=true, dataType="String", paramType="query", defaultValue="", example="")
	})
	@ApiResponses({
			@ApiResponse(code=200,message="OK", response= TeatDataResultVO.class),//반환되는VO
			@ApiResponse(code=401,message="Unauthorization", response= RestException.class),//예외처리VO
			@ApiResponse(code=403,message="Forbidden", response= RestException.class),
			@ApiResponse(code=400,message="Bad Request", response= RestException.class),
			@ApiResponse(code=500,message="ServerError", response= RestException.class)
	})
	@PostMapping("/getTestDataList")
	public  ResponseEntity<?> getListByTestData(@RequestParam("securityKey") String securityKey) throws Exception{
		TestDataResultVO result = new TestDataResultVO();

		authVO authResult = SecureUtil.decodeAuth(securityKey);
		if(authResult != null) {
			List<DataMainVO> items = v2ApiService.getTestListByTestData(authResult.getKey());
			result.setTotal(items.size());
			result.setItems(items);
			
		}else {
			logger.error("Unauthorization:securityKey값이 올바르지 않습니다");
			throw new IllegalArgumentException("securityKey값이 올바르지 않습니다");
		}
		
		
		return ResponseEntity.ok(result);
	}
	
}

5. 위의 컨트롤러를 통해 반환되는 TestDataResultVO.java

package com.graykang.test.v2api.model;

import java.util.List;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel
public class TestDataResultVO{
	
	@ApiModelProperty(value="int() 전체 건수")
	private int total;
	
	private List<DataMainVO> items;

	public List<DataMainVO> getItems() {
		return items;
	}

	public void setItems(List<DataMainVO> items) {
		this.items = items;
	}

	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}

}

6. 위의 TestDataResultVO.java 내에 정의된 List<DataMainVO> items 즉 DataMainVO.java는 생략...

 

728x90
반응형
LIST
Comments