Edited at
Java EEDay 12

JSFのコンセプト(考え方)って?

More than 3 years have passed since last update.


はじめに



12日目です。

Java EE Advent Calendar 2014の12日目です。昨日は@TTakakiyoさんの「Concurrency Utilities for Java EEをつかってみる」でした。明日は、@megascusさんです。


はじめに

本格的にコーディングを初めて1ヶ月に満たない初心者ですが、Java EE Advent Calendar

2014
へのお誘いをいただきチャレンジすることにしました。内容はJSFに関して初歩的な内容について書いています。経験が浅いため、間違いなどあるかもしれません。間違いがあれば指摘いただけると嬉しいです。


自己紹介


某ユーザー系企業でSEをやっています@tatsu983です。業務ではJavaEE7を使った自社製のフレームワーク開発を担当していますが、入社して約6年コーディングすることはほとんどありません。どちらかというとマネージメントがほとんどです。(そんな自分がフレームワークの開発とは・・・と思っていますが、やるからには良いものにしたいという意気込みで取り組んでいます。)

で、開発するフレームワークはJavaEE7がベース(選定理由は様々あります)ということもあり、情報収集目的でJavaOneにも参加し、様々な技術者の方と交流を持つことが出来ました。そんな方々の刺激受けたこともあったり、仕事のキャリアに対する考えもあり、技術力は必要だと感じ自分でもコーディングするなど、手を動かし始めて約1ヶ月が過ぎました。(コーディング歴1ヶ月ですw)JavaのJの字もわからないペーペーですが、技術力向上に努めてます。でも書き始めると難しくもありますが、楽しいですよね。そんな楽しさを日々感じながらコーディングしています。


今回のネタ


JSFの"コンセプト"に合った使い方ってなんだろう、という内容です。

JSFの話をする前に何でコンセプトなんて気にしたかというと、"自己紹介"のパートでも少し触れましたが業務でフレームワーク開発を任されてます。プロジェクトの中で一番苦労した点がコンセプトとか思想決めることだったからです。(過去形になっていますが、今でも答えは出ていない気もします。。)上司からは、フレームワークを作る上でとても重要だと何回も言われました。『思想やコンセプトがあるから、プロジェクトがブレた時の拠り所にもなるし、迷った時の判断基準になる』と。そのためか、何事にもコンセプトを考えながら取り組むようになった気がします。

 で、本題に戻りますがプロジェクトでEE7を使うのだから自分で使ったことないものを社内フレームワークとして推進することなんて出来ないな、と思いJavaEEを使ってアプリ開発しよー!と思いました。そのため開発するためにJSFの利用方法を調べてたら、そんなことどーでも言いよ!!と言われかねない細かいことで迷いましたのでネタにしています。皆さんの意見もいただけると幸いです。


どっちなんだろう


JSFを使って開発するにあたり、様々な方のブログやらsildeshareを拝見させていただいたり、参考書を見てみました。(書籍は主にBeginning JavaEE6わかりやすいJavaEEなどです。洋書もいくつかあさりました。)

結果、xhtml内に記載するEL式とBackingBeanの値をbindingするための実現方法に迷ったんです。(初歩的な内容ですが・・・。)以下にその2つのパターンのbinding方法を記載してみます。

コードは、ポイントになる部分だけ記載します。

まずはxhtmlに記載した内容(かなり簡略化して書いています。)


login.xhtml

    <h:inputText value="#{loginBb1.loginInfo.id}"/>

<h:inputSecret value="#{loginBb1.loginInfo.password}"/>
<h:commandButton value="Login" action="#{loginBb1.doLogin()}"/>

単純なログイン画面にidとpasswordを入力するテキストボックスとログインボタンが配置されているイメージです。

次に、BackingBeanを以下に記載します。


LoginBb1.java

@Named

@RequestScoped
public class LoginBb1 {

@Inject
private LoginService login;
private LoginInfo loginInfo = new LoginInfo();

public String doLogin(){
//簡略化して書いています
boolean auth = login.doLogin(loginInfo);
//中略(認証に成功したら次画面へ)
return "user?faces-redirect=true"
}

//loginInfoのgetter,setterは省略


Login情報を保持するクラスは以下の通りです。


LoginInfo.java

public class LoginInfo {

private String id;
private String pass;
//コンストラクタ,gettter,setterは省略

ここまでが、1つ目のパターンです。LoginInfoという情報の塊をクラスとしてBackingBeanに持たせるというものです。

次は2つ目のパターンです。

xhtmlは以下の通り。(EL式の内容に少し違いがあります。)


login.xhtml

    <h:inputText value="#{loginBb1.id}"/>

<h:inputSecret value="#{loginBb1.password}"/>
<h:commandButton value="Login" action="#{loginBb1.doLogin()}"/>

BackingBeanは以下の通りです。


LoginBb2.java

@Named

@RequestScoped
public class LoginBb2{

@Inject
private LoginService login;
private String id;
private String pass;

public String doLogin(){
//簡略化して書きます
boolean auth = login.doLogin(id, pass);
//中略(認証に成功したら次画面へ)
return "user?faces-redirect=true"
}

//id, passのgetter,setterは省略


後者のパターンは、よくサンプルコードなどでJavaEEのEL式の紹介をする際に見かけます。BackingBeanに直接情報を持たせるものです。

結局この2つのどちらを使っても同じことを実現できるのですが、どちらがJSFのコンセプトとして良いのだろう、って迷ったんです。どっちでも良いから選択肢を持たせているだけかもしれませんが。

イメージはこんな感じです。

パターン1.png

パターン2.png


私がとった方法


私は、入社して依頼コーディングの機会はほとんどありませんでしたが、入社した年に1度だけStruts1を使ったことがあり、フレームワークにはactionやMVCという考え方があることをそこで知りました。なので今回の開発時もStrutsの考え方と対比しながら開発を進めたため、BackingBeanはコントローラーっぽい役割をするものと考えながら進めていました。

ただ、今回のJSFの開発を通じ色んな方とお話をする中で、MVVMという概念を知りました。なんとなくJSFはこの考えに近い気もします。そんなことを考え出すと、BackingBeanは画面の状態を保持した方がいい(画面を表現するクラス)気もしてきて、パターン2の方がJSFの考えに近い気もしてきたんです。ただ、こうすると後々課題も出てきそうだなぁと。。


  • 画面部品がたくさんある場合、BackingBeanが肥大化する(メンテナンスしづらそう)
     

  • BackingBeanの中でSession情報を保持出来るのかなぁ


  • 画面情報をそのままJPAのEntityとして利用しづらくなる


などなど色々頭の中に浮かんできました。

で結局今回は、


  • システムとしてBackingBeanの構成に統一性を持たせたいなぁ

  • パターン1でも画面の状態を一つの意味のある塊(今回の場合はloginInfoという塊)として考えよう

 

などを考えてパターン1をシステム全体に用いて開発をしました。こうしておくことで、意味をもった情報の塊をSessionとして持つこともできます。(以下ではLoginUserを意味を持った情報の塊としています。)


LoginBb3.java

@Named

@RequestScoped
public class LoginBb3 implements Serializable {

@Inject
private LoginUser loginUser;

public String doLogin(){
//中略
return "user?faces-redirect=true"
}

//loginUserのgetter,setter



LoginUser.java

@Named

@SessionScoped
public class LoginUser implements Serializable {

private String id;
private String name;
private String email;

//getter,setter


ただ、パターン1にしたのは自分案としてであり、システムの要件によっても変わってくるかもしれません。Strutsからの移行が要件になると、なるべくStrutsで作成したシステム構成と同じ構成にした方が良いかもしれません。一概にこれが良い、とは言えないと思います。逆に言うとどんな構成にしろ柔軟に対応出来る良さがあるとも言える気がします。


まとめ



結局のところJSFのコンセプトって

自分で答えを出すことは出来ませんでした、というオチです。。今回の自分のとった考えがJSFのコンセプトというか考え方に沿っているかはわかりませんし、答えは無いような気もします。

ただ、自分がどのようなコンセプトでシステムを開発するかが重要だと思います。

そのため、パターン1と2が合わさっているシステムもあるかもしれません。また、1つの画面に複数のBackingBeanが存在するような構成になることもあるかもしれませんし、逆に複数の画面に対して1つのBackingBeanになることもあるかもしれません。

ただ、それが個人やプロジェクトメンバーで考えて出したシステムの思想やコンセプトであれば良いと思います。


終わりに

コーディング初心者が記載した内容なので、コードや考え方に間違えがあるかもしれませんし、もしかしたがJSFはこんなコンセプトです、というのがあるかもしれません。是非指摘していただきたいですし、皆さんはどんな風に考えているかコメントいただけると幸いです。

それでは、明日のJava EE Advent Calendar 2014は@megascusです。