| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

DWR

Page history last edited by PBworks 17 years, 7 months ago

DWR (Direct Web Remoting)

 

  • DWR은 Direct Web Remoting 의 약자로서 ajax를 기반으로 하여 client side 의 javascript 로 server side 의 Java Beans을 interactive하게 조작할 수 있는 framework 입니다.
  • 현재 stable version 은 1.1 이고 dwr.dev.java.net 에서 development version인 2.0 소스를 checkout 할 수 있습니다. 특히 2.0 에서는 rajax (reverse ajax)라는 개념으로 역으로 Java Beans에서 client side 의 javascript를 조작가능하도록 구현되어 있습니다.
  • 또한 Struts, Spring, Webwork, JSF 등 web framwork 와의 연동을 위한 libraries 를 제공하고 있습니다.
  • 테스트를 위한 sample 소스를 82서버의 개발cvs repository 에 'dwr_ex' module 로 등록되어 있으므로 checkout 받아 테스트할 수 있습니다.
  • 개발자인 Joe Walker가 운영중인 사이트 http://getahead.ltd.uk/dwr/ 에서 online manual과 많은 정보를 구할 수 있습니다.

 



DWR Architecture

 

  • DWR은 ajax 와 결합된 Client side, DWRServlet, Server side JavaBeans 를 가지는 MVC패턴과 유사한 구조입니다. 이는 Javascript 로 DWREngine(ajax engine)을 통해 view page 갱신없이 실시간 서비스를 호출하여 dhtml로 화면을 조작할 수 있는 기능을 제공합니다.
  • Client side 인 view page는 javascript + html 만으로도 충분히 개발가능하나 페이지 로딩 시 서버에서 가져온 데이터를 리스트 또는 상세내역으로 보여주어야 할 때는 JSP 페이지를 사용하여야 합니다.
  • DWRServlet의 경우 controller 의 역할로써 /dwr/engine.js, /dwr/util.js, /dwr/interface/TestObject.js 의 요청이 들어오면(uri-mapping) dwr.xml 에 등록된 TestObject을 참조하여 Javascript를 생성해주는 역할을 수행합니다.
  • JavaBeanTestObject의 경우 Business Layer의 component를 생성하여 서비스를 호출할 수 있는 메소드를 Javascript 에서 사용할 수 있도록 제공해주어야 합니다.

 

 

  • 위 그림에 대한 설명은 다음과 같습니다.
  • 1] Init 수행

페이지 로딩 시 /dwr/engine.js, /dwr/util.js, /dwr/interface/TestObject.js 의 요청이 들어오면 DWRServlet은 dwr.xml를 로딩하여 TestObject 에 대한 메소드를 Javascript로 호출할 수 있도록 생성해 줍니다. 이로써 TestObject를 Javascript에서 조작가능하게 됩니다.

  • 2] call method 수행

Init 수행 후 TestObject.getList() 호출 시 DWREngine 을 호출하여 서버쪽 TestObject JavaBean의 getList() 메소드를 호출하게 됩니다. 만약 getList() 메소드에 return value가 존재한다면 callback function 을 다음과 같이 정의하여야 합니다.

 

 1] callback function 분리 :

  // TestObject 의 getList() 메소드 호출.
  TestObject.getList(getListCallback);

  function getListCallback(data) {
    // returned value 처리
  };

 2] anonymous function 으로 구현 :  

  // TestObject 의 getList() 메소드 호출.
  TestObject.getList( {
    callback : function(data) {
      // returned value 처리
    },
    errorHandler : function(message, exception) {
      // server message, error 처리
    }
 });
 

 

  • 위와 같이 call method 이후 returned value 손쉽게 combo box 및 table에 자동 셋팅할수 있도록 util.js 내에 DWRUtil 을 제공합니다.

 

 


dwr libraries 설치

 

  • dwr 라이브러리는 dwr.jar 하나이며 참조하는 라이브러리도 함께 설치되어야 합니다.
  • 최소 설치 libraries :
  1. dwr.jar : dwr core library
  2. bsf-2.3.jar : Bean Scripting Framework library ( http://jakarta.apache.org/bsf/index.html )
  3. bsh-2.0b4.jar : Bean Shell Framework library ( http://www.beanshell.org/ )
  4. commons-logging-1.0.4.jar : Jakarta Common Logging library ( http://jakarta.apache.org/commons/logging/ )
  5. commons-validator-1.1.4.jar : Jakarta Common Validator library ( http://jakarta.apache.org/commons/validator/ )
  6. jakarta-oro-2.0.8.jar : Jakarta ORO library ( http://jakarta.apache.org/oro/ )
  7. log4j-1.2.12.jar : log4j library ( http://logging.apache.org/log4j/docs/index.html )

 

  • web framework 와 연동하기 위한 선택적인 libraries :
  1. spring.jar : Spring Framework http://www.springframework.org/
  2. struts.jar : Struts Framework http://struts.apache.org/
  3. hibernate3.jar : hibernate Framework http://www.hibernate.org/
  4. webwork.jar : webwork Framework http://www.opensymphony.com/webwork/
  5. jsf-api.jar, jsf-impl.jar : JSF Framework http://java.sun.com/javaee/javaserverfaces/reference/docs/index.html

 

등이 필요합니다.

 


DWRServlet 설정 - web.xml

 

 

  • dwr_ex 모듈 내 WebContent/WEB-INF/web.xml 를 참조하십시요.

 

  • 기본적인 DWRServlet 설정

 

 <servlet>
   <servlet-name>dwr-invoker</servlet-name>
   <display-name>DWR Servlet</display-name>
   <description>Direct Web Remoter Servlet</description>
   <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
   <init-param> 
     <param-name>debug</param-name>
     <param-value>true</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
   <servlet-name>dwr-invoker</servlet-name>
   <url-pattern>/dwr/*</url-pattern>
 </servlet-mapping>
 

 

 

  • dwr.xml 을 업무별로 나누어 사용이 가능합니다. http://getahead.ltd.uk/dwr/server/servlet/multiconfig 을 참조하십시요.
  • dwr-user.xml, dwr-admin.xml 두개의 설정파일을 사용하고자 하는 경우 DWRServlet 을 dwr-user-invoker, dwr-admin-invoker 두 개 설정, 각각의 dwr.xml을 설정합니다.

 

 <servlet>
   <servlet-name>dwr-user-invoker</servlet-name>
   <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
   <init-param>
     <param-name>config-user</param-name>
     <param-value>WEB-INF/dwr-user.xml</param-value>
   </init-param>
 </servlet>
 <servlet>
   <servlet-name>dwr-admin-invoker</servlet-name>
   <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
   <init-param>
     <param-name>config-admin</param-name>
     <param-value>WEB-INF/dwr-admin.xml</param-value>
   </init-param>
 </servlet>
 <servlet-mapping>
   <servlet-name>dwr-admin-invoker</servlet-name>
   <url-pattern>/dwradmin/*</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
   <servlet-name>dwr-user-invoker</servlet-name>
   <url-pattern>/dwruser/*</url-pattern>
 </servlet-mapping>
 

 


dwr.xml 작성

 

 

  1. dwr.xml에 javascript 객체로 조작할 JavaBean 을 설정함
  2. 해당 JavaBean에 대한 Life scope 지정이 가능 (page, script, request, session, application)
  3. JavaBean에서 사용해야할 메소드 filtering : include, exclude method 지정
  4. Value object(JavaBean) 사용하기 위한 각종 converter 제공
  5. ajax 요청을 가로채는 Filter 설정

 

  • 다음은 DwrTest을 Javascript 에서 사용하기 위한 설정입니다.
  • Foo 객체의 경우 updateFoo(Foo foo), deleteFoo(Foo foo) 메소드 호출 시 파라미터의 Value Object 로써 사용하기 위해 bean converter 로 설정되어 있음

 

 <dwr>
   <init>
     ...
   </init> 
 
   <allow>
 …
     <create creator="new" javascript="DwrTest" scope="request">
       <param name="class" value="fullbox.dwr.test.DwrTest"/>
     </create>
     <convert match="fullbox.dwr.test.Foo" converter="bean"/>
 …
   </allow>
 </dwr>
 

 


client page 작성

 

  • client page 내에는 다음을 반드시 작성하여야 합니다.
  1. DwrTest.js 는 동적으로 생성되는 스크립트로써 DwrTest 객체를 조작하기 위해서는 반드시 아래와 같이 작성해 주어야 함.
  2. engine.js 는 DWREngine 이 정의된 스크립트임
  3. util.js 는 DWRUtil 이 정의된 스크립트임
  4. example (dwr_ex.html 참조)

 

 <html>
   <head>
     ...
     <script language="javascript" src="/dwr/interface/DwrTest.js"></script>
     <script language="javascript" src="/dwr/engine.js"></script>
     <script language="javascript" src="/dwr/util.js"></script>
   </head>
   <body>
   </body>
 </html>
 

 


dwr_ex 모듈 테스트

 

  • 82서버 개발 cvs 에서 dwr_ex 모듈을 checkout 받습니다.
  • tomcat의 web context 로 'dwr_ex'를 설정하여 tomcat을 기동합니다.
  • eclipse wtp를 사용하여 web context로 등록하면 tomcat 에 다음과 같이 설정됩니다.

 

<Context docBase="dwr_ex" path="/dwr_ex" reloadable="true" source="org.eclipse.jst.j2ee.server:dwr_ex"/>
 

 


dwr example 개발

 

 

에러 메시지 핸들러 구현

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex01.html 을 참조하십시요.

 

  • Javascript 로 조작하기 위한 DwrExample 클래스를 다음과 같이 정의합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   public String getData1() {
     throw new NullPointerException("NullPointerException occurred!");
   }
 }
 

 

  • DwrExample 클래스를 dwr.xml 에 다음과 같이 설정합니다. scope 을 'session' 으로 설정하였으므로 DwrExample 생성 후 HttpSession 에 저장됩니다.

 

 <create creator="new" javascript="DwrExample" scope="session">
   <param name="class" value="fullbox.dwr.test.DwrExample"/>
 </create>
 

 

  • dwr_ex01.html 은 다음과 같이 작성합니다.
  • 메시지 처리 방법은 DWREngine 의 setErrorHandler(), setWarningHandler() 메소드에 의해 정의됩니다.
  • 자세한 내용은 http://getahead.ltd.uk/dwr/other/errors 을 참조하십시요.

 

  • 먼저 여러 개의 ErrorHandler function 을 지정합니다. 이 function 들은 error message 를 다양하게 표시하기 위한 로직을 포함하고 있습니다. 아래는 간단히 메시지만 다르게 하여 서로 다른 ErrorHandler function 을 구현한 예제입니다.

 

 // Global ErrorHandler 를 지정하는 function.
 function eh0(msg) {
   alert("Global ErrorHandler : " + msg);
 }
    
 // 새로운 ErrorHandler 를 지정하는 function 1).
 function eh1(msg) {
   alert("Applied New ErrorHandler : " + msg);
 }
    
 // 새로운 ErrorHandler 를 지정하는 function 2).
 function eh2(msg, ex) {
   // FunkyException 에 존재하는 getWhen() 메소드를 ex.when 으로 호출.
   alert(msg + ", date=" + ex.when);
 }
 

 

 

  • 한 페이지의 모든 메시지의 처리를 동일하게 표시하려면 body태그의 onLoad() 시 init()을 실행하도록 합니다. init() function 은 먼저 Global ErrorHandler function 인 eh0 을 설정합니다.

 

 // body onLoad() 에서 초기화하는 function : Global ErrorHandler를 설정.
 function init() {
   // ErrorHandler, WarningHandler 설정.
   DWREngine.setErrorHandler(eh0);
   DWREngine.setWarningHandler(eh0);
   // Loading Message 설정.
   DWRUtil.useLoadingMessage();
 }
 

 

  • 따라서 객체의 모든 메소드 호출 시 오류가 발생하면 위에서 정의한 대로 메시지가 처리됩니다.

 

  • 객체의 특정 메소드 호출 시(ex : DwrExample.getData1()) 처리 메시지를 다르게 보여주어야 한다면 해당 메소드를 호출하기 전에 DWREngine.setErrorHandler() 를 다음과 같이 재정의하여야 합니다.

 

 function getDataByAppliedErrorHandler() {
   // 새로운 ErrorHandler를 적용.
   DWREngine.setErrorHandler(eh1);
   DwrExample.getData1(getDataCallback);
 }
 

 

  • 단, 위 방법은 DWREngine.setErrorHandler() 에 직접 설정하는 것으로 Global하게 적용되므로 서로 다른 메소드 호출 시 각각 다른 방법으로 메시지를 처리하는 것은 부적절합니다.

 

  • Global ErrorHandler 의 설정을 그대로 유지하면서 DwrExample.getData1() 호출 시 다음과 같이 정의하여 특정 메시지를 처리할 수 있습니다.

 

 function getDataByLocalErrorHandler() {
   // 새로운 Local ErrorHandler를 적용.
   DwrExample.getData1({
     callback : getDataCallback,
     errorHandler : function(msg, ex) {
       alert("Local ErrorHandler : " + msg);
     }
   });
 }
 

 

  • 위와 같이 작성하면 Global ErrorHandler 의 설정과 Local ErrorHandler 의 설정을 분리할 수 있습니다.

 


사용자 정의 Exception 처리

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex01.html 을 참조하십시요.

 

  • 사용자 정의의 FunkyException 클래스를 다음과 같이 작성합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class FunkyException
 extends RuntimeException {
     
   private final static long serialVersionUID = 1L;
   private Date date; 
 
   public FunkyException(String msg) {
     super(msg);
   }
   public FunkyException(String msg, Date date) {
     super(msg);
     this.date = date;
   }
   
   public Date getWhen() {
     return date;
   }
 }
 

 

  • 먼저 구현한 Exception (ex : FunkyException) 을 dwr.xml 의 bean converter로 설정하여야 합니다.

 

 <convert match="fullbox.dwr.test.FunkyException" converter="bean" />
 

 

  • 다음은 DwrExample 클래스를 다음과 같이 작성합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
 
   public String getData1() { ... }
 
   public String getData2() {
     Date when = new Date();
     // FunkyException 예외 발생.
     throw new FunkyException("FunkyException occurred!", when);
   }
 }
 

 

  • dwr_ex01.html 에서 객체의 특정 메소드 호출 시(ex : DwrExample.getData2()) 처리 메시지를 다르게 보여주어야 한다면 해당 메소드를 호출하기 전에 DWREngine.setErrorHandler() 를 다음과 같이 재정의하여야 합니다.

 

 function getDataThrownFunkyExceptionByAppliedErrorHandler() {
   // 새로운 ErrorHandler를 적용.
   DWREngine.setErrorHandler(eh2);
   DwrExample.getData2(getDataCallback);    	    
 }
 

 

  • 단, 위 방법은 DWREngine.setErrorHandler() 에 직접 설정하는 것으로 Global하게 적용되므로 서로 다른 메소드 호출 시 각각 다른 방법으로 메시지를 처리하는 것은 부적절합니다.

 

  • Global ErrorHandler 의 설정을 그대로 유지하면서 DwrExample.getData2() 호출 시 다음과 같이 정의하여 특정 메시지를 처리할 수 있습니다.

 

 function getDataThrownFunkyExceptionByLocalErrorHandler() {
   // 새로운 Local ErrorHandler를 적용.
   DwrExample.getData2({
     callback : getDataCallback,
     errorHandler : function(msg, ex) {
       alert("Local ErrorHandler : " + msg + " , date=" + ex.when);
     }
   });
 }
 

 

  • 위와 같이 작성하면 Global ErrorHandler 의 설정과 Local ErrorHandler 의 설정을 분리할 수 있습니다.

 


JavaBean 값 셋팅

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex02.html 을 참조하십시요.

 

  • 이번 예제는 Javascript 객체를 통해 DwrExample JavaBean에 값을 셋팅하고 결과를 출력하는 예제입니다.

 

  • DwrExample 클래스에 name 을 셋팅하는 setName() 메소드와, Foo 객체를 셋팅하는 setFoo() 메소드를 추가합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   ... 이전 예제의 메소드 ...

   private Foo foo;
   
   public void setName(String name) {
     System.out.println("### name : " + name);
   }
    
   public void setFoo(Foo foo) {
     System.out.println("### foo.name : " + foo.getName());
     System.out.println("### foo.title : " + foo.getTitle());
     System.out.println("### foo.content : " + foo.getContent());
     this.foo = foo;
   }
    
   public Foo getFoo() {
     return foo;
   }
 }
 

 

  • Foo 클래스는 name, title, content 필드를 갖고 각 set, get 메소드를 가진 클래스입니다. dwr_ex 모듈 내 src/fullbox/dwr/test/Foo.java 를 참조하십시요.

 

 

  • dwr.xml 에 보면 Foo 클래스는 다음과 같이 bean converter 로 설정되어 있습니다.

 

 <convert match="fullbox.dwr.test.Foo" converter="bean"/>
 

 

 

  • dwr_ex02.html 에서 다음과 같이 function 을 작성합니다.

 

 // name 값을 DwrExample JavaBean에 셋팅.
 function setName() {
   var name = frm.name.value;
   DwrExample.setName(name);
 }
    
 // name, title, content 값을 DwrExample JavaBean에 셋팅.
 function setFoo() {
   var foo = {
     name : frm.name.value, 
     title : frm.title.value,
     content : frm.content.value
   };
   DwrExample.setFoo(foo);     
 }

 // 저장된 Foo 값을 가져오는 function.
 function getFoo() {
   DwrExample.getFoo(getFooCallback);
 }

 // getFoo()의 callback function.
 function getFooCallback(foo) {
   DWRUtil.setValue("data", 
     "name : " + foo.name + 
     " , title : " + foo.title + 
     " , content : " + foo.content);
 }
 

 

 

  • 입력폼을 생성하고 function setName(), setFoo() 을 호출하여 tomcat 콘솔 로그창에 셋팅된 값이 정상적으로 출력되는지 확인합니다.

 

  • getFoo() 을 호출하면 div 태그 내에 값이 변경되는지 확인합니다.

 

 


combobox 동적 구성

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex03.html 을 참조하십시요.

 

  • 이번 예제는 Javascript 객체를 통해 DwrExample JavaBean에 값을 가져와 동적으로 Combobox를 생성하는 예제입니다.

 

  • DwrExample 클래스에 주 리스트를 가져오는 메소드와 도시 리스트를 가져오는 메소드를 다음과 같이 정의합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   ... 이전 예제의 메소드 ...
   
   private String[][] address = {
        {"Florida", "Bryceville"}
       ,{"Florida", "Elkton"}
       ,{"Florida", "Glen Saint Mary"}
       ,{"Michigan", "Birmingham"}
       ,{"Michigan", "Marine City"}
       ,{"Michigan", "Chesterfield"}
       ,{"Minnesota", "Almelund"}
       ,{"Minnesota", "Castle Rock"}
       ,{"Minnesota", "Dalbo"}
       ,{"California", "Los Angeles"}
       ,{"California", "Orange"}
   };
   
   public Map getComboListState() {
     Map map = new HashMap();
     String curState;
     String prevState = "";
     for( int i = 0 ; i < address.length ; i++ ) {
       curState = address[i][0];
       if(!curState.equals(prevState))
         map.put(address[i][0], address[i][0]);
   
       prevState = curState;
     }
     return map;
   }
    
   public Map getComboListCity() {
     Map map = new HashMap();
     for( int i = 0 ; i < address.length ; i++ ) {
       map.put(address[i][1], address[i][1]);
     }
     return map;
   }
 }
 

 

  • dwr_ex03.html 에서 다음과 같이 function 을 작성합니다.

 

 // dynamic Combobox 설정 function.
 function getComboListState() {
   DwrExample.getComboListState(getListComboCallback);
 }
    
 // dynamic Combobox 설정 function.
 function getComboListCity() {
   DwrExample.getComboListCity(getListComboCallback);
 }
    
 // callback function.
 function getListComboCallback(data) {
   DWRUtil.removeAllOptions("listCombo");
   var defaultSelect = {"":" -- select -- "};
   DWRUtil.addOptions("listCombo", defaultSelect);
   DWRUtil.addOptions("listCombo", data);
 }
 

 

  • 빈 select 태그의 name 값을 'listCombo' 로 정의합니다.

 

  • function getComboListState(), getComboListCity() 를 호출하였을 때 listCombo 박스의 내용이 동적으로 변경되는지 확인합니다.

 


상위 combobox 선택에 따른 하위 combobox 동적 구성

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex04.html 을 참조하십시요.

 

  • 이번 예제는 상위 Combobox 에서 특정 주를 선택 시 해당하는 하위 도시 리스트를 sub Combobox에 동적으로 셋팅하는 예제입니다.

 

  • DwrExample 클래스에서 주 리스트를 가져오는 메소드는 combobox 동적 구성를 참조하며 도시 리스트를 가져오는 메소드는 다음과 같이 정의합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   ... 이전 예제의 메소드 ...   
   
   private String[][] address = { ... };

   public Map getComboListState() { ... }

   public Map getComboListCityByState(String state) {
     Map map = new HashMap();
     for( int i = 0 ; i < address.length ; i++ ) {
       if(address[i][0].equals(state))
         map.put(address[i][1], address[i][1]);
       }
       return map;
   }
 }
 

 

  • dwr_ex04.html 에서 다음과 같이 function 을 작성합니다.

 

 // init() function 에 페이지 로딩 시 stateCombo박스를 셋팅하는 것을 호출합니다.
 function init() {

    ... ErrorHandler 설정...

    // dynamic state Combobox 설정 function.
    DwrExample.getComboListState(getComboListStateCallback);
 
 }

 // dynamic Combobox 설정 function.
 function getComboListCityByState() {
   // $() 으로 현재 html doucument 내 지정된 id, ids 에 해당하는 element object를 가져옴.
   var state = $("stateCombo").value;
   DwrExample.getComboListCityByState(state, getComboListCityCallback);
 }
	
 // callback function.
 function getComboListStateCallback(data) {
   DWRUtil.removeAllOptions("stateCombo");
   var defaultSelect = {"":" -- select -- "};
   DWRUtil.addOptions("stateCombo", defaultSelect);
   DWRUtil.addOptions("stateCombo", data);
 }
    
 // callback function.
 function getComboListCityCallback(data) {
   DWRUtil.removeAllOptions("cityCombo");
   var defaultSelect = {"":" -- select -- "};
   DWRUtil.addOptions("cityCombo", defaultSelect);
   DWRUtil.addOptions("cityCombo", data);
 }
 

 

  • 두개의 빈 select 태그를 생성하고 각각 name 값을 'stateCombo', 'cityCombo' 로 정의합니다.

 

  • stateCombo 의 onChange="getComboListCityByState();" 를 설정합니다.

 

  • 작성완료 후 페이지 로딩 시 stateCombo 박스에 정상적으로 값이 셋팅되는지 확인합니다.

 

  • stateCombo박스의 값을 변경하면 정상적으로 cityCombo박스의 값이 변경되는지 확인합니다.

 


검색어추천 박스 만들기

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex05.html 을 참조하십시요.

 

  • 이번 예제는 입력박스에서 하나씩 입력할 때마다 실시간으로 입력된 단어로 시작되는 추천단어들을 검색해주는 예제입니다.

단, 현재 100 ~ 199 까지의 숫자문자열만 배열에 저장되어 있으므로 검색어 범위를 100 ~ 199 사이만 입력하여야 합니다. 그리고 검색어 추천 리스트에서 특정 검색어를 더블클릭하면 div 태그에 선택한 검색어를 표시합니다.

 

  • DwrExample 클래스에서 다음과 내용을 작성합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   ... 이전 예제의 메소드 ...

   private static String[] titles = new String[199];
   static {
     for( int i = 100 ; i < titles.length ; i++ ) {
       titles[i] = "" + i;
     }
   }
    
   public List getRecommendSearch(String title) {
     List result = new ArrayList();
     for( int i = 100 ; i < titles.length ; i++ ) {
       if(titles[i].startsWith(title)) {
         result.add(titles[i]); 
       }
     }
     return result;
   }
 }
 

 

 

  • dwr_ex05.html 에서 다음과 같이 function 을 작성합니다.

 

 function recommendSearch() {
   var arg = $("title").value;
   DwrExample.getRecommendSearch(arg, recommendSearchCallback);    
 }
    
 function recommendSearchCallback(data) {
   // table 내 각 열에 대한 정의를 다음과 같이 각 열대로의 function 을 정의함
   var cellFuncs = [
     function(data) {
       return "<input type='text' name='recommend' style='border:0px;cursor:hand' " + 
         " value='" + data + "' onClick='selectRecommend(this.value)' readOnly />";
     }
   ];
		
   DWRUtil.removeAllRows("RecommendTable");
   DWRUtil.addRows("RecommendTable", data, cellFuncs);
 }

 function selectRecommend(data) {
   DWRUtil.setValue("recommendDiv", data);
 }
 

 

  • 다음은 검색어를 입력할 입력박스와 div태그, 그리고 검색어 추천 리스트를 보여줄 table태그를 다음과 같이 정의합니다.

 

   <form name="frm">
     <table width="60%">
       <tr>
         <td width="50%">
           <input type="text" name="title" value="" onKeyUp="recommendSearch();" />
         </td>
         <td width="50%">
           <div id="recommendDiv" style="border:1px solid #000000;">
           Recommended argments
           </div>
         </td>
       </tr>
     </table>
   </form>

   <table style="border:1px solid #000000;" cellspacing="0" cellpadding="0">
     <tbody id="RecommendTable" border="0" >
     </tbody>
   </table>
 

 

 

  • 위 소스에서 입력박스에 있는 onKeyUp() 이벤트 핸들러를 통해서 키를 누른 후 땔 때마다 검색어 추천리스트를 서버에서 조회하게 됩니다. 정상적으로 작동하는 지 입력박스에 한단어씩 입력하여 테스트합니다.

 

  • 조회된 검색어 추천 리스트에서 더블클릭했을 때 입력박스 옆의 recommendDiv 에 선택한 검색어 추천 단어가 정상적으로 셋팅되는지 확인합니다.

 

 


간단한 게시판(CRUD 기능) 만들기

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex06.html 을 참조하십시요.

 

  • 이번 예제는 검색폼을 이용하여 검색한 리스트에서 입력,수정,삭제를 하는 간단한 게시판을 구현합니다.
  • 이 게시판은 페이지의 갱신없이 CRUD 가 수행되므로 동적인 페이지의 변경 및 리스트의 갱신 등을 필요로 하는 복잡한 화면에서 사용하기에 적절합니다.

 

  • DwrExample 클래스에서 다음과 같이 데이터베이스의 연결없이 static variable 로 CRUD를 처리하는 메소드를 간단히 구현합니다.

 

 package fullbox.dwr.test;
 import java.util.Date;
 public class DwrExample {
   
   ... 이전 예제의 메소드 ...

   // 데이터의 선언
   private static Map datas = new HashMap();
   static {
     for (int i = 100 ; i < 199 ; i++ ) {
       Foo foo = new Foo();
       foo.setName("" + i);
       foo.setTitle("title" + i);
       foo.setContent("content" + i);
       datas.put(foo.getName(), foo);
     }
   }
   
   // 조회 메소드
   public List listFoo(String name) {
     List result = new ArrayList();
     Iterator it = new TreeMap(datas).values().iterator();
     while(it.hasNext()) {
       Foo foo = (Foo)it.next();
       if(foo.getName().startsWith(name)) {
         result.add(foo);
       }
     }
     return result;
   }
   
   // 상세내역 조회 메소드
   public Foo viewFoo(String name) {
     return (Foo)datas.get(name);
   }
    
   // 입력, 수정 메소드
   public void updateFoo(Foo foo) {
     datas.remove(foo.getName());
     datas.put(foo.getName(), foo);
   }
    
   // 삭제 메소드
   public void deleteFoo(Foo foo) {
     datas.remove(foo.getName());
   }
 }
 

 

 

  • dwr_ex06.html 에서 다음과 같이 function 을 작성합니다.

 

 // 조회 function
 function listFoo() {
   var arg = $("search").value;
   // 첫번째 매개변수는 실매개변수로, 두번째는 callback function을 셋팅.
   DwrExample.listFoo(arg, listFooCallback); 
 }

 // 조회 callback function
 function listFooCallback(foos) {
   // fooTable tbody 내에서 다시 조회 되었을 때 id 가 'pattern'인 tr태그만 남겨두고 나머지 삭제.
   DWRUtil.removeAllRows("fooTable", { 
     filter : function(tr) {
       return (tr.id != "pattern");
     }
   });
    
   // 루프 돌면서 foo 리스트를 각 span 태그의 id에 해당하는 위치에 값 셋팅.
   for (var i = 0; i < foos.length; i++) {
     var foo = foos[i];
     var name = foo.name;
     DWRUtil.cloneNode("pattern", { idSuffix:name });
     DWRUtil.setValue("tname" + name, name);
     DWRUtil.setValue("ttitle" + name, foo.title);
     DWRUtil.setValue("tcontent" + name, foo.content);
     // 복사한 tr 태그를 화면에 나타나게 함.
     $("pattern" + name).style.display = "";
   }
 }
    
 // 상세내역 조회 function
 function viewFoo(pttnid) {
   // pttnid 는 'pattern110' 이런 형태이므로 'pattern' prefix를 잘라낸 나머지가 foo.name 임.
   var name = pttnid.substring(7);
   DwrExample.viewFoo(name, function(foo) {
     DWRUtil.setValue("name", foo.name);
     DWRUtil.setValue("title", foo.title);
     DWRUtil.setValue("content", foo.content);
     // 수정, 삭제 시 name 필드는 readonly로 셋팅.
     $("name").readonly = true;
   });
 }
    
 // 입력,수정 function
 function insertFoo() {
   var foo = {
     name : $("name").value, 
     title : $("title").value,
     content : $("content").value
   };
   // DWREngine의 batch 단위로 묶어서 일괄처리 함. performance 향상.
   DWREngine.beginBatch();
   DwrExample.updateFoo(foo);
   listFoo();
   DWREngine.endBatch();
 }
    
 // 삭제 function
 function deleteFoo() {
   var foo = {
     name : $("name").value, 
     title : null,
     content : null
   };
   // DWREngine의 batch 단위로 묶어서 일괄처리 함. performance 향상.
   DWREngine.beginBatch();
   DwrExample.deleteFoo(foo);
   listFoo();
   frmReset();
   DWREngine.endBatch();
 }
    
 // 폼 리셋 function
 function frmReset() {
   var val = frm.search.value;
   frm.reset();
   frm.search.value = val;
   frm.name.readonly = false;
 }
 

 

  • 위 스크립트는 기능별로 구현한 것이므로 function 내 주석을 참조하면 쉽게 이해할 수 있습니다.

 

  • 다음은 검색어를 입력할 입력박스와 조회버튼에 대한 태그를 다음과 같이 작성합니다. 이벤트 핸들러는 onclick 입니다.

 

 <table width="60%">
   <tr>
     <td>
       <input type="text" name="search" value="" />
       <input type="button" name="listfoo" value="search" onclick="listFoo();" />
     </td>
   </tr>
 </table>
 

 

 

  • 다음은 리스트를 표시할 테이블과 상세내역 테이블을 다음과 같이 작성합니다. 리스트 테이블의 tr태그 내의 viewFoo() function 이 onDblClick 이벤트핸들러로 설정되어 있습니다.

 

 <table width="60%" style="border:1px solid #000000;" cellspacing="0" cellpadding="0">
   <thead>
     <tr>
       <th width="20%">Name</th>
       <th width="40%">Title</th>
       <th width="40%">Content</th>
     </tr> 
   </thead>
   <tbody id="fooTable">
     <tr id="pattern" style="display:none;cursor:hand;" onDblClick="viewFoo(this.id);" >
       <td><span id="tname">Name</span></td>
       <td><span id="ttitle">Title</span></td>
       <td><span id="tcontent">Content</span></td>
     </tr>
   </tbody>
 </table>
 <br />
 <table width="60%">
   <tr>
     <td>Name</td>
     <td width="80%"><input type="text" id="name" name="name" value="" /></td>
   </tr>
   <tr>
     <td>Title</td>
     <td><input type="text" id="title" name="title" value="" /></td>
   </tr>
   <tr>
     <td>Content</td>
     <td><input type="text" id="content" name="content" value="" /></td>
   </tr>
 </table>
 

 

  • 위 소스에서 viewFoo() 의 매개변수의 값으로 tr 태그의 id 값을 넘겨주는 데 이는 'pattern' + 'name 값' 이므로 각 tr태그마다 유일하게 정의되어 있습니다. 그러므로 prefix 인 'pattern'을 제외한 'name 값'을 해당 tr태그의 키값으로 하여 각 foo 를 수정하거나 삭제할 수 있습니다.

 

  • 다음은 CUD 버튼을 작성합니다. 각각 function은 button 의 onclick 이벤트 핸들러로 설정되어 있습니다.

 

 <table width="60%">
   <tr>
     <td>
       <input type="button" name="insert" value="insert Foo" onclick="insertFoo();" />
       <input type="button" name="update" value="update Foo" onclick="insertFoo();" />
       <input type="button" name="delete" value="delete Foo" onclick="deleteFoo();" />
     </td>
   </tr>
 </table>
 

 

  • dwr_ex06.html 의 코드 작성 완료 후 테스트를 위하여 '100' ~ '199' (데이터값) 의 특정 값을 입력하여 'search' 버튼을 선택합니다.

 

  • 조회된 리스트에서 특정 데이터를 선택합니다. 그리고 아래 상세내역에서 title, content 항목을 수정 후 'update Foo' 버튼을 선택하면 정상적으로 수정되고 조회되는지 확인합니다.

 

  • 조회된 리스트에서 특정 데이터를 선택합니다. 그리고 아래 상세내역에서 'delete Foo' 버튼을 선택하면 정상적으로 삭제되고 조회 후 데이터가 삭제되었는지 확인합니다.

 

  • 아래 상세내역 초기화 상태에서 name, title, content 항목을 입력후 'insert Foo' 버튼을 선택하면 정상적으로 입력되고 조회되는지 확인합니다.

 


Web Framework Integration

 

  • struts, spring, webwork, jsf 등 web framework 의 bean 설정 파일에 등록된 JavaBeans를 DWR 에서 Javascript 로 조작가능하게 하는 것으로 간단한 설정만으로 연동이 가능합니다.

 

 


Struts Integration

 

  • DWR 보다 Struts 의 설정이 먼저 초기화되어야 하므로 web.xml 에 Servlet(Struts 의 ActionServlet, DWR의 DWRServlet) 설정 시 load-on-startup 태그로 초기화 순서를 정해야 합니다.

 

 <web-app>
 ...
 <servlet>
   <servlet-name>action</servlet-name>
   <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
   ...
   <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet>
   <servlet-name>dwr-invoker</servlet-name>
   <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
   ...
   <load-on-startup>2</load-on-startup>
 </servlet>
 ...
 </web-app>
 

 

 

  • Struts 의 설정파일인 struts-config.xml 에 다음과 같이 DwrExample 을 설정합니다.

 

 <struts-config>
 ..
   <form-beans>
     <form-bean name="DwrExample" type="fullbox.dwr.test.DwrExample" />
   </form-beans>
 ..
 </struts-config>
 

 

 

  • DWR 의 설정파일인 dwr.xml 에 struts-config.xml 에 설정된 DwrExample 을 다음과 같이 설정합니다.

 

 <allow>
  ...
  <create creator="struts" javascript="DwrExample">
    <param name="formBean" value="DwrExample"/>
  </create>
  ...
 </allow>
 

 

  • 이로써 Struts 에 설정된 DwrExample 을 DWR 에서 조작가능합니다.

 


Spring Integration

 

  • 'dwr_ex' 모듈 내 WebContent/dwr_ex06_spring.html 을 참조하십시요.

 

  • Spring의 설정파일을 로딩하기 위해 web.xml 에 다음과 같이 설정합니다.

 

 <web-app>
   ...
   <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>/WEB-INF/beans.xml</param-value>
   </context-param>
   <listener>
     <listener-class>
       org.springframework.web.context.ContextLoaderListener
     </listener-class>
   </listener>
   ...
 </web-app>
 

 

  • Spring 의 설정파일인 beans.xml 에 다음과 같이 DwrExample 을 설정합니다.

 

 <beans>
 ...
   <bean id="DwrExample" class="fullbox.dwr.test.DwrExample" />
 ...
 </beans>
 

 

  • DWR 의 설정파일인 dwr.xml 에 beans.xml 에 설정된 DwrExample 을 다음과 같이 설정합니다.

 

 <allow>
   ...
   <create creator="spring" javascript="DwrExample">
     <param name="beanName" value="DwrExample"/>
   </create>
   ...
 </allow>
 

 

  • 이로써 Spring 에 설정된 DwrExample 을 DWR 에서 조작가능합니다.


Webwork Integration ( 스터디 중...)

 


JSF Integration ( 스터디 중...)

 


reference sites

 

Comments (0)

You don't have permission to comment on this page.