본문으로 건너뛰기

3.1. 공공데이터포털(data.go.kr) Open API 데이터 연계

3.1.1. 기상청 단기예보 서비스 연계

공공데이터포털(data.go.kr)에서 기상청에서 제공하는 기상정보를 예제로 하는 데이터 연계입니다.

  1. 공공데이터포털(data.go.kr)에 가입 후 '데이터 찾기' 메뉴에서 '기상청 단기예보'로 검색 합니다.

  2. 검색결과에서 dataportal_open_api_tab를 선택합니다. 목록에서 '기상청_단기예보 ((구)_동네예보) 조회서비스'을 활용신청합니다. dataportal_kma_short_term_forecast_search_result

  3. '기상청_단기예보 ((구)_동네예보) 조회서비스'을 활용 신청한 후 마이페이지에서 (초단기실황조회, 초단기예보조회, 단기예보조회, 예보버전조회)서비스를 사용할 수 있습니다. dataportal_kma_short_term_forecast_services

  4. 각 서비스에서 dataportal_kma_service_confim_btn을 클릭하면 간단하게 서비스를 테스트 할 수 있습니다. dataportal_kma_short_term_forecast_service_detail 초단기실황조회 확인 결과 화면

    dataportal_kma_short_term_forecast_service_request_result 발급받은 키를 인증키에 넣고 미리보기 결과 화면

  5. 수집관리UI(외부에서 접속 가능한 ingest-web 컨테이너의 주소 (예: http://localhost:8080/)) 을 접속합니다.

    ingest-web_agent_menu

    Agent 관리 > Agent 설정 메뉴를 클릭합니다.

    Agent설정 목록 화면에서 ingest-web_add_new_btn 을 클릭하여 내용을 작성합니다. 작성 예시는 다음과 같습니다. 저장 후에는 작성한 성남시 기상관측의 내용을 변경할 수 있습니다. ingest-web_seongnam_agent_example

    • Agent ID: 'M000000001'을 입력합니다. 10자 내외의 중복되지 않는 영문자, 숫자로 이루어진 ID를 입력하시면 됩니다.
    • Agent 명: '성남시 기상관측'을 입력합니다. 영문자,한글, 숫자가 가능하면 간단하게 설명할 내용을 입력하시면 됩니다.
    • 사용여부: '사용'을 선택합니다.
    • 각 항목을 입력 후 저장버튼을 클릭합니다.
  6. 5번에서 저장 후의 화면에서 '성남시 기상관측'을 클릭합니다. 나오는 화면에서 ingest-web_add_new_btn2 을 클릭합니다. 아답터를 동록하는 화면이며 등록 예시는 다음과 같습니다. 작성완료 후 저장 버튼을 클릭합니다. 작성완료 후에는 수정/삭제가 가능합니다.

    ingest-web_seongnam_agent_adaptor_example

    • Adaptor ID: 'pocWeatherObserved'를 입력합니다.
    • Adaptor 명: '성남시 기상관측' 을 입력합니다.
    • Platform 유형: 'Open API'를 선택합니다.
    • 작성 완료 후 저장버튼을 클릭합니다. 저장 후 화면은 다음과 같습니다. ingest-web_seongnam_agent_adaptor_list
  7. 위 6번항의 저장 후 화면에서 Adaptor ID인 'pocWeatherObserved'를 클릭 하면 Instance 관리 화면으로 이동합니다. Instance 관리 화면에서 ingest-web_add_new_btn2 클릭합니다. 등록 예시는 다음과 같습니다.

    ingest-web_seongnam_agent_instance_example

    • 인스턴스명: '성남시 기상관측'을 입력합니다.
    • 데이터모델 변환: '미변환'선택합니다. 미변환은 기 제공된 Java Class 를 이용합니다. '변환'을 선택할 경우 인스턴스가 저장된 후에 데이터 변환관리가 가능합니다. ingest-web_data_convert_mgmt_btn를 클릭하여 변환클래스를 직접 작성할 수 있습니다. 데이터 변환관리는 [3.1.3 데이터변환 관리]을 참고하여 작성합니다.
    • Adpator 유형: '성남시 기상관측'을 선택합니다. 메뉴 Adaptor 유형 관리에서 등록 된 유형을 선택할 수 있습니다. 유형을 선택하면 인스턴스 상세 항목이 표시됩니다.
    • 사용여부: '사용'을 선택합니다.
    • 작성 완료 후 저장 버튼을 클릭합니다.

    ingest-web_seongnam_agent_instance_mandatory_information 인스턴스 등록 필수 정보

    • 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) 단위로 데이터를 가져옵니다.

    ingest-web_seongnam_agent_instance_meta_information 인스턴스 데이터 메타정보

    • 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 모델의 구성 요소입니다.
    • 인스턴스 정보데이터 메타정보의 항목을 작성한 후 저장버튼을 클릭합니다.
  8. 성남시기상관측 인스턴스를 저장합니다. 저장된 instance 목록에서 Instance ID인 pocWeatherObserved_001를 클릭하시면 나오는 화면에서 반드시 ingest-web_apply_btn 클릭하면 '설정이 적용되었습니다'라고 뜹니다. 버튼을 클릭해 주셔야 아답터의 시작/중지 및 모니터링이 가능합니다. ingest-web_seongnam_agent_instance_example2

  9. 메뉴 Agent관리 > Agent 운영 에서 Agent ID -> M000000001 을 클릭합니다. ingest-web_seongnam_agent_management_detail

    '성남시 기상관측' 어댑터에서 시작/중지 , 모니터링이 가능합니다, 모니터링 클릭하면 모니터링 로그팝업 이 뜹니다. 아답터의 status 가 'Not exist config file' 일 경우 위의 8번항에서 !ingest-web_apply_btn 을 클릭해 주셔야 합니다.

    ingest-web_seongnam_agent_management_monitoring_log

3.1.2. 신규 어댑터 추가

3.1.2.1. 어댑터 유형 등록

ingest-web_adaptor_type_list 어댑터 유형 (Open API, oneM2M Platform, U-City Platform, Legacy Platform(RDBMS), 기타)의 기본 항목을 저장할 수 있습니다. 여기서 등록된 항목은 인스턴스 등록의 "Adaptor 유형"에서 활용됩니다.

ingest-web_add_btn을 클릭하여 성남시 기상관측 유형을 등록해 보겠습니다.

ingest-web_adaptor_seongnam_weather_example

  • 대상플랫폼 연계 유형: 콤보 박스에서 'Open API' 를 선택합니다.
  • 어댑터 유형: 입력란에 성남시 기상관측 입력합니다.
  • 사용여부: 콤보박스에서 사용 을 선택합니다.

어댑터 유형을 저장한 뒤 어댑터 유형ID -> 'A000000007' 을 클릭하면 아답터 유형의 상세 항목을 등록할 수 있습니다.

3.1.2.2. 어댑터 파라미터 관리

어댑터유형-ingest-web_adaptor_seongnam_weather_example2

어댑터 파라미터 관리 화면은 어댑터 파라미터 관리 , [성남시기상관측] 세부항목 으로 두 부분으로 나누어져 있으며, 어댑터 파라미터 관리에서는 어댑터가 작동하기 위한 필수 항목들입니다. 반드시 등록해야합니다.

  • 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'을 선택하면 아래와 같이 정보가 표시됩니다. ingest_web_seongnam_data_conversion_mgmt 여기서 ingest-web_datamodel_conversion_mgnt_btn을 클릭하시면 데이터 변환 관리 화면으로 이동합니다.

3.1.3.1. 데이터모델 변환 관리 화면

아래는 데이터 변환관리 화면입니다. ingest_web_seongnam_data_conversion_mgmt_detail 변환클래스 작성 탭에서 원천데이터를 표준모델에 맞게 변환클래스를 작성합니다.

ingest-web_compile_validation_btn은 작성 중인 파일의 유효성을 체크합니다. 컴파일 오류가 없으면 하단의 회색구역에 컴파일에 성공했습니다. 라고 메세지를 출력합니다. 오류가 있을 경우 해당 오류를 회색구역에 출력합니다. 컴파일에 성공했을 경우 닫기 버튼을 누르신 후 반드시 ingest-web_apply_btn을 클릭해 주셔야 ingest-daemon 서버에 적용이 됩니다.

ingest_web_seongnam_data_conversion_mgmt_coding_area 변환클래스의 코딩 부분이며 주석 부분인 소스코드 첨부부분의 시작에서 종료 사이에 변환 부분을 작성합니다. 아래 성남시 기상관측 변환 예제 전문입니다.

@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