공공데이터 회원가입
처음 사용하는거라면 회원가입을 해야한다.

활용신청

API주소 JSON 변환
미리보기 확인을 누르고 미리보기 버튼을 눌러본다.

그러면 아래와 같이 데이터가 조회되는 페이지로 이동된다.

주소창의 주소를 복사해둔다.
아래 주소를 사용해도 데이터가 조회되지 않을것이다.(서비스키가 다름)
https://apis.data.go.kr/B551182/rprtPtntDiagCnfcInfoService1/getRprtPtntDiagCnfcInfo1?serviceKey=Mi509VSdtp6o1yGDQavvvddeDig%2F0dIDK5IdUUoT7344448wmnUEVQ1ueuZ2PLm6Pt%2BT8X7Bw%3D%3D&numOfRows=10&pageNo=1&_type=json
JSON data -> JAVA obj로 변환준비
위에서 복사해둔 주소를 아래 페이지에 붙여넣어도 되고 반환되는 json데이터를 붙여넣어도 된다.
나는 주소를 붙여넣어서 해보려 했더니 에러가 나서 일단 json파일을 붙여넣었다.

json데이터를 입력하고 preview버튼을 누르면 아래 데이터가 추출된다.
-----------------------------------com.example.Body.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Body {
@SerializedName("items")
@Expose
public Items items;
@SerializedName("numOfRows")
@Expose
public Integer numOfRows;
@SerializedName("pageNo")
@Expose
public Integer pageNo;
@SerializedName("totalCount")
@Expose
public Integer totalCount;
}
-----------------------------------com.example.Example.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Example {
@SerializedName("response")
@Expose
public Response response;
}
-----------------------------------com.example.Header.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Header {
@SerializedName("resultCode")
@Expose
public String resultCode;
@SerializedName("resultMsg")
@Expose
public String resultMsg;
}
-----------------------------------com.example.Item.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Item {
@SerializedName("addr")
@Expose
public String addr;
@SerializedName("cv19ExmTyCd")
@Expose
public String cv19ExmTyCd;
@SerializedName("dgmPrscPsblYn")
@Expose
public String dgmPrscPsblYn;
@SerializedName("diagBknPsblTelno")
@Expose
public String diagBknPsblTelno;
@SerializedName("infcPtntDiagTyCd")
@Expose
public String infcPtntDiagTyCd;
@SerializedName("onstpMadmYn")
@Expose
public String onstpMadmYn;
@SerializedName("rprtPtntDiagPsblYn")
@Expose
public String rprtPtntDiagPsblYn;
@SerializedName("sgguNm")
@Expose
public String sgguNm;
@SerializedName("sidoNm")
@Expose
public String sidoNm;
@SerializedName("yadmNm")
@Expose
public String yadmNm;
@SerializedName("ykiho")
@Expose
public String ykiho;
}
-----------------------------------com.example.Items.java-----------------------------------
package com.example;
import java.util.List;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Items {
@SerializedName("item")
@Expose
public List<Item> item;
}
-----------------------------------com.example.Response.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@Generated("jsonschema2pojo")
public class Response {
@SerializedName("header")
@Expose
public Header header;
@SerializedName("body")
@Expose
public Body body;
}
spring 앱 생성

의존성 도구 추가

버전호환이 되지 않는것 같음...
자세한것은 나중에 찾아보기로 함

build.gradle 수정
java version, spirng-boot version

application.properties파일명 변경 및 내용 삽입
batch, domain, web pakage 추가

일정주기로 반복작업하는 scheduled처리할 HospDownloadBatch.java파일과 공공데이터에서 받아온 데이터를 받아 줄 ResponseDto.java파일 생성

json파일을 java obj로 변환 준비할때 복사해두었던 java코드를 가져와서 수정했다.
package com.example.pcrhospital.batch;
import java.util.List;
import lombok.Data;
@Data
class Body {
private Items items;
private Integer numOfRows;
private Integer pageNo;
private Integer totalCount;
}
@Data
class Example {
private Response response;
}
@Data
class Header {
private String resultCode;
private String resultMsg;
}
@Data
class Item {
private String addr;
private String cv19ExmTyCd;
private String dgmPrscPsblYn;
private String diagBknPsblTelno;
private String infcPtntDiagTyCd;
private String onstpMadmYn;
private String rprtPtntDiagPsblYn;
private String sgguNm;
private String sidoNm;
private String yadmNm;
private String ykiho;
}
@Data
class Items {
private List<Item> item;
}
@Data
class Response {
private Header header;
private Body body;
}
@Data
public class ResponseDto {
private Response response;
}
test 코드 생성
앞서 확인하였던 api 주소를 가져와서 url 변수에 붙여넣는다.
인코딩 방지를 위해서 url을 URI로 다시 생성해서 인자에 넣는다.

RestTemplate객체로 호출해서 데이터를 가져오면 ResponseDto객체로 받을 수 있다.
위 코드를 실행하면 콘솔창에 정상적으로 데이터를 읽을 수 있음을 확인 가능하다.
JPA 모델 만들기
domain 패키지에 Hospital.java 파일 생성

서버를 재실행하면 테이블이 생성되는것을 알 수 있다.
공공데이터에서 조회한 전체 목록을 list에 담아내기
조회된 공공데이터 전체를 하나의 컬렉션에 담기 테스트 코드작성

/**
* <pre>
* 조회된 공공데이터 컬렉션에 담기
* </pre>
* @throws URISyntaxException
*/
@Test
public void download() throws URISyntaxException {
List<Hospital> hospitals = new ArrayList<>();
RestTemplate rt = new RestTemplate();
int totalCount = 2;
String url = "https://apis.data.go.kr/B551182/rprtPtntDiagCnfcInfoService1/getRprtPtntDiagCnfcInfo1?" +
"serviceKey="+ serviceKey +
"&pageNo=1" +
"&_type=json" +
"&numOfRows=";
ResponseDto totalCntDto = rt.getForObject(new URI(url+totalCount), ResponseDto.class);
totalCount = totalCntDto.getResponse().getBody().getTotalCount();
ResponseDto responseDto = rt.getForObject(new URI(url+totalCount), ResponseDto.class);
List<Item> items = responseDto.getResponse().getBody().getItems().getItem();
System.out.println("totalCount = " + items.size());
items.stream().map(item -> {
Hospital hospital = new Hospital();
hospital.setYkiho(item.getYkiho());
hospital.setAddr(item.getAddr());
hospital.setCv19ExmTyCd(item.getCv19ExmTyCd());
hospital.setDgmPrscPsblYn(item.getDgmPrscPsblYn());
hospital.setYadmNm(item.getYadmNm());
hospital.setDiagBknPsblTelno(item.getDiagBknPsblTelno());
hospital.setInfcPtntDiagTyCd(item.getInfcPtntDiagTyCd());
hospital.setOnstpMadmYn(item.getOnstpMadmYn());
hospital.setRprtPtntDiagPsblYn(item.getRprtPtntDiagPsblYn());
hospital.setSidoNm(item.getSidoNm());
hospital.setSgguNm(item.getSgguNm());
return hospital;
}).forEach(hospitals::add);
방법 2
// hospitals = items.stream().map((e) -> {
// return Hospital.builder()
// .addr(e.getAddr())
// .cv19ExmTyCd(e.getCv19ExmTyCd())
// .dgmPrscPsblYn(e.getDgmPrscPsblYn())
// .diagBknPsblTelno(e.getDiagBknPsblTelno())
// .infcPtntDiagTyCd(e.getInfcPtntDiagTyCd())
// .onstpMadmYn(e.getOnstpMadmYn())
// .infcPtntDiagTyCd(e.getInfcPtntDiagTyCd())
// .onstpMadmYn(e.getOnstpMadmYn())
// .rprtPtntDiagPsblYn(e.getRprtPtntDiagPsblYn())
// .sgguNm(e.getSgguNm())
// .sidoNm(e.getSidoNm())
// .yadmNm(e.getYadmNm())
// .ykiho(e.getYkiho())
// .build();
// }).collect(Collectors.toList());
assertEquals(totalCount, items.size());
}
데이터컬렉션 데이터베이스에 저장
스케쥴러에 포함시켜서 테스트하였다.

데이터베이스에서 확인
h2 database에 접속

모든 데이터가 저장되었음

view 만들기
view 페이지는 mustache를 이용하였다.
프로젝트에서 html확장자로 파일을 만들어서 html5템플릿만 로딩하고 확장자를 .mustache로 변경하였다.

<!DOCTYPE html>
<html lang="en">
<head>
<title>PCR 병원조회 서비스</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Onyu Love</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar"
aria-expanded="true" style="cursor: pointer">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/">홈</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<br>
<h3>병원 조회 서비스</h3>
<form action="/" method="get">
<div class="mb-3 mt-3">
<select class="form-select" name="sidoNm" id="sidoNm" onchange="">
{{#sidoNms}}
<option>{{.}}</option>
{{/sidoNms}}
</select>
</div>
<div class="mb-3">
<select class="form-select" name="sgguNm" id="sgguNm">
{{#sgguNms}}
<option>{{.}}</option>
{{/sgguNms}}
</select>
</div>
<button type="submit" class="btn btn-primary">병원찾기</button>
</form>
<hr/>
<table class="table">
<thead>
<tr>
<th>병원명</th>
<th>PCR검사여부</th>
<th>병원주소</th>
</tr>
</thead>
<tbody>
{{#hospitals}}
<tr>
<td>{{yadmNm}}</td>
<td>{{dgmPrscPsblYn}}</td>
<td>{{addr}}</td>
</tr>
{{/hospitals}}
</tbody>
</table>
</div>
<script>
let getSggNm = async (sidoNm) => {
let response = await fetch(`http://localhost:8000/api/sgguNm?sidoNm=${sidoNm}`);
let responseParsed = await response.json();
setSggNm(responseParsed)
}
let setSggNm = (sgguNms) => {
let sgguNmDom = document.getElementById('sgguNm');
sgguNmDom.innerHTML = '';
sgguNms.forEach((sgguNm) => {
let option = document.createElement('option');
option.text = sgguNm;
sgguNmDom.append(option);
})
}
let sidoNm = document.getElementById('sidoNm');
sidoNm.addEventListener('change', (e)=> {
let sidoNm = e.target.value;
getSggNm(sidoNm)
})
</script>
</body>
</html>
페이지 로딩을 위한 controller 생성

현재까지 완성된 코드이다.
데이터베이스에서 데이터를 불러올 repository 생성

mFindHospital 함수는 병원목록 조회
mFindSidoNm 함수는 시도명 셀렉트버튼에 목록을 불러오기 위한 함수
mFindSgguNm 함수는 시도명 아래 시군구 셀렉트버튼에 목록을 불러오기 위한 함수
조회 화면
