유저가 지정한 장소에 대해 네이버 지도앱의 길찾기 redirect URL을 구현하였다.
먼저 네이버 지도앱의 길찾기 URL을 확인하였다.
nmap://route/public?dlat={도착지 위도}&dlng={도착지 경도}dname={도착지 이름}
위 URL을 만들기 위해 위/경도를 가져와야 했는데, 이 부분은 네이버 지도 api 중 geocoding을 활용하였다. 자세한 설명은 아래 공식문서를 확인하자
https://api.ncloud-docs.com/docs/ai-naver-mapsgeocoding
Geocoding 사용법
아래 내용은 위/경도 를 가져오기 위해 사용한 방법으로, URL을 만드는 것과는 연관성이 없다.
현재 네이버 지도 api는 naver cloud platform에 속해있다. 따라서 회원가입을 진행해야 한다. (23년 7월 기준으로 나중에 또 바뀔거 같다. 자주 바뀌는듯..)
https://www.ncloud.com/?language=ko-KR
로그인 후 대시보드에서 AI·NAVER API 를 클릭한다.
그후 아래 화면에서 파란색 application 등록을 통해 새로 만들어준다. (staticMap도 사용할 줄 할고 해두었는데 사용하지 않았다.)
추가로, 네이버가 maps api를 모두 유료화하였기 때문에 무료이용량 횟수를 잘 보고 한도 횟수를 제한해두는 것이 좋을 것 같다.
현재 service는 아래와 같이 구현하였다. exception 일부는 또 수정해야 할 것 같다.
@Slf4j
@RequiredArgsConstructor
@Service
public class MapService {
@Value("${api.naver-client-id}")
String clientId;
@Value("${api.naver-client-secret}")
String clientSecret;
public String getMapUrl(String reqLocation) throws BaseException {
String resultUrl = null;
try {
String address = reqLocation;
String addr = URLEncoder.encode(address, "UTF-8");
log.debug("address = {}", address);
String apiURL = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query=" + addr;
URL url = new URL(apiURL);
log.debug("url = {}", url);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
con.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);
int responseCode = con.getResponseCode();
BufferedReader br;
if (responseCode == 200) {
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
} else {
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
ObjectMapper objectMapper = new ObjectMapper();
log.debug("response = {} response.string = {}", response, response.toString());
JsonNode jsonNode = objectMapper.readTree(response.toString());
log.debug("jsonNode = {}", jsonNode);
JsonNode addressesNode = jsonNode.get("addresses");
log.debug("addressesNode = {}", addressesNode);
if (addressesNode != null && addressesNode.isArray()) {
for (JsonNode addressNode : addressesNode) {
String roadAddress = getParsedUrl(addressNode.get("roadAddress").asText());
// String jibunAddress = addressNode.get("jibunAddress").asText();
String latitude = addressNode.get("y").asText();
String longitude = addressNode.get("x").asText();
log.debug("latitude = {} and longitude = {}", latitude, longitude);
resultUrl = "nmap://route/public?dlat=" + latitude + "&dlng=" + longitude + "&dname=" + roadAddress;
}
}
} catch (UnsupportedEncodingException e) {
log.debug("UnKnownAddrException 발생 ");
throw new BaseException(ResponseStatus.UNKNOWN_ADDR);
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return resultUrl;
}
public String getParsedUrl(String roadAddress) throws UnsupportedEncodingException {
String[] words = roadAddress.split(" ");
String last_addr = words[words.length - 1];
return URLEncoder.encode(last_addr, "UTF-8");
}
}
일단은 쿼리스트링을 통해 정확한 주소를 입력받도록 하였는데, 완전 정확한 주소가 아니면 출력이 되지 않는 문제가 있어 이는 나중에 다시 해결해야 할 것 같다. 아마 카카오 api 로 변경해서 가져오도록 할 예정이다.
현재 해당 코드는 카카오 api를 통해 유저가 지정한 location(ex. 아산병원)에 대해 그 장소에 대한 좌표를 확인하고, 그 값을 쿼리스트링으로 보내도록 하였다. 아래는 서비스단의 코드이다.
@Slf4j
@RequiredArgsConstructor
@Service
public class MapService {
@Value("${api.kakao-rest-api-key}")
String restApiKey;
public String getMapUrl(String reqLocation) throws BaseException {
String resultUrl = null;
try {
String address = reqLocation;
String addr = URLEncoder.encode(address, "UTF-8");
log.debug("address = {}", address);
// Geocoding 개요에 나와있는 API URL 입력.
String apiURL = "https://dapi.kakao.com/v2/local/search/keyword.json?page=1&size=1&sort=accuracy&query="+addr;
URL url = new URL(apiURL);
log.debug("url = {}", url);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
// 헤더
con.setRequestProperty("Authorization", "KakaoAK " + restApiKey);
// 요청 결과 확인. 정상 호출인 경우 200
int responseCode = con.getResponseCode();
BufferedReader br;
if (responseCode == 200) {
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
} else {
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
ObjectMapper objectMapper = new ObjectMapper();
log.debug("response = {} response.string = {}", response, response.toString());
JsonNode jsonNode = objectMapper.readTree(response.toString());
log.debug("jsonNode = {}", jsonNode);
JsonNode itemsNode = jsonNode.get("documents");
log.debug("documents = {}", itemsNode);
if (itemsNode != null && itemsNode.isArray() && itemsNode.size() > 0) {
JsonNode firstItem = itemsNode.get(0);
String mapx = firstItem.get("y").asText();
String mapy = firstItem.get("x").asText();
log.debug("mapx = {} and mapy = {}", mapx, mapy);
resultUrl = "nmap://route/public?dlat=" + mapx + "&dlng=" + mapy + "&dname=" + addr;
}
} catch (UnsupportedEncodingException e) { // 에러가 발생했을 때 예외 status 명시
log.debug("UnKnownAddrException 발생 ");
throw new BaseException(ResponseStatus.UNKNOWN_ADDR);
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return resultUrl;
}
'Backend DEv' 카테고리의 다른 글
[Spring] 소셜 로그인 3편: validate와 reissue (0) | 2023.09.14 |
---|---|
[Spring] 소셜 로그인 2편: 로그인과 로그아웃 (0) | 2023.09.02 |
[Flask] 점프 투 플라스크 01. 환경 세팅하기 (0) | 2023.03.09 |
[점프 투 FastAPI] 02. 마지막 (0) | 2023.02.24 |
[점프 투 FastAPI] 01. 환경 세팅하기 (0) | 2023.02.24 |
댓글