본문 바로가기
IT/ActionScript & Flex

blazeDS RemoteClass

by yjacket 2010. 7. 8.

하려는것

1) Flex 에서 RemoteObject 를 이용해 blazeds 서버의 메서드를 호출하고,
2) 서버는 RemoteClass 로 등록되어있는 객체를 반환하면
3) Flex 가 이를 받아 View 에서 볼 수 있도록 바인딩 한다.

예제1) 간단한 모델

Java

   1: public class Config
   2: {
   3:     private String text;
   4:  
   5:     public String getText()
   6:     {
   7:         return text;
   8:     }
   9:  
  10:     public void setText(s:String)
  11:     {
  12:         text = s;
  13:     }
  14: }

Flex
   1: package com.myapp.model.config
   2: {
   3:     [RemoteClass(alias="com.myapp.model.Config")]
   4:     
   5:     [Bindable]
   6:     public class Config
   7:     {
   8:         private var _text:String;
   9:  
  10:         public function get text():String
  11:         {
  12:             return _text;
  13:         }
  14:  
  15:         public function set text(s:String):void
  16:         {
  17:             _text = s;
  18:         }
  19:     }
  20: }

예제1은 특별히 설명할게 없다. 저렇게 하면 알아서 리모트 클래스로 처리되어 속성을 참조 할 수 있다.

플렉스에서 리모트 클래스로 등록한 Config객체는 text 가 속성으로 되어 있는데

RemoteObject 로 가져올때 자바객체의 getText(), setText() 메서드를 알아서 불러와 text에 집어 넣어준다.

 

예제2) 복잡한 모델

Java

   1: package com.myapp.model;
   2:  
   3: import com.myapp.model.BaseDataModel;
   4:  
   5: public class Config extends BaseDataModel
   6: {
   7:     private int seq;
   8:  
   9:     public int getSeq()
  10:     {
  11:         return seq;
  12:     }
  13:  
  14:     public void setSeq(int i)
  15:     {
  16:         this.seq = i;
  17:     }
  18:  
  19:     public int getInterval()
  20:     {
  21:         return getInt("interval", 60);
  22:     }
  23:  
  24:     public void setInterval(int i)
  25:     {
  26:         setInt("interval", i);
  27:     }
  28: }
   1: import java.util.HashMap;
   2:  
   3: public abstract class BaseDataModel
   4: {
   5:     /**
   6:      * "key1=value1&key2=value2& ... " 와 같은 문자열을 key&value 쌍으로 저장하고 있는 멤버  
   7:      */
   8:     private HashMap<String, String> dataHashMap = new HashMap<String, String>();
   9:     
  10:     /**
  11:      * @return
  12:      * dataHashMap의 요소를 "key=value& ... " 형식 문자열로 만들어 반환한다.
  13:      * 이 메서드는 오버라이드 할 수 없다. 
  14:      */
  15:     public final String getData()
  16:     {
  17:         return DataUtil.getDataString(dataHashMap);
  18:     }
  19:     
  20:     /**
  21:      * "key=value& ... " 형식 문자열을 파싱하여 dataHashMap 에 저장한다.
  22:      * 문자열 전달인자는 파싱되기 전 멤버변수인 data 에 저장된다.
  23:      * 이 메서드는 오버라이드 할 수 없다.
  24:      * @param data
  25:      */
  26:     public final void setData(String data)
  27:     {
  28:         dataHashMap = DataUtil.getDataHashMap(data);
  29:     }
  30:     
  31:     /**
  32:      * int 타입의 값을 문자열로 변환해 dataHashMap 에 저장한다.
  33:      * @param key
  34:      * @param value
  35:      */
  36:     protected void setInt(String key, int value)
  37:     {
  38:         dataHashMap.put(key, Integer.toString(value));
  39:     }
  40:  
  41:     /**
  42:      * dataHashMap 에서 key 에 해당하는 값을 참조해 int 형으로 반환한다.
  43:      * 참조한 값이 null 이면 0을 반환한다.
  44:      * @param key
  45:      * @return
  46:      */
  47:     protected int getInt(String key)
  48:     {
  49:         return Integer.getInteger(dataHashMap.get(key), 0);
  50:     }    
  51: }

 

Flex

   1: package com.myapp.model
   2: {    
   3:     [RemoteClass(alias="com.myapp.model.Config")]
   4:     
   5:     [Bindable]
   6:     public class Config
   7:     {    
   8:         private var _seq:int;
   9:         private var _interval:int;
  10:         private var _data:String;
  11:         
  12:         // ---------------------------------------------------
  13:         // Properties
  14:         // ---------------------------------------------------
  15:         public function get seq():int
  16:         {
  17:             return _seq;
  18:         }
  19:         
  20:         public function set seq(i:int):void
  21:         {
  22:             _seq = i;
  23:         }
  24:         
  25:         public function get interval():int
  26:         {
  27:             return _interval;
  28:         }
  29:         
  30:         public function set interval(i:int):void
  31:         {
  32:             _interval = i;
  33:         }
  34:         
  35:         public function get data():String
  36:         {
  37:             return _data;
  38:         }
  39:         
  40:         public function set data(s:String):void
  41:         {
  42:             _data = s;
  43:         }
  44:     }
  45: }

예제2의 경우를 동작시키기 위해 한 12시간은 쓴거 같다. 플렉스의 객체는 예제1과 동일한 형식이지만 속성이 2개 더 있다. 새로 생긴 2개의 속성은 자바단에서 구현이 예제 1과 다르다.

자바 객체는 다음 특징을 가진다.

1) BaseDataModel을 상속
2) seq는 예제1의 경우와 동일하며 public getter & setter 메서드가 seq 라는 private 변수를 단순 참조하는 전형적인 형태.
3) data 는 부모객체의 구현이며 public getter & setter 메서드가 dataHashMap 이라는 private 변수에 복잡한 연산을 통해 참조하는 형태
4) interval 은 public getter & setter 메서드가 부모객체의 메서드를 이용해 dataHashMap 을 참조하는 형태

이러한 상황을 구현하면서 매핑할 자바 클래스가 부모가 있는 클래스라고 해서 Flex 의 클래스 상속구조가 동일 할 필요는 없다는 사실을 확인했고, interval 과 data 와 같이 전형적인 구조가 아닌 속성을 매핑할때도 어렵게 생각 할 필요가 없었다.

시간을 12시간이나 소모시킨 주범은 다름아닌 데이터형이었다. 자바단에서 getInterval 의 리턴타입이 처음엔 Integer 로 되어 있었는데, 자바단에선 틀림없이 올바른 값이 저장되어 있었지만 플렉스로 넘어오면 무조건 0으로 바뀌는 것이다. 처음엔 리모트 클래스가 이런 유형, 즉, 상속된 객체라던지, getter & setter 에 해당하는 private 변수가 없는 경우를 지원하지 않는 줄 알고 별 방법을 다 동원해보았지만 해결되지 않았다. 모든 방법을 다 시도해봤다고 생각했을 무렵 설마 하고 Interger 로 정의되어 있던 리턴타입을 int 로 바꿨더니 거짓말 처럼 값이 넘어오더라--

새벽까지 이 코드 붙들고 하도 고생을 해서 나중에 잊어 먹고 성질 내지 않도록 남겨 놓는다.ㅎㅎ