mike-neckのブログ

Java or Groovy or Swift or Golang

JSFでbacking beanの[at]PostConstructがいつ実行されるか、中途半端にまとめた

わかりやすいJavaEEウェブ システム入門CDIの章を読んでたのですが…

  • 別にロガーを@Injectしてもおもろくない
  • FileUtil@Injectしてもおもろくない

という理由で、自作クラスを@Injectして遊んでたけど、JSF力なさすぎて一日潰したので、そのまとめ。


Abstract

最初の画面

f:id:mike_neck:20150329073341p:plain

これの選手番号のリンクを押したら

f:id:mike_neck:20150329073413p:plain

この画面になる

新規登録を押したら

f:id:mike_neck:20150329073439p:plain

この画面になる

で、編集完了したら元の画面に戻る感じ

f:id:mike_neck:20150329073605p:plain

(上記は新規登録の場合のイメージ)

ようにしたい


環境

  • OS : Mac OSX 10.10.2
  • サーバー : Glass Fish 4.1
  • Javaバージョン : Oracle Java8u40
  • IDE : IntelliJ IDEA 14.1

成功したやり方

画面とバッキングビーン

  • 最初の画面 → @SessionScopedなbacking bean(@ManagedBean(name="index"))
  • 編集の画面 → @RequestedScopedなbacking bean(@Named("edit"))

@Injectを使ってるとこ

  • indexeditの双方にPlayerRepositoryという単なるList<Player>(実装はCopyOnWriteArrayList<>)をラップしただけのシングルトンオブジェクト(@Singletonつけてる)を突っ込んでる
  • editの方は@ManagedProperty("#{index}")で最初の画面のbacking beanを受け取ってる

アクション

  • 最初の画面で選手番号のリンクをクリックした場合→#{index.edit(p.id)}を呼び出して(pPlayerってオブジェクト)、編集の画面に移る
  • 最初の画面で新規登録のボタンを押した場合→#{index.create()}を呼び出して、編集の画面に移る
  • 編集の画面で姓名と名前と学年からフォーカスが外れた時にajaxでvalidationかます
  • 編集の画面でキャンセルを押した場合→#{edit.cancel()}を呼び出して何もせずに最初の画面に戻る
  • 編集の画面で登録ボタンを押した場合→#{edit.register()}を呼び出して、PlayerRepositoryList<Player>に追加あるいは、List<Player>のオブジェクトを更新してから最初の画面に戻る

状態の受け渡し方

新規登録なのか、それとも既存選手の編集なのかを編集画面に渡したいので、indexの方に一度状態を持たせてから、editに移動させてる

indexの方のバッキングビーン(IndexBean)

    @Inject
    private PlayerRepository repo;

    private boolean newPlayer;
    private Long current;
    public String edit(Long id) {
        this.newPlayer = false;
        this.current = id;
        return EDIT;
    }
    public String create() {
        this.newPlayer = true;
        return EDIT;
    }

editの方のバッキングビーン(EditBean)

    @Inject
    private PlayerRepository repo;

    @ManagedProperty("#{index}")
    private IndexBean index;

    private boolean newPlayer;
    private Long id;

    @PostConstruct
    public void init() {
        this.newPlayer = index.isNewPlayer();
        if(!this.newPlayer) {
            this.id = index.getCurrent();
            Player p = repo.findPlayerById(this.id);
            // 以下略
        }
    }

うまくいった理由(適当に考察)

  • backing beanの初期化は下に貼り付けたツイートのようになっているっぽいので、@PostConstructの前の段階でeditの方にはindexrepoが設定されている
  • @ViewScopedだとajaxリクエストが発生する、登録ボタンを押すなどのタイミングでインスタンスが生成されないので、newPlayerが書き換えられることがない(@RequestScopedにしていたら、タブ二つで片方は新規登録、片方は編集操作すると、新規登録の方でnewPlayerが書き換えられていてヌルポで落ちた)

考察その2

IndexBeanの方は@RequestScopedでもよくね?(認証が必要なシステムのパターンを考慮していない)

結論

こっち見たほうが参考になる

d.hatena.ne.jp

kikutaro777.hatenablog.com

qiita.com


あと、わかりやすいJavaEEウェブ システム入門の書評(別に頼まれたわけではない)

  • なるほど、わかりやすい
  • 著者のサイトからサンプルコード落とせるので、わからなくなったら見られるのもよい
  • JavaEEに関する本はNetBeansが前提になっているので、他の有名IDEとか弱小IDEのことも忘れないであげてください。というか、IDE非依存に…(Oracleチュートリアルを嫁という話だった(´・ω・`))
  • Javaを書いている時間よりもxhtmlを書いている時間よりも、圧倒的にCSS書いている時間のほうが長くてつらい(grunt使うか、べつに画面の見栄えなんてどうでもいいという話だった(´・ω・`))
  • xhtmlを書いている時間のほうがJavaを書いている時間よりも長くてつらい

おわり