読者です 読者をやめる 読者になる 読者になる

Google Web Toolkit覚書(GAEプラグイン)

流れ

Eclipseにて「Webアプリケーション・プロジェクト」を作成したら、基本的なファイルは作られる。
プロジェクトにて右クリック、実行、Webアプリケーションを選択すると、実行できる。


プロジェクト作成時に(プロジェクト名を"Sample"とする。)
war/Sample.html
が作成される。
tdタグなどにid属性をつけておく。(Javaよりそのid値を利用しアクセスする)


src/パッケージ/Sample.gwt.xml
が何者かによって呼び出される(はず)
entry-pointタグのclass属性クラスがロードされる。
そのクラスがEntryPointインターフェースを実装しており、onModuleLoadが呼び出される。

final TextBox nameField = new TextBox();
RootPanel.get("nameFieldContainer").add(nameField);

htmlのid値が"nameFieldContainer"となっているため、そのエレメント内部にTextBoxが追加される。

サーバとの通信

clientパッケージに、
GreetingServiceインターフェース
GreetingServiceAsyncインターフェース
が必要。(名前は*Service, *ServiceAsyncが妥当?)
命名規則や、シグネチャが間違っている場合は書いてる途中に、
「No asynchronous version of method メソッド名 exists in type GreetingServiceAsync」
とか言われるけど、インターフェースx2、実装クラスをちゃんと記述したらエラーは無くなる。


serverパッケージに
GreetingServiceImplクラス
が必要。(名前は*ServiceImplが妥当?)
client.GreetingServiceを実装する。(Asyncが無い方)


サーバー側は通常のJavaが利用できる。(好きに書いて良い)
クライント側はjava.lang以下+java.util以下のパッケージ以外は、googleパッケージや自作クラスのみ利用可能(?)
sharedパッケージ以下にはサーバ・クライアント両方で利用するクラスを定義する。
POJOなBeanやバリデータなどを定義するためのパッケージ?
→ただし、
・バリデータでも基本以外のクラスも利用できないので、簡単なチェックのみを記述し、実際のチェックはサーバサイドで行うべき(?)
・サーバ・クライアント間のデータを、POJOなBeanに詰めてやりとりする事は可能。ただし、それをそのまま永続化(DBに登録)はできない。(アノテーションを付けると、コンパイル時に怒られる→org.datanucleus.metadata.InvalidMetaDataException: Class com.noboru.shared.SampleModel has application-identity and no objectid-class specified yet has 0 primary key fields. Unable to use SingleFieldIdentity.)


どのパッケージをクライアント側とする(JavaScriptに変換する?)かは、Sample.gwt.xmlのsourceタグによる?

永続化(JDOの場合)

package com.sample.server;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.sample.shared.TransModel;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class StoreModel {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;
	@Persistent
	private Date date;

	public StoreModel() {
	}

	public StoreModel(Date date, Integer amount, String store,
			String note) {
		this.date = date;
	}

	public StoreKakeiboModel(TransModel model) {
		SimpleDateFormat sdf = new SimpleDateFormat();
		sdf.applyPattern("yyyy/MM/dd");
		try {
			this.date = sdf.parse(model.getDate());
		} catch (ParseException e) {
			e.printStackTrace();
			this.date = null;
		}
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}
}

上記のように、いくつかのアノテーションが必要。
@PersistenceCapable
@PrimaryKey
@Persistent
が必要っぽい。


また、お約束クラス(?)が必要。(無くても毎回書けば動く)

package com.sample.server;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public class PMF {

	private static final PersistenceManagerFactory pmfInstance = JDOHelper
			.getPersistenceManagerFactory("transactions-optional");

	private PMF() {
	}

	public static PersistenceManagerFactory get() {
		return pmfInstance;
	}
}

transactions-optionalは、META-INFのjdoconfig.xmlによる?
いろいろ設定できるみたいだけど、不明。
デフォルトのままで動くので放置。


インサート(登録)は以下の通り

package com.sample.server;

import javax.jdo.PersistenceManager;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sample.client.GreetingService;
import com.sample.shared.KakeiboModel;

public class GreetingServiceImpl extends RemoteServiceServlet implements
		GreetingService {

	public void insertNew(TransModel model) {

		StoreModel newModel = new StoreModel(model);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(newModel);
		} finally {
			pm.close();
		}
	}
}

PersistenceManager#makePersistentの引数に永続化対象クラスを渡すだけ。
更新も同様にできる。(らしい)


SELECT(照会)は以下の通り。

	@SuppressWarnings("unchecked")
	public List<TransModel> listAll() {
		List<TransModel> ret = new ArrayList<TransModel>();

		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(StoreModel.class);
		query.setOrdering("date asc");

		List<StoreModel> list = (List<StoreModel>) query
				.execute();
		for (StoreModel storedData : list) {
			TransModel model = new TransModel();
			model.setId(Long.toString(storedData.getId()));
			model.setDate(Converter.dateToString(storedData.getDate()));

			ret.add(model);
		}
		return ret;
	}

ただ、サーバ側→クライアント側では、TransModelのコンストラクタにStoreModelを渡したりはできない。(serverパッケージをインポートできないため。)
サーバ側に、ファクトリークラスを作ったりしたらよい?

まとめ

GWTをやる気が薄れてきたので、文字として残しておく。
後で参考になるといいな。