GXT RIA App 만들기2011.03.01 23:08
오늘은 GWT에서 Service라는 개념에 대해 알아보고 실습해보자. GWT에서는 서버와 통신(RPC)하는 하나의 행위를 서비스라는 이름으로 불리운다. 지금까지 배웠던 부분들은 모두 Client단으로 최종 javascript로 변환되어 사용자에게 UI로 보여지는 것이다. 그러나 화면만으로는 프로그램이 데이터를 가질 수 없으므로 서버단과 통신하는 무엇인가가 필요한데 이것을 Service라 지칭한다.
서비스는 아래와 같이 2개의 인터페이스와 1개의 클래스가 한 쌍이된다.


1. com.gxt.riaapp.client.RiaAppPgmService 
   - 패키지를 보면 client아래 존재한다. 이 인터페이스에는 서비스에서 사용할 메소드를 명시하게 된다.
   - 이클립스에서는 최초 이 인터페이스를 생성하면 자동으로 나머지 인터페이스와 클래스를 생성해준다.
   - 우리가 메소드를 추가하고 싶다면 이 인터페이스에 메소드를 추가하게 되는데 추가할 경우 자동으로 xxxAsync, Impl 두개의 파일에 해당 메소드가 기본 구현되어지게 된다.

2. com.gxt.riaapp.client.RiaAppPgmServiceAsync
   - 이 인터페이스는 1번 인터페이스를 생성하면 자동으로 생성되게 된다. 이 인터페이스는 이클리스가 알아서 제어 해주므로 사실 개발자는 손댈 필요가 없다. 이 인터페이스는 서버와 통신을 주고 받는 역할을 한다고 보면되겠다.

3. com.gxt.riaapp.server.RiaAppPgmServiceImpl
  - 패키지에 주목하자. server아래 존재한다. 이 클래스는 Client와는 반대로 Server에서 실행 할 메소드들이 구현되어야 한다. 즉 위의 1,2번에 명시된 메소드가 최종 구현되는 곳이다. 이 클래스에서 SQL을 날리고 데이터를 불러와 리턴하면 Async인터페이스를 통해 xxxService가 클라이언트에게 전달한다고 생각하면 되겠다.

▶ 서비스를 생성해 보자. com.gxt.riaapp.client를 선택하자 여기서 마우스 우측클릭을 하고 아래와 같이 선택하자.


▶ RiaAppPgmService라는 이름으로 생성해보자.


▶ 위에서 설명했듣 client에 2개의 인터페이스 server에 한개의 클래스가 생성되었을 것이다. 여기서 한가지 주목할 부분이 web.xml파일이다. war/WEB-INF/web.xml파일을 열어보자. 아래와 같이 web.xml파일이 변경되었을 것이다. 이는 서버스가 Servlet기반이기 때문에 하나의 서비스가 추가되었을 경우 해당 서비스 이름으로 서블릿 설정이 web.xml파일에 추가되게 된다. 이 또한 자동으로 생성되게 되므로 손댈 필요는 없겠다


  
  
  
  
  
    RiaApp.html
  
  
  	RiaAppPgmService
  	com.gxt.riaapp.server.RiaAppPgmServiceImpl
  
  
  	RiaAppPgmService
  	/riaapp/RiaAppPgmService
  



▶ 이제 우리는 서비스에 메소드를 추가하고 그 메소드를 구현 해보 도록 하자. 구현이 끝나면 클라이언트에서 해당
 메소드를 호출하면 서버는 클라이언트에게 정보를 전달하는 지 확인해볼 수 있을 것이다.
▶ RiaAppPgmService.java를 열어 메소드를 선언해보자
package com.gxt.riaapp.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("RiaAppPgmService")
public interface RiaAppPgmService extends RemoteService {
	public int getSessionData() throws Throwable ; // 서버에서 세션을 전달받아 리턴하자.
	/**
	 * Utility class for simplifying access to the instance of async service.
	 */
	public static class Util {
		private static RiaAppPgmServiceAsync instance;
		public static RiaAppPgmServiceAsync getInstance(){
			if (instance == null) {
				instance = GWT.create(RiaAppPgmService.class);
			}
			return instance;
		}
	}
}

▶ 이제 Async 인터페이스와 Impl클래스를 열어보라 위에서 선언한 메소드가 선언 또는 구현되어 있을 것이다.
package com.gxt.riaapp.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface RiaAppPgmServiceAsync {
	public void getSessionData(AsyncCallback callback) ; // 서버에서 세션을 전달받아 리턴하자.
}
package com.gxt.riaapp.server;

import javax.servlet.http.HttpSession;

import com.gxt.riaapp.client.RiaAppPgmService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class RiaAppPgmServiceImpl extends RemoteServiceServlet implements RiaAppPgmService {
	private HttpSession getSession() {
		return this.getThreadLocalRequest().getSession();
	}
	@Override
	public int getSessionData() throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("여기는 서버예요...");
		return 0;
	}
}



▶ 이제 client에서 getSessionData메소드를 호출해보자 Impl클래스의 메소드가 실행되어 System.out.println("여기는 서버예요..");가 실행되는 지 보도록 하자. 또한 실행됨과 동시에 리턴되는 값이 무엇인지도 확인해보자. 이러한 형태로 서버와 통신해서 최종적으로는 데이터베이스의 데이터등을 리턴하는 것이다.
▶ RiaApp.java를 수정해서 위의 getSessionData메소드를 호출해보자.
	public void onModuleLoad() {
		model = new RiaAppModel();
	    Registry.register(MODEL, model);  // 최초 실행시 Registry에 RiaAppModel을 등록한다.
		dispatcher = Dispatcher.get();
	    dispatcher.addController(new AppController());
	    dispatcher.addController(new NavigationController());  // 좌측
	    dispatcher.addController(new ContentController());
	    dispatcher.dispatch(AppEvents.Init);
	    
	    if(model.getEntries().size()>0) // 등록된 첫번째 프로그램을 보여준다.
			showPage(model.getEntries().get(0));

	    onSubmit(); // 서버쪽 메소드를 호출해서 세션이 유효한지 확인한다.
	   
	}

	public int onSubmit() {
		service.getSessionData( new AsyncCallback() {
			@Override
			public void onSuccess(Integer result) {
				String time = new Date().toString();
				//if(result == -1){
					System.out.println("서버에서 리턴해준 결과는 "+result);
				//}			}
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.alert("로그인", "세션이 종료되었습니다. \n 다시 로그인 해주세요", null);
			}
		});
		return 0;
	}


▶ 이제 실행해 보자.  아래 그림처럼 server 쪽 메소드에서 "여기는 서버예요"를 출력하고 그 다음 클라이언트쪽 메소드에서 "서버에서 리턴해준..."라고 출력된다. 여기서 주목할 부분은 위의 onSubmit()메소드에서 보여주는 것처럼 서버쪽 메소드를 호출하고 결과를 리턴받는데 성공할 경우 onSuccess()메소드가 실행되고 그렇지 않고 문제가 발생할 경우 onFailure()메소드가 호출되게 된다.
이 두개의 메소드는 두고두고 나올테니 기억하도록 하자.

▶ 이제 getSessionData메소드를 역할에 맞게 수정하도록 하자. 이 메소드는 세션이 유효한지 체크하는 것이다.
일단 메소드의 리턴 type을 변경하자 단지 세션이 유효한지 여부를 판단 할 것이라면 유효하지 않은 경우에는 onFailure메소드가 실행되도록 하고 onFailure메소드에서는 유효하지 않다는 메시지와 함께 로그인 페이지로 이동하도록 하면 될것이므로 리턴타입은 void로 변경하는것이 좋을 듯 하다.

// RiaAppPgmService.java
	public void getSessionData() throws Throwable ; // 서버에서 세션을 전달받아 리턴하자.

// RiaAppPgmServiceAsync.java
	public void getSessionData(AsyncCallback callback) ; // 서버에서 세션을 전달받아 리턴하자.

// RiaAppPgmServiceImpl.java
	@Override
	public void getSessionData() throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("여기는 서버예요...");
	}

// RiaApp.java 
	public void onSubmit() {
		service.getSessionData( new AsyncCallback() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.alert("로그인", "세션이 종료되었습니다. \n 다시 로그인 해주세요", null);
			}
			@Override
			public void onSuccess(Void result) {
				// TODO Auto-generated method stub
				
			}
		});
	}
이제 기존 int형이었던 메소드를 void로 변경하였으니 Impl클래스의 메소드를 구현해보도록 하자. 이 메소드는 세션을 구해와 유효한지 확인하는 메소드이므로 일단 세션정보를 얻어오도록 코딩하자. RiaAppPgmServiceImpl 클래스에 아래의 메소드를 추가하고 세션을 구해와 유효한지 확인해보자.
package com.gxt.riaapp.server;

import javax.servlet.http.HttpSession;

import com.gxt.riaapp.client.RiaAppPgmService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class RiaAppPgmServiceImpl extends RemoteServiceServlet implements RiaAppPgmService {
	private HttpSession getSession() {
		return this.getThreadLocalRequest().getSession();
	}
	@Override
	public void getSessionData() throws Throwable {
		HttpSession session = getSession();
		if( null == session.getAttribute("loginid")) // index.html페이지에서 전달해주고 loginChk.jsp에서 생성한 세션정보
			throw new Throwable("세션이 종료되었습니다.");
		else
			System.out.println("로그인 아이디는 : "+(String)session.getAttribute("loginid"));
	}
}


이제 실행해 보자. RiaApp.html파일을 실행할 경우와 index.html파일을 통해 로그인을 했을 경우와 비교를 해보자. 일단 RiaApp.html을 실행할 경우 아래 그림처럼 세션이 종료되었다는 경고창이 보일 것이다. 이는 로그인을 하지 않았으므로 세션이 존재하지 않아 경고창을 보여주는 것이다.

이제 index.htlm파일을 실행하여 정상적으로 로그인해보자. 아래 그림처럼 서버쪽 메소드에서 세션정보를 확인할 수 있다.

▶ 자 이제 생각을 해보자. RiaApp.html은 실제 프로그램이 돌아가는 영역이고 index.html은 로그인 페이지다. RiaApp.html을 실행해서 세션이 존재하지 않을 경우 즉 로그인이 되어 있지 않거나 일정시간 사용하지 않아 세션이 끊겼을 경우 "세션이 종료되었습니다.."라는 메시지를 출력해주었다. 그럼 이제 무엇을 해야할 까? 경고창이 나오고 ok버튼을 클릭했을 경우 로그인 페이지로 유도하는 것이 필요할 듯 하다. 로그인 페이지로 유도하고 로그인을 하고 다시 RiaApp.html을 호출하여 프로그램을 보여줄수 있도록 하는것이다.
▶ 그럼 무엇이 필요할까 생각해보자. 우선 위의 경고창에서 보듣 "ok"버튼을 클릭했을 경우 이 클릭한 이벤트를 이용해서 로그인 페이지로 이동하는 코드를 만들어 보자. 우선 "ok"버튼을 감시할 리스너를 선언하자.
// RiaApp.java를 수정하자.
	/**
	 * Native Javascript Call
	 */
	private native void goIndex() /*-{ 
		$wnd.location.href = "/index.html"; 
	}-*/;

	/**
	 * 세션이 유효하지 않을 경우 뛰워주는 경고창 내의 OK버튼을 감시할 리스너
	 */
	final Listener btnListener = new Listener() {  
		public void handleEvent(MessageBoxEvent ce) {  
			goIndex();
		}  
	};  
	public void onSubmit() {
		service.getSessionData( new AsyncCallback() {
			@Override
			public void onFailure(Throwable caught) {
				// 버튼 리스트를 설정
				MessageBox.alert("로그인", "세션이 종료되었습니다. \n 다시 로그인 해주세요", btnListener);
			}
			@Override
			public void onSuccess(Void result) {
				// TODO Auto-generated method stub
				
			}
		});
	}

이제 실행해 보자. RiaApp.html을 실행해 보면 로그인을 하지 않았으므로 "세션이 종료되었습니다. 다시 로그인해주세요"라는 메시지를 출력하고 "OK"버튼을 클릭하면 로그인 페이지로 이동하게 될것이다. 이렇게 하면 기본적으로 로그인에 대한 처리가 완료되었다.
Posted by 1 베니94

댓글을 달아 주세요

  1. soul

    이렇게 계속 강좌를 올려주셔서 정말 많은 도움이 됩니다. 감사합니다.

    이건 강좌와는 상관없는 질문일수 있는데요..

    제가 만든 jar 파일을 import 시켜서 사용할순 없나요?

    실행하면 계속 오류가 나고 자료를 찾아봐도 잘 나와있지 않아서요 ^^

    2011.03.07 12:09 [ ADDR : EDIT/ DEL : REPLY ]
    • gwt에는 제약사항이 있습니다.
      참고글: http://blog.naver.com/moviel0ve?Redirect=Log&logNo=130035105414
      위의 글을 자세히 읽어보시면 gwt의 제약사항이 무엇인지 나와있을 겁니다.
      추가하신 라이브러리가 어떤 자바패키지를 이용했는지는 알수 없으나 예측컨데 gwt에서 제한된 클래스를 사용해서 개발된 라이브러리일 가능성이 높고 이 경우 프로젝트 내의 client 모듈에서는 사용이 안될것입니다.

      2011.03.07 13:38 신고 [ ADDR : EDIT/ DEL ]
    • soul

      답변 정말 감사드립니다.
      정말 알수록 어려운길이군요 ㅎㅎ
      앞으로도 깨알같은 강좌 계속 부탁드려요~

      2011.03.07 13:57 [ ADDR : EDIT/ DEL ]
  2. zeno

    안녕하세요.. 우연하게 블로그를 찾게 되었는데요.. 좋은 정보 정말 감사드립니다.. 저도 gwt 프로젝트를 하는 중인데요.
    저 같은 경우에, 서버쪽에서 session.setAttiribute("id") 로 세팅을 함에도 불구하고... F5 키를 누르면 세션이 해제되어
    다시 로그인 페이지로 돌아갑니다... 혹시 이런 문제 없으셨는지요 ?
    저는 로그인 페이지를 html 에서 작업한건 아니구요. gwt 로 UI 를 그려서, id / pw 값을 서블릿단에서 받아서,
    DB 검증 후, session 에 담는 로직입니다.. 세션 해제 되는 문제에 대해 구글링을 아무리해도 .. 명확한 답이 없네요.
    쿠키로 처리하라는 말도 있는데.. 쿠키는 좀 아닌것 같구요.. 그래서.. 조언 부탁드립니다...

    2012.02.20 10:36 [ ADDR : EDIT/ DEL : REPLY ]
    • F5키를 눌렀을때 세션이 해제되어 로그인 페이지로 가는것이 확실한가요?
      코딩에 따라 세션과는 무관하게 로그인페이지로 가는경우도 있어요~ 세션이 어떤 상태인지 정확히 로그를 찍어볼 필요가 있겠습니다.

      2012.02.21 09:11 신고 [ ADDR : EDIT/ DEL ]
  3. zeno

    안녕하세요.. 위의 문제는 EntryPoint 페이지를 분기문으로 분리해서 발생하는 것 같습니다. 그러니까.. EntryPoint 페이지가 2개가 있고, 세션에 따라 분기되게 했는데요.. RootPanel 에 페이지가 분기되면 세션 쪽이 문제가 되는 것 같습니다.
    뭐가 문제인지는 정확히 파악을 못했구요. ㅡㅡㅋ.. 시간이 없는 관계로 우선 RootPanel 분기처리 안되게 하니까.
    세션이 정상작동 하고 있습니다.

    2012.03.06 19:21 [ ADDR : EDIT/ DEL : REPLY ]
  4. zeno

    여기에 문의를 계속드려도 모르겠습니다만, 현재.. 여러가지 문제에 직면하고 있는데.. 그중에 2가지만 우선 질문을 드려도 될지 모르겠습니다..
    첫째는, 클라이언트쪽 로그가 안찍힙니다.
    http://allen-sauer.com/com.allen_sauer.gwt.log.demo.LogDemo/LogDemo.html?log_level=TRACE
    위 사이트를 참조해서 세팅을 했구요. 어디가 문제인지 모르겠습니다.
    xxx.gwt.xml 파일에 <inherits name="com.allen_sauer.gwt.log.gwt-log-DEBUG" /> 추가하고..
    클라이언트 페이지에 Log.debug.. 등을 호출했으나.. 위 사이트 처럼 로그가 찍히지 않네요.
    혹시, 제가 더 세팅해야 될 곳이 있는지.. 문의 드립니다.

    둘째는, ListGrid 를 서버에서 ibatis + json 으로 가져오는 로직으로 crud 를 구현하고 있는데요.
    getGrid().setSelectionAppearance(SelectionAppearance.CHECKBOX);
    옵션으로 자동으로 header에 checkbox 가 만들어지도록 했는데.... checked 된 row 값에 접근하는 방법을 모르겠습니다. 아무리 찾아봐도 방법을 못찾아서.. ListGridField Boolean 형태로 만들어서 다시 구현을 하긴 했는데..
    문제는 전체선택을 하기 위한 , 메소드를 구현했는데요. for() { dataGrid.getRecord(i).setAttribute("SEL", true); }
    이 부분이 실행이 안됩니다.. Grid 에 데이터가 있는 상태에서 강제로 seleected 되도록 했는데.. 작동을 안하네요.

    혹시, 이부분 해결을 하셨는지 문의드립니다.

    죄송합니다.. 이렇게 긴글을 남겨서요.. 이틀째.. ListGrid 쪽만 보고 있는데.. 생각처럼 잘 안되서 답답하네요..
    그럼.. 답변 부탁드립니다.. 꾸벅~

    2012.03.06 19:34 [ ADDR : EDIT/ DEL : REPLY ]
    • zeno

      저는 SMARTGWT 로 현재 개발중이구요..
      getGrid().setSelectionAppearance(SelectionAppearance.CHECKBOX);

      접근문제는 해결했습니다.

      -> getGrid().getSelectedRecords()
      라는 메소드가 지원을 하네요..
      간단한 문제를 놓치고 있었습니다.. 질문을 드리고 나니.. 좀 정리가 된 것 같습니다..^^;

      로그 문제는 아직 잘 안되고 있습니다.
      시간되시면 답변 부탁드릴께요..

      염치없지만.. 앞으로 종종 문의드리겠습니다.

      2012.03.06 20:29 [ ADDR : EDIT/ DEL ]
  5. zeno

    안녕하세요.. 위 로그는 그냥 브라우저 디버깅 모드를 사용하기로 했습니다. 브라우저 상에 div 태그로 로그가 보이게 하는 건 .. 잘 안되네요..

    베니님께서 올리신 글중에 데이터 처리방식에 대한 내용이 없는 것 같아서... 질문드립니다.
    저는 쿼리 조회시, 서블릿에서 넘겨받은 (조회조건)파라미터로 ibatis 를 이용해서, 받은 데이터를 json 변환 후 callback 시, string 을 grid 에 넘기는 방식으로 코딩을 했는데요.. 여기까지는 문제가 없습니다.
    이부분은 smartgwt 부분이긴한데.. ( gwt 는 아직 해보지 못했습니다 )..
    DataSource 를 이용해서, 서버에 DB 결과값을 json 형태의 파일로 저장후, Grid 에서 해당 Datasource 파일에서 데이터를 가져오는 방식으로 변환하려고 합니다. ( LiveGrid 등이 지원이 안되서요..)
    그런데, RemoteServiceServlet 를 상속받은 서블릿에서 FileWrite 가 안되고 있습니다. ( 앱엔진 지원안함 )
    혹시, list 성 프로그램 조회는 어떻게 구현하셨는지요 ?

    여기에 계속 글을 남겨도 되는지 모르겠습니다.. ^^:;

    2012.03.13 11:40 [ ADDR : EDIT/ DEL : REPLY ]
  6. 저는 return this.getThreadLocalRequest().getSession();
    이 코드에서 아래와 같은 에러가 납니다.ㅠ
    The method getThreadLocalRequest() is undefined for the type

    GWT + Maven Project 로 만들어서 사용하고있는데 왜그런건가요?ㅠ

    2014.06.24 14:52 신고 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.31 17:53
오늘 강좌에서는 로그인 페이지와 세션에 대해 애기해보자. 우리는 지금까지 어플리케이션의 뼈대를 구성하고 추가적으로 개발할 프로그램이 자리 잡을 수 있도록 프로그램영역과 좌측 트리메뉴 등을 구성했다. 이제 관리자페이지에 접근할 수 있도록 로그인 페이지를 만들고 아이디와 패스워드를 통해 인증처리를 추가해 보도록 하자.


 

로그인 페이지를 만들어 보자 . 우선 본인은 디자이너가 아니므로 내 손으로 html을 만들면 흉해질 것이므로 tistory의 로그인페이지를 살짝 긁어와 맘대로 사용해보자. 뭐 상업적으로 이용하는건 아니니깐 .. 암튼 본인이 바꿀 수 있으면 바꾸시고 ~

▷ 티스토리에서 훔쳐온 로그인페이지를 그대로 이용하자

▷ 소스는 아래와 같다. war폴더에 index.html이라는 이름으로 파일을 생성하자.






	
▷ 이제 실행시켜 보자. 근데 실행하기 전에 Run Configuration에 대해 간략히 언급을 하고 가자. 아래와 같이 Run Configuration을 실행해보자.

▶ Run Configuration 의 실행 모습이다. 기본적으로 해당 프로젝트의 Root에 마우스우측 클릭하고 실행하면 그 프로젝트의 이름으로 된 html파일이 실행되도록 설정되어 있다 . 나의 경우 Name필드에 .html을 떼어버리고 RiaApp로 변경하고 그 밑의 Server 탭에서 서버구동시 포트를 변경할 수 있도록 세팅가능하도 여러개의 GWT어플리케이션을 구동할 때 포트를 달리하여 사용할 수 있다..

▶ Server탭의 포트 설정 부분

▶ 위의 설정이 끝나면 Apply를 클릭하고 다음번에 GWT어플리케이션을 실행할 때는 아래 그림처럼 하면 간편하죠!


▶ 자 이제 본론으로 들어가서 브라우저에 우리가 만든 index.html을 실행 해보도 록 하자.

이제 아이디와 패스워드를 아무렇게나 넣고 로그인 버튼을 클릭해보자. 아마 아무 반응이 없을 것이다. 콘솔 창을 통해 무슨일이 일어났는지 보자. 아래 로그를 보니 /common/loginChk.jsp가 없다고 나온다. 우리는 index.html에 계정을 넣고 로그인 버튼을 클릭했을 경우 /common/loginChk.jsp로 보내도록 코딩했다. 이 파일에서는 index.html에서 받아온 계정을 확인하고 세션을 생성하고 실제 Gxt 어플리케이션을 실행하는 역할을 하도록 해야한다.

▶ /common/loginChk.jsp를 생성하고 아래와 같이 코딩하자.
<%
// 1. 로그인 계정의 유효성을 확인하는 로직
// 2. 세션 생성
// Gwt 어플리케이션에서 이 세션을 어떻게 이용할 수 있는지
// 확인할 수 있다.
session.setAttribute("loginid", request.getParameter("loginid"));
%>
< script language='javascript'>
parent.location.href="/RiaApp.html?gwt.codesvr=127.0.0.1:9997#0001";
< /script>
▶ 이제 다시 실행해 보자. index.html을 실행하고 계정을 입력하고 로그인 버튼을 클릭하면 Gxt어플리케이션이 실행될 것이다.

오늘은 여기까지... 다음에는 RiaApp.html을 조금 정비하고 GWT에서 서비스를 이용하는 방법과 세션의 사용법을 배워보도록 하자.
Posted by 1 베니94

댓글을 달아 주세요

  1. paul

    감사합니다. 너무 주옥같은 연재.., 대단 하십니다.

    2011.02.15 09:26 [ ADDR : EDIT/ DEL : REPLY ]
    • 네 가끔 달리는 리플에 연재를 그만둘까두 싶다가 다시
      하게 되네요 ㅋㅋ 별루 보는사람이 없나 싶어서 말이죠.

      어느정도 끝나면 extjs, 나 sencha를 해볼까 싶습니다.
      회사에서 자꾸 모바일모바일해서 말이죠.
      암튼 열공하세요 ^^

      2011.03.04 18:07 신고 [ ADDR : EDIT/ DEL ]
  2. soul

    너무 잘보고 배워갑니다..
    혹시 다음 10번째는 언제쯤 볼 수 있을까욤?

    2011.02.28 13:40 [ ADDR : EDIT/ DEL : REPLY ]
    • 네 관심 가져주셔서 감사합니다.
      금주 내로 글을 올리도록 계획하고 있습니다.
      조금만 기다려 주세요 ^^

      2011.03.01 22:02 신고 [ ADDR : EDIT/ DEL ]
  3. 안녕, 내 배우자와 나는 특정 웹 사이트가 귀하의 광대한 세계와 다량의 훨씬 더 기사 또는 블로그 게시물이 방법을 받고 넓은 관련된 가능성이있을 수 있습니다 경우에 추측 현재 가치와 함께 매우 도움이 될 수 있고 그 본적 웹 웹 사이트입니다. 경우에는 우리를 허용하도록 당신은 행복 약, 자연 고기는 아무도 보상을 기대하고 있습니다.

    2011.08.17 20:40 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.28 09:14

오늘은 상단부분을 완성해보도록 하자. 최초 생각했던 것은 상단에는 단순 html을 삽입 로그인 정보정도만 보여주려고 했으나 계획을 변경해서 일반어플리케이션에서 볼수 있는 풀다운 메뉴와 툴바를 추가해보도록 하자. 풀다운 메뉴는 좌측 메뉴로는 도저히 정리되지 않을 경우나 좌측메뉴와는 별개로 성격이 아주 다른 프로그램들을 모아두거나 하면 될테고 툴바는 미리 보여줄 필요가 있는 자주 쓰는 프로그램을 모아놓는 용도로 사용하자.

☞ 오늘 만들게 될 화면이다. 최상단에 메뉴가 들어가고 그 아래에 툴바를 배치하자.

최초 계획과는 달리 상단부분에 html이 아닌 Menu와 툴바를 넣기로 했으므로 기존 AppView클래스의 northPanel을 HtmlContainer가 아닌 ContentPanel로 변경하여 Menu와 툴바를 삽입하도록 하자.

☞ northPanel과 createNorth()메소드를 변경하자.
//	private HtmlContainer 	northPanel;	// 상단영역
	private ContentPanel	northPanel;

	private void createNorth() {
		BorderLayoutData data = new BorderLayoutData(LayoutRegion.NORTH, 45);
		data.setMargins(new Margins(0, 5, 5, 5));
		northPanel = new ContentPanel();
		northPanel.setHeaderVisible(false);
		ToolBar tb = new ToolBar();
		Button topBtn = new Button("로그아웃");
		topBtn.setIcon(RiaApp.ICONS.go_out());
		tb.add(topBtn);
		topBtn = new Button("사용자정보수정");
		topBtn.setIcon(RiaApp.ICONS.accordion());
		tb.add(topBtn);
		topBtn = new Button("접속로그");
		topBtn.setIcon(RiaApp.ICONS.text());
		tb.add(topBtn);
		tb.setAlignment(HorizontalAlignment.RIGHT);
		northPanel.setBottomComponent(tb);
		Menu menu = new Menu();   
		  
	    MenuItem item1 = new MenuItem("Edit");   
	    menu.add(item1);   
	  
	    MenuItem item2 = new MenuItem("Open File");   
	    menu.add(item2);   
	  
	    Menu sub = new Menu();   
	    sub.add(new MenuItem("readme.txt"));   
	    sub.add(new MenuItem("helloworld.txt"));   
	    item2.setSubMenu(sub);   
	    	
	    MenuBar bar = new MenuBar();   
	    bar.setBorders(true);   
	    bar.setStyleAttribute("borderTop", "none");   
	    bar.add(new MenuBarItem("New", menu));   
	  
	    Menu sub2 = new Menu();   
	    sub2.add(new MenuItem("Cut"));   
	    sub2.add(new MenuItem("Copy"));   
	  
	    MenuBarItem edit = new MenuBarItem("Edit", sub2);   
	    bar.add(edit);   
	  
	    sub = new Menu();   
	    sub.add(new MenuItem("Search"));   
	    sub.add(new MenuItem("File"));   
	    sub.add(new MenuItem("Java"));   
	  
	    MenuBarItem item3 = new MenuBarItem("Search", sub);   
	    bar.add(item3);   
	       
	    menu = new Menu();   
	  
	    CheckMenuItem menuItem = new CheckMenuItem("I Like Cats");   
	    menuItem.setChecked(true);   
	    menu.add(menuItem);   
	  
	    menuItem = new CheckMenuItem("I Like Dogs");   
	    menu.add(menuItem);   
	  
	  
	    menu.add(new SeparatorMenuItem());   
	  
	    MenuItem radios = new MenuItem("Radio Options");   
	    menu.add(radios);   
	  
	    Menu radioMenu = new Menu();   
	    CheckMenuItem r = new CheckMenuItem("Blue Theme");   
	    r.setGroup("radios");   
	    r.setChecked(true);   
	    radioMenu.add(r);   
	    r = new CheckMenuItem("Gray Theme");   
	    r.setGroup("radios");   
	    radioMenu.add(r);   
	    radios.setSubMenu(radioMenu);   
	  
	    MenuItem date = new MenuItem("Choose a Date");   
	    menu.add(date);   
	  
	    date.setSubMenu(new DateMenu());   
	       
	    MenuBarItem item4 = new MenuBarItem("Foo", menu);   
	    bar.add(item4);   
	    northPanel.add(bar);
	    
	    northPanel.setAutoHeight(true);
		viewport.add(northPanel, data);
	}
☞ 위와 같이 코딩하면 에러가 날것이다. RiaApp.ICONS...이 부분이다. 이부분은 툴바에 설정하는 아이콘 이미지로 com.gxt.riaapp.client.resource라는 이름으로 패키지를 생성하고 아래 클래스를 추가해 보자. 아래의 ResourceIcons클래스는 보여질 이미지를 추가하고 해당 이미지를 툴바나 기타 아이콘으로 사용하기 위함이다.
package com.gxt.riaapp.client.resource.icon;

import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ImageBundle;
@SuppressWarnings("deprecation")
public interface ResourceIcons extends ImageBundle {

  @Resource("table.png")
  AbstractImagePrototype table();

  @Resource("add16.gif")
  AbstractImagePrototype add16();

  @Resource("add24.gif")
  AbstractImagePrototype add24();

  @Resource("add32.gif")
  AbstractImagePrototype add32();

  @Resource("application_side_list.png")
  AbstractImagePrototype side_list();

  @Resource("application_form.png")
  AbstractImagePrototype form();

  @Resource("connect.png")
  AbstractImagePrototype connect();

  @Resource("user_add.png")
  AbstractImagePrototype user_add();

  @Resource("user_delete.png")
  AbstractImagePrototype user_delete();

  @Resource("accordion.gif")
  AbstractImagePrototype accordion();

  @Resource("add.gif")
  AbstractImagePrototype add();

  @Resource("delete.gif")
  AbstractImagePrototype delete();

  @Resource("calendar.gif")
  AbstractImagePrototype calendar();

  @Resource("menu-show.gif")
  AbstractImagePrototype menu_show();

  @Resource("list-items.gif")
  AbstractImagePrototype list_items();

  @Resource("album.gif")
  AbstractImagePrototype album();

  @Resource("text.png")
  AbstractImagePrototype text();

  @Resource("plugin.png")
  AbstractImagePrototype plugin();
  
  @Resource("music.png")
  AbstractImagePrototype music();
  
  @Resource("table_refresh.png")
  AbstractImagePrototype refresh();
  
  @Resource("folder_go.png")
  AbstractImagePrototype go_out();
  
  @Resource("excel_download16.png")
  AbstractImagePrototype excel16();
  
  @Resource("excel_download32.png")
  AbstractImagePrototype excel32();
}
☞ 같은 패키지에 이미지도 추가하자. gxt쪽 샘플에서 사용하는 이미지로 gxt 루트에서 찾아보면 될것이다.
 
마지막으로 테마를 변경하자. 이 강좌 맨위의 이미지를 보면 이전에 푸른색 계열의 색상에서 세련된 회색계열로 변경되었다. 개인적으로 푸른색은 좀 촌스러워서 바꿔봤다. war폴더내의 RiaApp.html파일에 한줄 추가하자.
    
     
    
Posted by 1 베니94

댓글을 달아 주세요

GXT RIA App 만들기2011.01.20 23:09

오늘 시간에는 중간 프로그램 영역을 코딩하도록 하자. 중간 프로그램 영역은 좌측 메뉴에서 하나의 Row를 클릭했을 때 이곳에 해당 프로그램이 보여지도록 해야한다.
1. Controller와 View를 하나씩 생성하자. ContentController.java와 ContentView.java를 mvc패키지내에 생성하고 아래와 같이 코딩하자.

☞ ContentController.java
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.gxt.riaapp.client.AppEvents;

public class ContentController extends Controller {
	private ContentView view;

	public ContentController() {
		registerEventTypes(AppEvents.Init, AppEvents.ShowPage);
	}

	public void initialize() {
		view = new ContentView(this);
	}

	public void handleEvent(AppEvent event) {
		forwardToView(view, event);
	}

}
☞ ContentView.java
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.gxt.riaapp.client.AppEvents;
import com.gxt.riaapp.client.mvc.model.Entry;

public class ContentView extends View {
	private TabPanel tabPanel;
	
	public ContentView(Controller controller) {
		super(controller);
	}
	
	@Override
	protected void initialize() {
		tabPanel = new TabPanel();
		tabPanel.setCloseContextMenu(true);
		tabPanel.setBorderStyle(false);
		tabPanel.setBodyBorder(false);
		tabPanel.setTabScroll(true);
		tabPanel.setAnimScroll(true);
		ContentPanel center = (ContentPanel) Registry.get(AppView.CENTER_PANEL);
	    center.add(tabPanel);
	    center.layout();
	}
	
	public void onShowPage(Entry entry) {
		System.out.println("ContentView.onShowPage() called.." + entry.getName());
	}
	
	@Override
	protected void handleEvent(AppEvent event) {
		EventType type = event.getType();
		if(type == AppEvents.ShowPage){	// Init일 경우에는 작동하지 않음.
			Entry entry = event.getData(); // 이벤트에 전달된 객체를 가져온다.
			onShowPage(entry);
		}
	}
}

☞ RiaApp.java를 수정하자.
	public void onModuleLoad() {
		model = new RiaAppModel();
	    Registry.register(MODEL, model);  // 최초 실행시 Registry에 RiaAppModel을 등록한다.
	    
		dispatcher = Dispatcher.get();
	    dispatcher.addController(new AppController());
	    dispatcher.addController(new NavigationController());  // 좌측
	    dispatcher.addController(new ContentController());
	    dispatcher.dispatch(AppEvents.Init);
	    
	    if(model.getEntries().size()>0) // 등록된 첫번째 프로그램을 보여준다.
			showPage(model.getEntries().get(0));
	}

	/**
	 * ShowPage이벤트를 가지고 있는 Controller를 통해 ContentView를 보여준다. 여기서 중요한 것은 이벤트와 함께
	 * Entry 객체를 전달했다는 것이다. 이 객체는 화면에 보여줘야할 우리가 클릭한 객체로 이 객체를 전달하면 ContentView에서
	 * 이 객체를 이벤트를 통해 전달 받고 화면에 보여주게 된다.
	 * 
	 * @param entry
	 */
	public static void showPage(Entry entry) {
		AppEvent appEvent = new AppEvent(AppEvents.ShowPage, entry); // 이벤트에 객체전달
		appEvent.setHistoryEvent(true);
		appEvent.setToken(entry.getId());
		Dispatcher.forwardEvent(appEvent);  // ShopPage이벤트가 등록되어 있는 ContentController가 ContentView를 보여주게된다.
	}

☞ 이제 실행해 보자 이번에 수정한 부분은 ContentController를 RiaApp에 등록했고 이 컨트롤러를 통해 ContentView가 실행되게 된다. 이때 ContentView가 보여지게 되는 과정에 주목하자.
 RiaApp에 ContentController를 등록하면서 우리는 RiaAppModel의 첫번째 객체를 RiaApp.showPage()메소드에 전달했다.
이 메소드는 AppEvent를 생성하는데 AppEvent는 인자로 이벤트타입과 객체를 받게 된다. 이 애기는 특정이벤트를 콜하면서 객체를 전달할 수 있다는 애기다. showPage메소드의 맨아래 코딩을 보면 Dispatcher클래스의 forwardEvent()메소드를 통해 해당 이벤트가 등록되어 있는 Controller에게 제어권을 넘기고 해당 Controller는 handleEvent메소드에 정의 된 View를 보여지게 된다.
 여기서는 ContentController를 통해 ContentView가 보여지게 되는 것이다. 그러나 이번에도 실행한 결과 별반 달라진게 없을 것이다. 단지 아래 그림처럼 ContentView클래스의 onShowPage()가 호출되는 것을 콘솔을 통해 확인할 수 있다.

2. 이제 프로그램 영역이 마저 보일 수 있도록 수정해 보자

☞ SmplProgram.java를 com.gxt.riaapp.client.mvc 아래에 추가하고 아래와 같이 코딩하자. 이 클래스를 우측 프로그램 영역에 보이도록 할 것이다.
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.google.gwt.user.client.Element;

public class SmplProgram  extends LayoutContainer {
	@Override
	protected void onRender(Element parent, int index) {
		// TODO Auto-generated method stub
		super.onRender(parent, index);
		VerticalPanel vp = new VerticalPanel();
		vp.setSpacing(10);
		Button btn =new Button("테스트");
		setLayout(new FlowLayout(10));
		vp.add(btn);
		add(vp);
	}
}
☞ RiaAppModel.java의 생성자를 아래와 같이 수정하자.
	public RiaAppModel() {
		Category pgm = new Category("시스템관리","SYS00002");
		pgm.add("시스템사용자관리", "0001", new SmplProgram());
		addCategory(pgm);
		loadEntries(this);
	}
☞ Entry 클래스의 생성자를 약간 수정하자.
	
    public Entry(String name, String id, LayoutContainer example) {
		this.name = name;
		set("name", name);
		set("id", id);
		this.id = id;
		set("program", example); // example를 program으로 변경하자.
	}
	public LayoutContainer getProgram() {  // 추가하자
		return (LayoutContainer) get("program");
	}
☞ model패키지내에 Page클래스를 추가하자. 이 클래스는 Entry클래스를 받아 TabPanel에 TabItem을 추가할 수 있도록 구현되어 있다.
package com.gxt.riaapp.client.mvc.model;

import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
/**
 * 이 클래스는 Entry를 받아 TabPanel에 추가할 수 있는 TabItem으로 변환하여 TabPanel에 추가하는 역할을 한다.
 * @author KYS
 *
 */
public class Page extends TabPanel {
	protected Entry entry;
	public Page(final Entry entry) {
		this.entry = entry;
		setTabPosition(TabPosition.BOTTOM);
		setBorderStyle(false);
		setBodyBorder(false);
		
		TabItem demo = new TabItem();
		demo.setScrollMode(Scroll.AUTO);
		demo.setHideMode(entry.getHideMode());
		demo.add(entry.getProgram());  // RiaAppModel에서 add한 프로그램
		add(demo);
	}
}

☞ ContentView 클래스의 onShowPage() 메소드를 아래와 같이 추가 코딩하도록 하자.
	public void onShowPage(Entry entry) {
		System.out.println("ContentView.onShowPage() called.." + entry.get("page"));
		Page page = entry.get("page");
	    if (page == null) {	// entry에 page가 세팅되어 있지 않다면 이 Entry는 우측 프로그램 영역에 없는 Entry이다.
	      page = new Page(entry);	// Page객체를 생성하고
	      entry.set("page", page); // entry에 page를 추가한다.
	    }
	    /**
	     * page id로 검색해서 없다면 추가하는 로직
	     */
		TabItem item = tabPanel.findItem("page__" + page.getId(), false);
		if (item == null) {
			item = new TabItem();
			item.setData("entry", entry);
			item.setClosable(entry.isClosable());
			item.setId("page__" + page.getId()); // 나중에 찾을 수 있도록 아이디 세팅
			item.setText(entry.getName());
			item.setLayout(new FitLayout());
			item.add(page); // TabItem
			tabPanel.add(item);
		}
	}
☞ 이제 다시 실행해 보도 록 하자 실행된 브라우저에서 F5키를 누르면 RiaAppModel에 추가한 SmplProgram이 프로그램 영역에 보이는 것을 확인 할 수 있다.
 
3. 여기까지 해서 프로그램영역에 신규로 작성한 프로그램이 출력되도록 코딩하였다. 그러나 위의 그림처림 "시스템사용자관리"가 화면에 출력되는 것은 좌측 메뉴를 클릭해서 출력되는 것이 아니라 RiaApp.java에 RiaAppModel클래스에 등록된 프로그램중 0번째 즉 첫번째 프로그램이 출력되도록 코딩되어 있어 보여지는 것이다.
 등록된 프로그램이 복수개이면 좌측 메뉴를 클릭해서 우측 프로그램 영역에 보여지도록 해야한다. 보통은 Model에 등록된 0번째 프로그램은 게시판이나 전체상황을 볼수 있는 상황판이 떠야하므로 0번째 프로그램에는 게시판이나 상황판을 배치하고 이 후부터 업무용 프로그램을 배치하도록 하는것이 맞을 듯 하다.

이제부터는 여러개의 프로그램을 등록하고 좌측 메뉴의 프로그램을 클릭해서 우측 프로그램 영역에 출력되도록 만들어보자.

☞ SmplProgram.java를 아래와 같이 수정하자.
public class SmplProgram  extends LayoutContainer {
	String txt = "";
	public SmplProgram(String txt) {
		this.txt = txt;
	}
	@Override
	protected void onRender(Element parent, int index) {
		// TODO Auto-generated method stub
		super.onRender(parent, index);
		VerticalPanel vp = new VerticalPanel();
		vp.setSpacing(10);
		Button btn =new Button(txt);
		setLayout(new FlowLayout(10));
		vp.add(btn);
		add(vp);
	}
}


☞ RiaAppModel을 아래와 같이 수정하여 여러개의 프로그램을 좌측메뉴에 추가해보자.
	public RiaAppModel() {
		Category pgm = new Category("시스템관리","SYS00002");
		pgm.add("시스템사용자관리1", "0001", new SmplProgram("시스템사용자관리1"));
		pgm.add("시스템사용자관리2", "0002", new SmplProgram("시스템사용자관리2"));
		pgm.add("시스템사용자관리3", "0003", new SmplProgram("시스템사용자관리3"));
		pgm.add("시스템사용자관리4", "0004", new SmplProgram("시스템사용자관리4"));
		addCategory(pgm);
		loadEntries(this);
	}
☞ 여기까지 실행해서 좌측 트리메뉴를 확인하면 위에서 추가한 4개의 트리가 보일 것 이다. 그러나 트리를 클릭해도 아무런 반응이 없을 것이다. 이제 트리를 클릭했을 경우 우측 프로그램 영역에 프로그램이 보여지도록 하자. 좌측 영역이므로 NavigationView클래스에서 해당 트리가 SelectionChanged 될 경우 클릭한 프로그램이 보이도록 수정하자. 아래와 같이 NavigationView.java의 initialize()메소드에 추가 코딩을 하자.
	@Override
	protected void initialize() {
		super.initialize();
		model = (RiaAppModel) Registry.get(RiaApp.MODEL);
		/**
		 * 트리내에서 다른 트리를 클릭했을 경우.
		 */
		SelectionService.get().addListener(
				new SelectionChangedListener() {
					public void selectionChanged(SelectionChangedEvent event) {
						List sel = event.getSelection();
						if (sel.size() > 0) {
							TreeModel m = (TreeModel) event.getSelection().get(0);
							if (m != null && m instanceof Entry) {
								RiaApp.showPage((Entry) m);
							}
						}
					}
				}
		);
		// 필터 생성
		....
☞ 이제 실행해서 작동이 되는지 확인해보자. 실행하여 좌측 트리메뉴를 펼쳐 클릭해보면 아래와 같이 클릭한 프로그램에 우측 TabPanel에 TabItem으로 추가되는 것을 볼수 있다.

☞ 마지막으로 프로그램 영역의 맨 아래 부분에 대한 처리를 추가하도록 하자. 우리는 프로그램 영역의 아래쪽에 도움말 탭을 추가하려고 한다. 즉 현재 위의 그림과 같이 보여지고 있는 프로그램 영역과 함께 도움말 탭을 추가하여 해당 프로그램에 대한 도움말을 추가할 영역을 만들어 주자. 도움말 영역은 html파일이 추가 될 수 있도록 url을 지정가능하게 하자.

// Entry.java
	public String getSourceUrl() {
		Object o = (Object) get("program");
		String name = o.getClass().getName();

		name = name.substring(name.lastIndexOf("program.") + 9);
		name = "code/" + name + ".html";
		name = name.replaceFirst("\\.", "/");

		return name;
	}
// Page.java
		....
		TabItem demo = new TabItem();
		demo.setScrollMode(Scroll.AUTO);
		demo.setHideMode(entry.getHideMode());
		demo.setText("프로그램");
		demo.add(entry.getProgram());
		add(demo);
		if (entry.isClosable()) {
			TabItem source = new TabItem();
			source.setText("도움말");
			source.setUrl(entry.getSourceUrl());
			add(source);
		}
Posted by 1 베니94

댓글을 달아 주세요

  1. beowulf

    안녕하세요

    항상 좋은글 잘 보고 있습니다.

    많은 도움을 받고 있습니다.

    다름이 아니고

    gwt를 전용 브라우저로 쓰고 리스트 메뉴를 누를때 마다 같은 도메인의 url을 불러서 컨텐츠 영역에

    페이지를 보이고 싶은데요... 당췌 못 찾겠습니다.

    수박 겉핡기로 막 했더니 영 힘드네요ㅠㅠ

    html container나 뭐 이런걸 써야 할것 같은데요... 개념을 잘 모르겠습니다 ㅠㅠ

    염치 불구하고 이렇게 질문 드립니다.

    건승 하십시오.

    2011.03.08 15:41 [ ADDR : EDIT/ DEL : REPLY ]
    • 쪼금만 구체적으로 다가 설명을 주시면 ..ㅋㅋ
      답변이 맞을지는 모르겠지만 말씀하신대로 HtmlContainer를 사용할실 수 있겠습니다.
      아래와 같이 말이죠
      HtmlContainer topPanel = null;
      topPanel.setUrl("http://www.daum.net");
      도움이 안되셨다면 조그만 더 구체적으로 상황을 알려주시며
      답을 찾아보겠습니다.

      2011.03.08 22:53 신고 [ ADDR : EDIT/ DEL ]
  2. beowulf

    현재 GWT로 연재 해 주시는 예제를 따라하면서 ERP전용 브라우저를 만들고 있습니다^^

    딱 제가 찾는 걸 연재 해 주셔서 눈물 흘릴뻔 했죠 감사합니다.

    지금 상황은 왼쪽에 트리메뉴 리스트를 만들고 트리메뉴 클릭시 메뉴에 담겨 있는 url 정보에 해당하는 jsp를 컨텐츠패널로 불러 오고 싶습니다.

    트리메뉴 만들고 탭 생기고 하는 7장 까지는 따라 했는데 방금 말한 jsp페이지 불러오는걸 못하고 있습니다 ㅠㅠ

    리플 달아주신 내용으로 일단 도전해 보겠지만 잘 될려나 싶네요^^;;; 항상 연재 감사하게 생각하고 있습니다.

    건승하세요~

    2011.03.09 10:47 [ ADDR : EDIT/ DEL : REPLY ]
    • 네 ~ 도움이 많이되었으면 좋겠네요.
      항상 방법은 있으니깐요 열심히 하셔요!~

      2011.03.11 13:30 신고 [ ADDR : EDIT/ DEL ]
  3. public void onShowPage(Entry entry) {
    .....
    if (item == null) {
    ......
    }
    tabPanel.setSelection(item);
    }

    위 코드 넣어주면 좌측 메뉴 클릭시 ContentView의 TabPanel 이 자동으로 Selection 됩니다.

    2014.11.18 20:55 신고 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.17 23:56
오늘은 이전 강좌에 이어 프로그램의 뼈대를 완성해 보자


AppView.java를 마져 수정하자. AppView클래스는 아래와 같이 크게 4개의 변수가 사용된다.

  1. northPanel     : 상단 구성에 사용 될 객체로 Html로 구성할 것이므로 HtmlContainer를 사용하도록 한다.
  2. westPanel     : 좌측 메뉴영역으로 ContentPanel클래스를 사용하도록 하자. ContentPanel은 다양한 컴포넌트를 탑재할 수 있는 클래스로 앞으로도 많이 사용될 것이다.
  3. contentPanel : 중간 프로그램 영역으로 좌측과 동일하게 ContentPanel클래스를 사용하도록 하자
  4. viewport       : 위의 1~3의 영역을 올려 놓을 객체로 Viewport클래스를 사용한다. Viewport클래스는 Layout에 따라 컴포넌트를 탑재할 수 클래스이다.

▶ AppView.java를 수정하자. 좌,우,상단의 변수를 설정하자. 또한 initialize()함수를 통해 각 영역을 탑재할 viewport를 생성한다. viewport가 화면에 보여지기 위해선 RootPanel에 viewport를 add하자.
 public static final String CENTER_PANEL = "centerPanel";
public static final String WEST_PANEL = "westPanel";
public static final String NORTH_PANEL = "northPanel";
public static final String VIEWPORT = "viewPort";
private Viewport 		viewport; 	// 상단, 좌측, 중간의 3부분을 탑재 할 viewportt
private HtmlContainer 	northPanel;	// 상단영역
private ContentPanel 	westPanel;	// 좌측 메뉴영역
private ContentPanel 	centerPanel;// 중간 프로그램영역

@Override
protected void initialize() {
    super.initialize();
    viewport = new Viewport();
    viewport.setLayout(new BorderLayout());

    RootPanel.get().add(viewport);
}
▶ 이제 각각의 영역을 생성할 메소드를 코딩해 보자. 아래 메소드들은 각각의 영역에 맞게 HtmlContainer, ContentPanel등을 생성하여 viewport에 추가하고 있다.
/**
 * 상단 영역 구성하기
 */
private void createNorth() {
    StringBuffer sb = new StringBuffer();
    sb.append("");
    sb.append("");
    sb.append("");
    sb.append("
상단 영역
"); northPanel = new HtmlContainer(sb.toString()); BorderLayoutData data = new BorderLayoutData(LayoutRegion.NORTH, 75); data.setMargins(new Margins(0,0,0,0)); viewport.add(northPanel, data); } /** * 좌측 메뉴영역 */ private void createWest() { BorderLayoutData data = new BorderLayoutData(LayoutRegion.WEST, 220, 150, 320); data.setMargins(new Margins(5, 5, 5, 5)); data.setCollapsible(true); westPanel = new ContentPanel(); ToolBar toolBar = new ToolBar(); westPanel.setTopComponent(toolBar); viewport.add(westPanel, data); } /** * 중간 프로그램 영역 */ private void createCenter() { centerPanel = new ContentPanel(); centerPanel.setBorders(false); centerPanel.setHeaderVisible(false); centerPanel.setLayout(new FitLayout()); BorderLayoutData data = new BorderLayoutData(LayoutRegion.CENTER); data.setMargins(new Margins(5, 5, 5, 0)); viewport.add(centerPanel, data); }

▶ 위에서 만든 메소드를 initialize()함수에서 실행 하도록 코딩하자.
	@Override
	protected void initialize() {
		super.initialize();
		viewport = new Viewport();
		viewport.setLayout(new BorderLayout());
		
		createNorth();
		createWest();
		createCenter();
		
		RootPanel.get().add(viewport);
	}
▶ 이제 실행해서 결과물을 확인해 보도록 하자. RiaApp.gwt.xml파일에서 마우스 우측 클릭하고 Run As -> Web Application을 클릭 한다. 주소를 카피해서 브라우저에 실행 한다.
▶ 실행된 모습이다. 우리가 원했던 형태로 잘 구성된 것을 확인 할 수 있다.
Posted by 1 베니94

댓글을 달아 주세요

  1. kojoscap

    늦은시간 까지 고생하셨습니다
    다음이 기대되네요

    2011.01.18 01:14 [ ADDR : EDIT/ DEL : REPLY ]
  2. bgr1017

    감사합니다!

    2015.04.27 16:20 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.15 03:44

1. 본격적인 코딩에 들어가기 전에 프로젝트 생성 시 만들어진 파일들을 정리하자

▶ RiaApp.java를 아래와 같이 정리한다.


▶ war 밑에 위치한 RiaApp.html을 아래와 같이 정리한다.


▶ RiaApp.gwt.xml파일을 아래와 같이 정리한다.


▶ 이제 gxt기능을 사용하기 위한 라이브러리를 등록하자. gxt.jar파일을 그림과 같이 lib폴더에 복사하고 Build Path를 잡아주자.




2. 이제 필요한 클래스를 하나씩 만들어 보자. 현재 상태에서 어플리케이션을 실행해도 아무것도 나오지 않는다.
우리는 여기에 하나씩 살을 붙여 UI를 구성해 보도록 하자


▶ 이번 강좌에서 필요한 클래스는 3가지 클래스가 필요하다.
 AppEvents.java  EventType클래스를 이용해 이벤트를 정의 한다.
 AppController.java  Controller 클래스를 상속받아 AppView가 실행될 수 있도록 돕는다.
 Controller 클래스는 MVC모델의 C에 해당된다고 생각하면 되겠다.
 AppView.java  View클래스를 상속받아 화면에 보여질 UI구성요소 등을 정의한다.
 MVC모델의 V에 해당되겠다.

▶ 일단 AppEvents.java에 이벤트를 정의 하자. 이름에서 대강의 쓰임새를 알 수 있을 것이다. 이렇게 이벤트를 정의하여
    Controller나 View에서 사용할 수 있는 것이다.
package com.gxt.riaapp.client;
import com.extjs.gxt.ui.client.event.EventType;
public class AppEvents {
    public static final EventType Init = new EventType();
    public static final EventType ShowPage = new EventType();
    public static final EventType HidePage = new EventType();
    public static final EventType TabChange = new EventType();
    public static final EventType ChartLoading = new EventType();
    public static final EventType Login = new EventType();
    public static final EventType Error = new EventType();
}
▶ 이번에는 우리가 만들 어플리케이션의 뼈대를 구성할 View 클래스를 생성해 보자. 아래 클래스는 View클래스를
    상속 받고 최소한의 생성자와 handleEvent() 메소드만 정의 되어 있다. 여기에 살을 붙여 기본 틀을 구성하게 된다.
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;

public class AppView extends View {
    public AppView(Controller controller) {
        super(controller);
    }
    @Override
    protected void handleEvent(AppEvent event) {
    }
}
▶ 다음은 위의 두개의 클래스를 통제할 Controller클래스를 생성한다. 이 클래스는 최초의 Init이벤트가 호출될 시 AppView로
    이동하여 기본 화면 틀을 보이도록 제어하는 역할을 하게 된다.
package com.gxt.riaapp.client.mvc;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.gxt.riaapp.client.AppEvents;

public class AppController extends Controller {
    private AppView appView;
    public AppController() {
        appView = new AppView(this);
        registerEventTypes(AppEvents.Init); // 등록과 동시에 handleEvent메소드 호출
    }
    @Override
    public void handleEvent(AppEvent event) {
        if (event.getType() == AppEvents.Init) { // 호출시 전달된 이벤트가 Init라면 
            forwardToView(appView, event);
        }
    }
}
▶ 이제 위에서 생성한 Controller를 RiaApp클래스에 탑재 해 보도록 하자. 아래 소스에서 주목할 부분은 Dispatcher 클래스에
    Controller를 추가하고 이벤트를 전달하여 Dispatcher내의 여러 Controller들이 움직이도록 하는데 있다.
package com.gxt.riaapp.client;

import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.google.gwt.core.client.EntryPoint;
import com.gxt.riaapp.client.mvc.AppController;

/**
 * Entry point classes define onModuleLoad().
 */
public class RiaApp implements EntryPoint {
	private Dispatcher dispatcher;
	public void onModuleLoad() {
		dispatcher = Dispatcher.get();
	    dispatcher.addController(new AppController());
	    dispatcher.dispatch(AppEvents.Init);
	}
}

3. 이제 AppView클래스를 수정하여 아래 그림과 같은 표대를 만들어 보자 .

Posted by 1 베니94

댓글을 달아 주세요

  1. kojoscap

    기대되는데요~~~잘보고있습니다...감사~

    2011.01.17 17:12 [ ADDR : EDIT/ DEL : REPLY ]
  2. ijava

    잘보고 있습니다. gwt나 gxt에 대해 관심은 있는데 실 적용된에 쓸만한 코드를 찾기 힘들고
    간단한 샘플들 만 여기저기 널여 있는데 베니님의 강의를 보고 실적용할 수 있는 정도에
    수준을 보여주실 거 같아 기대가 됩니다.
    수고하세요

    2011.01.17 18:18 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.13 21:09
강좌 소스를 공유하기 위해 구글프로젝트에 프로젝트를 생성하고 구글에서 제공하는 svn을 이용해
소스를 받을 수 있도록 세팅한다
.

 

1. 프로젝트를 생성하자
   - 구글 코드 code.google.co.kr에 접속하여 프로젝트를 생성한다.
   - 이를 통해 강좌 소스를 svn을 통해 내려받을 수 있다. 이부분은 따라하지 마세요



▶code.google.com으로 접속해서 ext-gwt-ria-app로 검색하면 아래처럼 우리가 생성한 프로젝트를 확인할 수 있다.


▶ File -> New -> Other를 선택한 후 아래화면에서 "SVN"입력한다.


 
▶ "Project from SVN"을 선택하고 "Next"를 클릭한면 아래화면을 확인 할 수 있다.
▶ "Create a new repository location"을 체크하고 "Next"를 클릭한다.


▶ URL란에 http://ext-gwt-ria-app.googlecode.com/svn/RiaApp/를 입력하고 "Next"를 클릭한다.


▶ Date를 체크하고 "Finish"를 클릭한다.


▶svn client가 위에서 정해 준 주소로 접속해 RiaApp프로젝트를 검색한다.


▶ "Next"를 클릭한다.


▶ 로컬디스크에 저장할 workspace를 선택한다. 별다른게 없다면 "Finish"를 클릭하자.


▶ 최종 로컬 이클립스에 내려온 모습니다. 이전에 프로젝트가 동일한 이름으로 만들어져 있었다면 이클립스는 프로젝트를
    지우고 svn서버에서 내려받은 파일로 프로젝트를 구성하게 될것 이다.


▶ 이 과정을 거치게 되면 강좌소스를 변경하게 되면 svn을 통해 소스를 내려받을 수 있게 된다. 간단하게 내가 소스를 수정하고
   수정된 소스를 내려받는 과정을 알아보도록 하자.
   사전에 RiaApp.java를 일부 수정하였다. 수정된 내용을 내려 받을 수 있는지 보도록 하자.
▶ 그전에 필자가 이미 소스를 수정해서 커밋했으므로 어떤 내용이 커밋되었는지 구글 코드를 통해 먼저확인 할 수 있다.
▶ 구글코드(code.google.com)에 접속해 "ext-gwt-ria-app"로 프로젝트를 검색하고 아래와 같이 "Source"를 클릭하여
    변경된 내용을 확인 할 수 있다. "r5 변경된 내용을 내려받는지 확인한다"는 조금전에 필자가 커밋한 내용이다.
    "r5"를 클릭하자


▶ "r5"를 클릭하면 변경된 내용이 어떤 파일인지 확인 할 수 있다. 변경된 파일은 RiaApp.java이고 로그메시지는 "변경된 내용..."이다.
    이제 자신의 이클립스의 svn을 통해 변경된 RiaApp.java를 내려받아 보자.


▶ 아래의 그림과 같이 RiaApp.java파일에서 마우스우측 클릭하고 Team->Update를 클릭하자. 만약 어떤 파일이 수정되었는지
    모른다면 프로젝트 루트에서 같은 방법으로 전체 파일을 업데이트 받을 수 있다.

▶ 아래와 같이 RiaApp.java가 svn을 통해서 필자가 업데이트 한 내용을 로컬로 내려받은 것을 확인 할 수 있다.


이렇게 해서 강좌에서 사용되는 소스파일을 간단하게 svn을 통해 내려받게 된다. 그러나 여러분에게는 권한이 없으므로 각자가 수정한 소스를 커밋할 수는 없다. 단 로컬에서 수정은 자유롭다. - 끝 -
Posted by 1 베니94

댓글을 달아 주세요

Gxt , Ext Gwt강좌2011.01.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 ]

GXT RIA App 만들기2011.01.11 00:40
1. Gxt를 사용할 수 있도록 프로젝트 설정을 변경하자.

 ▶ com.gxt.riaapp에서 우측 마우스 클릭하고 "Google Web Toolkit"-> Convert project into GWT project를 선택하자


▶ Configure for using Ext GWT (GXT)를 선택한다.

▶ 내려받은 Gxt모듈의 디렉토리를 지정해준다. 이 부분이 이해되지 않는다면 이전 강좌를 확인하고 Gxt라이브러리를
    다운받도록 하자.


▶ 아래와 같이 RiaApp.gwt.xml파일에 Gxt관련 한줄이 추가된 것을 확인 할 수 있다. 물론 내부적으로는 Gxt라이브러리
   홈을 지정해 줌으로써 classpath등이 잡히게 될 것이다.

Posted by 1 베니94

댓글을 달아 주세요

  1. beowulf

    안녕하세요 유용하게 잘 보고 있습니다.

    궁금한게 있어서 여쭤보려구요^^

    현재 저는 GWT SDK 2.2.0을 사용하고 ECLIPSE는 HELIOS를 사용중입니다.

    위 예제를 따라 하다 보니

    "Convert Project into GWT project"가 저한테는 생성되지 않는 메뉴입니다.

    위 과정을 거치지 않아도 될까요?^^

    또 혹시 연재중 실제 어플리케이션 완성후에 톰캣 서버에 올리는 방법도 연재고려중 이신지 궁금합니다^^

    연재 올리시느라 고생이 많으십니다.

    항상 건승하세요.

    2011.03.04 10:54 [ ADDR : EDIT/ DEL : REPLY ]
  2. 우선 제 강좌중에 " http://benney.tistory.com/entry/Ext-GwtGxt-강좌02-Gwt-개발환경-설정하기 "를 다시 확인해보세요
    당시에는 2.0이였지만 지금은 2.2가 나오겠죠. 방법은 동일합니다. 위의 내용대로 설치하셨시고 web Application을 생성하셨다면 문제없이 "Convert Project into GWT Project"메뉴가 보이실 겁니다.
    아 그리고 톰캣서버에 배포하는 부분도 다룰 예정입니다. 뭐든 배포를 해야 서비스를 할 수 있을 테니깐요.
    저의 경우 war파일로 배포하고 있구요. 그전에 컴파일하고 빌드하고 해서 서버에 적용하면 되겠습니다.

    2011.03.04 17:19 신고 [ ADDR : EDIT/ DEL : REPLY ]

GXT RIA App 만들기2011.01.09 13:07

오늘 부터 Gxt를 이용해 실제 사용 가능 한 어플리케이션을 개발해보자 .
 이 어플리케이션에는 아래의 내용이 기본 들어가게 된다.

- 사용자 권한->사용자별 프로그램
- 세션 -> 특정 시간을 사용하지 않을 경우 재로그인 유도
- GXT의 모든 UI객체
- 다양한 종류의 RPC통신 방법(솔직히 몇개안됨)GXT를 이용해 이미 개발한 바 있는
 시스템의
소스를 일부 수정하여 만들어보도록 한다.


관련 기술
1. Gxt
2. iBatis
3. Database
4. Jsp
등등....

2011/01/06 - [Gxt, Gwt] - 스크린 샷
Posted by 1 베니94

댓글을 달아 주세요

  1. Gxt 관심

    기대되는데요~^^
    강좌 열심히 따라하고 있습니다.

    2011.01.10 17:54 [ ADDR : EDIT/ DEL : REPLY ]
  2. 좋은 정보 갑사 합니다...

    2011.03.03 17:11 신고 [ ADDR : EDIT/ DEL : REPLY ]