‡๐Ÿ‘ฉ‍๐Ÿ’ป ‡/ºSpring

[Spring] ์Šคํ”„๋ง ๋ฌธ์„œํ™”(Spring DOC) - Swagger UI

Trudy | ์†ก์—ฐ 2023. 12. 26. 16:13

๐Ÿ“Swagger UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ 

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-boot-starter</artifactId>
			<version>3.0.0</version>
		</dependency>

 

๐Ÿ“application.yml์— ์„ค์ • ์ถ”๊ฐ€

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

 

์œ„ ๋‘ ์„ค์ •์„ ํ•˜๊ณ  ๋‚˜๋ฉด Swagger UI๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 ++) application.yml์— ์„ค์ • ์ถ”๊ฐ€ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. 

Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

 


 

๐Ÿ“ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


 

โ˜… Swagger ์„ค์ •ํŒŒ์ผ - Swagger.config

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;

@Configuration
public class SwaggerConfig {

    // Swagger Docket ๋นˆ์„ ์ƒ์„ฑํ•˜์—ฌ API ๋ฌธ์„œํ™” ์„ค์ •์„ ๋ฐ˜ํ™˜
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                
                // ๋ฌธ์„œํ™”ํ•  ๋Œ€์ƒ ์ปจํŠธ๋กค๋Ÿฌ ํŒจํ‚ค์ง€๋ฅผ ์ง€์ •
                .apis(
                        RequestHandlerSelectors.basePackage("com.example.demo.member")
                                .or(RequestHandlerSelectors.basePackage("com.example.demo.product"))
                )
                // ๋ชจ๋“  ๊ฒฝ๋กœ๋ฅผ ๋ฌธ์„œํ™” ๋Œ€์ƒ์œผ๋กœ ์ง€์ •
                .paths(PathSelectors.any())
                .build()
                // API ์ •๋ณด๋ฅผ ์„ค์ •
                .apiInfo(apiInfo("์Šคํ”„๋ง ์ˆ˜์—…", "v1.0"));
    }

    // API์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋ฐ˜ํ™˜
    private ApiInfo apiInfo(String title, String version) {
        return new ApiInfo(
                title,  // API์˜ ์ œ๋ชฉ
                "์Šคํ”„๋ง ๋ฌธ์„œํ™” Swagger ์‹ค์Šต",  // API์˜ ์„ค๋ช…
                version,  // API์˜ ๋ฒ„์ „
                "http://www.a.com",  // API์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด ๋งํฌ
                // API์— ๋Œ€ํ•œ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด (์ด๋ฆ„, ๋ธ”๋กœ๊ทธ ์ฃผ์†Œ, ์ด๋ฉ”์ผ)
                new Contact("๋ธ”๋กœ๊ทธ ์ฃผ์†Œ", "https://xoxoxoxox.tistory.com", "songyeon0607@naver.com"),
                "Licenses",  // API ๋ผ์ด์„ ์Šค
                "http://b.com",  // ๋ผ์ด์„ ์Šค์— ๋Œ€ํ•œ ๋งํฌ
                new ArrayList<>()  // Vendor Extensions (๋ฒค๋” ํ™•์žฅ)
        );
    }
}

 

ApiInfo apiInfo() {}; API์˜ ๋Œ€ํ•œ ์ •๋ณด ์„ค์ •

- title : API ์ด๋ฆ„

- version : API ๋ฒ„์ „

 

RequestHandlerSelectors.basePackage(String packageName)

Swagger๋ฅผ ์ ์šฉํ•  ํด๋ž˜์Šค์˜ package๋ช…์„ ๋ช…์‹œ

 

PathSelectors.any()

ํ•ด๋‹น package ํ•˜์œ„์— ์žˆ๋Š” ๋ชจ๋“  url์— swagger ์ ์šฉ


๊ทธ ์™ธ ํŒŒ์ผ๋“ค(์ปจํŠธ๋กค๋Ÿฌ์™€ ๋ฉ”์†Œ๋“œ์˜ ๋Œ€ํ•œ ์ด๋ฆ„ ํŽธ์ง‘ ์ž‘์—…)

 

MemberController

package com.example.demo.member.controller;

import com.example.demo.member.model.LoginMemberReq;
import com.example.demo.member.model.SignupMemberReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@Api(value = "ํšŒ์› ์ปจํŠธ๋กค๋Ÿฌ v1", tags = "ํšŒ์› API")
@RequestMapping("/member")
public class MemberController {
    @ApiOperation(value = "๋กœ๊ทธ์ธ")
    @RequestMapping(method = RequestMethod.POST, value = "/login")
    public ResponseEntity login(@Valid LoginMemberReq loginMemberReq) {

        return ResponseEntity.ok().body("login process");
    }
    @ApiOperation(value = "ํšŒ์› ๊ฐ€์ž…")
    @RequestMapping(method = RequestMethod.POST, value = "/signup")
    public ResponseEntity signup(SignupMemberReq signupMemberReq) {
        return ResponseEntity.ok().body("signup process");
    }
}

 

ProductController

package com.example.demo.product.controller;

import com.example.demo.member.model.SignupMemberReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(value = "์ƒํ’ˆ ์ปจํŠธ๋กค๋Ÿฌ v1", tags = "์ƒํ’ˆ API")
@RequestMapping("/product")
public class ProductController {
    @RequestMapping(method = RequestMethod.GET, value = "/list")
    @ApiOperation(value = "์ƒํ’ˆ ๋ชฉ๋ก")
    public ResponseEntity list() {
        return ResponseEntity.ok().body("product list");
    }
}

 

LoginMemberReq

package com.example.demo.member.model;

import io.swagger.annotations.ApiParam;
import lombok.*;

import javax.validation.constraints.*;

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class LoginMemberReq {
    @ApiParam(value = "ํšŒ์›์˜ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅ", required = true, example = "test01@test.com")
    private String email;

    @ApiParam(value = "ํšŒ์›์˜ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅ", required = true, example = "qwer1234")
    private String password;

}

 


๐Ÿ“์‹คํ–‰๊ฒฐ๊ณผ

์œ„์ฒ˜๋Ÿผ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ์•„๋ž˜ url๋กœ ์ ‘์†ํ•˜๋ฉด swagger-ui๊ฐ€ ๋œจ๊ฒŒ ๋œ๋‹ค.

API ์ด๋ฆ„๋“ค์„ ์„ค์ •ํ•ด์ค€ ๋Œ€๋กœ ์ž˜ ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.