[jquery]를 이용한 Simpleweb

2014. 3. 18. 14:44개발관련기록/JQuery

반응형

http://dev.anyframejava.org/docs/anyframe/plugin/simpleweb-json/1.0.2/reference/html/ch05.html#simpleweb_simpleweb_json_tab





5.JSON 기반의 Simpleweb 개발

이번 장에서는 Simpleweb Plugin (simpleweb-json) 설치시 생성되는 Sample Application을 중심으로 JSON 기반의 Simpleweb을 개발하는 방법에 대해 설명하도록 한다. JSON 객체를 주고받는 Simpleweb을 개발하는 경우는 주로 jQuery를 사용한 Application을 개발할 경우이다. 기본적으로 Simpleweb Plugin (simple-json) 설치시 생성되는 Sample Application에서 제공하는 jQuery의 컴포넌트는 jqgrid, jstree, autocomplete, dropdown, jquery-ui, quickpager, uploadify 가 있다. jQuery 관련 파일(js, css)은 [프로젝트]/src/main/webapp/simple-json/jquery 폴더 하위에 모두 존재한다.

이러한 jQuery 관련 js나 css 파일은 simpleweb-json에서 사용하는 standard.jsp의 상단에 정의되어 있다. 다음은 Simpleweb Plugin 설치로 추가된 standard.jsp 파일의 일부이다.

<!-- for jquery -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jquery-1.4.2.min.js'/>"></script>
	<link rel="stylesheet" href="<c:url value='/simpleweb-json/css/jquery.css'/>" type="text/css" />
	<link rel="stylesheet" href="<c:url value='/simpleweb-json/css/pagination.css'/>" type="text/css" />
	
	 <!-- jquery:autocomplete -->
	<link rel="stylesheet" type="text/css" href="<c:url value='/simpleweb-json/jquery/autocomplete/jquery.autocomplete.css'/>" />
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/autocomplete/jquery.autocomplete.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/autocomplete/jquery.bgiframe.min.js'/>"></script>	

	<!-- jquery ui, jqGrid -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jqgrid/i18n/grid.locale-en.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jquery-ui/jquery-ui-1.7.2.custom.min.js'/>"></script>
	<link href="<c:url value='/simpleweb-json/jquery/jqgrid/ui.jqgrid.css'/>" rel="stylesheet" type="text/css" /> 
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jqgrid/jquery.jqGrid.min.js'/>"></script>
	
	<!-- jquery form -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/form/jquery.form.js'/>"></script>
	
	<!-- jquery:jstree-0.9.9 -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jstree/lib/jquery.cookie.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jstree/lib/jquery.metadata.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jstree/jquery.tree.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jstree/plugins/jquery.tree.contextmenu.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/jstree/plugins/jquery.tree.cookie.js'/>"></script>
	
	<!-- jquery popup -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/nyromodal/js/jquery.nyroModal-1.6.2.pack.js'/>"></script>
	<link href="<c:url value='/simpleweb-json/jquery/nyromodal/styles/nyroModal.css'/>" rel="stylesheet" type="text/css" />

	<!-- jquery tab -->
	<link href="<c:url value='/simpleweb-json/jquery/jquery-ui/jquery-ui.css'/>" rel="stylesheet" type="text/css" />
		
	<!-- jquery uploadify -->
	<link rel="stylesheet" href="<c:url value='/simpleweb-json/jquery/uploadify/uploadify.css'/>" type="text/css" />
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/uploadify/swfobject.js'/>"></script>
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/uploadify/jquery.uploadify.v2.1.0.min.js'/>"></script>
	
	<!-- jquery image dropdown -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/dropdown/msdropdown/js/jquery.dd.js'/>"></script>
	<link href="<c:url value='/simpleweb-json/jquery/dropdown/msdropdown/dd.css'/>" rel="stylesheet" type="text/css" />
	
	<!--  quick pager -->
	<script type="text/javascript" src="<c:url value='/simpleweb-json/jquery/quickpager/quickpager.mod.jquery.js'/>"></script>

위에서 import되어 있는 js 파일과 css 파일 중에서 필요한 컴포넌트에 대한 파일만 정의하도록 한다. jQuery에서는 이외에도 여러가지 다양한 Plugin 형태의 컴포넌트를 제공하고 있으며 필요에 따라 연계하여 사용하면 된다. 기본적으로 JSON 타입의 객체를 사용한다 할지라도 기본적인 Anyframe Tag Library 사용법은 VO나 Map을 사용할 때와 동일하다. 위에서 언급한 기본적인 jQuery의 컴포넌트 연계 방법에 대해 알아보도록 하자.

5.1.jqgrid

jqgrid는 리스트 출력을 위한 jQuery Plugin이다. 다음은 Simpleweb Plugin 설치로 추가된 리스트를 출력하는 list.jsp 파일의 일부이다.

jQuery("#grid").jqGrid( 
	url: "<c:url value='/simplejson.do?layout=jsonLayout&service=simplewebJsonMovieFinder.getPagingList(searchvo)
		&viewName=jsonView' />",
	mtype:'POST',
	datatype : "json",
	//column 이름
	colNames : [ '<anyframe:message code="movie.genre" />','id','<anyframe:message code="movie.title" />'...],
	jsonReader: {repeatitems: false},
	//각 column에 들어가게될 데이터
	colModel : [ 
	{name : 'genre.name', index : 'genre.name', align : 'center'}, {key : true, name : 'movieId', hidden : true}...],
	width : 780, height : 69,	scroll : false, forceFit:true,	multiselect : true, viewrecords : true,	
	//출력해줄 row의 갯수
	rowNum : 3, 
	sortable : true,
	
	//error 처리
	loadError: function(xhr,st,err) {
		alert('<anyframe:message code="error.moviefinderimpl.getpaginglist" />'); 
	}, 
	
	//cell duble click 이벤트 처리
	ondblClickRow: function(rowId) {
		rowData = jQuery("#grid").getRowData(rowId);
		jQuery("#getLink").attr("href",
		   "<c:url value='/simplejsoncommon.do?layout=jsonLayout&service=simplewebJsonMovieService.get(movieId)&
		   tiles=body:/WEB-INF/jsp/simpleweb-json/moviefinder/movie/form.jsp&
		   initdataService=simplewebJsonGenreService.getDropDownGenreList()&
		   initdataResult=genreList&movieId=' />" + rowData.movieId);
		document.getElementById("getLink").focus();
    }
});

jqgrid에서는 리스트 출력을 위한 url을 "url" 속성을 통해서 정의하고 있는데 이 때, Get 방식으로 요청을 보내기 때문에 SimpleWeb 공통 Controller에서 필요한 속성을 link tag나 submit tag없이 parameter로 셋팅해서 보내줘야 한다. 이 때, layout, service, tiles는 기존 tag에서 작성했을 때와 동일 하게 작성한다. 단, init tag의 valuelist로 key, value 쌍으로 정의했던 초기화 데이터 셋팅에 대해서는 key에 해당하는 값을 "initdataResult" value 값을 "initdataService"로 보내준다. JSON 객체를 사용하는 경우 리턴되는 viewName은 반드시 "jsonView"로 정의한다.

위의 코드에서는 ondbClickRow 라는 callback 함수를 사용하여 cell double click 이벤트를 처리하고 있다. Simpleweb Sample Application에서는 해당 cell의 상세 정보를 popup으로 출력하는 로직을 구현하고 있다. jQuery 함수 내에서 Spring JS의 함수를 바로 호출할 수는 없으므로 "getLink"라는 임의의 link를 만들고 href 속성과 이벤트 발생시 popup을 출력할 수 있도록 되어있다. 다음은, JSP에 작성된 getLink와 Spring JS 코드의 일부이다.

<a id="getLink" name="getLink"></a>
<script type="text/javascript"> 
 Spring.addDecoration(new Spring.AjaxEventDecoration({
	   elementId: getLink,
	   event: "onfocus",
	   popup: true,
	   params: {fragments:"body"}
	   }));
</script>

이렇게 jqgrid에 대한 Script 코드가 완성 되면 리스트를 출력 해줄 부분에 아래와 같이 table을 이용해서 리스트를 출력해 줄 수 있도록 한다.

<table id="grid" class="scroll" cellpadding="0" cellspacing="0"><tr><td/></tr></table>

위와 같이 jqgrid로 구현된 리스트의 모습은 아래와 같다.

※ jqgrid를 사용하여 리스트를 작성할 때 너무 많은 양의 데이터를 한꺼번에 출력하려고 하면 리스트를 출력하는데 있어서 많은 시간이 걸리거나 브라우저가 멈추는 현상이 발생할 수 있다. 이에 한번에 출력하는 데이터의 건수는 100개 이내로 하며 데이터가 많을 경우 pager를 이용해 paging 처리 할 것을 권고한다.

5.2.quickpager

jqgrid는 기본적으로 Paging 처리를 위한 Pager를 제공하고 있다. Anyframe에서는 pagenavigator와 유사한 Pager 출력을 위해 quickpager를 확장하여 사용하고 있다. quickpager를 사용하기 위해서는 리스트 Script내의 loadComplete 함수 안에 paging 정보를 셋팅 해주고 search 버튼을 클릭하는 이벤트를 발생 시키도록 한다. 관련 jQuery 코드는 아래와 같다.

jQuery("#grid").jqGrid( 
	{
		중략...
		loadComplete : function(xhr) {
			$("#pagination").quickPager( {
	    		pageSize: "3",
	    		pageUnit: "3",
	    		//page index를 전달할 값의 id
	    		pageIndexId: "pageIndex",
	    		//search botton의 id
	    		searchButtonId: "searchMovies", 
	    		currentPage: jQuery("#grid").getGridParam("page"),
	    		totalCount: jQuery("#grid").getGridParam("records"),
	    		searchUrl: "#"
	    		});
	    }
		...중략...
	});
$("#searchMovies").click( function() {
	jQuery("#grid").setGridParam({page:$("#pageIndex").val()});
	jQuery("#grid").setPostData({searchKeyword:$("#searchKeyword").val(), nowPlayingCondition:$("#nowPlayingCondition").val()});
	jQuery("#grid").setGridParam({
	url:"<c:url value='/simplejson.do?layout=jsonLayout&service=simplewebJsonMovieFinder.getPagingList(searchvo)&viewName=jsonView' />"})
			.trigger("reloadGrid");
});

위와 같이 Script 코드가 작성 되면 pagenavigator 출력 부분에 아래와 같이 div 영역을 표시해준다.

<div id=".boardNavigation">
	<input type="hidden" id="pageIndex" name="pageIndex" value="1" />
	<div id="pagination" class="pagination"></div>
</div>

위와 같이 정의한 quickpager는 아래와 같은 pagenavigator를 출력하게 된다.

jqgrid에서 제공하는 pager

jqgrid에서도 paging 처리를 위한 간편한 pager를 제공한다. 구현 방법은 아래와 같다.

//jqgrid 속성 설정 내에 정의
pager : jQuery('#pager')

<!-- JSP 내의 pager 출력 부분에 정의 -->
<div id="pager" class="scroll" style="text-align: center;"></div>

다음 그림은 pager 적용 모습이다.

5.3.autocomplete

autocomplete plugin은 사용자가 입력한 prefix를 가지고 자동 완성 기능을 제공하는 Plugin이다.

$("#searchKeyword").autocomplete(
		"<c:url value='/simplejson.do?layout=jsonLayout&service=simplewebJsonMovieService.getMovieTitleList(q)
			&viewName=jsonView' />", {
		//속성 정의
		width : 200,
		scrollHeight : 200,
		selectFirst:true,
		mustMatch:true,
		matchCase:true,
		autoFill:true,
		scroll: true
});

위의 Script 코드에서 볼 수 있듯이 마찬가지로 Simpleweb 공통 Controller를 사용하고 있으며 자동 완성 기능을 위해 호출해야할 비즈니스 서비스를 정의하고 있다. 이 때, autocomple Plugin은 입력 된 값을 "q"라는 key로 Request Parameter로 보내기 때문에 argument의 이름은 반드시 "q"로 정의해준다.

다음은 autocomplete이 적용된 input box의 모습이다.

5.4.jstree

jstree는 Tree를 출력해주는 컴포넌트이다. 기본 적인 구현 방법은 아래와 같다.

$("#tree").tree({
	data : {type : "json", async : true, 
		opts : {method : "POST", 
		    url : "<c:url value='/simplejsontree.do?service=simplewebJsonGenreService.getGenreList(searchVO)&viewName=jsonView' />"}},
	callback : {}
});

<div id="tree" class="demo" style="overflow: auto; height: 445px; width: 280px; border: 1px solid #C9CFDD;">
	<span>Movie Tree</span>
</div>

jstree 컴포넌트도 url을 가지고 페이지 로드시 Tree를 출력한다. 이 때도 마찬가지로 Simpleweb 기능을 이용하여 service를 지정해주고 viewName을 "jsonView"로 명시해 준다. 위에서 호출하는 "/simplejsontree.do"의 bean 정의는 아래와 같다.

<bean name="/simplejsontree.do" class="${package}.simpleweb.json.moviefinder.web.MovieTreeController">
	<property name="beanMethodsRepo" ref="jsonBeanMethodsRepo" />
</bean>	

MovieTreeController는 내부적으로 SimpleJSONTreeController를 상속받고 있으며 setTreeData() 메소드를 오버라이드 하고있다. jstree를 이용한 Tree 컴포넌트를 출력하려고 할때 Controller 작성 방법에 대해서는 SimpleJSONTreeController 부분을 참고한다. 또한, jstree는 Tree 출력을 위해 여러가지 callback 메소드를 제공한다. 다음은 callback 메소드 정의 예이다.

$("#tree").tree({
	..증략... 
	callback : {
		beforeopen : function (NODE, TREE_OBJ) {
			var nodeId = NODE.id;
			TREE_OBJ.settings.data.opts.url = 
				"<c:url value='/simplejsontree.do?service=simplewebJsonMovieFinder.getListByCategory(searchVO)&
					searchKeyword="+nodeId+"&viewName=jsonView' />";
		},
						
		beforedata	: function(NODE, TREE_OBJ) {
			if(NODE==false){
				TREE_OBJ.settings.data.opts.url = 
					"<c:url value='/simplejsontree.do?service=simplewebJsonGenreService.getGenreList(searchVO)&
					viewName=jsonView' />";
				return {id : $(NODE).attr("id") || "0",searchKeyword : NODE.id || document.getElementById("searchKeyword").value}
			}
			else{return {id : $(NODE).attr("id") || "0"}}
		},
		beforecreate : function(NODE) {
			if($(NODE).parents("li:eq(0)").attr("id")!=null){return alert("can not create here!");}
			return true;
		},
		oncreate : function(NODE, REF_NODE, TYPE, TREE_OBJ, RB) {
			var genreId = $(NODE).parents("li:eq(0)").attr("id");
			var title = NODE.data;
			$.post("<c:url value='/simplejson.do?layout=jsonLayout&service=simplewebJsonMovieService.create(movie)&
				viewName=jsonView'/>",
				{title : NODE.data, director : "", actors : "", "genre.genreId" : $(NODE).parents("li:eq(0)").attr("id")}, function(data) {});
		},
		beforedelete : function(NODE) {
			if($(NODE).parents("li:eq(0)").attr("id")==null){
				return alert("can not delete genre!");
			}
			return confirm("Are you sure you want to delete this movie?");
		},
		ondelete : function(NODE, TREE_OBJ, RB) {
			$.post("<c:url value='/simplejson.do?layout=jsonLayout&service=simplewebJsonMovieService.remove(movieId)&
				viewName=jsonView'/>",
				{ movieId : NODE.id}, function(data) {});
		},
		onselect : function(NODE, TREE_OBJ) {
			...중략.. 
		}
	}
});

다음은 jstree를 이용하여 Tree를 출력한 화면이다.

5.5.ui-tab

jQuery의 ui Plugin을 사용하면 간단하게 tab을 적용할 수 있다.

<script type="text/javascript">
	$(function() {
		$("#tabs").tabs();
		$("#tabs").hide();
		$("#tabs").show();
	}
</script>
		
<div id="tabs">  
	<ul>
		<li><a href="#genreTab">Genre Information</a></li>
		<li><a href="#movieTab">Movie Information</a></li>
	</ul>  <!-- tab containers --> 
	<div id="genreTab">
		<!-- genreTab contents-->
	</div>
	<div id="movieTab">
		<!-- movieTab contents-->
	</div>
</div>

다음은 tab이 적용된 화면의 모습이다.

5.6.dropdown

jQuery의 msDropDown Plugin을 사용하여 combobox를 구현할 수 있다. tab 컴포넌트와 마찬가지로 기존 HTML을 그대로 사용하면서 간단하게 구현할 수 있다.

<script type="text/javascript">
	$(function() {
		$('#genreId').msDropDown();
	}
</script>

<form:select id="genreId" path="genre.genreId"  cssStyle="width:210px;">
   <form:options items="${genreList}" itemValue="genreId" itemLabel="name"/>
</form:select>

다음은 msDropDown Plugin이 적용된 combobox 화면이다.

5.7.uploadify

Simpleweb Plugin의 Sample Application에서는 파일 업로드를 위한 uplodify Plugin의 적용을 위해 upload.jsp를 사용하고 있다. upload.jsp의 내용은 아래와 같다.

<%@ page language="java" autoFlush="true" contentType="text/html;charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<script type="text/javascript">
$(document).ready(function() {
	$("#uploadify").uploadify({
		uploader	: "<c:url value='/simpleweb-json/jquery/uploadify/uploadify.swf'/>",
		script		: "<c:url value='/simpleFile/jsonUpload.do'/>",
		cancelImg	: "<c:url value='/simpleweb-json/images/cancel.png'/>",
		queueID		: "fileQueue",
		fileDataName: "fileData",
		auto		: false,
		multi		: false,
		width		: 81,
		height		: 24,
		sizeLimit	: 10000000,
		buttonImg	: "<c:url value='/simpleweb-json/images/uploadBrowse.png'/>",
		onComplete	: function(event,queueID,fileObj,response,data) {
			eval("var respJson="+response);
			$('#hiddenUploadedFiles').val($('#hiddenUploadedFiles').val()+','+respJson.uploadResult.fileNm);
			$('#fileDir').val(respJson.uploadResult.fileDir);
			$('#uploadify').uploadifySettings('scriptData', {'fileDir' : $('#fileDir').val()});
		  }
	});
	$("#uploadClearButton").click( function() {
		jQuery('#uploadify').uploadifyClearQueue();
	});
});
</script>

<table width="150" height="100" border="0" bordercolor="red"> 
	<tr> 
		<td>
			<div id="fileQueue" style="width:176px;height:60px;"></div>  
			<!-- hidden attributes -->
			<input type="hidden" id="hiddenUploadedFiles" name="hiddenUploadedFiles" />
			<input type="hidden" id="filePathsAttrName" name="filePathsAttrName" value="filePaths" />
			<input type="hidden" id="fileDir" name="fileDir" />
			<!-- browse/clear button -->
			<div id="buttons" align="center" style="padding-top:5px"> 
				<input type="file" id="uploadify" name="uploadify" width="80"/> 
				<img id="uploadClearButton" 
				    src="<c:url value='/simpleweb-json/images/clear.jpg'/>" width="57" height="24"..." />
			</div>
		</td>
	</tr>
</table>

script 속성으로 정의되어 있는 "/simpleFile/jsonUpload.do" 요청에 대한 Bean 정의는 아래와 같다.

<bean name="/simpleFile/jsonUpload.do" class="anyframe.web.springmvc.controller.FileUploadController">
		<property name="idGenerationService" ref="jsonUuidGenerationService" />		
	</bean>

위의 JSP 코드에서 볼 수 있듯이 fileData와 fileDir을 FileUploadController에서 받아 처리하고 처리 결과에 대해 다시 Model 객체로 리턴해준다. 개발자는 uplodify Plugin을 FileUploadController와 upload.jsp 파일을 이용하여 파일 업로드를 구현할 수 있으며 파일 업로드를 구현할 JSP 페이지에 upload.jsp 파일을 include하고 submit tag의 setProperty 속성을 정의하고 upload에 대해 true로 설정해 준다.

<jsp:include page="/WEB-INF/jsp/simpleweb-map/common/upload.jsp" flush="true"/>
<anyframe:submit id="addlink" form="movieForm" action="/simplemap.do" service="simplewebMovieService.create(movie)" ...>
    <anyframe:setProperty name="upload" value="true" />	
</anyframe:submit>

다음은 upload.jsp를 include하고 있는 form.jsp 페이지를 웹 브라우저를 통해 본 UI 모습이다. Browse 버튼을 클릭하여 파일을 첨부할 수 있다.

또한, uplodify()의 multi 속성을 true로 설정하면 여러개의 파일을 업로드할 수 있다.

$("#uploadify").uploadify({
	..
	multi : false,
	...
})

업로드된 그림 파일을 JSP에서 확인하기 위해 c tag를 사용하여 아래와 같이 작성한다.

<c:forTokens var="token" items="${movie.filePaths}" delims=",">
	<img src="<c:url value='${token}'/>" alt="<spring:message code='movie.posterFile'/>" border="0" width="80" height="100" />
</c:forTokens>


반응형