DWR : Easy Ajax for JAVA dwr

출처 : http://hopeland.kr/220


작년인가 JCO컨퍼런스에서 들었던 DWR을 이제서야.. 사용해보았습니다.
그때 시연에서 봤던것처럼 참 편하고 요긴합니다.
DWR 사이트를 참고해서 DWR에 대해 간단하게 소개 합니다.

====================================================================
자바 오픈소스 라이브러리인 DWR은 Ajax 웹사이트에 사용할 수 있으며
크게 두개의 부분으로 구성되어 있습니다.
서블릿이 실행되고있는 서버에 요청을 처리하고 브라우저로 응답을 보내는 부분과
브라우저에서 실행되고있는 자바스크립트에 요청을 보내고 웹페이지를 다이나믹하게 업데이트하는 부분 입니다.
DWR은 자바 클래스를 기반으로 자바스크립트를 다이나믹하게 생성합니다.
=====================================================================

개요 부분은 나름 해석이 될듯해서 한번 번역해서 써볼랬는데... 힘드네요..
그냥 링크를 보시는게 나을듯합니다. 구글 번역을 써봐도 쉬 이해할만해 보입니다.
소개는 제가 이해한 내용과 설치 및 간단한 예제를 보여드릴 수 있도록 하겠습니다.
사용자의 입장에서 보면 DWR은 자바의 메소드를 자바스크립트에서 사용할 수 있도록 해줍니다.
중요한건 간단하게 사용할 수 있다는 점입니다.
기존에 직접 Ajax를 이용해서 데이터 가져오고 처리하던때에는 기존에 사용되던 메소드라 하더라도
데이터를 가공하기위한 작업이 꼭 필요했지만 DWR을 이용하면 메소드에서 리턴해주는 리턴값들이 스크립트에서 사용하기 용이한 형태로 변환되어 집니다. 그래서 편리합니다.

간단한 예제를 위한 준비를 하도록 하겠습니다.
1. DWR jar파일을 다운받아 설치합니다. [다운로드]
   - jar파일은 webapp디렉토리 아래 WEB-INF/lib에 둡니다.

2. 해당 webapp의 web.xml에 dwr맵핑을 위한 내용을 추가합니다.

<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-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>
  * DWR2.0의 경우는 servlet이 달라서 <servlet-class>태그 값이 다릅니다.  
org.directwebremoting.servlet.DwrServlet


   3. 위 web.xml파일과 같은 위치에 dwr.xml파일을 생성합니다.
      
dwr.xml파일에서 DWR의 각종설정들이 가능합니다.

<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
    "http://www.getahead.ltd.uk/dwr/dwr10.dtd">

<dwr>
  <allow>
    <create creator="new" javascript="JDate">
      <param name="class" value="java.util.Date"/>
    </create>
   </allow>
</dwr>



여기까지만 셋팅하시면 기본 설정을 완료되었습니다.
위 dwr.xml설정에서는 java.util.Date클래스를 dwr에서 사용가능하도록 설정이 되어있습니다.

사용하시는 환경에따라서
http://[사용도메인]/[webapp경로]/dwr/
의 url로 접근해보시면 현재 설정에서 사용가능한 클래스의 리스트가 보입니다.
현재는 Date클래스만 허용되어 있으니 해당 항목만 보일것입니다.
해당항목의 링크를 클릭해보시면 해당 클래스에서 사용가능한 메소드의 리스트와
해당 메소드를 사용하기위해 html 페이지에 삽입해야하는 스크립트가 보입니다.

 위 내용이 정상적으로 보이시면 환경설정은 잘 끝났고 눈썰미가 좋으신 분은 이미 활용이 가능하실것
 같습니다.

그럼 데이터를 가져오는 부분까지의 간단한 예제를 위해 설정을 조금 추가해 보겠습니다.
우선 dwr.xml을 아래처럼 변경합니다.
기존 Date 클래스 설정과 동일한 깊이에  MyTest클래스에 대한 설정과
MyBean에 대한 설정이 추가되었습니다.
javascript 속성에는 스크립트에서 사용될 클래스명이고.
class라는 속성값을 가진 param의 value속성 값은 각자의 상황에 맞는 패키지 경로를 적어주시면
됩니다.

새로 보이는 convert태그는 일반적으로 데이터를 주고받을때 사용되는 bean을 DWR에서
사용하도록 허용해주는 부분입니다.
상세한 설명은 뒷부분에서 새로 설명하도록 하겠습니다.
설정은 톰캣4.1의 경우 재시작을 해야 적용이 됩니다.

<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
    "http://www.getahead.ltd.uk/dwr/dwr10.dtd">

<dwr>
  <allow>
    <create creator="new" javascript="JDate">
      <param name="class" value="java.util.Date"/>
    </create>
    <create creator="new" javascript="Chat">
      <param name="class" value="com.hopeland.dwr.Chat"/>
    </create>
   <create creator="new" javascript="Test">
      <param name="class" value="com.hopeland.dwr.MyTest"/>
    </create>
   <convert converter="bean" match="com.hopeland.dwr.MyBean"/>
  </allow>
</dwr>


MyTest.java
package kr.hopeland.dwr;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.directwebremoting.proxy.dwr.Util;

import uk.ltd.getahead.dwr.WebContext;
import uk.ltd.getahead.dwr.WebContextFactory;

public class MyTest{
 private static HashMap<String,String> hm = new HashMap<String, String>();
 private static ArrayList<String> list = new ArrayList<String>();
 private static String str = "테스트~!!";
 private static String [] strs = {"배열1","배열2"};
 private String name = "하이바";
 private String age = "31";
 
    public HashMap<String, String> getMap() {
     hm.put("key1", "맵값1");
     hm.put("key2", "맵값2");
     hm.put("key3", "맵값3");
     return hm;
    }
   
    public ArrayList<String> getList(){
     list.add("리스트1");
     list.add("리스트2");
     list.add("리스트3");
     return list;
    }
   
    public String getString() {
     return str;
    }
   
    public String [] getStrings(){
     return strs;
    }
   
    public void testBean(MyBean mb) {
     System.out.println("age="+mb.getAge());
     System.out.println("name="+mb.getName());
     HashMap<String, String> hm = mb.getHm();
     System.out.println(hm.get("aa"));
    }
   
}


MyBean.java
package kr.hopeland.dwr;

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.List;

    public class MyBean{
     private String name = null;
     private int age = 0;
     private HashMap<String, String> hm = null;
    
     public int getAge() {
      return age;
     }
     public void setAge(int age) {
      System.out.println("age set="+age);
      this.age = age;
     }
     public HashMap<String, String> getHm() {
      return hm;
     }
     public void setHm(HashMap<String, String> hm) {
      this.hm = hm;
     }
     public String getName() {
      return name;
     }
     public void setName(String name) {
      this.name = name;
     }
      
      
    }

test.html

<html>
 <head>
  <title> dwr연습</title>
 </head>
 <script type='text/javascript' src='/ohpoint/dwr/interface/Test.js'></script>
 <script type='text/javascript' src='/ohpoint/dwr/engine.js'></script>
 <script type='text/javascript' src='/ohpoint/dwr/util.js'></script>
 <script type="text/javascript">
  function getData(){
   Test.getString(doAction);
  }
   
  function doAction(len){
   alert(len);
  }
 
  function setData(){
   var p = { name:"Fred", age:21, hm:{aa:"1",bb:"2"}};
   Test.testBean(p, doAction2);
  }

  function doAction2(map){
   alert(map.name);
  }

 </script>
 
 <body>
  <input type="button" onclick="javascript:getData();" value="값가져오기 테스트" />
  <input type="button" onclick="javascript:setData();" value="bean테스트" />
 </body>
</html>


test.html을 살펴보면
스크립트 선언부에 아래와 같은 내용이 들어있습니다.
<script type='text/javascript' src='/ohpoint/dwr/interface/Test.js'></script>
<script type='text/javascript' src='/ohpoint/dwr/engine.js'></script>
<script type='text/javascript' src='/ohpoint/dwr/util.js'></script>

위쪽 2개의 스크립트는 해당 클래스를 사용하기위한 필수 스크립트이며 마지막 스크립트는 옵션입니다.
dwr.xml에서 설정된 스크립트에서 사용할 이름에 맞게 js파일명은 변경하시면 됩니다.

스크립트의 getData 함수에 있는 Test.getString(doAction); 부분이 실제 클레스를 생성하여
해당 객체의 getString이라는 메소드를 실행하는 부분입니다.
doAction은 해당 메소드를 실행한 후 에 실행될 스크립트 함수입니다. 콜백함수 라고 부르는걸로 기억합니다..
현재 스크립트에서 Test이름으로 불리는 클래스(실제명은 MyTest)의 getString메소드는 인자가 없는경우이고
인자가 있는경우라면 Test.getString(인자값1,인자값2,콜백함수명); 의 형태가 되겠습니다.

getString메소드가 실행된 후에 doAction함수의 인자값인 len으로 메소드의 리턴값이 전달됩니다.
DWR에서는 자바의 primitive  타입들은 자동으로 변환이 되어 넘겨집니다.

기본적으로 DWR에서는 int,String 등의 primitive 타입들은 자동으로 변환이 됩니다.
추가로 Array나 Collection,Bean 등은 dwr.xml에 선언을 하는 방법이 문서에 있는데
bean을 제외한 Array, Map등은 DWR2.0에서 사용해본 결과 메소드에서 해당 형으로 결과를 리턴하면
스크립트에서는 JSON형태로 잘 넘어와지는 것을 확인하였습니다.
영어가 달려서... 전혀 엉뚱하게 이해하고 있을 수도 있으니.. 주의해주시고 지적해주시면 감사드리겠습니다.

위 html예제에서 getData 함수가 실행되면
1. MyTest클래스의 getString 메소드가 실행되어진 후에 리턴값이 doAction함수의 인자로 넘거값니다.
2. doAction 함수에서는 alert창으로 len값을 보여줍니다.

만약 getMap 메소드를 호출하시도록 변경을 해보시면 오브젝트 형이 넘어오는 것을 확인하실 수 있습니다.
(http://[사용도메인]/[webapp경로]/dwr/ 경로에서 해당 클래스의 사용가능한 메소드 리스트에서는
결과값을 바로 보실 수 있습니다.)

끝으로 DB관련 작업시에 많이 사용되는 bean값을 리턴 받는 방법을 살펴보겠습니다.

앞부분에서 dwr.xml에서 추가된
<convert converter="bean" match="com.hopeland.dwr.MyBean"/>

부분입니다.
위 내용을 추가하면 MyBean이라는 bean을 인자로 받을 수도 보낼 수도 있습니다.
스크립트에서 인자로 받는 경우에는 MAP과 마찬가지로 JSON형태로 넘어옵니다.

우선 setData 함수를 보면
var p로 MyBean에 셋팅할 값을 JSON형태로 설정하고 있습니다.
MyBean.java와 var p를 보시면 쉽게 이해가 가실겁니다.
Test.testBean(p, doAction2);
부분에서 p를 인자로 넘긴후 서버의 메소드가 실행된 후에 doAction2의 인자값으로 서버에서 선언된
MyBean값이 넘어오고 있습니다.
map.name의 값은 최소 var p에서 선언했던 Fred 입니다.

이상으로 간단하게(?) DWR의 요점이라 생각되는 부분을 살펴봤습니다..
사실 코딩에 관련된 글을 포스팅해보는게 처음인데.. 확실한 지식을 가지고 있지않으니
시간도 많이 걸리고 많이 어렵네요..
다른사람에게 쉽게 설명할 수 있어야 진짜 지식이다라는게 실감이 됩니다.
DWR 2.0에서는 Reverse AJAX라는 이름으로 간단하게 서버에서 클라이언트의 함수를 실행할 수 도있습니다!!!
관련 포스트
해당 기술을 이용한 주식현황표 (테이블을 한번 클릭해주세요.)

앞으로는 좋은 라이브러리들을 공부하는데에도 시간을 잘 써야 할 것 같습니다.
직접 구현하면서 기술을 이해하는것도 중요하고 이해하고 사용할 수 있다면
많들어져있는 좋은 라이브러리들을 잘 활용하는것도 중요한 능력인것 같습니다.
DWR 시작하시는데 도움이 되었으면 좋겠습니다.

덧글

댓글 입력 영역