일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- linux grep
- Maven vs Gradle
- linux'|'
- Thymeleaf 오류#Thymeleaf Exception processing template ""
- Bandit Level 7 → Level 8
- banditlevel8
- SQL vs PL/SQL
- 코딩일기
- aws ec2 window
- kakaomapapi kakaoapi kakaomap study
- gradle 배포
- error JNI
- wargame bandit7
- 프로그래머스 #코딩테스트 #입문 #lv.0 #나머지구하기
- oracle commit
- 개발자 면접 질문
- JNI error
- 톰캣 독립실행
- commit 안찍힐 때
- ExecuteUpdate()
- Springboot WebPage 배포
- var 와 let의 차이점
- linux uniq -u
- AWS회원가입
- 톰캣 실행 에러
- aws ec2 putty 연결
- executeUpdate() commit
- The JAVA_HOME environment variable is not defined correctly
- EC2 인스턴스 생성하기
- Bandit Level 8 → Level 9
- Today
- Total
"코딩세끼"
Kakao Map API 사용하기 본문
1. 요구사항
- 매장찾기 지역명 : 지역별로 위치한 매장 찾기.
- 매장찾기 매장명 : 매장 주소를 검색해서 키워드로 찾기.
- 매장찾기 현위치 : 내 위치에서 5Km이내에 있는 매장을 찾기.
벤치마킹 사이트 : 피자알볼로
2. 구현
- 사용 API : Kakao API
- DB 환경 :
1. 주소찾기API를 통해 입력된 시/도, 구/군, 상세주소를 별도컬럼에 저장한다.
2. API 입력받은 주소를 기준하여 위도(xLatitude), 경도(yLongtitude)를 저장한다.
2.1 지역명 찾기
- 검색의 폭을 줄이는 방식으로 접근함.
Depth1(Sido) 과 Depth2(Gugun) 을 기준으로 나누어 Depth1의 기준으로 Depth2를 찾고 없으면 alert!
Controller 에서는 List Type으로 자료를 담아와서 전달하였다.
- Sql 문
<select id="selectFcAddress" resultType="vo.FranchiseVO">
select FCID, FCAREA, FCADDRESS, FCPHONE,lat,lon from franchise
where fcarea = #{Depth1} and
fcaddress like ('%'||#{Depth2}||'%')
order by fcid
</select>
<!-- 지역명선택시 -->
<div class="row " id="outer_1" style=" margin-top:50px;">
<!-- 지역명 시도, -->
<div class="col" style="height: 64px;">
<select class="form-select form-select-lg" id="Sido" name="Sido"
aria-label="Default select example" onchange="depth1_change(value); $('#fcInfo_all').empty();" >
<option value='none'>시/도 선택</option>
<option value="강원">강원</option>
<option value="경기">경기</option>
<option value="경남">경남</option>
<option value="경북">경북</option>
<option value="광주">광주</option>
<option value="대구">대구</option>
<option value="대전">대전</option>
<option value="부산">부산</option>
<option value="서울">서울</option>
<option value="세종">세종</option>
<option value="울산">울산</option>
<option value="인천">인천</option>
<option value="전남">전남</option>
<option value="전북">전북</option>
<option value="제주">제주</option>
<option value="충남">충남</option>
<option value="충북">충북</option>
</select>
<div id ="result"></div>
</div>
<!-- 지역명 구군 -->
<div class="col" style="height: 64px;">
<select class="form-select form-select-lg" id="Gugun" name="Gugun" aria-label="Default select example" onchange="depth2_change(value); $('#fcInfo_all').empty();">
<option value="none">지역을 선택하세요.</option>
</select>
</div>
</div>
<!-- 지역명선택 종료 -->
<!-- 지도표시시작 -->
<div class="row" id="outer_1_map" style="display:block; margin-top:40px;" >
<div class="col" style="height: 600px; margin-bottom:50px;overflow: hidden;">
<!-- 지도본체시작 -->
<div id="map" style="width:100%; height:100%; border: 1px solid #DC3545;"></div>
<!-- 지도본체종료 -->
</div>
<script src="//dapi.kakao.com/v2/maps/sdk.js?appkey=63fe094a0bad5ef07be77c4f00959da2&libraries=services"></script>
<script>
let mapContainer = document.getElementById('map'), // 지도를 표시할 div
mapOption = {
center: new kakao.maps.LatLng(37.359515565737276, 127.10538427434284), // 지도의 중심좌표
level: 3 // 지도의 확대 레벨
};
// 지도를 생성합니다
let map = new kakao.maps.Map(mapContainer, mapOption);
// Depth1 이 바뀌고 depth2에 defualt값으로 들어가는 것도 실행 돼야 하기 때문에
// depth2에 대한 event도 함께 포함한다.
function depth1_change(e){
// 서울
const SU = ['강남구','강동구','강북구','강서구','관악구','광진구','구로구',
'금천구','노원구','도봉구','동대문구','동작구','마포구','서대문구',
'서초구','성동구','성북구','송파구','양천구','영등포구','용산구',
'은평구','종로구','중구','중랑구'];
//경기
const GG = ['고양시 덕양구','고양시 일산구','과천시','광명시','광주시','구리시','군포시',
'김포시','남양주시','동두천시','부천시 소사구','부천시 오정구','부천시 원미구','성남시 분당구',
'성남시 수정구','성남시 중원구','수원시 권선구','수원시 장안구',
'수원시 팔달구','시흥시','안산시 단원구','안산시 상록구','안성시','안양시 동안구',
'안양시 만안구','오산시','용인시','의왕시','의정부시','이천시','파주시','평택시',
'하남시','화성시','가평군','양주군','양평군','여주군','연천군','포천군'];
//인천
const IC = [ "계양구", "미추홀구", "남동구", "동구", "부평구", "서구", "연수구", "중구", "강화군", "옹진군" ];
//강원
const GW = [ "춘천시", "원주시", "강릉시", "동해시", "태백시", "속초시", "삼척시", "홍천군", "횡성군", "영월군", "평창군", "정선군", "철원군", "화천군", "양구군", "인제군", "고성군", "양양군" ];
//충남
const CN = [ "천안시 동남구", "천안시 서북구", "공주시", "보령시", "아산시", "서산시", "논산시", "계룡시", "당진시", "금산군", "부여군", "서천군", "청양군", "홍성군", "예산군", "태안군" ];
//충북
const CB = [ "청주시 상당구", "청주시 서원구", "청주시 흥덕구", "청주시 청원구", "충주시", "제천시", "보은군", "옥천군", "영동군", "증평군", "진천군", "괴산군", "음성군", "단양군" ];
//대전
const DJ = [ "대덕구", "동구", "서구", "유성구", "중구" ] ;
//세종
const SJ = [ "세종특별자치시" ];
//광주
const GJ = [ "광산구", "남구", "동구", "북구", "서구" ];
//전북
const JB = [ "전주시 완산구", "전주시 덕진구", "군산시", "익산시", "정읍시", "남원시", "김제시", "완주군", "진안군", "무주군", "장수군", "임실군", "순창군", "고창군", "부안군" ];
//전남
const JN = [ "목포시", "여수시", "순천시", "나주시", "광양시", "담양군", "곡성군", "구례군", "고흥군", "보성군", "화순군", "장흥군", "강진군", "해남군", "영암군", "무안군", "함평군", "영광군", "장성군", "완도군", "진도군", "신안군" ];
//경북
const GB = [ "포항시 남구", "포항시 북구", "경주시", "김천시", "안동시", "구미시", "영주시", "영천시", "상주시", "문경시", "경산시", "군위군", "의성군", "청송군", "영양군", "영덕군", "청도군", "고령군", "성주군", "칠곡군", "예천군", "봉화군", "울진군", "울릉군" ];
//경남
const GN = [ "창원시 의창구", "창원시 성산구", "창원시 마산합포구", "창원시 마산회원구", "창원시 진해구", "진주시", "통영시", "사천시", "김해시", "밀양시", "거제시", "양산시", "의령군", "함안군", "창녕군", "고성군", "남해군", "하동군", "산청군", "함양군", "거창군", "합천군" ];
//부산
const BS = [ "강서구", "금정구", "남구", "동구", "동래구", "부산진구", "북구", "사상구", "사하구", "서구", "수영구", "연제구", "영도구", "중구", "해운대구", "기장군" ];
//대구
const DG = [ "남구", "달서구", "동구", "북구", "서구", "수성구", "중구", "달성군" ];
//울산
const US = [ "남구", "동구", "북구", "중구", "울주군" ];
//제주
const JJ = [ "서귀포시", "제주시" ];
console.log("ID=Sido => "+$('#Sido').val());
var target = document.getElementById("Gugun");
target.options.length = 0;
if(e == "경기") var Depth2 = GG;
else if(e == "서울")var Depth2 = SU;
else if(e == "경남")var Depth2 = GN;
else if(e == "경북")var Depth2 = GB;
else if(e == "광주")var Depth2 = GJ;
else if(e == "대구")var Depth2 = DG;
else if(e == "대전")var Depth2 = DJ;
else if(e == "부산")var Depth2 = BS;
else if(e == "울산")var Depth2 = US;
else if(e == "인천")var Depth2 = IC;
else if(e == "전남")var Depth2 = JN;
else if(e == "전북")var Depth2 = JB;
else if(e == "제주")var Depth2 = JJ;
else if(e == "충남")var Depth2 = CN;
else if(e == "충북")var Depth2 = CB;
else if(e == "강원")var Depth2 = GW;
else if(e == "세종")var Depth2 = SJ;
for (x in Depth2) {
var option = document.createElement("option");
option.value = Depth2[x];
option.innerHTML = Depth2[x];
target.appendChild(option);
} // for
depth2_change($('#Gugun').val());
}// function
//function depth2
function depth2_change(e){
console.log("ID=Gugun => "+$('#Gugun').val());
var Depth2 = e;
var Depth1 = $('#Sido').val();
$.ajax ({
type : 'get',
url : 'fcSearchArea',
headers : {Authorization:'KakaoAK {63fe094a0bad5ef07be77c4f00959da2}'},
data : {
Depth1 : Depth1 ,
Depth2 : Depth2
},
success : function(data){
if(data.success=='success'){
console.log("data.list : "+ data.list+" <=controller");
$('#fcInfo_all').empty();
if(data.list.length<1){
alert ("가맹점이 없습니다. \n다시 검색해주세요.")
return;
}
setMarkers();
var addrs = [];
var contents = [];
var fcPhone = [];
var list = data.list;
for(var i = 0 ; i<list.length;i++){
var fc = {};
fc.fcAddress=list[i].fcAddress;
fc.fcId=list[i].fcId;
fc.fcPhone=list[i].fcPhone;
fc.ylat=list[i].lat;
fc.xlon=list[i].lon;
addrs.push(fc);
console.log("addrs.length = ",addrs.length);
}// for
// 지도의 중심좌표를 표시 위치에 따라 재설정 하기위한 bounds 생성
var bounds = new kakao.maps.LatLngBounds();
var total = (addrs.length);
console.log("total",total);
var counter = 0;
markingMap();
// ========================================== 프랜차이즈 마킹 시작 !! =================================================
function markingMap() {
var contents = [];
for(var i=0; i<total; i++) {
var coords = new kakao.maps.LatLng(addrs[i].ylat, addrs[i].xlon);
console.log('i='+i+'yLat[i]='+addrs[i].ylat+' xLng[i]='+addrs[i].xlon+' fcId =',addrs[i].fcId);
// marking 좌표를 포함하도록 영역 정보를 확장한다.
bounds.extend(coords);
// 마커를 생성합니다
marker = new kakao.maps.Marker({
map: map, // 마커를 표시할 지도
position: coords,// 마커의 위치
image : icon
});
markers.push(marker); //지역명
// 커스텀 오버레이를 생성합니다
var content = '<div class="customoverlay" >' +
'<div class="title">' + addrs[i].fcId+ '점</div>' +
'</div>';
var customOverlay = new kakao.maps.CustomOverlay({
position: coords,
content: content,
yAnchor: 3
});
(function(marker, customOverlay) {
// 마커에 mouseover 이벤트를 등록하고 마우스 오버 시 인포윈도우를 표시합니다
kakao.maps.event.addListener(marker, 'mouseover', function(mouseEvent) {
customOverlay.setMap(map);
});
// 마커에 mouseout 이벤트를 등록하고 마우스 아웃 시 인포윈도우를 닫습니다
kakao.maps.event.addListener(marker, 'mouseout', function(mouseEvent) {
customOverlay.setMap(null);
});
})(marker, customOverlay);
// ========================================== 프랜차이즈 마킹 종료 !! =================================================
} //for
map.setBounds(bounds);
} // function markingMap
// 마커에 이벤트를 등록하는 함수 만들고 즉시 호출하여 클로저를 만듭니다
// 클로저를 만들어 주지 않으면 마지막 마커에만 이벤트가 등록됩니다
// card 밑에 띄우기
$('#fcInfo').load('fcSearch?card=card #fcInfo'); // 지역명 카드띄우기 시작.
} //if(data.success=='success')
else {
alert('해당 지역에 가맹점이 없습니다.');
}
}, error : function(){
alert("통신 오류입니다. 다시 시도하세요.");
}
})//ajax
}// function
</script>
</div>
<!-- 지도표시종료 -->
★ 작성시 시행착오
1. 주소를 좌표로 변환하는데에 필요한 설계 오류.
2. 주소를 가맹점 Create 시 바로 y경도 x위도로 변경해야 하는데 중점을 둬야 한다는 것에는 중요치 않게 여겼다.
● 그런데 왜 중요해졌냐?
- js 작성시 ajax 를 사용하는 방식을 주로 사용했고, ajax 사용시 "A= 콜백Data(주소)를 불러오는 시간" +
"B= 주소를 좌표로 변환해주는 시간" 이 "C=지역이름으로 요청되는 그 순간!!" 에 Data가 정확하고 빠르게 응답이 와야 하는데, 그렇지 못했고 Data도 마지막 Data 혹은 꼬여진 Data로 표현되는 오류가 있었다.
요청, 응답(C , A+B) 시간이 같거나 (A+B)가 커버리니까 DATA의 오류가 발생했었다, 하지만 이를 해결하는 방법이 콜백지옥이라는 지옥의 콜백함수인 promise(), then() 이고 이를 작성하여 해결하는 것보다, DB에 저장할 때 컬럼 두개를 만들어서 주소입력시 바로 주소를 좌표로 변환하는 형태가 만들어지는 것이 더 좋은 DATA 관리 및 효율이 좋게 느껴졌다.
해당 주소 -> 좌표 변경 코드.
$('#fcSubmitBtn').click(function() {
if (fcincheck() == true) {
var geocoder = new kakao.maps.services.Geocoder(); // jsgeocode
var address = $('#address').val();
var lat;
var lon;
geocoder.addressSearch(address, function(result, status) { // jsgeocode
if (status === kakao.maps.services.Status.OK) {
console.log('result', result);
lat = result[0].y; // 경도
lon = result[0].x; // 위도
console.log('lat', lat);
console.log('fcPassword', $('#fcPassword').val());
$.ajax({
type : "post",
url : "fcinsert",
data : {
fcId : $('#fcId').val(),
fcPassword : $('#fcPassword').val(),
fcName : $('#fcName').val(),
fcAddress : $('#address').val()+" "+$('#addressDetail').val(),
fcArea : $('#fcArea').val(),
fcPhone : $('#fcPhone').val(),
hoId : $('#fchoId').val(),
fcClose : "N",
lat : lat, // 경도
lon :lon // 위도
},
success : function(data) {
if (data.success == 'success') {
alert('계정생성에 성공했습니다.');
fcInputClear();
location.reload();
}
if (data.success == 'fail') {
alert('계정생성에 실패했습니다.');
fcInputClear();
}
},
error : function() {
alert("서버와 접속에 실패했습니다.");
fcInputClear();
}
})// ajax
}// if geocoder 성공
else{
alert("서버와 접속이 실패했습니다.");
fcInputClear();
}
}) //geocoder
}// if check
})// $('#fcSubmitBtn').click(function()
3. 어려웠지만, 일단 구현한 코드
- 작성하면서 특이하게 느꼈던 점.
HTML에서 <script></script> tag를 써서 작성하는데, 여기까지는 뭐 크게 이해에 어렵진 않았다.
그러나 내가 어려웠던 부분은 안에서 function 0000 ()을 순서대로 잘 불러오지 못했다는 점,
이점이 좀 생각보다 어려원 점이었다. 이부분을 study 해보니 passing 이라는 개념이 있던데,
하면서 공부할 개념은 아니었던 것 같다. passing 과 callback과 promise() then()으로 해결한다는
것을 알았다.
개인적으로 반복을 왠만하면 줄이고자 노력하고 있는데, 이번에는 많은 시간을 쏟아 부어도 안됐을만큼
HTML <body>태그에 기재하는 <script>문 어디서 로딩순서가 꼬였는지 모를정도로 실행 순서에 이해가 어려웠다.
4. 구현된 실제화면
'프로그래머로 전직하기 > 첫번째 프로젝트 : Federico' 카테고리의 다른 글
JNI 오류( A jni error) (0) | 2022.01.31 |
---|---|
2. 메뉴 삭제 관리 (0) | 2022.01.28 |
1. 본사-메뉴-삭제 (0) | 2022.01.22 |
오늘 공부한 내용. (0) | 2022.01.14 |