3.1. 공공데이터포털(data.go.kr) Open API 데이터 연계
3.1.1. 기상청 단기예보 서비스 연계
공공데이터포털(data.go.kr)에서 기상청에서 제공하는 기상정보를 예제로 하는 데이터 연계입니다.
공공데이터포털(data.go.kr)에 가입 후 '데이터 찾기' 메뉴에서 '기상청 단기예보'로 검색 합니다.
검색결과에서
를 선택합니다. 목록에서 '기상청_단기예보 ((구)_동네예보) 조회서비스'을 활용신청합니다.
'기상청_단기예보 ((구)_동네예보) 조회서비스'을 활용 신청한 후 마이페이지에서 (초단기실황조회, 초단기예보조회, 단기예보조회, 예보버전조회)서비스를 사용할 수 있습니다.
각 서비스에서
을 클릭하면 간단하게 서비스를 테스트 할 수 있습니다.
초단기실황조회 확인 결과 화면
발급받은 키를 인증키에 넣고 미리보기 결과 화면
수집관리UI(외부에서 접속 가능한 ingest-web 컨테이너의 주소 (예: http://localhost:8080/)) 을 접속합니다.
Agent 관리 > Agent 설정 메뉴를 클릭합니다.
Agent설정 목록 화면에서
을 클릭하여 내용을 작성합니다. 작성 예시는 다음과 같습니다. 저장 후에는 작성한 성남시 기상관측의 내용을 변경할 수 있습니다.
- Agent ID: 'M000000001'을 입력합니다. 10자 내외의 중복되지 않는 영문자, 숫자로 이루어진 ID를 입력하시면 됩니다.
- Agent 명: '성남시 기상관측'을 입력합니다. 영문자,한글, 숫자가 가능하면 간단하게 설명할 내용을 입력하시면 됩니다.
- 사용여부: '사용'을 선택합니다.
- 각 항목을 입력 후 저장버튼을 클릭합니다.
5번에서 저장 후의 화면에서 '성남시 기상관측'을 클릭합니다. 나오는 화면에서
을 클릭합니다. 아답터를 동록하는 화면이며 등록 예시는 다음과 같습니다. 작성완료 후 저장 버튼을 클릭합니다. 작성완료 후에는 수정/삭제가 가능합니다.
- Adaptor ID: 'pocWeatherObserved'를 입력합니다.
- Adaptor 명: '성남시 기상관측' 을 입력합니다.
- Platform 유형: 'Open API'를 선택합니다.
- 작성 완료 후 저장버튼을 클릭합니다. 저장 후 화면은 다음과 같습니다.
위 6번항의 저장 후 화면에서 Adaptor ID인 'pocWeatherObserved'를 클릭 하면 Instance 관리 화면으로 이동합니다. Instance 관리 화면에서
클릭합니다. 등록 예시는 다음과 같습니다.
- 인스턴스명: '성남시 기상관측'을 입력합니다.
- 데이터모델 변환: '미변환'선택합니다. 미변환은 기 제공된 Java Class 를 이용합니다. '변환'을 선택할 경우 인스턴스가 저장된 후에 데이터 변환관리가 가능합니다.
를 클릭하여 변환클래스를 직접 작성할 수 있습니다. 데이터 변환관리는 [3.1.3 데이터변환 관리]을 참고하여 작성합니다.
- Adpator 유형: '성남시 기상관측'을 선택합니다. 메뉴 Adaptor 유형 관리에서 등록 된 유형을 선택할 수 있습니다. 유형을 선택하면 인스턴스 상세 항목이 표시됩니다.
- 사용여부: '사용'을 선택합니다.
- 작성 완료 후 저장 버튼을 클릭합니다.
인스턴스 등록 필수 정보
- DATASET_ID: 'pocWeatherObserved'를 입력합니다. City Data Hub 시스템의 데이터셋 아이디를 입력합니다.
- MODEL_ID: 'WeatherObserved'를 입력합니다. City Data Hub 시스템의 모델 아이디를 입력합니다.
- INVOKE_CLASS: 'com.cityhub.adapter.convex.ConvWeatherObserved'를 입력합니다. 변환 클래스입니다.
- CONN_TERM: '3600'를 입력합니다. 초단위이며 1시간(60*60) 단위로 데이터를 가져옵니다.
인스턴스 데이터 메타정보
- ParamVarible: 'base_date,base_time'를 입력합니다. 기상측정OPEN API에서 가변값 처리를 위해 사용할 변수를 설정합니다.
- base_date: 'yyyyMMdd,MINUTE,-40'를 입력합니다. 20220920으로 변환되며 'MINUTE,-40'은 현시간으로부터 40분전을 의미합니다. 9월21일 0시 30분에 수집할 경우 20220921이 아닌 20220920으로 반환합니다.
- base_time: 'HHmm,MINUTE,-40'를 입렵합니다. 현재 시간이 오후 3시 45분일 경우 1505으로 변환됩니다. 이와같이 하는 이유는 기상청 정보 갱신주기 문제로 인해서 입니다.
- gs1Code: 'urn:datahub:WeatherObserved:14858'를 입력합니다. 성남시 수정구의 아이디 값입니다.
- url_addr: 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst?dataType=json&numOfRows=1000&nx=63&ny=124&serviceKey='를 입력합니다. 서비스 키(serviceKey)는 공공데이터포털에서 활용신청 후 발급 받은 키를 적용해 주시면 됩니다. 'nx=63, ny=124'는 기상정보를 구하고자하는 위경도 입니다.
- addressCountry: 'KR'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- addressRegion: '경기도'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- addressLocality: '성남시'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- addressTown: '수정구'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- streetAddress: '경기도 성남시 수정구 수정로 319'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- location: '[127.14858, 37.4557691]'를 입력합니다. WeatherObserved 모델의 구성 요소입니다.
- 인스턴스 정보 및 데이터 메타정보의 항목을 작성한 후 저장버튼을 클릭합니다.
성남시기상관측 인스턴스를 저장합니다. 저장된 instance 목록에서 Instance ID인 pocWeatherObserved_001를 클릭하시면 나오는 화면에서 반드시
클릭하면 '설정이 적용되었습니다'라고 뜹니다. 버튼을 클릭해 주셔야 아답터의 시작/중지 및 모니터링이 가능합니다.
메뉴 Agent관리 > Agent 운영 에서 Agent ID -> M000000001 을 클릭합니다.
'성남시 기상관측' 어댑터에서 시작/중지 , 모니터링이 가능합니다, 모니터링 클릭하면 모니터링 로그팝업 이 뜹니다. 아답터의 status 가 'Not exist config file' 일 경우 위의 8번항에서 !
을 클릭해 주셔야 합니다.
3.1.2. 신규 어댑터 추가
3.1.2.1. 어댑터 유형 등록
어댑터 유형 (Open API, oneM2M Platform, U-City Platform, Legacy Platform(RDBMS), 기타)의 기본 항목을 저장할 수 있습니다. 여기서 등록된 항목은 인스턴스 등록의 "Adaptor 유형"에서 활용됩니다.
을 클릭하여 성남시 기상관측 유형을 등록해 보겠습니다.
- 대상플랫폼 연계 유형: 콤보 박스에서 'Open API' 를 선택합니다.
- 어댑터 유형: 입력란에 성남시 기상관측 입력합니다.
- 사용여부: 콤보박스에서 사용 을 선택합니다.
어댑터 유형을 저장한 뒤 어댑터 유형ID -> 'A000000007' 을 클릭하면 아답터 유형의 상세 항목을 등록할 수 있습니다.
3.1.2.2. 어댑터 파라미터 관리
어댑터 파라미터 관리 화면은 어댑터 파라미터 관리 , [성남시기상관측] 세부항목 으로 두 부분으로 나누어져 있으며, 어댑터 파라미터 관리에서는 어댑터가 작동하기 위한 필수 항목들입니다. 반드시 등록해야합니다.
- MODEL_ID: City Data Hub 시스템에서 사용하는 모델의 ID 값을 입력합니다. 'WeatherObserved'를 입력합니다.
- CONN_TERM: 갱신 주기를 입력합니다. 단위는 초단위 입니다. '3600'을 입력합니다. 1시간 주기입니다.
- INVOKE_CLASS: 기 등록된 실핼 클래스를 등록합니다. 또는 원천데이터에서 표준데이터 변환하는 클래스를 입력합니다. 'com.cityhub.adapter.convex.ConvWeatherObserved'을 입력합니다.
- DATASET_ID: City Data Hub 시스템에서 등록된 DATASET_ID 를 입력합니다. 'pocWeatherObserved'를 입력합니다.
3.1.2.3. [성남시기상관측] 세부항목
[성남시기상관측] 세부항목 은 공공데이터포털에서 데이터를 가지고 오기 위한 파라미터를 설정하는 곳입니다.
- url_addr: 공공데이터포털에서 기상관측 서비스의 URL을 입력합니다. 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst?dataType=json&numOfRows=1000&nx=63&ny=124&serviceKey=인증키'를 입력합니다. 파라미터 값 중에 serviceKey는 공공데이터포털에서 활성화된 인증키를 등록합니다.nx=37&ny=127값은 측정하고자 하는 위치의 위경도 입니다.
- ParamVariable: 기상관측의 경우 base_date, base_time이 가변값입니다. 어댑터 관리 시스템의 예약어인 ParamVariable 를 이용하여 가변값을 처리합니다.
- base_date: 현재 연월일을 가지고 오기 위해서 'yyyyMMdd,MINUTE,-40'를 입력합니다. 'MINUTE,-40' 갱싱 주기 차이 때문에 현시간으로 부터 40분전 연월일을 가져옵니다.
- base_time: 현재 시간을 가지고 오기 위해서 'HHmm,MINUTE,-40'를 입력합니다. 'MINUTE,-40' 갱싱 주기 차이 때문에 현시간으로 부터 40분전 시간을 가져옵니다.
- location: '[127.14858, 37.4557691]'를 입력합니다.
- addressCountry: 'KR', 표준모델에서 쓰이는 메타정보의 국가를 입력합니다.
- addressRegion: '경기도', 표준모델에서 쓰이는 메타정보의 지역명(도)을 입력합니다.
- addressLocality: '성남시', 표준모델에서 쓰이는 메타정보의 지역명(시)을 입력합니다.
- addressTown: '수정구', 표준모델에서 쓰이는 메타정보의 지역명(군구) 입력합니다.
- streetAddress: '경기도 성남시 수정구 수정로 319', 표준모델에서 쓰이는 메타정보의 도로명주소를 입력합니다.
- gs1Code: 'urn:datahub:WeatherObserved:14858', 항목명칭인 gs1Code 편의상 등록한 이름이며, ID , id_prefix 등 필요에 맞게 등록 가능합니다.
3.1.3 데이터변환 관리
3.1.1.의 7번 지시사항에서 데이터모델 변환을 선택하고 저장 후 인스턴스 목록에서 'pocWeatherObserved_001'을 선택하면 아래와 같이 정보가 표시됩니다.
여기서
을 클릭하시면 데이터 변환 관리 화면으로 이동합니다.
3.1.3.1. 데이터모델 변환 관리 화면
아래는 데이터 변환관리 화면입니다.
변환클래스 작성 탭에서 원천데이터를 표준모델에 맞게 변환클래스를 작성합니다.
은 작성 중인 파일의 유효성을 체크합니다. 컴파일 오류가 없으면 하단의 회색구역에 컴파일에 성공했습니다. 라고 메세지를 출력합니다. 오류가 있을 경우 해당 오류를 회색구역에 출력합니다. 컴파일에 성공했을 경우 닫기 버튼을 누르신 후 반드시
을 클릭해 주셔야 ingest-daemon 서버에 적용이 됩니다.
변환클래스의 코딩 부분이며 주석 부분인 소스코드 첨부부분의 시작에서 종료 사이에 변환 부분을 작성합니다.
아래 성남시 기상관측 변환 예제 전문입니다.
@Override
public String doit() {
List<Map<String,Object>> modelList = new LinkedList<>();
String id = "";
try {
// 표준모델 가져오기
JSONObject modelTemplate = templateItem.getJSONObject(ConfItem.getString("modelId"));
JSONArray svcList = ConfItem.getJSONArray("serviceList");
for (int i = 0; i < svcList.length(); i++) {
JSONObject iSvc = svcList.getJSONObject(i);
id = iSvc.getString("gs1Code");
JsonUtil jsonModel = new JsonUtil(modelTemplate.toString());
// 원시 모델 가져오기
JsonUtil ju = new JsonUtil((JSONObject) CommonUtil.getData(iSvc));
// 원시 데이터를 파싱해서 표준모델에 맞게 변환 하는 부분 - 시작
// 예제 부분이며 '시작-종료' 까지 내용을 제거 한 후 표준 모델에 맞게 구현
JSONArray arrList = ju.getArray("response.body.items.item");
toLogger(SocketCode.DATA_RECEIVE, id, ju.toString().getBytes());
Map<String,Object> wMap = new LinkedHashMap<>();
for (Object obj : arrList) {
JSONObject item = (JSONObject) obj;
if ("PTY".equals(item.getString("category"))) {
wMap.put("rainType", WeatherType.findBy(item.getInt("obsrValue")).getEngNm());
}
if ("T1H".equals(item.getString("category"))) {
wMap.put("temperature", JsonUtil.nvl(item.get("obsrValue"), DataType.FLOAT));
}
if ("RN1".equals(item.getString("category"))) {
wMap.put("rainfall", JsonUtil.nvl(item.get("obsrValue"), DataType.FLOAT));
wMap.put("hourlyRainfall", JsonUtil.nvl(item.get("obsrValue"), DataType.INTEGER));
}
if ("WSD".equals(item.getString("category"))) {
wMap.put("windSpeed", JsonUtil.nvl(item.get("obsrValue"), DataType.FLOAT));
}
if ("REH".equals(item.getString("category"))) {
wMap.put("humidity", JsonUtil.nvl(item.get("obsrValue"), DataType.FLOAT));
}
if ("S06".equals(item.getString("category"))) {
wMap.put("snowfall", JsonUtil.nvl(item.get("obsrValue"), DataType.FLOAT));
}
} // end for
jsonModel.put("id", iSvc.getString("gs1Code"));
jsonModel.put("address.value.addressCountry", JsonUtil.nvl(iSvc.getString("addressCountry")) );
jsonModel.put("address.value.addressRegion", JsonUtil.nvl(iSvc.getString("addressRegion")) );
jsonModel.put("address.value.addressLocality", JsonUtil.nvl(iSvc.getString("addressLocality")) );
jsonModel.put("address.value.addressTown", JsonUtil.nvl(iSvc.getString("addressTown")) );
jsonModel.put("address.value.streetAddress", JsonUtil.nvl(iSvc.getString("streetAddress")) );
jsonModel.put("weatherObservation.value", wMap);
jsonModel.put("weatherObservation.observedAt", DateUtil.getTime());
jsonModel.put("location.observedAt", DateUtil.getTime());
jsonModel.put("location.value.coordinates", iSvc.getJSONArray("location").toList());
// 원시 데이터를 파싱해서 표준모델에 맞게 변환 하는 부분 - 종료
toLogger(SocketCode.DATA_CONVERT_SUCCESS, id, jsonModel.toString().getBytes());
toLogger(SocketCode.DATA_SAVE_REQ, id, jsonModel.toString().getBytes());
modelList.add(jsonModel.toMap());
} // for (int i = 0; i < svcList.length(); i++)
// 데이터허브에 전송
sendEvent(modelList, ConfItem.getString("datasetId"));
} catch (Exception e) {
toLogger(SocketCode.DATA_CONVERT_FAIL, id, e.getMessage());
log.error("Exception : " + ExceptionUtils.getStackTrace(e));
}
return "Success";
} // end of doit