giljabi.kr는 경로탐색과 고도 정보 취득하는 서비스 2개는 외부 API를 사용하고 있습니다.
구글맵의 direct api를 사용하고 싶은데, 한국에서는 서비스가 안되어 openrouteservice를 사용합니다. 경로탐색은 openrouteservie를 사용하고 있고, 고도 정보는 google api를 사용하고 있습니다. 오늘은 openrouteservice에서 사용하는 경로 탐색 기능을 api로 작성하는 방법입니다.
자세한 내용은 웹페이지에 접속해보면 알 수 있습니다.
Openrouteservice
Directions Openrouteservice’s directions can be used all around the globe. Consume rich route instructions in your applications for cars, trucks, different bike profiles, walking, hiking or wheelchair. Make use of plenty of options, ranging from differen
openrouteservice.org
여기서 사용할 api는 direction api입니다. /v2/direction/{profile}/json api를 이용하겠습니다. 가입 후 api key를 받으면 사용 가능합니다. api key를 헤더 정보에 넣고 시작 위치, 목표 위치를 입력하면 응답을 받을 수 있습니다.
입력 데이터 body에 아래와 같이 입력하고 "call action"을 클릭하면 아래 그림과 같이 지도에 표현되는 화면을 볼 수 있습니다.
{"elevation":"true","coordinates":[[127.021374295649,37.58052832938857],[127.0391273352651,37.58340695922779]]}
먼저 요청 데이터는 postman에서 아래와 같이 입력합니다. 카카오 지도에서 2개 위치정보를 구한 다음에 아래와 같이 작성해서 요청합니다.
{
"start_lat": 37.58052832938857,
"start_lng": 127.021374295649,
"target_lat": 37.58340695922779,
"target_lng": 127.0391273352651,
"profile": "cycling-road"
}
서버에서 openrouteservice에 요청하는 방법이며 apikey는 발급받은 키를 입력하면 됩니다. 우리는 고도 정보도 필요하므로 elevation을 true로 요청합니다.
//https://api.openrouteservice.org/v2/directions/%s/json
directionUrl = String.format(directionUrl, request.getProfile());
Double[] start = new Double[]{request.getStart_lng(), request.getStart_lat()};
Double[] target = new Double[]{request.getTarget_lng(), request.getTarget_lat()};
Double[][] coordinates = {start, target}; //2개 위치만 사용
HttpPost httpPost = new HttpPost(directionUrl);
httpPost.setHeader("Authorization", apikey);
httpPost.setHeader("Accept", "application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8");
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
JSONObject json = new JSONObject();
json.put("coordinates", coordinates); //좌표 배열로 입력 가능....
json.put("elevation", "true");
이제 요청하고 결과를 받아 옵니다.
StringEntity postEntity = new StringEntity(json.toString());
httpPost.setEntity(postEntity);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
CloseableHttpResponse response = httpClient.execute(httpPost);
if (response.getStatusLine().getStatusCode() != 200)
throw new Exception(response.getStatusLine().getStatusCode() +
":openrouteservice 오류입니다.");
ResponseHandler<String> handler = new BasicResponseHandler();
String body = handler.handleResponse(response);
log.info(body);
예외처리는 좀 더 다듬어야 하지만 지금은 넘어가고 나중에 처리합니다. 응답된 데이터는 아래와 같이 나옵니다.
{"routes":[
{"summary":
{"distance":1965.2,"duration":302.8,"ascent":1.8,"descent":9.8},
"segments":
[{"distance":1965.2,"duration":302.8,
"steps":[
{"distance":46.4,"duration":9.3,"type":11,"instruction":"Head southeast on 보문로13가길","name":"보문로13가길","way_points":[0,2]},
{"distance":51.5,"duration":10.3,"type":0,"instruction":"Turn left onto 보문로13길","name":"보문로13길","way_points":[2,3]},
{"distance":201.2,"duration":30.2,"type":1,"instruction":"Turn right onto 보문로","name":"보문로","way_points":[3,6]},
{"distance":48.3,"duration":7.2,"type":0,"instruction":"Turn left","name":"-","way_points":[6,9]},
{"distance":659.6,"duration":98.9,"type":4,"instruction":"Turn slight left onto 안암로","name":"안암로","way_points":[9,21]},
{"distance":97.3,"duration":14.6,"type":1,"instruction":"Turn right","name":"-","way_points":[21,33]},
{"distance":758.4,"duration":113.8,"type":1,"instruction":"Turn right onto 약령시로","name":"약령시로","way_points":[33,55]},
{"distance":55.9,"duration":9.2,"type":0,"instruction":"Turn left onto 고산자로","name":"고산자로","way_points":[55,59]},
{"distance":46.7,"duration":9.3,"type":1,"instruction":"Turn right onto 고산자로46길","name":"고산자로46길","way_points":[59,61]},
{"distance":0.0,"duration":0.0,"type":10,"instruction":"Arrive at 고산자로46길, on the right","name":"-","way_points":[61,61]}
],"ascent":1.7749999999999986,"descent":9.84172496795654}
],
"bbox":[127.021337,37.578574,20.93,127.039125,37.583459,29.78],
"geometry":"g}jdFkzgfWgtD@??jAi@?a@kB?|CkA?tCuA`@XKHDYHD_ARASHOUHkAoBz@s@mA\\c@u@Lu@qA@aA}A?sCuE?GI?wBqDmBaC}DwEs@sA[KS@FIBDIDDOFBIH@SH?MHAIHGWHGKHIOHOKH[GH?CH?i@HAg@HGeEz@Aa@HAsA\\C{Cz@AuAjBCwB`F?Ef@AuAvBEuCnF?Kf@AcB`C?GR?}@f@CqCvBE}BbBCgBpAAg@NCcA\\Ao@R[?HI?Ha@@N[?RAYRAmAz@",
"way_points":[0,61]
}
],
"bbox":[127.021337,37.578574,20.93,127.039125,37.583459,29.78],
"metadata":{
"attribution":"openrouteservice.org | OpenStreetMap contributors",
"service":"routing","timestamp":1632560803968,
"query":{
"coordinates":[[127.021374295649,37.58052832938857],[127.0391273352651,37.58340695922779]],
"profile":"cycling-road","format":"json","elevation":true
},
"engine":{
"version":"6.6.1","build_date":"2021-07-12T01:00:30Z","graph_date":"2021-09-14T09:51:09Z"
}
}
}
많은 데이터가 있습니다만 우리가 필요한 건 중간쯤에 있는 geometry 정보입니다. 데이터는 encoding 되어 있어 decoding을 해야 합니다. decoding 방법은 https://github.com/GIScience/openrouteservice-docs 여기에 나와 있습니다. json데이터를 Object로 파싱 하는 class를 하나 만들어서 geometry를 추출하고 decoding 한 후 배열로 처리해서 postman에서 응답 데이터를 확인하면 아래와 같습니다.
{
"status": 200,
"code": "OK",
"message": null,
"data": [
{
"lat": 127.02134,
"lng": 37.58052,
"ele": 29.0
},
{
"lat": 127.02134,
"lng": 37.58051,
"ele": 29.0
},
...
}
여기까지 openrouteservice를 사용하는 api 간단한 설명입니다.