S2Clickアプリケーションの設計方針
S2Clickではアプリケーションを以下のコンポーネントの組み合わせで作成します。 なお、ここではデータベースアクセスにS2JDBCを使用するものと仮定しています。 S2JDBC以外のデータベースアクセスフレームワークを使用する場合はサービスの部分を読み替えてください。
また、本ドキュメントはClickの基本的な知識を有しているものという前提に基づいています。 Clickに関する基礎知識についてはClick Wikiなどを参照してください。
| コンポーネント | 命名規則 | 説明 |
|---|---|---|
| ページ | ルートパッケージ.page.XxxPage | 画面に対応するクラス。初期表示データの取得、ボタンクリックなどのイベント発生時の処理などを行う。
S2ClickPageクラスを継承して実装する。 |
| フォーム | ルートパッケージ.form.XxxForm | 入力値を格納するクラス。フォームの再利用を行わない場合はページクラス内のインナークラスとして作成してもよい。
S2ClickFormを継承して実装する。 |
| サービス | ルートパッケージ.service.XxxService | S2JDBCのJdbcManagerを使用してデータベースアクセスを行うクラス。
小規模なアプリケーションではページクラス内で直接JdbcManagerを使ってもよい。 |
サンプルを通して各コンポーネントの実装方法を紹介します。 このサンプルは入力フォームから投稿したメッセージをデータベースに登録し、 新着順に一覧表示するという簡単なメッセージボードアプリケーションをイメージしています。 また、Clickに関する基本的な知識はすでに持っている前提で説明を行います。
フォームクラス
まずはフォームクラスです。 Clickのサンプルではページクラス内でフォームを組み立てる手法が用いられていますが、 そうするとページクラスがフォームを組み立てるためのコードで埋め尽くされてしまうこと、 また登録画面と編集画面など、類似のフォームの共通化が難しくなってしまうことなどから S2Clickではフォームを単独のクラスとして作成することを推奨しています。
フォームクラスはorg.seasar.s2click.control.S2ClickFormを継承して実装します。
setFieldAutoRegisteration()メソッドにtrueを設定しておくと、
フィールドとして定義されたコントロールが自動的に自分自身に追加されます。
package org.seasar.s2click.example.form;
import org.apache.click.control.Submit;
import org.apache.click.control.TextField;
import org.seasar.s2click.control.S2ClickForm;
public class MessageForm extends S2ClickForm {
private static final long serialVersionUID = 1L;
public TextField name = new TextField("name", true);
public TextField message = new TextField("message", true);
public Submit submit = new Submit("add");
public MessageForm(String name){
super(name);
setFieldAutoRegisteration(true);
setJavaScriptValidation(true);
}
}
ページクラス
続いてページクラスです。 フォームを組み立てるためのコードがフォームクラスに分離された以外は通常のClickのページクラスとそれほど変わりはありません。 フォームクラスはnewして使用し、データベースにアクセスするためのサービスクラスをDIしています。
ページクラスはorg.seasar.s2click.S2ClickPageを継承して実装します。
この例では使用していませんが、S2ClickPageを継承することでバイナリやJSONをレスポンスに書き出すためのメソッドや、
@Requestアノテーションによるリクエストパラメータのフィールドへのバインド機能などを利用することができます。
package org.seasar.s2click.example.page;
import java.util.Date;
import javax.annotation.Resource;
import org.seasar.s2click.example.entity.Message;
import org.seasar.s2click.example.form.MessageForm;
import org.seasar.s2click.example.service.MessageService;
public class MessagePage extends S2ClickPage {
@Resource
protected MessageService messageService;
public MessageForm form = new MessageForm("form");
public MessagePage(){
form.submit.setListener(this, "doAdd");
}
@Override
public void onRender() {
addModel("messageList", messageService.getMessages());
}
public boolean doAdd(){
if(form.isValid()){
Message message = new Message();
message.name = form.name.getValue();
message.message = form.message.getValue();
message.date = new Date();
messageService.insert(message);
setRedirect(MessagePage.class);
return false;
}
return true;
}
}
サービスクラス
最後にサービスクラスです。
ここでは実装を単純にするためS2JDBCが提供するorg.seasar.extension.jdbc.service.S2AbstractServiceを継承していますが、特にその必要はありません。
実際のところ、エンティティとサービスを一対一で作成するケース以外ではS2AbstractServiceは使いづらいでしょう。
小さなアプリケーションではサービスレイヤを設けず、ページクラスに直接JdbcManagerをDIしてデータベースアクセスコードをページクラス内に記述するという選択も考えられますが、
ページクラスにデータベースアクセスコードを含めてしまうとユニットテストが難しくなるというトレードオフがあります。
package org.seasar.s2click.example.service;
import java.util.List;
import org.seasar.extension.jdbc.service.S2AbstractService;
import org.seasar.s2click.example.entity.Message;
public class MessageService extends S2AbstractService<Message> {
public List<Message> getMessages(){
return jdbcManager.from(Message.class).orderBy("messageId desc").getResultList();
}
}