2010년 1월 11일 월요일

흰둥씨의 DWR강좌

방장은 누규? 채팅사이트 조이팅스토리를 운영하며 마케팅, 사업 등에 관심이 많은 철이

 

 
흰둥이’s DWR 강좌

 

 

강좌라기 보단, IBM 기술문서를 번역하려다, 사용자의 이해를 좀 쉽게 도모하고저(?) 별도의 매뉴얼로 작성합니다. 그리 어려운 개념이 아니며 자바스크립트만 이용할 수 있다면 어플리케이션의 큰 변경 리스크 없이 간간히 적용하기에 좋습니다. 지금부터라도 한번씩 자신의 어플리케이션에 간단하게 나마 적용해 보시기 바랍니다. 사용자가 매우 좋아할 까요.. ^_^

 

아약스의 기본 개념은 여기서 언급하지 않습니다. 관련자료가 워낙 많기 때문에 참조할 문서가 많으실 겁니다. 못찾겠다면 이문서를 일단 보세요.

(http://cafe.naver.com/ArticleRead.nhn?clubid=10068252&menuid=&listtype=A&boardtype=L&page=&articleid=1577)

 

DWR(Direct Web Remoting) 은 서버사이드 빈과, 자바스크립트, 그리고 DWR 서블릿으로 구성되어 있는 아파치 라이센스를 가진 라이브러리 입니다. 용어에서 보실수 있듯이 말그대로 서버에 존재하는 클래스를 마치 로컬에서 호출하듯이 사용하게 해주는 겁니다. RMI와 흡사하지요? , DWR은 서버의 자바클래스와, 클라이언트의 자바스크립트 의 원격호출기능을 정의합니다. 서버에 Cart 라는 클래스가 있고, getCartItem이란 메서드가 있다면, 클라이언트의 스크립트 상에서 똑 같은 객체명 Cart.getCartItem() 으로 호출하여 반환값을 사용할 수 있는겁니다.

 

 물론, 이러한 로직은 Ajax를 이용해 처리되는데요. 우리는 아약스를 위한 XMLHttpRequest등의 개체에 전혀 신경쓸 필요가 없다는게 장점입니다. DWR이 다 알아서 제너레이션을 해주거든요. Ajax 코딩해 보신분들은 이것이 매우 번거롭고 귀찮다는걸 아실겁니다. ^_^ .. DWR의 구성요소를 잠깐 살펴볼까요?

 

DWR 서블릿 : 일종의 맵퍼? 후킹? 뭐 그런의미의 DWR만의 컨트롤러 예요. 물론 내용은 신경쓰실 필요 없구요. 라이브러리만 연결해 놓으시고, 초기로딩시 올라올 수 있게 몇몇 설정만 간단히 해주시면 됩니다. 주요기능은 스크립트 자동 제너레이션이나, 데이터 이동등의 역할을 하는 컨트롤러 예요.

 

서버사이드 빈 : 서버와 클라이언트 사이를 오고갈 빈즈예요. DWR이 서버에 있는 빈을 자바스크립트로 자동 변환작업 을 해주어, 클라이언트 스크립트에서 마치 자신의 클래스를 쓰는마냥 서버의 각종 value들을 획득할수 있게 합니다. 우리가 실제로 작성해야 하는 것들입니다.

 

자바스크립트 : DWR에 매우 유용한 스크립트 라이브러리를 포함합니다. 예를들자면 테이블에 열을 삭제/추가해주거나, 변수접근을 용이하게 해주거나 하는따위의 유틸들이죠. 프로토타입(http://particletree.com/features/quick-guide-to-prototype/)을 아신다면 쉽게 이해가 가실겁니다.

이걸 사용하면 스크립트에 들어가는 공수가 매우 줄어든답니다.

백문이 불여일견! 다 필요없고 실제 사용예제로 바로 들어가겠습니다. 이론보단 실전 ^_^

 

일단, 예제파일을 아래에서 받으세요.

이 예제는 간단히 쇼핑몰을 구현한 것이구요. 전체 쇼핑 리스트와 자신의 카트, 그리고 검색 및 카트에 추가하기 등이 지원되는 매우 간단한 예제예요. 이해하기 편하실 겁니다.

(http://www.ibm.com/developerworks/views/download.jsp?contentid=98221&filename=j-ajax3dwr.zip&method=ftp&locale=worldwide)

예제파일을 받으면 아래와 같이 구성되 있는걸 확인하실 수 있습니다.

 

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

Lib 밑에는 dwr.jar 파일이 들어있습니다. 이파일은 위에서 설명드렸던 dwr 서블릿들이예요.

반드시 필요하겠죠?

Src 에는 서버빈 2개와 Util, DAO가 들어있습니다.

Web 엔 웹 인터페이스가 들어있는데, 파일 하나입니다. 매우 간단하죠? ^^

Ant 를 이용해 배포하시거나, 수동으로 하시거나 자신의 배포 환경에 적당히 배포하시기 바랍니다.

저같은경우엔, 이클립스에 아래와 같이 만들었습니다. (! 예제는 JDK5.0 으로 코딩되어 있으니 주의하시기 바랍니다.)

 

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

자 이제 모두 제 위치에 적당히 배포하셨다면, 설정부분을 하나씩 확인하겠습니다.

1. web.xml 설정

   - 이곳엔 dwr invoke 설정과 모든 dwr관련 리소스에 대한 맵핑을 선언합니다.

<servlet>

    <servlet-name>dwr-invoker</servlet-name>

    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>

    <init-param>

      <param-name>debug</param-name>

      <param-value>true</param-value>

    </init-param>

  </servlet>

 

  <servlet-mapping>

    <servlet-name>dwr-invoker</servlet-name>

    <url-pattern>/dwr/*</url-pattern>

</servlet-mapping>

 

uk.ltd.getahead.dwr.DWRServlet -> 이녀석이 주요 핵심 컨트롤러 겠죠? 내용이 궁금하시면 들여다 보시구요. 맵핑은 /dwr/ 하위로 들어오는 모든 클래스에 대한 맵핑이네요?

 

2. dwr.xml

- 이건 파일명대로 dwr에 대한 별도 설정입니다. 물론 DWRServlet에서 참조하겠죠?

- 아래에 xml 내용에 설명을 붙여놓았으니 참조하세요~

<dwr>

  //최상위 노드입니다.

<allow>

  //create onvert 엘리먼트 2개를 설정합니다.

  //create 는 서버의 클래스 인스턴스를 생성하고자 할 때 설정합니다.

  //converter 는 빈과 자바스크립트 사이의 맵핑을 선언합니다.

    <create creator="new" javascript="Catalogue">

       //새로운 디폴트 생성자로 인스턴스를 생성하고, 클라이언트 스크립트에선 Catalogue라는 이름으로 접근이 가능하게 합니다.

      <param name="class" value="developerworks.ajax.store.CatalogueDAO"/>

      //실제 생성되는 클래스 명이죠?

      <include method="getItem"/>

      <include method="findItems"/>

      //클라이언트 스크립트에서 사용할 수 있는 (공개하는) 메서드 명 선언입니다.

    //이렇게 해놓으면 클라이언트에선 Catalogue.getItem() 식으로 직접 호출이 가능하게 됩니다.

    //메서드 명들을 보시면 무슨일을 할는지 대충 감이 오시죠? 자세한건 서버 클래스에서 계속~

    </create>

    <create creator="new" scope="session" javascript="Cart">

      <param name="class" value="developerworks.ajax.store.Cart"/>

      <include method="addItemToCart"/>

      <include method="getFormattedTotalPrice"/>

      <include method="getCart"/>

    </create>

    <convert converter="bean" match="developerworks.ajax.store.Item">

      <param name="include" value="id,name,description,formattedPrice"/>

    </convert>

    <convert converter="bean" match="developerworks.ajax.store.Cart">

      <param name="include" value="simpleContents,formattedTotalPrice"/>

    </convert>

  </allow>

</dwr>

 

3. 이제 dwr.xml 에 선언되 있는 각종 클래스들의 내용을 보실까요?

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

자 메인 DAO가 있구요. 아이템을 아이디로 가져오거나, 특정 표현식으로 검색을 할수 있는 메서드가 있네요. , Cart 라는 빈은 자신의 쇼핑가방이죠? 카트에 아이템을 추가할 수 있고, 내용과 현재까지의 총가격등을 조회할 수 있게 되어있네요? 간단하지요?

실제 내용은 다운받은 예제 클래스 파일을 참조하세요. 위에 있는 클래스명과 공개되는 메서드들이 dwr.xml 에 설정되 있는걸 알수있습니다.

 

4. . 이제 설정은 모두 끝났구요. 이제 클라이언트에서 스크립트를 통해 직접 사용해 주시면 되겠습니다.

 

먼져, 서버용으로 생성한 Catalog CatalogDAO등에 대한 자동생성된 자바스크립트를 확인하셔야 하는데요. Default web.xml에서 맵핑해놓은 url /dwr/* 으로 접근하시면 dwr.xml 에 설정되어 있는 상태와 자동생성될 .js 파일들을 확인하실 수 있습니다.

웹브라우져에서 http:host/web-app/dwr/ 로 접근해보시면 아래와 같은 화면이 나옵니다.

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

 

화면에 보시면 Cart Catalogue 가 링크되어있지요? 이 두개의 파일은 위에서 dwr.xml 에 설정해 놓으신걸 기억하실 겁니다. 이제 특정 링크를 클릭해보세요.

그럼 아래와 같이 세부 정보가 표시됩니다.

 

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

링크에 표시된 것 처럼 url 을 사용하고자 하는 html 이나 jsp 에서 그대로 이용하시면 됩니다.

물론 이 js 는 동적으로 생성되는것이라 실제 디렉토리엔 안보일꺼예요. 바로 이 js Cart 라는 객체를 스크립트에서 접근할 수 있게 만들어 주는 셈이죠.

이제 다운받은 쇼핑몰 예제의 index.html shopping.js 파일을 확인해 보겠습니다.

 

Index.html 에선 아래와 같이 js 들을 사용하고 있지요?

 

이미지를 클릭하시면 원본크기로 보실수 있습니다.

 

여기서 Catalogue Cart dwr 에서 생성해준 서버클래스에 해당하는 분들이구요.

engine.js util.js 는 기본제공되는 dwr 엔진과 유틸이랍니다. (같은거 물론 두번 사용하실 필요 없겠지요? ^^)

그리고, 마지막에 shopping.js 는 직접 코딩하실 내용입니다.

이제 shopping.js 를 확인해 볼까요?

 

 

Shopping.js 에는 onload 시 초기 로드될 펑션이 정의되있습니다.

window.onload = function() {

  // Update Cart state from session

Cart.getCart(displayCart);

-> Cart 란 개체를 사용하고 있지요? 게다 getCart란 메서드도 호출하고 있구요.

-> 물론, shopping.js 내의 어디에도 해당 객체와 메서드는 없습니다. 이건 Cart.js 내에 있구요.

-> Cart.js 는 서버의 Cart 클래스를 DWR이 제너레이션 해준 스크립트죠?

-> 대충 감이 오실겁니다. 그럼 인자로 displayCart 는 무엇일까요?

-> 바로 콜백(callback)입니다. Cart.getCart 가 반환하는 Cart 를 스크립트 내의 displayCart 펑션으로 받아서 처리하라. 라는 것입니다. 물론, dwr.js 내에 convert 에서 각 빈들을 잘 맵핑해놓아서 dwr이 반환값을 알아서 스크립트에 맞게 컨버트 해줍니다.

$("searchform").onsubmit = searchFormSubmitHandler;

-> 첨보는 표현식이죠? 스크립트 문법이 아니구요. Dwr util 스크립트에서 제공해주는 펑션입니다. 풀어서 쓰면 d0cument.form.searchform.onsubmit 정도가 되겠네요.

-> onsubmit 을 내부 펑션으로 치환하는거죠?

}

 

이부분만 제대로 이해가 가셨다면, 이제 원리 다 이해하신겁니다. 어때요? 쉽지요?

우리는 서버에 Cart 란 클래스를 자바로 만들어놓고, dwr에 설정해놓으면, 클라이언트에선 위와같이 cart.getCart 식으로 곧바로 호출하여 결과값을 화면내에 다이나믹하게 반영하는겁니다.

물론, 서버의 cart.getCart 를 호출할때엔, Ajax를 사용함으로 페이지 리로딩이 일어나지 않습니다.

(이게 ajax를 사용하긴 하는건가? 하고 의구심이 들지요? 직접 실행해보세요~)

 

그외 클라이언트에서의 처리부분은 모두 스크립트가 담당합니다.

그럼 콜백함수인 displayCart 부분을 쫌 살펴볼까요?

 

 

function displayCart(cart) {

 

  // Clear existing content of Cart

  var contentsUL = $("contents");

contentsUL.innerHTML="";

-> contents 내부 HTML을 모두 제거합니다.

 

  // Loop over cart items

  for (var I in cart.simpleContents) {

    -> 스크립트 개체로 변환된 cart 를 가지고 루프를 돌면서..

    -> 카드 표시부분에 아이템을 하나씩 채워 넣습니다.

    // Add a list element with the name and quantity of each

    var li = d0cument.createElement("li");

    li.appendChild(

             d0cument.createTextNode(cart.simpleContents[I] + " x " + I)

                  );

    contentsUL.appendChild(li);

-> 마지막으로 총 가격을 갱신합니다.

  var totalSpan = $("totalprice");

  totalSpan.innerHTML = cart.formattedTotalPrice;

}

 

끝으로, 카트에 아이템을 추가하실 땐, 위처럼 매번 서버에 반영하고 다시 자신의 카트를 조회하고 하면 서버에 접근이 너무 많이 가겠죠? 클라이언트에 캐시 개념을 두시면 쉽게 해결하실 수 있습니다. 일단 스크립트로만 작업해놓고, 나중에 반영하면 되겠죠?

 

중요한건 이러한 개념을 응용해서 나름대로 써먹는 거죠. 간단한 히스토리 콤보를 지금 한번 생각해서 만들어 보세요. ~

지금까지 허접한 DWR 간단 사용 강좌 였습니다. ^______^

 

감사합니다.

출처: http://cafe.naver.com/javalove.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1588

 

 

 

 



P 이경철님의 파란블로그에서 발행된 글입니다.

댓글 없음:

댓글 쓰기