오늘은 2일 차! 9시에 수업을 시작했다.
어제 내용을 잠깐 복습하였는데, QGIS에서 PostgreSQL로 연결하여 레이어를 추가할 수 있었고 그렇게 연결해 두면 QGIS에서 레이어를 변경했을 때 그 변경내용이 PostgreSQL과 GeoServer에 자동으로 반영이 된다.
오늘은 본격적으로 스프링부트로 웹페이지를 만들었다. Spring Tool Suite를 사용하여 프로젝트를 생성한 다음에 강사님께서 미리 준비해 두신 틀을 적용한 후 필요한 기능들을 추가해 보는 과정이었다.
브이월드 지오코딩 구현을 통해서 클릭한 좌표의 주소를 반환하거나 좌표를 입력했을때 그 위치로 이동하는 것을 실습하였다.
지오코딩에 사용되는 api들은 브이월드에서 다양하게 참고가능하다.
브이월드
국가가 보유하고 있는 공개 가능한 공간정보를 모든 국민이 자유롭게 활용할 수 있도록 다양한 방법을 제공합니다.
www.vworld.kr
강사님께서 jsp파일을 만들어 오셔서 기본적인 화면의 틀은 이미 갖춰져 있었다. 수업시간에는 '지도 띄우기' 버튼을 눌렀을 때 지도가 화면에 보이게 하거나, '검색' 버튼을 눌렀을 때 어제 구축한 DB의 목록들이 뜨게 하는 것이었다.
먼저 vworld 위치 검색 api를 사용하여 지도를 클릭했을 때 그 지점의 도로명 주소가 화면에 보이도록 하였다.
아래 코드와 같이 ajax를 사용하여서 GET방식으로 위치 좌표에 해당하는 도로명주소를 json형식으로 가져올 수 있다.
//vworld 위치 검색 api
function fn_geocodeVworld(){
$.ajax({
url: "https://api.vworld.kr/req/address?",
type: "GET",
dataType: "jsonp",
data: {
service: "address",
request: "GetAddress",
version: "2.0",
crs: "EPSG:4326",
type: "BOTH",
point: $('#evntLon').val()+","+$('#evntLat').val(),
format: "json",
errorformat: "json",
key: GLOBAL.VWORLD_API_KEY
},
success: function (res) {
//console.log(result);
$('#geocoding_res').text(res.response.result[0].text);
}
});
}
다음은 DB에 있는 값들을 가져와서 화면에 띄웠다. 이 과정에는 Controller, Service, mapper 등의 순서로 코드를 작성하여서 json값으로 화면의 왼쪽에 목록으로 띄우도록 했다. 먼저 json값이 화면에 보이는지 확인한 후 화면에 적용했다.
function fn_searchResHandler(data){
if(!SEARCH_POI_INIT){
OL_MAP.addLayer(SEARCHPOI_LAYER); //측정 레이어 추가
SEARCH_POI_INIT = true; //레이어 호출 여부 플레이그
}
//검색 아이콘 소스 클리어
SEARCHPOI_SOURCE.clear();
resultList = data.res;
let result = '';
$('#searchres_db').empty();
$('#tab3 h2').html("<span>부산관광지</span> 검색결과입니다.");
//응답 객체에 담긴 리스트 크기 만큼 반복 수행
resultList.forEach(function(data, idx) {
result += '<li class="title active" data-pointx=' + data.lng + ' data-pointy=' + data.lat + ' onclick="fn_getNearstMetro(\'' + data.gid + '\')"><ul>';
result += '<li>' + data.name + '</li>'; //명칭
result += '<li class="addr">' + data.addr1 + '</li>'; //지번주소
result += '<li class="phone">' + data.title + "</li></li></ul>"; //도로명주소
$('#searchres_db').html(result);
//아이콘 feature 생성
let iconFeature = new ol.Feature({
geometry: new ol.geom.Point([data.lng, data.lat]), //검색결과의 경위도 컬럼명인 point.x, point.y
name: data.name //검색결과 명칭 이름
});
//벡터소스에 feature add
SEARCHPOI_SOURCE.addFeature(iconFeature);
})
//화면 영역을 소스의 extent범위로 이동
OL_MAP.getView().fit(SEARCHPOI_SOURCE.getExtent(), OL_MAP.getSize());
}
지하철 50m 근방에 있는 부산 명소들의 목록을 불러오는 것 까지 한 다음에는 명소 하나를 클릭했을 때 주변 지하철역 3개를 표시하고 선으로 이어지도록 했다. 이 과정에서는 앞에서와 쿼리문을 다르게 하였다. 쿼리문에서 거리를 계산하여서 관광명소와 가까운 지하철역 3개를 가져올 수 있다.
<?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="com.lx.mapapp.repo.SchMapper">
<!-- 부산 관광지 목록 가져오기 -->
<select id = "getAttData" resultType="HashMap">
SELECT * FROM busan_att_euckr bat
</select>
<!-- 관광지와 가까운 지하철역 3개 가져오기 -->
<select id="getNearstMetro" resultType="HashMap" parameterType="Map">
SELECT bat.name, bat.lat, bat.lng, bmt.st_nm as mname, bmt.st_x as mlng, bmt.st_y as mlat, round((ST_DistanceSphere(bat.geom,
bmt.geom)/1000)::numeric, 2) AS DISTANCE
FROM busan_att_euckr bat, busan_line1 bmt WHERE bat.gid = #{attid}::numeric
ORDER BY DISTANCE
LIMIT 3
</select>
</mapper>
마지막으로 스위치를 켰을때 GeoServer에 올렸던 WMS레이어를 지도위에 표시하였다. jsp코드에서 id로 지오서버의 레이어 이름을 받아서 해당 레이어가 있는지 확인한 후에 지오서버 url을 통해서 WMS레이어를 호출하게 된다.
# WMS 레이어 호출 코드
//################################################################################ 레이어 매시업
function fn_addWmsLayer(_flag, _layerNm, _type){
var wms_layer = ""; //레이어 변수
if(fn_findLayerByName(_layerNm)) { //호출한 레이어가 이미 등록되어 있는지 확인
wms_layer = fn_findLayerByName(_layerNm);
wms_layer.setVisible(_flag);
}else{
if(_flag){ //첫 호출이면서 체크박스 TRUE일때
if(_type == 'vworld'){ //브이월드 WMS호출
wms_layer = new ol.layer.TileWMS({
name: _layerNm,
extent: [124.57849539297766, 32.56623775540233, 129.97428592822916, 39.22393370585444], //한반도 EXTENT
source: new ol.source.TileWMS({
url: GLOBAL.GEOSERVER_WMS_URL, //브이원드 호출 URL
//브이월드 API 사용에 필요한 파라미터 입력
params: {'LAYERS': _layerNm, 'TILED': true, 'KEY': GLOBAL.VWORLD_API_KEY, 'DOMAIN':GLOBAL.VWORLD_API_DOMAIN},
transition: 0
})
})
}else{ //GEOSERVER WMS호출
wms_layer = new ol.layer.Tile({
name: _layerNm,
extent: [124.57849539297766, 32.56623775540233, 129.97428592822916, 39.22393370585444],
source: new ol.source.TileWMS({
url: GLOBAL.GEOSERVER_WMS_URL,
params: {'LAYERS': _layerNm, 'TILED': true},
transition: 0
})
})
OL_MAP.addLayer(wms_layer);
}
}
}
}
// 레이어 이름으로 해당 레이어가 있는지 확인하는 함수
function fn_findLayerByName(layerName) {
const layers = OL_MAP.getLayers().getArray();
return layers.find(layer => layer.get('name') === layerName);
}
# 화면 코드
<h3>WFS 레이어 _ DB</h3>
<ul class="underground_Facility">
<li>
<span class="color_legend" style="background: #ffff"></span>
부산1호선노선도
<label class="input_switch fl_r">
<input type="checkbox" onchange="fn_addWmsLayer(this.checked, this.id,'geoserver')" id="lxsp:busan_line1">
<span class="input_slider round"></span>
</label>
</li>
<li>
<span class="color_legend" style="background: #ffff"></span>
부산1호선버퍼
<label class="input_switch fl_r">
<input type="checkbox" onchange="fn_addWmsLayer(this.checked, this.id,'geoserver')" id="lxsp:busan_metro_buffer">
<span class="input_slider round"></span>
</label>
</li>
</ul>
이렇게 스프링부트 실습이 끝났다. 수업시간에 코드 흐름을 한번 설명해주시고 혼자서 해볼 시간을 주셔서 잘 따라갈 수 있었다. 마지막에 테스트도 90점으로 마무리! 중간에 오류가 나거나 질문이 있을 때 강사님께서 친절하게 설명해 주셨고, 이틀 동안 열정 넘치게 강의해 주셔서 알찬 교육이었다.
보통 GIS관련 강의들은 첫번째날 처럼 QGIS를 조금 사용하고 실습이 없는 경우가 많은데 이번 강의는 스프링부트로 직접 코드를 작성하고 api를 사용해 볼 수 있어서 더 좋았던 것 같다.
다음에도 코딩 관련 교육이 있으면 꼭 들어야겠다. ☆*: .。. o(≧▽≦)o .。.:*☆
'매일코딩' 카테고리의 다른 글
[일코+13] 스프링부트 자율학습 1주차 완료! (0) | 2025.02.24 |
---|---|
[일코+12] 스무스 오퍼레이터~~🌶️🚙 (0) | 2025.02.23 |
[일코+10] LX 오픈소스 GIS기반 스프링부트 웹 개발 교육(1) (0) | 2025.02.21 |
[일코+9] 사무실의 먼지가 되... (1) | 2025.02.20 |
[일코+8] 스프링 부트 시작하기 / 윈도우 설치는 SSD에 하자 (1) | 2025.02.19 |