2022.12.14 - [정보기술] - (1) 구글 지도 API – 지도 만들기
2022.12.14 - [정보기술] - (2) 구글 지도 API - 단일 마커 표시하기
2022.12.14 - [정보기술] - (3) 구글 지도 API - 다중 마커 표시하기
2022.12.14 - [정보기술] - (4) 구글 지도 API - 정보창 표시하기
2022.12.14 - [정보기술] - (5) 구글 지도 API - 자동완성주소 검색하기
2022.12.14 - [정보기술] - (6) 번외 - 자동완성주소 검색에 관하여
2022.12.14 - [정보기술] - (7) 구글 지도 API - 특정 주소의 좌표 확인하기
2022.12.14 - [정보기술] - (8) 구글 지도 API - 좌표 DB 등록하기
2022.12.14 - [정보기술] - (9) 구글 지도 API - 검색 인터페이스 구현
2022.12.14 - [정보기술] - (10) 번외 - 검색지점 기준 반경거리 계산 (하버사인 공식)
2022.12.14 - [정보기술] - (11) 구글 지도 API - 좌표 DB 불러오기 (xml 이용)
2022.12.14 - [정보기술] - (12) 구글 지도 API - 위치기반 서비스 제공 (끝)
본 포스팅은 기존 포스팅에서부터 이어지는 내용입니다.
아래 그림에서 보면 사용자가 위치 정보 서비스를 제공받는 과정은 크게 두 가지로 나뉘는데 구글 지도 API를 이용하면 먼저 주소 자동완성 검색을 이용해 검색기준 좌표를 DB에 전송하고 DB에서는 특정조건 (예를 들어 검색기준 반경 10km 등) 맞는 결과를 출력합니다.
본 포스팅에서는 서비스의 핵심기능을 위한 세 가지 jsp를 소개합니다.
먼저 장소 검색을 위한 main.jsp는 지난 포스팅에 작성해 두었습니다. 먼저 장소 출력을 위한 search.jsp와 구글지도의 장소배열 출력을 위한 xml.jsp 를 작성합니다.
첫번째로 search.jsp 입니다.
이 스크립트는 크게 보면
(1) DB에 접속을 하기 위한 스크립트 구문과 mysql 쿼리스트링
(2) xml.jsp로부터 받아온 정보로 구글 지도와 구글 정보창(infowindow) 구현 (xml 구현을 위한 jdom 라이브러리)
이 때 xml.jsp 파일은 중간부분의 download url=”” 구문을 통해 search.jsp가 로드되면 자동으로 불러오게 됩니다.
(3) 마지막으로 하버사인 공식에 의해 검색지점으로부터 10km 이내의 세미나 정보(위도, 경도, 장소명, 주소)를 불러옵니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import = "java.io.IOException"
import = "java.sql.Connection"
import = "java.sql.DriverManager"
import = "java.sql.SQLException"
import = "java.sql.Statement"
import = "java.sql.ResultSet"
import = "org.jdom2.*"
import = "org.jdom2.output.*"
%>
<!DOCTYPE html>
<html lang="ko">
<%
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
String ds = "";
double clat = Double.parseDouble(request.getParameter("center_lat"));
double clng = Double.parseDouble(request.getParameter("center_lng"));
//콘솔 출력 테스트
System.out.println(clat);
System.out.println(clng);
try {
System.out.println("드라이버 로드 성공 !");
String url = "jdbc:mysql://(DB 아이피)/(DB 테이블)?allowPublicKeyRetrieval=true&useSSL=false";
String account = "(DB 아이디)";
String pass = "(DB 비밀번호)";
String qu = "select * from (DB테이블)";
// 이 때 *은 모든 필드(컬럼)을 의미하며 콤마로 별도의 필드(컬럼)을 지정해 줄 수 있다.
con = DriverManager.getConnection(url, account, pass);
System.out.println(con.toString());
System.out.println("JDBC Connector 연결 성공 !");
stmt = con.createStatement();
rs = stmt.executeQuery(qu);
System.out.println("SQLServerStatement 개체 생성 !");
//org.jdom2.* 사용
Element root=new Element("markers");
Document doc=new Document(root);
%>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title> Seminar Load</title>
<style>
body{
font-family:"맑은 고딕", "고딕", "굴림";
}
html, body {
margin: 0px;
padding: 0px;
}
#wrapper{
width:100%;
margin: 0 auto;
}
/* Always set the map height explicitly to define the size of the div
*element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
#classlist {
width:45%;
margin-top: 15vh;
margin-left: 5vh;
height: 85vh;
float: left;
}
#maplist {
position: fixed;
margin-top: 15vh;
margin-left: 45%;
width:55%;
height: 85vh;
float: left;
}
</style>
<!-- xml 파일로부터 데이터 불러오기 -->
<script>
// Change this depending on the name of your PHP or XML file
// 아래 내용은 xml 파일로부터 태그네임 marker에서 각 엘레먼트들을 getAttribute로 가져온 것.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(<%=clat%>, <%=clng%>),
zoom: 14
});
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP or XML file
downloadUrl('./xml.jsp?dclat=<%=clat%>&dclng=<%=clng%>', function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName('marker');
Array.prototype.forEach.call(markers, function(markerElem) {
var place_name = markerElem.getAttribute('place_name');
var address = markerElem.getAttribute('address');
var point = new google.maps.LatLng(
parseFloat(markerElem.getAttribute('lat')),
parseFloat(markerElem.getAttribute('lng')));
// 아래내용은 infowindow에 관한 설정 document.createElement
var infowincontent = document.createElement('div');
// 아마 Strong은 html 구현으로서 굵은 글씨를 의미. 마찬가지로 세줄아래의 br도 줄 띄우기.
var strong = document.createElement('strong');
strong.textContent = place_name
infowincontent.appendChild(strong);
infowincontent.appendChild(document.createElement('br'));
var text = document.createElement('text');
text.textContent = address
infowincontent.appendChild(text);
// 마커 특성 설정
var marker = new google.maps.Marker({
map: map,
position: point,
});
// 클릭하면 인포윈도우 오픈 이벤트가 발생
marker.addListener('click', function() {
infoWindow.setContent(infowincontent);
infoWindow.open(map, marker);
});
});
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
</script>
<!-- async defer를 사용하면 html 내부에서 위치에 상관없이 실행시킬 수 있다. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
</head>
<body>
<div>
<div id="wrapper">
<div id="classlist"> <br><br> 조건에 맞는 세미나 목록입니다 <br><br>
<%
//등록된 세미나 불러오기
while(rs.next()) {
//하버사인 공식 (검색지점으로부터의 거리 계산)
double distance;
double radius = 6371; // 지구 반지름(km)
double toRadian = Math.PI / 180;
double locationlat = Double.parseDouble(rs.getString("lat"));
double locationlng = Double.parseDouble(rs.getString("lng"));
double deltaLatitude = Math.abs(clat - locationlat) * toRadian;
double deltaLongitude = Math.abs(clng - locationlng) * toRadian;
double sinDeltaLat = Math.sin(deltaLatitude / 2);
double sinDeltaLng = Math.sin(deltaLongitude / 2);
double squareRoot = Math.sqrt(
sinDeltaLat * sinDeltaLat +
Math.cos(clat * toRadian) * Math.cos(locationlat * toRadian) * sinDeltaLng * sinDeltaLng);
distance = 2 * radius * Math.asin(squareRoot);
System.out.println(distance);
// 검색기준지점으로부터 하버사인 거리가 10km 미만인 클래스만 구글맵에 출력 (향후 해당값은 검색조건필터로 활용가능)
if (distance < 10) {
out.println("<table>");
out.println("<tr>");
out.println("<td>" + rs.getString("address") + "</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>" + rs.getString("place_name") +"</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>" + rs.getString("lat") + "</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>" + rs.getString("lng") + "</td>");
out.println("</tr>");
out.println("</table>");
continue;
}
}
</div>
<div id = "maplist">
<div id = "map">
</div>
</div>
</div>
<%
}
catch(SQLException e) {
System.out.println("SQLException : " + e.getMessage());
} finally {
if(stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con != null) {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
%>
</body>
다음은 xml 문서입니다.
main.jsp로부터 입력받아 search.jsp를 통해 전달받은 기준점의 위도, 경도 변수를 ddclat, ddclng에 저장했습니다.
이후는 하버사인 공식을 적용하고 xml 문서 생성 양식을 따릅니다.
<%@ page language="java" contentType="text/xml; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page
import = "java.io.IOException"
import = "java.io.FileWriter"
import = "java.sql.Connection"
import = "java.sql.DriverManager"
import = "java.sql.SQLException"
import = "java.sql.Statement"
import = "java.sql.ResultSet"
import = "org.jdom2.*"
import = "org.jdom2.output.*"
%>
<%
double ddclat = Double.parseDouble(request.getParameter("dclat"));
double ddclng = Double.parseDouble(request.getParameter("dclng"));
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
System.out.println("드라이버 로드 성공 !");
String url = "jdbc:mysql://(DB 아이피)/(DB 테이블)?useSSL=false";
String account = "(DB 아이디)";
String pass = "(DB 비밀번호)";
String qu = "select * from (DB 테이블)";
// 이 때 *은 모든 필드(컬럼)을 의미하며 콤마로 별도의 필드(컬럼)을 지정해 줄 수 있다.
con = DriverManager.getConnection(url, account, pass);
System.out.println(con.toString());
System.out.println("XML JDBC Connector 연결 성공 !");
stmt = con.createStatement();
rs = stmt.executeQuery(qu);
System.out.println("XML SQLServerStatement 개체 생성 !");
//org.jdom2.* 라이브러리 사용
Element mapmarker2=new Element("markers");
Document doc=new Document(mapmarker2);
while(rs.next()) {
//하버사인 공식 (검색지점으로부터의 거리 계산)
double distance;
double radius = 6371; // 지구 반지름(km)
double toRadian = Math.PI / 180;
double locationlat = Double.parseDouble(rs.getString("lat"));
double locationlng = Double.parseDouble(rs.getString("lng"));
double deltaLatitude = Math.abs(ddclat - locationlat) * toRadian;
double deltaLongitude = Math.abs(ddclng - locationlng) * toRadian;
double sinDeltaLat = Math.sin(deltaLatitude / 2);
double sinDeltaLng = Math.sin(deltaLongitude / 2);
double squareRoot = Math.sqrt(
sinDeltaLat * sinDeltaLat +
Math.cos(ddclat * toRadian) * Math.cos(locationlat * toRadian) * sinDeltaLng * sinDeltaLng);
distance = 2 * radius * Math.asin(squareRoot);
// 검색기준지점으로부터 하버사인 거리가 10km 미만인 클래스만 구글맵에 출력 (향후 해당값은 검색조건필터로 활용가능)
if (distance < 10){
Element data=new Element("marker");
data.setAttribute("place_name", rs.getString("place_name"));
data.setAttribute("address", rs.getString("address"));
data.setAttribute("lat", rs.getString("lat"));
data.setAttribute("lng", rs.getString("lng"));
mapmarker2.addContent(data);
XMLOutputter xout=new XMLOutputter();
Format f=xout.getFormat();
f.setEncoding("utf-8");
f.setIndent("\t");
f.setLineSeparator("\r\n");
f.setTextMode(Format.TextMode.TRIM);
xout.setFormat(f);
String result=xout.outputString(doc);
out.clear();
out.print(result);
continue;
}
}
}
catch(SQLException e) {
System.out.println("SQLException : " + e.getMessage());
} finally {
if(stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con != null) {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
%>
아마 여기에서 의문이 생기셨을지도 모르겠는데요
왜 하버사인 공식이 search.jsp와 xml.jsp에 둘다 들어간거죠? 라는 질문에는 다음과 같이 답변을 드립니다.
앞서 말씀드렸다시피, 본 포스팅은 유사 에어비엔비와 호텔스컴바인을 구현하는 것이 목표로 즉, 화면을 기준으로 왼쪽에는 리스트, 오른쪽에는 맵을 출력하는 것이 디자인의 핵심인데
search.jsp는 왼쪽의 세미나 리스트를 구현하기 위한 jsp 파일이며
xml.jsp는 오른쪽의 맵을 구현하기 위한 jsp 파일입니다!
search.jsp를 자세히 보시면 구글 지도의 정보창(infowindow)의 내용에 들어가는 변수가 xml.jsp로부터 받은 파라미터 인것을 확인하실 수 있습니다.
웹문서 구조는 아래 그림을 참조하시기 바랍니다.
2022.12.14 - [정보기술] - (12) 구글 지도 API - 위치기반 서비스 제공 (끝)
(12) 구글 지도 API - 위치기반 서비스 제공 (끝)
2022.12.14 - [정보기술] - (1) 구글 지도 API – 지도 만들기 2022.12.14 - [정보기술] - (2) 구글 지도 API - 단일 마커 표시하기 2022.12.14 - [정보기술] - (3) 구글 지도 API - 다중 마커 표시하기 2022.12.14 - [정보
iftraveler.tistory.com
'정보기술' 카테고리의 다른 글
카카오 지도 API 활용하기 - 에어비엔비 스타일 사이트 만들기 (1) | 2022.12.17 |
---|---|
(12) 구글 지도 API - 위치기반 서비스 제공 (끝) (1) | 2022.12.14 |
(10) 번외 - 검색지점 기준 반경거리 계산 (하버사인 공식) (0) | 2022.12.14 |
(9) 구글 지도 API - 검색 인터페이스 구현 (0) | 2022.12.14 |
(8) 구글 지도 API - 좌표 DB 등록하기 (0) | 2022.12.14 |
댓글