시작 및 준비

프로그래밍을 준비하기 위한 시작 및 준비사항 입니다.

실행 환경

본 가이드는 다음과 같은 환경에서 실행 됩니다.

dependency에 대한 자세한 내용은 Swit CTS Github 을 참조하여 주시기 바랍니다.

토큰 저장

1. 시작하며

Swit API를 사용하기 위해서는 기본적으로 토큰이 필요 합니다. 자세한 사항은 Swit Developers의 OAuth flow 를 참조해 주세요


2. 토큰의 저장


3. 토큰 객체 생성

3.1. SwitTokenEntity

package io.swit.api.model.entity.eai;

import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@Table(name = "swit_token")
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public class SwitTokenEntity {

    @Id
    @Column(name = "token_id", nullable = false, length = 30)
    private String tokenId = "SWIT";

    @Column(name = "access_token", length = 500, nullable = false)
    private String accessToken;

    @Column(name = "refresh_token", length = 500, nullable = false)
    private String refreshToken;

    @Column(name = "expire_in", nullable = true)
    private Long expireIn;

    @Column(name = "scope", length = 100, nullable = true)
    private String scope;

    @Column(name = "token_type", length = 50, nullable = false)
    private String tokenType;

}

3.2. SwitTokenDto

package io.swit.api.model.dto.eai;

import io.swit.api.model.entity.eai.SwitTokenEntity;
import lombok.Data;

@Data
public class SwitTokenDto {
    /** 토큰 아이디 */
    private String tokenId;

    /** 접근 토큰 */
    private String accessToken;

    /** 재인증 토큰 */
    private String refreshToken;

    /** 만료시간 */
    private Long expireIn;

    /** 인증 점위 */
    private String scope;

    /** 토큰 타입 */
    private String tokenType;



    /**
     * 엔티티 변환
     * @return 스윗 유저 토큰 엔티티
     */
    public SwitTokenEntity toEntity() {
        SwitTokenEntity entity = new SwitTokenEntity();
        entity.setTokenId(tokenId);
        entity.setAccessToken(this.accessToken);
        entity.setRefreshToken(this.refreshToken);
        entity.setExpireIn(this.expireIn);
        entity.setScope(this.scope);
        entity.setTokenType(this.tokenType);
        return entity;
    }
}

3.3. SwitTokenRepository

package io.swit.api.data.repository.eai;

import io.swit.api.model.entity.eai.SwitTokenEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SwitTokenRepository extends JpaRepository<SwitTokenEntity, String> {
}

3.4. AuthQuery

package io.swit.api.data.query.eai;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.swit.api.data.repository.eai.SwitTokenRepository;
import io.swit.api.model.dto.eai.SwitTokenDto;
import io.swit.api.model.entity.eai.QSwitTokenEntity;
import io.swit.api.model.entity.eai.SwitTokenEntity;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@AllArgsConstructor
public class AuthQuery {
   /**
     * 사용자 토큰 저장
     * @param param 사용자 토큰 파라미터
     * @throws Exception
     */
  public void saveSwitToken(SwitTokenDto param) throws Exception {
    this.switUserTokenRepository.save(param.toEntity());
  } 
}

3.5. AuthService

package io.swit.api.service.eai;

import io.swit.api.data.query.eai.AuthQuery;
import io.swit.api.model.dto.eai.SwitTokenDto;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

@Service
@AllArgsConstructor
@Slf4j
public class AuthService {
  private AuthQuery authQuery;
  /**
    * 사용자 토큰 저장
    * @param param 사용자 토큰 파라미터
    * @throws Exception
    */
  public void saveSwitToken(SwitTokenDto param) throws Exception {
    this.authQuery.saveSwitToken(param);
  }
}

4. 인증 및 가져오기

4.1. 인증용 컨트롤러 작성

@GetMapping(value = "/callback")
    public ResponseEntity<?> getOauthCallback(
            HttpServletRequest req,
            HttpServletResponse res,
            HttpSession session
    ) {
        String code = "";
        String state = "";
        SwitTokenDto retDto = new SwitTokenDto();

        WebClient webClient = WebClient.builder()
                .baseUrl(var.API_URL)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .build();
        try {
            code = req.getParameter("code").trim();
            state = req.getParameter("state").trim();
            String redirectUri = req.getRequestURL().toString().replace("http://", "https://");

            MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
            body.add("grant_type", "authorization_code");
            body.add("code", code);
            body.add("client_id", var.CLIENT_ID);
            body.add("client_secret", var.CLIENT_SECRET);
            body.add("redirect_uri", redirectUri);

            String retVal =  webClient.post()
                    .uri(var.TOKEN_URL)
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .bodyValue(body)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            JsonParser parser = new JsonParser();
            Object obj = parser.parse(retVal);
            JsonObject jsonObject = (JsonObject)obj;

            retDto.setAccessToken(jsonObject.get("access_token").toString().replace("\"", ""));
            retDto.setRefreshToken(jsonObject.get("refresh_token").toString().replace("\"", ""));
            retDto.setExpireIn(Long.parseLong(jsonObject.get("expires_in").toString()));
            retDto.setScope(jsonObject.get("scope").toString().replace("\"", ""));
            retDto.setTokenType(jsonObject.get("token_type").toString().replace("\"", ""));

            // 받아온 토큰을 데이터베이스에 저장한다.
            retDto.setTokenId("cts-api");
            this.authService.saveSwitToken(retDto);
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseEntity.internalServerError().body(e.getMessage());
        }
        return ResponseEntity.ok(retDto);
    }

4.2. 인증용 토큰 가져오기

 /**
     * DB에 저장된 토큰정보 가져오기
     * @param tokenId 가져올 토큰 아이디
     * @return 토큰 정보
     * @throws Exception 오류정보
     */
    public SwitTokenDto getSwitToken(String tokenId) throws Exception {
        QSwitTokenEntity sut = new QSwitTokenEntity("sut");
        JPAQuery<SwitTokenEntity> query = queryFactory.selectFrom(sut);
        SwitTokenDto tokenDto = new SwitTokenDto();

        BooleanBuilder where = new BooleanBuilder();
        where.and(sut.tokenId.eq(tokenId));

        tokenDto = query.select(
                Projections.bean(SwitTokenDto.class,
                        sut.tokenId,
                        sut.accessToken,
                        sut.tokenType,
                        sut.expireIn,
                        sut.scope,
                        sut.refreshToken
                )
        ).where(where).fetchFirst();
        return tokenDto;
    }

RestfulAPI를 호출하기 위한 Class 및 Method 생성

1. 시작하며

2. 예제 코드

package io.swit.api.util;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.swit.api.config.Variables;
import io.swit.api.model.dto.eai.SwitTokenDto;
import io.swit.api.service.com.LogService;
import io.swit.api.service.eai.AuthService;
import lombok.AllArgsConstructor;
import org.json.simple.JSONObject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.LocalDateTime;

@Component
@AllArgsConstructor
public class HttpUtils{

    private Variables var;
    private AuthService authService;
    private LogService logService;

    /**
     * POST 호출을 위한 Method
     * @param apiUrl 호출 URL
     * @param params 파라미터
     * @param tokenDto 토큰 정보
     * @return
     * @throws Exception
     */
    public JsonObject post(String apiUrl, JSONObject params, SwitTokenDto tokenDto) throws Exception {
        try{
            // API 호출을 위해 WebClient 설정
            WebClient webClient = WebClient.builder()
                    .baseUrl(String.format("%s/v1/api/%s", var.API_URL, apiUrl))
                    .defaultHeaders(httpHeaders -> {
                        httpHeaders.set("Accept", "application/json");
                        httpHeaders.set(
                          "Authorization",
                          String.format("Bearer %s", tokenDto.getAccessToken().replace("\"", ""))
                        );
                        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
                    })
                    .build();
            // API 호출 및 결과 수신
            String retVal =  webClient.post()
                    .bodyValue(params)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            // 수신된 결과를 JSON Object로 변환
            JsonParser parser = new JsonParser();
            JsonObject jsonObject = new JsonObject();
            if(retVal != null) {
                Object obj = parser.parse(retVal);
                jsonObject = (JsonObject) obj;
            }
            return jsonObject;
        }catch (Exception e){
            if(e.getMessage().contains("Unauthorized")){
                return this.post(apiUrl,params,authService.getRefreshToken());
            }else{
                logService.saveErrorLog(e, "[POST]"+apiUrl);
                throw new Exception(e);
            }
        }
    }

    /**
     * Get Method
     * @param apiUrl API 주소
     * @param tokenDto 토큰 정보
     * @return
     * @throws Exception
     */
    public JsonObject get(String apiUrl, SwitTokenDto tokenDto) throws Exception {
        try{
            // 전송을 위해 WebClient 설정
            WebClient webClient = WebClient.builder()
                    .baseUrl(String.format("%s/v1/api/%s", var.API_URL, apiUrl))
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                    .build();

            // API 호출 및 결과 수신
            String retVal =  webClient.get()
                    .headers(
                            httpHeaders -> {
                                httpHeaders.set("Accept", "application/json");
                                httpHeaders.set(
                                  "Authorization",
                                  String.format("Bearer %s", tokenDto.getAccessToken().replace("\"", ""))
                                );
                            }
                    )
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            // 수신한 결과를 JSON Object로 변환
            JsonParser parser = new JsonParser();
            Object obj = parser.parse(retVal);
            JsonObject jsonObject = (JsonObject)obj;

            return jsonObject;
        }catch (Exception e){
            if(e.getMessage().contains("Unauthorized")){
                return this.get(apiUrl,authService.getRefreshToken());
            }else{
                logService.saveErrorLog(e, "[GET]"+apiUrl);
                throw new Exception(e);
            }
        }
    }
}

3. 코드 설명

// API 호출을 위해 WebClient 설정
WebClient webClient = WebClient.builder()
        .baseUrl(String.format("%s/v1/api/%s", var.API_URL, apiUrl))
        .defaultHeaders(httpHeaders -> {
            httpHeaders.set("Accept", "application/json");
            httpHeaders.set("Authorization", String.format("Bearer %s", tokenDto.getAccessToken().replace("\"", "")));
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        })
        .build();