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(); } }