[Spring Boot] swagger 설정 방법


 

서버에서 제공해주는 API를 간단하게 테스트 해볼 수 있는 있는 도구인 Swagger 설정 방법에 대해 알아보겠다.

 


[수행 환경]

Windows 10
IntelliJ
java 11
gradle-7.6


[Gradle 설정]
//swagger
implementation 'io.springfox:springfox-swagger2:2.9.2'
implementation 'io.springfox:springfox-swagger-ui:2.9.2'

 

SwaggerConfig 클래스 작성
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.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.Arrays;
import java.util.List;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .host("127.0.0.1:8081")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.test"))
                .paths(PathSelectors.ant("/v1/**"))
                .build()
                .securityContexts(Arrays.asList(securityContext()))
                .securitySchemes(Arrays.asList(apiKey()));
    }

    private ApiKey apiKey() {
        return new ApiKey("Authorization", "Authorization", "header");
    }

    private SecurityContext securityContext() {
        return springfox
                .documentation
                .spi.service
                .contexts
                .SecurityContext
                .builder()
                .securityReferences(defaultAuth()).forPaths(PathSelectors.any()).build();
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
    }
}

 

[사용 예제] testController
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/v1")
@RestController
@AllArgsConstructor
@Api(tags = {"01. 테스트 API"})
public class TestContorller {
    private final UserClient userClient;

    @GetMapping("/test")
    @ApiOperation(value = "test 테스트")
    public String test() {
        return "안녕";
    }
}

 

[실행 후 접속 방법]
http://127.0.0.1:8081/swagger-ui.html#

 

반응형

[Spring Boot] QueryDsl 설정 방법


Spring Boot에서 QueryDsl을 설정하는 방법에 대해 알아보도록 하겠다.QueryDsl은 쿼리문을 함수 형식으로 작성 하도록 되어있다. Mybatis나 JPA nativeQuery를 사용해 직접 잘못된 쿼리문을 사용했을 때 컴파일시 오류가 발생하지 않고 런타임시 오류가 발생하는 단점이 있지만 QueryDsl은 정해진 함수만 사용하려 쿼리문을 잘못 작성 하는 실수를 줄이고 잘못 작성 되었을 경우 컴파일시 에러가 발생해 오류를 쉽게 찾을 수 있다.


[수행 환경]

Windows 10
IntelliJ
java 11
gradle-7.6


[Gradle 설정]
.....

dependencies {
   ....
   
   //queryDSL
   implementation 'com.querydsl:querydsl-jpa'
   implementation 'com.querydsl:querydsl-core'
   implementation 'com.querydsl:querydsl-collections'
   implementation "com.querydsl:querydsl-sql:${dependencyManagement.importedProperties['querydsl.version']}"
   annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
   annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
   annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
}

def generated = 'src/main/generated'

tasks.withType(JavaCompile) {
options.getGeneratedSourceOutputDirectory().set(file(generated))
}

sourceSets {
main.java.srcDirs += [generated]
}

clean {
delete file(generated)
}

 

[예제] ConnInfo Entity 작
import lombok.*;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ConnInfo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer seq;
    private String id;
    private String ip;
    private LocalDateTime sysCreateDt;
}

 

[예제] CustomConnInfoRepository 인터페이스 작성
public interface CustomConnInfoRepository {
    ConnInfo findSeq(Integer seq);
}

 

[예제] CustomConnInfoRepositoryImpl 클래스 작성
@Slf4j
public class CustomConnInfoRepositoryImpl implements CustomConnInfoRepository {

    JPAQueryFactory query;

    public CustomConnInfoRepositoryImpl(EntityManager em) {query = new JPAQueryFactory(em);}

    @Override
    public ConnInfo findSeq(Integer seq) {
        ConnInfo connInfo = query.selectFrom(QConnInfo.connInfo) //<--- QueryDSL 사용하는 부분
                .where(
                        QConnInfo.connInfo.seq.eq(seq)
                )
                .fetchOne();
        return connInfo;
    }
}

 

[예제] ConnInfoRepository 인터페이스 작성
// JPA에 CustomConnInfoRepository 인터페이스를 상속 받는다.
public interface ConnInfoRepository extends JpaRepository<ConnInfo, Integer>, CustomConnInfoRepository {

}

 

[예제] queryDsl 사용 부분 호출
//Repository는 보통 Service에서 호출하므로 위에서 구현한 함수도 Service
ConnInfo seq = connInfoRepository.findSeq(1);
호출시 Seq 값이 1인 ConnInfo 정보를 리턴 한다.

 

 

 

반응형

[Spring Boot] Feign Client 사용법

 


내 서비스에서 다른 API를 호출해서 결과를 받을 수 있는 방법을 알아보자.

유사한 API로는 RestTemplate이 있지만 Spring Cloud에서 제공하는 Feign client를 이용해 다른 서버 API 호출 방법을 설명해 보겠다.

호출 할 URL은 https://randomuser.me/api/?nat=us 인데 매번 호출 할 때마다 결과 값은 다르다.

결과 값 중 성별/이메일만 응답 줄 수 있도록 예제를 작성했다.


[환경]

Windows 10
IntelliJ 
java 11
gradle-7.6

[Gradle 설정]

//feign
implementation platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

 


[프로그램 전체]

MainApplication class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableFeignClients  //<================ 메인에서 추가 해줘야 한다.
@EnableScheduling
@SpringBootApplication
public class MainApplication {
        public static void main(String[] args) {
            SpringApplication.run(MainApplication.class, args);
         }
}
UserClient class
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "userClient", url = "https://randomuser.me") //<=====호출할 URL 설정
public interface UserClient {

    @GetMapping(value = "/api/") //<========== 함수 호출시  https://randomuser.me/api/ 가 되도록 설정
    GetUsersResponse getUsers(@RequestParam("nat") String nation); 
}
GetUsersResponse class
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class GetUsersResponse {
    private List<Result> results;

    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Result {
        private String gender;
        private String email;
    }
}
TestController - swagger 설정이 되어 있어야 합니다.
@Slf4j
@RequestMapping("/v1")
@RestController
@AllArgsConstructor
@Api(tags = {"01. 테스트 API"})
public class TestController {

    private final UserClient userClient;

    @GetMapping("/feign")
    @ApiOperation(value = "Feign 테스트")
    public CommonResponse<?> feign() {
        GetUsersResponse users = userClient.getUsers("nat=us"); //<=== API에 파라미터로 nat=us를 넣는다.
        return CommonResponse.createSuccessWithNoContent();
    }

}

 

[실행 결과]

{
  "results": [
    {
      "gender": "female",
      "email": "leonie.gonzalez@example.com"
    }
  ]
}

 

 

 

반응형

+ Recent posts