Gxt , Ext Gwt강좌2011. 1. 11. 10:27
2011/01/06 - [Gxt , Ext Gwt강좌] - Ext Gwt[Gxt] 강좌07-GxtSmpl모듈 개발하기


1. 우리는 gxtsmpl.client아래에 GxtSmplService라는 이름으로 서비스를 생성하였다. 이제 생성된 서비스를 이용하여
     서비스내에 메소드를 작성하고 이 작성된 메소드를 Client UI에서 이용할 수 있도록 코딩하도록 하자.
우선 추가한 Service에 데이터베이스에서 테이블의 내용을 끌고 올 메소드를 정의하자.
// GxtSmplService.java   
public interface GxtSmplService extends RemoteService {   
/**  
 * Utility class for simplifying access to the instance of async service.  
 */  
  public static class Util {   
    private static GxtSmplServiceAsync instance;   
      public static GxtSmplServiceAsync getInstance(){   
        if (instance == null) {   
          instance = GWT.create(GxtSmplService.class);   
        }   
        return instance;   
      }   
  }   
  // Return type과 LoadConfig에 주목하자.   
  public BaseListLoadResult getSystemUserList(BaseListLoadConfig config, HashMap param) throws Throwable;   
}   
// GxtSmplServiceAsync.java   
public interface GxtSmplServiceAsync {   
  public void getSystemUserList(BaseListLoadConfig config, HashMap param,
 AsyncCallback> callback);   
}  
2. 위와 같이 GxtSmplService.java에 메소드를 정의하게 되면 같은 패키지의 GxtSmplServiceAsync.java와 GxtSmplServiceImpl.java에도 동일한 메소드가 정의 된다. GxtSmplService.java와 GxtSmplServiceAsync.java는 인터페이스로 메소드를 정의하고 실제 구현은 server패키지내의 GxtSmplServiceImpl.java에서 하게 된다. com.hansol.gxtsmpl.server.GxtServiceImpl.java를 열어서 아래와 같이 시스템 로그를 남겨 클라이언트에서 서버와 통신하는지 알아보도록 하자.
@Override  
public BaseListLoadResult getSystemUserList(BaseListLoadConfig config, HashMap param) 
throws Throwable {   
  System.out.println("호출되나.....");   
}  

이제 실제 클라이언트 단에서 위의 메소드를 콜하도록 GridSmplTabItem클래스의 prepareService메소드를 수정하자.
	
private GxtSmplServiceAsync service; // 서비스선언
private HashMap param = new HashMap(); // 파라메터 전달용 hashmap
	/**
	 * Desc : 서버통신모듈 관련
	 */
	public void prepareService(){
		downGridPanel = new ContentPanel();
		downGridPanel.setHeading("관리자 현황");
		downGridPanel.setWidth(800);
		downGridPanel.setHeight(400);
		service = (GxtSmplServiceAsync) Registry.get(GxtApp.SERVICE);
		proxy = new RpcProxy>() {
			@Override
			public void load(Object loadConfig,	AsyncCallback> callback) {
				//try{param.put("search_name", search_name.getValue());}catch(Exception e){System.out.println("!!!!!!!!!!!!!!!!"+ e.toString());};
				
				service.getSystemUserList((BaseListLoadConfig) loadConfig, param, callback); // 추가한 메소드 호출
			}
		};
		loader = new BaseListLoader>(proxy);
		loader.setRemoteSort(true);
		store = new ListStore(loader);
		store.setMonitorChanges(true);
	}
------------------------------------------------------------------------------------------
// GxtApp.java의 상단에 아래 내용 추가해주세요. 그래야 위에서 호출하는 GxtApp.SERVICE가 
// 에러가 안나겠죠.
------------------------------------------------------------------------------------------
// 서버와 통신모듈 선언
	public static final String SERVICE = "GxtSmplService";

3. 이제 예제를 실행하면 아래와 같이 Console창에 로그가 출력되는 것을 확인 할 수 있다.

4. 이제 Client와 Server가 통신하는 것을 확인했으니 Impl클래스를 제대로 구현해서 Grid에 내용이 표시되도록 해보자. 우리는 데이터베이스안 데이터를 Select해와야 하므로 디비와 통신하기 위한 설정이 필요하다. 여기서는 간단하게 jdbc드라이버와 jdbc드라이버를 구현하는 클래스를 만들도록 해보자.
우선 jdbc드라이버를 war/WEB-INF/lib폴더에 카피하고 이클립스가 인식하도록 아래 그림과 같이 Build Path를 잡아주도록 하자.


5. 이제 DBSource라는 클래스를 만들고 디비커넥션을 맺어 올수 있도록 코딩하자. 클래스는 server 아래에 두도록 한다.
package com.hansol.gxtsmpl.server;   
  
import java.sql.Connection;   
import java.sql.DriverManager;   
  
public class DBSource {   
  static String driver;   
  static String url;   
  static String user;   
  static String passwd;   
  
  public static  Connection getConnection( String name) throws Exception{   
    driver = "oracle.jdbc.driver.OracleDriver";   
    url = "jdbc:oracle:thin:@디비서버아이피:포트:SID";      
    user = "user명";   
    passwd = "패스워드";   
    Class.forName(driver);   
    Connection con = DriverManager.getConnection(url, user, passwd);   
    return con;       
  }   
}  
6. 이제 Impl클래스의 메소드를 변경해보자. 기존 System.out.println("호출되나''");는 삭제하고 아래와 같이 코딩하자.
@Override  
public BaseListLoadResult getSystemUserList(   
  BaseListLoadConfig config, HashMap param) throws Throwable {   
  // return시 java.util.List에 LoginUserInfo객체를 차곡차곡 쌓아 리턴한다.   
  List returnValue = new ArrayList();   
  Connection conn = null; // 데이터베이스 커넥션 객체   
  PreparedStatement pstmt = null;  // 쿼리를 실행할 Statement객체   
  ResultSet rs = null;  // 쿼리를 실행한 후 꺼내온 데이터를 담을 객체   
  StringBuffer sql = new StringBuffer(); // SQL을 정의할 StringBuffer클래스   
  try{   
    conn = DBSource.getConnection(); // DBSource클래스에서 커넥션을 생성한다.   
    // 이하 쿼리 정의    
    // 쿼리는 테이블 내의 데이터를 모두 가져온다.    
    // 이때 주의할 것은 Client Grid의 컬럼정의 시(new ColumnConfig("userSabun",    
    // "사번", 75)) ColumnConfig생성시 사용된 이름과 컬럼명이 동일해야 Sort처리시 쿼리에     
    // 문제가 발생하지 않는다 해서 아래 쿼리에서는 alias를 주어 실제 컬럼명과 Grid에서   
    //  사용된 컬럼명을 일치 시켜주도록 하고 SubQuery를 사용해 sort시 문제가 발생하지    
    // 않도록 조치했다.   
    sql.append(" select * from (");   
    sql.append(" Select userid userSabun, username userName,     \n");   
    sql.append("  orgoid userOrgOid, orgname userOrgName,    \n");   
    sql.append("  teamname userTeamName, inputdate,     \n");   
    sql.append("  confirmyn confirmYnTmp,        \n");   
    sql.append("  decode(confirmyn,'Y','예','아니오') confirmYnName \n");   
    sql.append("  From COMMONLOGINUSER         \n");   
    sql.append(" ) \n");   
    // Sort에 대한 처리 LoadConfig에서 Sort에 대한 속성이 정의 되어 있다.   
    // Grid화면에서 컬럼을 클릭할 때 마다 Sort에 대한 속성이 변경되어 서버에 전달된다.   
    if(config.getSortField() == null) sql.append(" order by username asc ");   
    else sql.append(" order by "+ config.getSortField()+" "+ config.getSortDir());   
    // 쿼리문을 통해 statement생성   
    pstmt = conn.prepareStatement(sql.toString());   
    // statement를 통해 생성 된 결과를 ResultSet에 담는다.   
    rs = pstmt.executeQuery();   
    // loop돌면서   
    while(rs.next()){   
      // LoginUserInfo객체를 생성   
      LoginUserInfo entity = new LoginUserInfo();   
      entity.setUserName(rs.getString("username"));   
      entity.setUserSabun(rs.getString("userSabun"));   
      entity.setUserOrgOid(rs.getString("userOrgOid"));   
      entity.setUserOrgName(rs.getString("userOrgName"));   
      entity.setUserTeamName(rs.getString("userTeamName"));   
      entity.setInputDate(rs.getDate("inputdate"));   
      entity.setConfirmYnName(rs.getString("confirmYnName"));   
      entity.setConfirmYnTmp(rs.getString("confirmYnTmp"));   
      // return할 java.util.List객체에 차곡차곡 쌓는다.   
      returnValue.add(entity);   
    }   
  } finally {   
    // 사용된 자원에 대한 해제는 필수적으로...   
    try{ rs.close(); }catch(Exception e){}   
    try{ pstmt.close(); }catch(Exception e){}   
    try{ conn.close(); }catch(Exception e){}   
  }   
  // java.util.List에 담긴 데이터를 최종 리턴Type인 BaseListLoadResult를 생성하여 리턴.   
  return new BaseListLoadResult (returnValue);   
}  


7. 이제 코딩이 끝났으니 이클립스 Console에서 빨간색 버튼을 클릭해 실행을 정지 시키고 다시 시작해보자 우리는 Server쪽 메소드를 변경하였으므로 이과정이 꼭 필요하다. Client쪽이 변경된 경우에는 브라우저를 리프레시하면 변경된 내용이 적용되지만 서버쪽은 꼭 리스타트해줘야 변경된 내용을 확인 할 수 있다.
내용에 비해 Grid가 좀 큰듯하여 TabItem의 Width를 500으로 Grid의 Height를 240으로 변경하였다.실행된 화면을 확인하자

Posted by 1 베니94

댓글을 달아 주세요

  1. andromeda

    강좌 잘보고 있습니다 ^^
    요근래 GWT에 대해 급관심을 가지다가 benny님의 블로그를 자주보게 되네요.
    새해 복 많이 받으시고 좋은 글 감사합니다.
    아참 질문 하나 해도 될까요..
    gwt로 검색해보면 대개 GWT, Ext Gwt, Gwt Ext....이렇게 세가지가 나오더라구요. 간단한 차이점이나 개념?
    정도 여쭙고 싶어요.
    주말 잘 보내시고 자주 올께요 - *

    2011.01.14 10:37 [ ADDR : EDIT/ DEL : REPLY ]
  2. 흠.. 좀 설명을 드리면요..
    첫째는 Gwt가 있겠죠. Google web Toolkit에 약자일 테구요.
    - 자바를 이용해서 일반 swing이나 이클립스의 swt처럼 개발할 수 있도록 지원하고 컴파일하면 웹파일 자바스크립트나 html등으로 변경되어 최종적으로는 웹프로그램이 서버에 올라가서 작동하는 개념이죠.

    둘째는 Ext Gwt 줄여서 Gxt라고 부르죠 .. 이놈의 시작은 extjs로 시작하는데요. extjs는 gwt와는 전혀 별개로 javascript를 이용해서 Ria 프로그램이 가능하도록 하는 일종에 UI프레임웍이로고 할 수 있죠.
    extjs.com 이제는 http://www.sencha.com/로 변경되었지만 아무튼 이놈을 예전에 써봤는데 상당히 괜찮은듯 합니다. 자바스크립트하고 기타 css를 알아야 한다는 단점이 있지만요.
    Gxt는 위에서 설명한 extjs를 Gwt버전으로 만든 놈이라고 생각하시면 되겠습니다. 그러니깐 최종 결과물 화면상 보기에는
    extjs나 Gxt나 똑 같다는 거죠.

    세번째로 Gwt Ext가 있는데요 . 이놈은 Gxt하고는 좀 다른놈인에요. 전에 언뜻 들은 애기로는 Ext Gwt를 만든 사람중에 한명이 나와서 비슷하게 새로 만들었다는 소문이.. ㅋㅋ 아무튼 그렇습니다.

    2011.01.14 12:54 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. andromeda

    답변 감사합니다 ^^;
    지난주에 좀 해보다가 패키지가 꼬여서 좌절(?)했는데 이번주엔 잘해봐야겠네요 - *
    행복한 한 주 시작하세요 ~

    2011.01.17 09:37 [ ADDR : EDIT/ DEL : REPLY ]
  4. 감사합니다

    6장까지는 잘따라가겠는데 7장에서 힘드네요..
    지금 소스가 어디의 소스인지 상단이라하면 어느정도인지 등등..
    6장까지는 쉽게 갔는데 7장에서 멈췄습니다 ㅜㅜ

    2011.02.24 14:26 [ ADDR : EDIT/ DEL : REPLY ]
  5. 복슬이

    블로그 글 잘 봤습니다. ^^

    그런데 빠진 부분이 있는 것 같네요.

    GridSmplTabItem 클래스에서 prepareService() 메소드 안에 load() 구현부분이 빠진 것 같네요..


    proxy = new RpcProxy<BaseListLoadResult<LoginUserInfo>>() {
    @Override
    protected void load(Object loadConfig, AsyncCallback<BaseListLoadResult<LoginUserInfo>> callback) {
    GxtSmplServiceAsync ins = GxtSmplService.Util.getInstance();
    HashMap param = new HashMap();
    ins.getSystemUserList((BaseListLoadConfig) loadConfig, param, callback);
    }
    };

    2011.03.05 12:49 [ ADDR : EDIT/ DEL : REPLY ]
    • 아 죄송합니다. 제가 나중에 구현한다고 주석달아 놓구선
      그부분을 강좌에서 빼먹었네요 ㅠㅠ 댓글의 내용대로 맞습니다. 수정토록 하겠습니다.

      2011.03.05 21:35 신고 [ ADDR : EDIT/ DEL ]
  6. 김한웅

    2번 에서 GridSmplTabItem클래스의 prepareService메소드를 수정 할때 11줄에 GxtApp.SERVICE 이부분은 GxtApp에서 따로 지정해줘야 될것은 없나요?
    그리고 15줄에 param와 search_name에 대한 선언이 없는것 같은데? 어떻게 지정해주죠?

    2011.03.30 15:52 [ ADDR : EDIT/ DEL : REPLY ]
    • 답변 늦어서 죄송합니다.
      GxtApp.java에 public static final String SERVICE = "GxtSmplService"; 이부분이 추가되어야 합니다. 옮기는 중 빠졌습니다.

      그리고 preparedService에서 사용하고 있는 param은
      클래스 상단에 아래와 같이 선언하시면 됩니다.
      private HashMap param = new HashMap();

      2011.05.20 17:10 신고 [ ADDR : EDIT/ DEL ]
  7. 솔베이지군

    베니94님 search_name 변수는 어디서 나온것인가요~~?

    2011.11.17 17:33 [ ADDR : EDIT/ DEL : REPLY ]
    • 그 부분은 주석으로 막혀야 할 부분이군요.
      여기서는 search_name이 검색조건의 검색텍스트를
      입력할 textfield 정도를 나중에 추가하려고
      넣었던 부분이라 주석달고 실행하셔야 겠습니다.

      2011.11.21 19:26 신고 [ ADDR : EDIT/ DEL ]
  8. 개미군단

    먼저 강좌 잘보았습니다.
    강좌를 보고 개발해 보았는데 데이터가 50건 정도를 리스트 출력하는 속도가 너무 느립니다.
    DB 속도가 느려서 그런지 체크 해보았는데 쿼리하는데 1초도 안걸립니다.
    그런데 리스트에 출력 되는 속도는 12초가 넘어 가더군요 해결 할 수 있는 방법이 없을 까요?

    2012.09.13 09:49 [ ADDR : EDIT/ DEL : REPLY ]
  9. 깡99

    안녕하세요 강좌보고 따라하는 중입니다.
    데이터베이스 로드해서 데이터를 받아오는것 까지는 되는데, 그리드에 로드한 데이터가 나오지 않습니다
    어떻게 하면 좋을까요?

    2015.05.13 19:29 [ ADDR : EDIT/ DEL : REPLY ]