안녕하세요. 그린주입니다 ๑'ٮ'๑
경험이 많이 부족하지만 최선을 다해 적어보겠습니다!
개요
이번 글에서는 Open API 공휴일 정보 조회 및 DB tb_holiday 저장하기 3편 - DB tb_holiday에 저장하는 방법을 공유하고자 합니다.
참고로 2편의 explorer 코드가 있다는 가정하에 진행합니다.
2편에서는 공휴일 정보를 조회하기 위해 연도와 월을 받아서 조회했다면, 3편에서는 파라미터를 받지 않고 api를 요청하여 현재 연도를 가져와 내년 12월까지 공휴일 정보를 DB에 저장하도록 구성했습니다.
파라미터를 받지 않은 이유는 SpringBatch와 Jenkins Scheduler를 활용해 매년 1월 1일에 주기적으로 실행하기 위함입니다.
## 1편 활용 신청 방법 바로가기
https://green-joo.tistory.com/7
## 2편 공휴일 정보 조회 바로가기
https://green-joo.tistory.com/8
목차
Holiday.java
HolidayRepository.java
OpenApiController.java
OpenApiExplorer.java
OpenApiService.java
Holiday.java
entity 코드는 아래와 같습니다.
public class Holiday {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String holidayDate;
private String holidayName;
}
HolidayRepository.java
repository 코드는 아래와 같습니다.
public interface HolidayRepository extends JpaRepository<Holiday, Long>{
boolean existsByHolidayDate(String holidayDate); // 공휴일 중복 체크
}
OpenApiController.java
controller 코드는 아래와 같습니다.
public class OpenApiController {
private final OpenApiService openApiService;
@GetMapping("/holiday")
public ResponseEntity<?> getHolidayController() throws IOException { // 공유일 가져오기
return ResponseEntity.ok(openApiService.getHolidayService());
}
}
OpenApiExplorer.java
공휴일 API에서 제공해준 샘플 코드를 활용한 explorer 코드는 아래와 같습니다.
public class OpenApiExplorer {
public JSONObject getHolidayExplorer(String solYear, String solMonth) throws IOException {
StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo"); /*URL*/
urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=******"); /*Service Key*/
urlBuilder.append("&" + URLEncoder.encode("solYear", "UTF-8") + "=" + URLEncoder.encode(solYear, "UTF-8")); /*연*/
urlBuilder.append("&" + URLEncoder.encode("solMonth", "UTF-8") + "=" + URLEncoder.encode(solMonth, "UTF-8")); /*월*/
URL url = new URL(urlBuilder.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
System.out.println("Response code: " + conn.getResponseCode());
BufferedReader rd;
if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
} else {
rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
}
StringBuilder xmlSb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
xmlSb.append(line);
}
rd.close();
conn.disconnect();
JSONObject jsonSb = XML.toJSONObject(xmlSb.toString());
return jsonSb;
}
}
OpenApiService.java
service 코드는 아래와 같습니다.
public class OpenApiService {
private final OpenApiExplorer openApiExplorer;
private final HolidayRepository holidayRepository;
@Transactional
public List<Holiday> getHolidayService() throws IOException { // 공휴일 가져오기
// 샘플코드를 활용해서 xml -> jsonObject로 변환
List<Holiday> holidayList = new ArrayList<>();
// 올해
String solYear = String.valueOf(LocalDate.now().getYear());
for (int solMonth = 1; solMonth <= 12; solMonth++) {
// 숫자 2자리 맞춤
String strMonth = String.valueOf(solMonth);
while (strMonth.length() < 2) {
strMonth = "0" + strMonth;
}
JSONObject jsonData = openApiExplorer.getHolidayExplorer(solYear, strMonth);
JSONObject body = jsonData.getJSONObject("response").getJSONObject("body");
if (body.getInt("totalCount") != 0) {
// 공휴일 값이 하나일 때는 item이 jsonObject로 받아지기 때문에 조건문 사용
if (body.getInt("totalCount") == 1) {
JSONObject item = body.getJSONObject("items").getJSONObject("item");
if (item.getString("isHoliday").equals("Y")) { // 공휴일이 맞을 경우
String holidayDate = String.valueOf(item.getInt("locdate"));
if (!holidayRepository.existsByHolidayDate(holidayDate)) { // 중복 방지
String holidayName = item.getString("dateName");
Holiday holiday = com.drplus.drpay.domain.Holiday.builder()
.holidayDate(holidayDate)
.holidayName(holidayName)
.build();
holidayList.add(holiday);
}
}
} else {
JSONArray items = body.getJSONObject("items").getJSONArray("item");
for (Object item : items) { // 해당 월 공휴일 갯수
JSONObject map = new JSONObject(new Gson().toJson(item)).getJSONObject("map");
if (map.getString("isHoliday").equals("Y")) { // 공휴일이 맞을 경우
String holidayDate = String.valueOf(map.getInt("locdate"));
if (!holidayRepository.existsByHolidayDate(holidayDate)) { // 중복 방지
String holidayName = map.getString("dateName");
Holiday holiday = com.drplus.drpay.domain.Holiday.builder()
.holidayDate(holidayDate)
.holidayName(holidayName)
.build();
holidayList.add(holiday);
}
}
}
}
}
if (solYear.equals(String.valueOf(LocalDate.now().getYear())) && solMonth == 12) {
// 내년까지 저장
solYear = String.valueOf(LocalDate.now().plusYears(1).getYear());
solMonth = 1;
}
}
if (!holidayList.isEmpty()) {
holidayRepository.saveAll(holidayList);
return holidayList;
} else {
return holidayList;
}
}
}
getHolidayService 메서드
올해 1월 부터 내년 12월까지의 공휴일을 조회하고 DB에 저장하는 메서드
getHolidayService 코드 순서
- now().getYear로 올해 연도 String을 생성합니다.
- for문으로 1월부터 12월까지 반복문을 돌립니다. 1-9월은 앞에 0을 붙여 두자리수로 변경
ˇ 한자리 수로 요청 시 제대로 응답되지 않습니다. - getHolidayExplorer에서 받은 jsonObject에서 body에 해당하는 부분을 가져옵니다.
ˇ body 안에는 페이지당 항목수 / 페이지 / 모든 항목수 / 아이템(날짜/순번/종류/휴일 여부/명칭) - 항목수에 따라 item의 타입이 다르기 때문에 totalCount(모든 항목수)를 확인하여 타입 생성
ˇ 1개일 경우 item(jsonObject), 2개 이상일 경우 item(jsonArray)
- 휴일 여부 확인 후 날짜(Int) 데이터를 추출해 DB에 중복된 값인지 확인
ˇ 공휴일로 조회할 경우 휴일이 무조건 "Y"인지 활용 가이드에 설명이 없어 넣어두었습니다. - 명칭(String) 데이터 추출 후 Holiday로 빌드하여 List에 추가
ˇ 바로 Insert하지 않고 List에 저장한 이유는 결과값을 반환하기 위함입니다. - 올해면서 solMonth이 12월인 경우 solYear을 내년으로 solMonth은 1로 변경 후 for문 시작
- 내년까지 조회가 끝났다면 List의 isEmpty()에 따라 최종 holidayList를 반환
ˇ List값이 비어있지 않을 경우 전체 저장 후 List 반환, 비어있을 경우 빈 List 반환
[ Api Test ]
test 실행
// 비어있을 경우
[]
// 비어있지 않을 경우
[
{
"id": 1,
"holidayDate": "20210101",
"holidayName": "1월1일"
},
.
.
{
"id": 35,
"holidayDate": "20221225",
"holidayName": "기독탄신일"
}
]
DB 확인
성공!!
마무리
이렇게 Open API 공휴일 정보 조회 및 DB tb_holiday 저장하기 3편 - DB tb_holiday에 저장하기에 대해 알아보았습니다. 다들 성공하셨을까요?? 끝까지 화이팅 입니다!
- 4편은 "Jenkins를 Batch Scheduler로 활용하기"입니다!
https://green-joo.tistory.com/14
긴 글 봐주셔서 감사합니다!
오늘도 행복한 하루 보내세요 ✿'◡'✿