반응형
카카오 지도 API 사용하여 마커 클러스터 이용하기 (Spring Framework, geolocation API, Kakao Map API)

카카오 지도 API를 사용하여 마커 클러스터를 이용하는 방법 입니다. 사용 목적은 "전체 사용자들이 어느 동네에 포진해 있는지 확인하기 위해" 이며, 전체적인 로직은 아래와 같습니다.

  • a. 메인 페이지 호출 시 로그인된 사용자의 회원번호, 위도, 경도를 DB에 저장
  • b. 메뉴 -> 지도 클릭 시 마커 클러스터된 카카오 지도 페이지 호출
  • c. 카카오 지도 페이지 호출 시 controller에서 DB에 저장된 위도, 경도 리스트를 기반으로 json 형식의 파일을 로컬에 저장
  • d. 카카오 지도 페이지는 API를 사용하여 json 파일을 확인 후 호출

해당 방법의 경우 매번 호출 시 마다 json 파일을 삭제 / 저장 등의 작업이 이루어지기 때문에 사용자가 많다면 배치를 통해 몇시간에 한번씩 업데이트 해주는것이 좋을것으로 보입니다. 또한 IP기반으로 위치를 확인할 경우 정확성이 매우 떨어지니 참고 해주세요.

 

1. Kakao 지도 API Key 발급받기

Kakao 지도 Web API 가이드 (https://apis.map.kakao.com/web/guide/)를 따라하여 API Key를 발급 받습니다.

 

2. (Views) 메인 페이지에서 로그인 시 위도와 경도 저장하기

메인 페이지에 아래와 같은 코드를 삽입하여 geolocation API을 이용해 로그인 시 로그인 유저의 번호와 위도, 경도를 저장 합니다. 본인의 환경에 따라 필요한 부분들을 수정 해주세요.

	<c:choose>
		<c:when test="${not empty loginUser }">
			<script>
		  (function location(){
		  	navigator.geolocation.getCurrentPosition(
		  	function(position) {
		  		var positionLat = position.coords.latitude;
		  		var positionLon = position.coords.longitude;
				    
		  		$.ajax({
		  			url : "location.lo",
		  			data : {
		  				locationLatitude : positionLat,
		  				locationLongitude : positionLon,
		  				userNo : ${loginUser.userNo}
		  			},
		  			success : function(result){
						
		  			},
		  			error : function(){
		  				console.log("통신실패");
		  			}
		  		})
		  	},
		  	);
		  })();
		  </script>
		</c:when>
	</c:choose>

 

3. (Views) jsp 파일에 마커 클러스터러 적용하기

마찬가지로 가이드(https://apis.map.kakao.com/web/sample/basicClusterer/)를 참고하여 작성하고, script 선언부분의 "API Key 입력 필요" 와 ajax url 부분을 본인의 환경에 따라 수정 합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<br><br><br><br>
<div id="map" style="width:100%;height:350px;"></div>

<!-- API Key 입력 필요 -->
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=[발급받은 APIKEY 입력]&libraries=clusterer"></script>
<script>
	$.ajax({
    	// url은 본인의 환경에 따라 작성 합니다.
		url : "locationMapList.lo",
		data : {},
		success : function(result){
		    var map = new kakao.maps.Map(document.getElementById('map'), { // 지도를 표시할 div
		        center : new kakao.maps.LatLng(36.2683, 127.6358), // 지도의 중심좌표 
		        level : 14 // 지도의 확대 레벨 
		    });
		    
		    // 마커 클러스터러를 생성합니다 
		    var clusterer = new kakao.maps.MarkerClusterer({
		        map: map, // 마커들을 클러스터로 관리하고 표시할 지도 객체 
		        averageCenter: true, // 클러스터에 포함된 마커들의 평균 위치를 클러스터 마커 위치로 설정 
		        minLevel: 10 // 클러스터 할 최소 지도 레벨 
		    });
		 	
		    // 데이터를 가져오기 위해 jQuery를 사용합니다
		    // 데이터를 가져와 마커를 생성하고 클러스터러 객체에 넘겨줍니다
		    $.get("resources/kakaoMap/kakaoMap.json", function(data) {
		        // 데이터에서 좌표 값을 가지고 마커를 표시합니다
		        // 마커 클러스터러로 관리할 마커 객체는 생성할 때 지도 객체를 설정하지 않습니다
		        var markers = $(data.positions).map(function(i, position) {
		            return new kakao.maps.Marker({
		                position : new kakao.maps.LatLng(position.lat, position.lng)
		            });
		        });
		        // 클러스터러에 마커들을 추가합니다
		        clusterer.addMarkers(markers);
		    });
		},
		error : function(){
			console.log("통신실패");
		}
	})
</script>
</body>
</html>

 

4. DTO
@NoArgsConstructor 
@AllArgsConstructor 
@Setter
@Getter
@ToString
@EqualsAndHashCode
public class Location {
	private int locationNo;
	private int userNo;
	private float locationLatitude;
	private float locationLongitude;
	private Date locationDate;
}

 

5. Controller
  1. 메인 페이지 호출 시 회원번호, 위도, 경도 저장 또는 업데이트 하기 위한 메서드
  2. 메뉴에서 지도 클릭 시 페이지를 호출하기 위한 메서드
  3. 지도 페이지를 호출하기 위해 json 형식으로 파일을 저장하기 위한 메서드
@Controller
public class LocationController {

	@Autowired
	private LocationService LocationService;
	
	// (1)
	@RequestMapping("location.lo")
	public String selectList(float locationLatitude, float locationLongitude, int userNo) {
		
		Location l = new Location();
		l.setLocationLatitude(locationLatitude);
		l.setLocationLongitude(locationLongitude);
		l.setUserNo(userNo);
		
		int listCount = LocationService.selectListCount(l);
		
		// 최초 로그인 시 insert
		if(listCount == 0) {
			int result = LocationService.insertCoordinate(l);
		} else { // 기존 데이터가 있을때 update
			int result = LocationService.updateCoordinate(l);
		}
		
		return "redirect:/";
	}
	
	// (2)
	@RequestMapping("locationMap.lo")
	public String selectMap() {

		return "location/location";
	}
	
	// (3)
	@RequestMapping("locationMapList.lo")
	@ResponseBody
	public String selectMapList() {
		ArrayList<Location> list = LocationService.selectMapList();
		
		String data = "";
		for(int i=0; i<list.size(); i++) {
			if(i==0 && list.size()>0) {
				data = "{\n  \"positions\" : [\n    {\n    \"lng\": "+list.get(i).getLocationLongitude()+",\n    \"lat\": "+list.get(i).getLocationLatitude()+"\n    } ,";
			} else if(i>0 && i<list.size()-1) {
				data += " {\n    \"lng\": "+list.get(i).getLocationLongitude()+",\n    \"lat\": "+list.get(i).getLocationLatitude()+"\n    } ,";
			} else if(i==list.size()-1) {
				data += " {\n    \"lng\": "+list.get(i).getLocationLongitude()+",\n    \"lat\": "+list.get(i).getLocationLatitude()+"}\n  ]\n}";
			}
		}
		
        // 본인 환경에 따라 new File 부분의 경로를 수정 해주세요.
        // ex. D:\\test\\resources\\kakaoMap/kakaoMap.json
	    File myFile = new File("~~~~\\resources\\kakaoMap/kakaoMap.json");
	    try {
	    	if(myFile.exists()){
	    		myFile.delete();
	    	}
	    	myFile.createNewFile();
	        BufferedWriter writer = new BufferedWriter(new FileWriter(myFile));
	        writer.write(data);
	        writer.close();
	    } catch (IOException e) {
	      e.printStackTrace();
	      System.out.println("예외 처리");
	      System.out.println("파일을 처리하는 과정에서 오류가 발생했습니다.");
	    }
	    
		return "";
	}
}

 

6.  Service / ServiceImpl
import java.util.ArrayList;

public interface LocationService {
	// 존재여부 확인
	int selectListCount(Location l);
	
	// 좌표 저장
	int insertCoordinate(Location l);

	// 좌표 업데이트
	int updateCoordinate(Location l);
	
	// 좌표 리스트 검색
	ArrayList<Location> selectMapList();
}
import java.util.ArrayList;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LocationServiceImpl implements LocationService {
	
	@Autowired
	private LocationDao lDao;
	
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	@Override
	public int insertCoordinate(Location l) {
		return lDao.insertCoordinate(sqlSession,l);
	}

	@Override
	public int selectListCount(Location l) {
		return lDao.selectListCount(sqlSession, l);
	}

	@Override
	public int updateCoordinate(Location l) {
		return lDao.updateCoordinate(sqlSession,l);
	}

	@Override
	public ArrayList<Location> selectMapList() {
		return lDao.selectMapList(sqlSession);
	}
}

 

7. DAO
환경에 따라 mapper namespace와 id 값을 변경 해주세요.
@Repository
public class LocationDao {

	public int insertCoordinate(SqlSessionTemplate sqlSession, Location l) {
		return sqlSession.insert("locationMapper.insertCoordinate",l);
	}

	public int selectListCount(SqlSessionTemplate sqlSession, Location l) {
		return sqlSession.selectOne("locationMapper.selectListCount",l);
	}
	public int updateCoordinate(SqlSessionTemplate sqlSession, Location l) {
		return sqlSession.update("locationMapper.updateCoordinate",l);
	}

	public ArrayList<Location> selectMapList(SqlSessionTemplate sqlSession) {
		return (ArrayList)sqlSession.selectList("locationMapper.selectMapList");
	}
}

 

8. Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper 
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="locationMapper">
	<select id="selectListCount" resultType="_int">
		SELECT COUNT(*)
		FROM LOCATION_TB
        WHERE USER_NO = #{userNo}
	</select>
		
	<insert id="insertCoordinate" parameterType="location">
		INSERT INTO LOCATION_TB(
					LOCATION_NO,
					USER_NO,
					LOCATION_LATITUDE,
					LOCATION_LONGITUDE,
					LOCATION_DATE
		)
		VALUES (
			SEQ_LOCATION_NO.NEXTVAL,
			#{userNo},
			#{locationLatitude},
			#{locationLongitude},
			SYSDATE
		)
	</insert>
	
	<update id="updateCoordinate" parameterType="location">
		UPDATE LOCATION_TB
		SET LOCATION_LATITUDE = #{locationLatitude},
			LOCATION_LONGITUDE = #{locationLongitude}
		WHERE USER_NO = #{userNo}
	</update>
	
		
	<resultMap type="location" id="loResultSet">
		<result column="LOCATION_LATITUDE" property="locationLatitude"/>
		<result column="LOCATION_LONGITUDE" property="locationLongitude"/>
	</resultMap>
	
	<select id="selectMapList" resultMap="loResultSet">
		SELECT LOCATION_LATITUDE,
		       LOCATION_LONGITUDE
		FROM LOCATION_TB
	</select>
</mapper>

 

9. DB Table
CREATE TABLE LOCATION_TB(
    LOCATION_NO NUMBER PRIMARY KEY,
    USER_NO NUMBER NOT NULL,
    LOCATION_LATITUDE NUMBER NOT NULL,
    LOCATION_LONGITUDE NUMBER NOT NULL,
    LOCATION_DATE DATE DEFAULT SYSDATE NOT NULL,
    FOREIGN KEY(USER_NO) REFERENCES MEMBER(USER_NO)
);

COMMENT ON COLUMN LOCATION_TB.LOCATION_NO IS '위치번호';
COMMENT ON COLUMN LOCATION_TB.USER_NO IS '회원번호';
COMMENT ON COLUMN LOCATION_TB.LOCATION_LATITUDE IS '위도';
COMMENT ON COLUMN LOCATION_TB.LOCATION_LONGITUDE IS '경도';
COMMENT ON COLUMN LOCATION_TB.LOCATION_DATE IS '마지막 업데이트 시간';

CREATE SEQUENCE SEQ_LOCATION_NO
INCREMENT BY 1
MINVALUE 1
NOCACHE;

 

반응형
반응형
택배 배송 조회 API (스마트 택배 API 웹 템플릿사용)

스마트택배 배송 조회 API와 웹 템플릿을 사용하는 방법 입니다. (무료 버전)

 

1. 스윗트래커 홈페이지(https://tracking.sweettracker.co.kr/) 로 이동하여 회원가입 후 로그인을 해주세요.

 

2. 좌측 메뉴 API KEY 관리 → KEY 목록 → 이용권 구매를 클릭 한 후 원하는 이용권 등급을 선택하여 "다음"을 클릭 해주세요.

이용정책에 따르면 이용권은 1개월을 기준으로 유효기간이 설정되며 무료 이용권(월 1,000건)의 경우 재사용이 불가능 했습니다. 

※ 단순히 API KEY 재사용만 불가능한 것 인지, 재구매하여 새로운 API KEY를 받는것도 불가능한 것 인지는 정확하게 나오지 않았으니 참고 부탁 드립니다.

 

3. 스마트택배 docs (http://info.sweettracker.co.kr/apidoc/)에 접속하여 사용법에 따라 진행합니다.

해당 홈페이지 가장 하단으로 넘어가 템플릿 샘플 코드를 테스트중인 HTML 문서에 복사+붙여넣기를 하신 후 HTML에 들어가보면 API key, 택배사 코드, 운송장 번호 input이 생성되어 있습니다.

  1. API key : 1번에서 진행했던 스윗트래커 홈페이지에 로그인하여 API KEY 관리 → KEY 목록을 클릭하면 확인하실 수 있습니다.
  2. 택배사 코드 : 스마트택배 docs 문서에 각 택배사별 연동 코드가 기입되어 있어 참고하여 작성하면 됩니다.
  3. 운송장 번호 : 클라이언트가 입력할 운송장 번호 입력창 입니다.

웹 템플릿은 샘플 코드에 있는 form action에 있는 URL의 마지막 번호를 원하는 템플릿의 번호로 입력하시면 적용 됩니다. (1번 cyan, 2번 pink, 3번 gray, 4번 tropical, 5번 sky)

조회 화면

반응형

+ Recent posts