본 내용은 혼자서 공부하기 위한 용도로 사용된 것으로 비효율적일 수 있으며 실용적이지 않을 수 있습니다.
정류장 정보나 실시간 노선 정보에 대해 안내해주는 페이지는 완성하였다. 이제 살펴볼 것은 노선 정보탭으로 노선에 대한 정보와 노선의 경로에 대한 정보를 볼 수 있고 경로들의 정류장 위치를 확인할 수 있다.
1. Controller
GCBusController.java
@RequestMapping(value="/routeInfoPage.do") public ModelAndView routeInfoPage(CommandMap commandMap) throws Exception{ ModelAndView mv = new ModelAndView("route_info"); mv.addObject("routeno",commandMap.get("routeno")); mv.addObject("routeid",commandMap.get("routeid")); return mv; } @RequestMapping(value="/routeInfo.do") public @ResponseBody ModelAndView routeInfo(@RequestBody Map<String,Object> map) throws Exception{ Map<String,Object> temp = gcBusServ.routeInfo(map); map.put("map", temp.get("info")); map.put("path", temp.get("path")); return new ModelAndView("jsonView",map); }
- 노선 정보 페이지와 노선에 대한 정보 요청을 받을 Controller이다.
2. Service
GCBusService.java
Map<String,Object> routeInfo(Map<String, Object> map) throws Exception;
GCBusServiceImpl.java
@Override public Map<String, Object> routeInfo(Map<String, Object> map) throws Exception { Map<String,Object> temp = new HashMap<String,Object>(); temp.put("info", gcBusDAO.selectRouteId(map)); temp.put("path",gcBusDAO.selectRoutePath(map)); return temp; }
- 노선에 대한 정보와 노선이 거치는 경로에 대한 정보를 DAO로부터 받아온다.
3. DAO
@SuppressWarnings("unchecked") public Map<String, Object> selectRouteId(Map<String, Object> map) { return (Map<String,Object>)selectOne("gcbus.selectRouteId",map); } @SuppressWarnings("unchecked") public List<Map<String,Object>> selectRoutePath(Map<String,Object> map){ return (List<Map<String,Object>>)selectList("gcbus.selectRoutePath",map); }
- 위 서비스에서 호출한 DAO 메서드이다. 각각 노선 정보와 노선 경로를 리턴한다.
4. SQL
gcBus_SQL.xml
<select id="selectRouteId" parameterType="HashMap" resultType="HashMap"> <![CDATA[ SELECT ROUTEID, ROUTENO, STARTNODENM, ENDNODENM, STARTVEHICLETIME, ENDVEHICLETIME FROM ROUTE_INFO WHERE ROUTEID=#{ROUTEID} ORDER BY ROUTENO ]]> </select> <select id="selectRoutePath" parameterType="HashMap" resultType="HashMap"> <![CDATA[ SELECT route.ROUTEID, route.NODEORD, route.NODENAME, route.NODEID, node.GPSLATI AS LAT, node.GPSLONG AS LNG FROM ROUTE_ORDER route, NODE_INFO node WHERE route.ROUTEID=#{ROUTEID} AND route.NODEID=node.NODEID ORDER BY NODEORD ]]> </select>
- 특별함 없는 SQL문이고, 노선 경로 정보의 경우 정류장의 위치정보까지 받아오기 위하여 정류장의 아이디를 통해 정류장 정보 테이블과 조인하여 정보를 불러왔다.
5. JavaScript
map.js
function fn_clickPath(obj){ $("span[name^=nodeinfo]").removeClass("markerSelected"); obj.addClass("markerSelected"); //지도 중심을 변경합니다. map.setCenter(new daum.maps.LatLng(obj.attr("lat"),obj.attr("lng"))); fn_setOverlay(obj); } function fn_setOverlay(obj){ if(customOverlay!=null){ customOverlay.setMap(null); } customOverlay = new daum.maps.CustomOverlay({ map: map, clickable: false, content: '<a href="#this" onclick="fn_clickOverlay();"><span class="customOverlay">'+obj.html()+'</span></a>', position: new daum.maps.LatLng(obj.attr("lat"),obj.attr("lng")), xAnchor: 0.5, yAnchor: 3, zIndex: 3 }); customOverlay.setMap(map); } function fn_nodeLineMaker(){ // 지도에 표시할 선을 생성합니다 var polyline = new daum.maps.Polyline({ path: linePath, // 선을 구성하는 좌표배열 입니다 strokeWeight: 3, // 선의 두께 입니다 strokeColor: '#FF0000', // 선의 색깔입니다 strokeOpacity: 0.7, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다 strokeStyle: 'solid' // 선의 스타일입니다 }); // 지도에 선을 표시합니다 polyline.setMap(map); //지도의 중심 좌표를 정류장 출발점의 중심으로 위치 변경합니다. map.setCenter(linePath[0]); //마커들의 배열에 폴리라인을 같이 넣어 관리합니다. markers.push(polyline); }
6. JSP
/WEB-INF/jsp/route_info.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE> <html> <head> <%@ include file="/WEB-INF/include/include-header.jspf" %> <title>노선 정보</title> </head> <body> <%@ include file="/WEB-INF/include/include-gnb.jspf" %> <div id="body" > <div id="searchMenu" class="leftBox"> <div id="searchBox" class="leftBox" > <p class="margin0">버스 번호 <input type="text" value="${routeno}" id="routeno" style="width:100px; height:30px;"></p> <a href="#this" id="sc_btn" class="btn" >찾기</a> </div> </div> <div id="resultBox" class="leftBox"> </div> <div id="bodyBox"> <div id="mapBox" class="mapBox_info"> </div> <div id="infoBox"> <table id="routeTable" class="routeTable" border="1"> </table> </div> </div> </div> <%@ include file="/WEB-INF/include/include-body.jspf" %> <script src="<c:url value='/js/daumAPI/map.js'/>" charset="utf-8"></script> <script type="text/javascript"> if(gfn_isNull($("#routeno").attr("value"))==false){ fn_clickSearchButton(); fn_clickRoute("${routeid}"); } $("#route_info").addClass("selected"); $("document").ready(function(){ $("#sc_btn").on("click",function(e){ e.preventDefault(); fn_clickSearchButton(); }) $("#routeno").keyup(function(e){ if(e.keyCode==13){ fn_clickSearchButton(); } }) }); function fn_clickSearchButton(){ $("#bodyBox").removeClass("none"); $("#resultBox").children().remove(); /* 이 부분에서 노선 번호를 서버로 보내주고 서버에서는 데이터베이스를 통해 정류장 정보를 가져와 ajax로 리턴해준다. 보내는 데이터 : routeNo 받는 데이터 : route_Info의 데이터 */ $.ajax({ dataType:"json", contentType:"application/json", url: "/gcbus/routeList.do", type:"POST", data:JSON.stringify({ROUTENO:$("#routeno").val()}), success:function(result){ for(var i=0; i<result["list"].length;i++){ var map = result["list"][i]; var str = "<a href='#this' routeid='"+map["ROUTEID"]+"' name='route"+i+"' id='route"+i+"' class='result sc_node_result'>"+map["ROUTENO"]+"<span class='routeSpan'>("+map["STARTNODENM"]+"~"+map["ENDNODENM"]+")</span></a>"; $("#resultBox").append(str); } $("a[name^=route]").on("click",function(e){ e.preventDefault(); fn_clickRoute($(this).attr("routeid")); }) }, error:function(){ alert("실패"); } }) } function fn_clickRoute(obj){ $("#routeTable").children().remove(); $("#routeTable").siblings().remove(); //마커들을 지워줍니다. setMarkers(null); //라인 배열을 비워줍니다. linePath=[]; /* 이 부분에서 노선 ID를 서버로 보내주고 서버에서는 데이터베이스를 통해 정류장 정보를 가져와 ajax로 리턴해준다. 보내는 데이터 : routeId 받는 데이터 : route_Info의 데이터 */ $.ajax({ dataType:"json", type:"POST", contentType:"application/json", data:JSON.stringify({ROUTEID: obj }), url:"/gcbus/routeInfo.do", success:function(result){ var map=result["map"]; if(map["STARTVEHICLETIME"]==null){ map["STARTVEHICLETIME"]="xxxx"; map["ENDVEHICLETIME"]="xxxx"; } var str = "<tbody><tr><th>노선번호</th><td colspan='3'>"+map["ROUTENO"] +"</td></tr><tr><th>기점</th><td class='nodename'>"+map["STARTNODENM"]+"</td>" +"<th>첫차시간</th><td class='vehicletime'>"+map["STARTVEHICLETIME"][0]+map["STARTVEHICLETIME"][1]+":"+map["STARTVEHICLETIME"][2]+map["STARTVEHICLETIME"][3]+ "</td></tr><tr><th>종점</th><td class='nodename'>"+map["ENDNODENM"]+ "</td><th>막차시간</th><td class='vehicletime'>"+map["ENDVEHICLETIME"][0]+map["ENDVEHICLETIME"][1]+":"+map["ENDVEHICLETIME"][2]+map["ENDVEHICLETIME"][3]+"</td></tr></tbody>"; $("#routeTable").before("<p>노선 정보</p>"); $("#routeTable").append(str); $("#routeTable").after("<hr/><p>노선 경로</p><span>(정류장 이름을 클릭하면 해당 정류소 위치로 이동)</span><ul id='routePath'></ul>"); var path=result["path"]; var direction="right"; for(var i=0,count=0;i<path.length;i++,count++){ var str ="<li class='direction_li li_"+direction+"'><span class='topline_span'></span>"; if(count==4&&i!=(path.length-1)){ str+="<span class='rightline_span'></span>"; }else if(count==9&&i!=(path.length-1)){ str+="<span class='leftline_span'></span>"; } if(i==(path.length-1)){ direction="arrive"; } str+="<img class='direction_img' src='./image/direction_"+direction+".png'/><span id='path"+i+"' nodeid="+path[i]["NODEID"]+" name='nodeinfo"+i+"' lat='"+path[i]["LAT"]+"' lng='"+path[i]["LNG"]+"' class='direction_nodename'>"+path[i]["NODENAME"]+"</span></li>"; if(count==4){ direction="left"; }else if(count==9){ direction="right"; count=-1;//카운트값이 다시 0이 되어야하는데 for문의 증가문으로 더해지기 때문에 -1을 해줌으로써 for문이 다시 실행되면 0이 된다. }//클래스명 변경 혹은 이미지 변경을 위하여 디렉션 변경 $("#routePath").append(str); //정류소들을 전부 마커에 표기 해줍니다. fn_nodeMarkerMaker($("#path"+i)); //객체의 값을 라인 배열에 넣어줍니다. linePath.push(new daum.maps.LatLng($("#path"+i).attr("lat"), $("#path"+i).attr("lng"))); $("li[class^=direction]").on("click",function(e){ e.preventDefault(); fn_clickPath($(this).children("span[name^=nodeinfo]")); }) } //라인 메이커를 지도에 표시하는 함수입니다. fn_nodeLineMaker(); }, error:function(){ alert("실패"); } }) } function fn_clickOverlay(){ var obj = $(".markerSelected"); var comSubmit = new ComSubmit(); comSubmit.addParam("nodeid",obj.attr("nodeid")); comSubmit.addParam("lat",obj.attr("lat")); comSubmit.addParam("lng",obj.attr("lng")); comSubmit.addParam("nodename",obj.html()); comSubmit.setUrl("<c:url value='/main.do'/>"); comSubmit.submit(); } </script> </body> </html>
- 노선 정보 페이지의 경우 우측 부분은 노선의 경로를 출력한다.
- 36~39라인
정류장 정보 페이지에서 노선을 클릭하여 노선 정보 페이지로 전환되었을 때 바로 노선의 정보와 경로를 출력하는 부분이다.
- 48~52라인
엔터키에 대한 이벤트 처리 부분이다.
- 55~86라인
fn_clickSearchButton() 함수는 서버로 노선 번호를 보낸 뒤 정류장 정보를 받아온다. 그리고 우측 상단에 출력해준다.
- 88~168라인
fn_clickRoute() 함수는 노선의 아이디값을 서버로 보내 노선 경로에 대한 정보를 받아온 뒤 우측 하단에 보기 좋게 출력해준다. 이 함수의 대부분은 출력을 위함으로 큰 의미까지는 없다. 출력한 경로 클릭 이벤트로 위의 Javascript 부분에서 작성하였던 fn_clickPath() 함수를 호출한다. 그리고 경로들의 정류장들을 줄로 잇는 함수인 fn_nodeLineMaker()를 호출한다. 이 부분도 위에 javascript 부분에서 작성하였다.
- 171~181라인
오버레이된 정류장 이름을 클릭하였을 시 정류장 정보로 이동 되도록 클릭 이벤트로 정류장 정보 페이지로 전환을 시키는 함수로 정류장의 id, 이름, 위도, 경도를 함께 보내준다.
7. 테스트
BIS 기능에 대해서는 이번 테스트로 완성이 될 것이다. 이번 테스트가 잘 되는지 해보자.
일단 버스 노선의 메인 페이지이다. 정류소 찾기와 달리 지도의 크기가 작다. 우측에 정류소의 정보를 위해서 작게 배치하였다.
검색 결과로 버스 노선의 결과들이 출력되고 있다.
노선을 클릭해보자.
다음과 같은 노선의 정보와 경로가 뜰 것이다.
이번엔 경로를 클릭하면
다음과 같이 해당 경로가 블럭되면서 중심이 이동되고 해당 정류장 이름이 오버레이된다.
오버레이된 정류장 이름을 클릭하면
정류장 찾기 페이지로 전환되면서 실시간 버스 정보를 확인할 수 있다.(늦은 시간이라 실시간으로 들어오는 버스가 없다.)
여기까지 잘 따라왔다면 필자의 BIS 기능은 모두 구현한 것이다. 길찾기는 추후 구현 시에 포스팅하도록 하겠다. 게시판의 경우 2017/12/24 - [코딩/Spring] - Spring 개발 - 게시판 만들기(8) - 게시판 목록 만들기 이 글을 참고하여 만들어 각자 클릭 이벤트로 페이지 전환 시키는 것을 해보도록 하자.