Google Web Toolkit
2015.12.26 21:55
-
Google Web Toolkit
-
소개
-
-
-
Google Web Toolkit(이하 GWT)는 Java 코드를 JavaScript로 컴파일 하여 브라우저(클라이언트)에서 실행할 수 있도록 도와주는 도구이다.
-
GWT는 클라이언트/서버 사이드 모두 Java 만 사용한다.
-
클라이언트 사이드에 Java 코드를 JavaScript 와 DHTML로 변환하기 위한 컴파일러를 따로 제공한다. (App Engine 코드 보다 컴파일 시간이 오래 걸림.)
-
JavaScript가 Java의 API를 완벽히 제공하고 있지 않기 때문에 클라이언트 사이드의 코드를 작성시 제약사항이 있다.
-
-
-
제약사항
-
-
-
모든 primitive Type(char, int, float, byte 등) 과 관련 클래스등은 모두 지원하지만 long 은 double로 변환되기때문에 int를 사용하는 것을 권장한다.
-
JavaScript는 Single-Thread 방식을 사용하기 때문에 멀티스레드 API는 제공되지 않는다.
-
Reflection은 지원되지 않는다. GWT.getTypeName 메소드를 통해 오브젝트 클래스 명을 얻을 수 있다.
-
Java.util에서 제공하는 몇가지 오브젝트 컨테이너(Stack, Vector, HashMap 등)를 사용할수 있다. (Date도 사용가능)
-
-
-
프로젝트 디렉토리
-
-
-
app Engine 프로젝트와 GWT 프로젝트 폴더는 좀 차이가 있다.
-
소스를 보면 크게 *.client와 *.server 두가지로 나뉘어져 있다. 이렇게 나눈 이유는 *.client 팩키지 부분의 소스는 javaScript로 Convert 된다.
-
/src
-
/*.client
-
Client 용 java 코드가 들어있다. 컴파일후 JavaScript 가 되는부분
-
-
/*.server
-
Server 용 java 코드가 들어있다.
-
-
-
/test : JUnit test 를 위한 디렉토리
-
-
-
UI
-
UI 위젯
-
-
-
-
-
UI를 만드는 과정은 Java에서 Swing과 매우 유사하다.
-
Com.google.gwt.user.client.ui.*
-
최상위 패널은 RootPanel이며, HTML 소스과 연결 방법은 매우 간단하다.
-
-
*.html
…
<div id=”uiPanel”></div>
...
------------------------------------------------------------------
*.java
...
public void onModuleLoad(){
RootPanel.get(“uiPanel”);
...
-
-
-
위젯 이벤트
-
-
-
-
-
마우스/키보드 이벤트 역시 동일하게 작성하면 된다.
-
Com.google.gwt.event.dom.client.*
-
-
private VerticalPanel buttonPanel = new VerticalPanel();
private Button memoAdd = new Button("Add");
public void onModuleLoad() {
buttonPanel.add(memoAdd);
RootPanel.get("memoList").add(buttonPanel);
memoAdd.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
//action...
}
});
}
-
-
-
위젯 스타일 작성
-
-
-
-
-
-
기본적인 스타일은 위젯마다 기본적인 size나 들어있다.
-
Table의 setBorderwidth 같은 아주 기본적인 역할을 하는 함수가 있다.
-
-
-
-
-
-
-
CSS
-
-
-
-
-
-
-
html에서 사용하듯 css 를 이용하여 스타일을 작성할수 있다.
-
각 위젯 마다 addStyleName() 메소드를 사용하여 쉽게 스타일을 추가 할 수 있다.
-
CSS 파일은 /war 디렉토리에 html과 jsp 파일과 동일한 위치에 있다.
-
-
-
test.css
-------------------
...
.watchList {
border: 1px solid silver;
padding: 2px;
margin-bottom: 6px;
}
.cellSyle{
background-color: #2062B8;
color: white;
}
*.html
------------------
…
<head>
<link tpe=”text/css” rel=”stylesheet” href=”test.css”>
</head>
<body>
<div id=”test”></div>
...
*.java
-------------------
private FlexTable table = new FlexTable();
public void onModuleLoad() {
table.addStyleName(“watchList”);
table.getCellFormatter().addStyleName(0, 0, “cellStyle”);
...
-
-
-
JavaScript 변환
-
-
-
-
-
javaScript 로 변환전
-
label 과 Button 하나씩 세로로 노인 코드이다.
-
-
-
...
public class MAL implements EntryPoint {
private VerticalPanel pp = new VerticalPanel();
private Label label = new Label();
private Button button = new Button();
public void onModuleLoad() {
label.setText(“name”);
button.setText(“ButtonName”);
pp.add(label);
pp.add(button);
RootPanel.get("malware").add(pp);
}
}
-
-
-
Html 코드
-
-
...
<body>
<div id="malware"></div>
</body>
…
-
-
-
javaScript 로 변환후
-
코드를 보면 UI코드가 해당 id가 있는 tag의 들어간다.
-
iframe 태그를 사용해 변환된 script를 가져온다.
-
이 변환된 script는 알아보기가 매우 힘들게 되어있다.
-
-
-
...
<body>
<div id="malware">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="left" style="vertical-align: top; "><div class="gwt-Label">name</div></td>
</tr>
<tr>
<td align="left" style="vertical-align: top; "><button type="button" class="gwt-Button">buttonName</button></td>
</tr>
</tbody>
</table>
</div>
<iframe src="javascript:''" id="mal" style="position: absolute; width: 0px; height: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; " tabindex="-1">
<html>
…
…
</html>
</iframe>
</body>
-
-
Client-Server 통신
-
-
-
GWT 어플리케이션은 클라이언트에서 실행되는 프로그램이기때문에 데이터를 저장할수 있는 방법이 없다. 그외에 클라이언트와 서버 간의 데이터를 주고 받기 위하여 서버-클라이언트간 통신방법이 필요하다.
-
GWT 에서 JSON, RPC, Cross-Site 3가지 방법을 제공한다.
-
-
-
-
JSON
-
-
-
-
-
JSON은 XML과 비슷한 데이터 표현 포멧 형태이다.
-
-
-
-
-
-
Format
-
-
-
-
-
-
-
서버 어플리케이션에서 제공하려는 데이터를 다음과 같은 포멧형태로 제공한다.
-
기본적인 object 표현 포멧 형식
-
-
-
-
[
{ “property” : “value”,
…
},
{“property” : “value”,
…
},
...
]
-
-
-
-
배열 표현 형식
-
-
-
-
[
value,
value,
....
]
-
-
-
-
Client 에서 JSON data 받아오기
-
-
-
-
-
-
-
JSON Object 를 받을 Class 생성
-
-
-
import java.io.Serializable;
public class StockPrice implements Serializable{
private String symbol;
private double price;
public StockPrice(){}
public StockPrice(String symbol, double price, double change){
this.symbol = symbol;
this.price = price;
this.change = change;
}
…
getter/setter
...
-
-
-
-
JSON Object 의 메소드를 이어주는 JavaScriptObject 생성
-
javascript code를 만들려면 /*- java code -*/; 사이에 넣으면 된다.
-
-
-
-
...
public class StockData extends JavaScriptObject{
protected StockData() {}
public final native String getSymbol() /*-{ return this.symbol; }-*/;
public final native double getPrice() /*-{ return this.price; }-*/;
}
-
-
-
-
JSON string 을 위에서 만든 객체의 배열로 변환 할수 있는 코드
-
-
-
private final native JsArray<StockData> asArrayOfStockData(String json) /*-{
return eval(json)
}-*/;
-
-
-
-
Request 생성
-
url은 JSON Data를 받을수 있는 페이지이다.
-
Response 를 받은경우 Response 객체의 JSON data 가 문자열 형태로 들어 있다.
-
문자열을 위에서 만든 객체 배열로 변환하는 함수를 통해 JsArray 형태의 객체 배열을 얻는다.
-
-
-
-
url = URL.encode(url);
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Error");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError(response.getStatusCode());
}
}
});
} catch (RequestException e) {
e.printStackTrace();
}
...
-
-
-
RPC
-
-
-
-
-
서버와 직접적으로 통신할수 있는 방법으로 서버측의 함수를 직접 호출하는 방법이다.
-
필요한 만큼 구현해야되는 사항도 많다.
-
-
-
-
-
-
클라이언트
-
-
-
-
-
-
서버로 부터 서비스 받을 interface를 작성한다.
-
RemoteService 클래스를 상속받아야 한다.
-
Annotation “RemoteServiceRelativePath” 을 통해 실제 호출할 함수의 위치를 입력한다.
-
-
-
package com.memo.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("/savememo")
public interface saveMemoService extends RemoteService{
Integer saveMemo(String title, String content);
}
-
-
-
서비스를 호출하기 위한 interface 작성
-
위에서 작성한 메소드명과 동일하게 작성한다.
-
파라메터는 두가지로 분류된다. 일반 파라메터와 Callback 부분으로 Callback 부분은 항상 마지막에 와야 하며, 반드시 하나가 존재해야한다. 그에 반해 일반 파라메터는 서버로 전송할 정보가 없다면 없어도 된다.
-
Callback 은 서버로 부터 RPC 서비스의 대한 결과값을 받는 부분이다.
-
-
-
package com.memo.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface saveMemoServiceAsync {
void saveMemo(String title, String content, AsyncCallback<Integer> callback);
}
-
-
-
서비스 호출
-
서비스를 호출할수 있는 saveMemoServiceAsync 의 객체를 생성
-
callback의 인스턴스를 생성한다.
-
서비스가 성공적이인 경우 callback에 onSuccess() 호출 되고 실패시에 onFailure() 가 호출된다.
-
서비스를 호출한다.
-
-
-
package com.visual.memo.client;
...
public class Memo implements EntryPoint {
..
private saveMemoServiceAsync saveMemoSvc = GWT.create(saveMemoService.class);
…
private void saveMemo(){
ServiceDefTarget target = (ServiceDefTarget) saveMemoSvc;
target.setServiceEntryPoint("/savememo");
AsyncCallback<Integer> callback = new AsyncCallback<Integer>() {
public void onSuccess(Integer result) {
stateLabel.setText("saved/code:"+result.toString());
}
public void onFailure(Throwable caught) {
stateLabel.setText("Error : saveMemo_" + caught.getMessage());
}
};
saveMemoSvc.saveMemo(“title”, “content”, callback);
}
…
}
-
-
-
-
서버
-
-
-
-
-
-
-
서비스 구현
-
RCP 서비스 구현을 위해 RemoteServiceServelt을 상속받는다.
-
또한 클라이언트에서 작성된 interface를 이곳에서 구현한다.
-
-
-
-
package com.visual.memo.server;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.visual.memo.client.saveMemoService;
public class saveMemoServiceImpl extends RemoteServiceServlet implements saveMemoService{
public Integer saveMemo(String title, String content) {
…
return 0;
}
}
-
-
-
-
Web.xml 수정
-
실제 브라우저 상에서 http://real_domain/savememo 라는 입력이 왔을때 com.memo.server.saveMemoServiceImpl Servlet을 실행되게 하는 부분이다.
-
-
-
-
…
<web-app>
<servlet>
<servlet-name>saveMemo</servlet-name>
<servlet-class>com.memo.server.saveMemoServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>saveMemo</servlet-name>
<url-pattern>/savememo</url-pattern>
</servlet-mapping>
…
</web-app>
-
-
Internationalization
-
소개
-
-
-
-
-
하나의 어플리케이션에서 다양한 언어를 지원하기 위한 방법이다.
-
-
-
-
-
구현
-
-
-
-
-
Properties 파일 생성
-
파일이름은 “interfaceName_언어.properties”
-
interface 이름은 모두 동일하게 생성한다.
-
langConstants_ko.properties
name=이름
title=제목
-
langConstants_jp.properties
-
-
-
-
name=なまえ
title=だいもく
-
-
-
-
Constants 를 상속받은 interface를 생성한다.
-
파일명은 properties 파일에서 interfaceName 명을 사용해야한다.
-
DefaultStringValue Annotation를 사용해서 언어선택을 하지 않은 경우 기본적으로 출력할 값을 입력한다.
-
Properties 파일로부터 받아올 문자열 필드명을 메소드명과 동일하게 한다.
-
-
-
package com.visual.mal.client;
import com.google.gwt.i18n.client.Constants;
public interface langConstants extends Constants {
@DefaultStringValue("name")
String name();
@DefaultStringValue("buttonName")
String title();
}
-
-
-
*.gwt.xml 파일 수정
-
properties 파일의 언어 부분을 values 값으로 넣는다.
-
-
-
<module>
...
<extend-property name="locale" values="ko"/>
<extend-property name="locale" values="jp"/>
…
</module>
-
-
JUnit test
-
-
-
JUnit Test 는 GWT 프로젝트에 대해 단위 테스트를 할수 있게 해준다.
-
/test 디렉토리에 test class 를 만들고 GWTTestCase Class 상속받음으로 사용할수 있다.
-
테스트의 사용되는 함수
-
assertTrue(조건) : 조건이 참이면 pass
-
assertFalse(조건) : 조건이 거진이면 pass
-
assertEquals( Object, Object ) : 두 비교 객체가 같으면 pass
객체가 아니어도 Primitive Data Type 도 가능 -
assertNotSame(Object, Obejct) : 두 비교 객체가 같이 않으면 pass
-
assertNotNull(Object) : 객체가 null 이 아니면 pass
-
-
위의 테스트를 pass 못하면 Errors 가 발생하게 된다.
-
GAE 프로젝트와 GWT 프로젝트를 동시의 개발하는 경우에 아래 와 같은 Error가 발생한다.
-
Timeout class가 GWT와 GAE 라이브러리의 중복되 들어있어서 아래와 같은 에러가 발생한다.
-
java.lang.NoSuchMethodError: org.mortbay.thread.Timeout
-
-
[출처] http://visu4l.tistory.com/375
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
댓글 0
| 번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
|---|---|---|---|---|
| 6 |
Spring MVC 시작하기
| 졸리운_곰 | 2016.07.31 | 155 |
| 5 |
Spring MVC 기초
| 졸리운_곰 | 2016.07.31 | 178 |
| 4 | GWT 소개 | 졸리운_곰 | 2015.12.26 | 158 |
| » | Google Web Toolkit | 졸리운_곰 | 2015.12.26 | 171 |
| 2 | [MyBatis] MyBatis 프레임워크의 트랜잭션 제어 | 가을의곰을... | 2013.12.30 | 891 |
| 1 | [ibatis] 부적합한 열 인덱스 | 가을의곰을... | 2013.12.27 | 1505 |

