Skip to content

Commit

Permalink
공공데이터 저장 코드 구조 개선 (#133)
Browse files Browse the repository at this point in the history
* refactor: 카카오 API 호출 코드 리팩토링

* refactor: URL 생성 코드 개선

* refactor: JPA bulk insert 수행하도록 개선
  • Loading branch information
Hanjaemo authored Oct 4, 2024
1 parent d54f00f commit 00d5a69
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public enum ErrorCode {
NOT_FOUND_TAG(NOT_FOUND, "해당 이름과 일치하는 수거함 태그가 없습니다."),

// 500
UNEXPECTED_ERROR_EXTERNAL_API(INTERNAL_SERVER_ERROR, "외부 API 호출 시 알 수 없는 예외가 발생했습니다.");
UNEXPECTED_ERROR_EXTERNAL_API(INTERNAL_SERVER_ERROR, "외부 API 호출 시 알 수 없는 예외가 발생했습니다."),
ERROR_PARSING_JSON_KAKAO_API(INTERNAL_SERVER_ERROR, "Error parsing JSON from Kakao API");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;
import contest.collectingbox.module.collectingbox.domain.CollectingBox;
import contest.collectingbox.module.collectingbox.domain.Tag;
import contest.collectingbox.module.collectingbox.domain.repository.CollectingBoxRepository;
import contest.collectingbox.module.location.domain.repository.DongInfoRepository;
Expand All @@ -19,10 +20,7 @@

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;

@Slf4j
@Component
Expand Down Expand Up @@ -51,7 +49,7 @@ private List<PublicDataApiInfo> getEntities(List<SavePublicDataApiInfoRequest> r

@Transactional
public long loadPublicData(List<LoadPublicDataRequest> requests) {
long loadedDataCount = 0;
List<CollectingBox> boxes = new ArrayList<>();
for (LoadPublicDataRequest request : requests) {
log.info("======= {} - {} =======", request.getSigungu(), request.getTag().getLabel());

Expand All @@ -74,15 +72,17 @@ public long loadPublicData(List<LoadPublicDataRequest> requests) {
// 카카오 주소 검색 API 응답 출력
log.info("query = {}, response = {}", query, addressInfo);

// insert DB
// 수거함 객체 저장
if (addressInfo != null && addressInfo.isSigunguEquals(sigungu)) {
collectingBoxRepository.save(addressInfo.toCollectingBox(dongInfoRepository));
loadedDataCount++;
boxes.add(addressInfo.toCollectingBox(dongInfoRepository));
}
}
}

return loadedDataCount;
// bulk insert
collectingBoxRepository.saveAll(boxes);

return boxes.size();
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AddressInfoMapper {
public static AddressInfoDto jsonObjectToAddressInfoDto(JSONObject document, Tag tag) {
public static AddressInfoDto mapToAddressInfo(JSONObject document, Tag tag) {
JSONObject address = document.getJSONObject("address");
JSONObject roadAddress = document.getJSONObject("road_address");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package contest.collectingbox.module.publicdata.domain;

import contest.collectingbox.global.exception.CollectingBoxException;
import contest.collectingbox.module.collectingbox.domain.Tag;
import contest.collectingbox.module.publicdata.dto.AddressInfoDto;
import lombok.RequiredArgsConstructor;
Expand All @@ -8,13 +9,18 @@
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

import static contest.collectingbox.global.exception.ErrorCode.ERROR_PARSING_JSON_KAKAO_API;
import static contest.collectingbox.global.exception.ErrorCode.UNEXPECTED_ERROR_EXTERNAL_API;
import static java.nio.charset.StandardCharsets.UTF_8;

@Component
Expand All @@ -31,8 +37,8 @@ public AddressInfoDto fetchAddressInfo(String query, Tag tag) {
ResponseEntity<String> response = callKakaoAPI(query);

// 카카오 API 예외 처리
if (response.getStatusCode() != HttpStatus.OK) {
throw new RuntimeException("Kakao API failed status = " + response.getStatusCode());
if (response.getStatusCode().isError()) {
throw new CollectingBoxException(UNEXPECTED_ERROR_EXTERNAL_API);
}

// 주소 정보 추출
Expand All @@ -49,16 +55,16 @@ public AddressInfoDto fetchAddressInfo(String query, Tag tag) {
return null;
}

return AddressInfoMapper.jsonObjectToAddressInfoDto(document, tag);
return AddressInfoMapper.mapToAddressInfo(document, tag);
} catch (JSONException e) {
throw new RuntimeException("Error parsing JSON from Kakao API", e);
throw new CollectingBoxException(ERROR_PARSING_JSON_KAKAO_API);
}
}

private ResponseEntity<String> callKakaoAPI(String query) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Authorization", "KakaoAK " + apiKey);
httpHeaders.set("Authorization", "KakaoAK %s".formatted(apiKey));
HttpEntity<Object> httpEntity = new HttpEntity<>(httpHeaders);
URI targetUrl = UriComponentsBuilder.fromUriString(API_URL).queryParam("query", query)
.build().encode(UTF_8).toUri();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

import static contest.collectingbox.global.exception.ErrorCode.UNEXPECTED_ERROR_EXTERNAL_API;
import static java.nio.charset.StandardCharsets.UTF_8;

@Component
public class OpenDataApiManager {

private static final String API_URL = "https://api.odcloud.kr/api%s?serviceKey=%s&perPage=%d";
private static final String API_URL = "https://api.odcloud.kr/api%s";

@Value("${public-data.api.key}")
private String apiKey;
Expand All @@ -36,8 +40,11 @@ public JSONArray fetchOpenData(String callAddress, int perPage) {
return new JSONObject(response.getBody()).getJSONArray("data");
}

private String getUrl(String callAddress, int perPage) {
return String.format(API_URL, callAddress, apiKey, perPage);
private URI getUrl(String callAddress, int perPage) {
return UriComponentsBuilder.fromUriString(String.format(API_URL, callAddress))
.queryParam("serviceKey", apiKey)
.queryParam("perPage", perPage)
.build().encode(UTF_8).toUri();
}

private boolean isError(ResponseEntity<String> response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,4 @@ public class LoadPublicDataRequest {
private String sigungu;
private Tag tag;
private String callAddress;

public String getUrlWithPerPage(String apiKey, int perPage) {
return String.format("https://api.odcloud.kr/api%s?serviceKey=%s&perPage=%d", callAddress, apiKey, perPage);
}
}

0 comments on commit 00d5a69

Please sign in to comment.