最近Javaしてますか?
昔はServletとJSPでやったな・・・Seasar2には感動したっけ、そんな思い出が浮かんだとしたらあなたのJavaはJ2EE、JavaEE的には5.0ぐらいで止まっているといわなければなりません。
※Seasar2は2016/9/26にサポートが停止になります。OSSであるためforkされメンテナンスが続く可能性はありますが、一つの時代の区切りになると思います。
あれからJavaも進化を重ね、最新版のJavaEE7.0では他言語のフレームワークの生産性にも引けを取りません。
まだJavaやってるの(苦笑)の時代が長すぎたのか、2013年のリリースにもかかわらずJavaEE7.0についての記事は充実しているとは言えない状況です。ただ、その仕組みは素晴らしいものがあるのでこれを機に久々にJavaでもやってみるかなと思ってもらえれば幸いです。
※2017/9/21、色々ありましたがとうとうJavaEE8がリリースされました!JavaEE8ベースの記事の公開を検討しています。
今回は技術インターンを行うに当たって事前に調べた内容が元になっており、サンプルコードは以下に置いておきました。Wikiには参考資料を張り付けておいたので、実際に作成する際の参考にしてもらえればと思います。
なお、記載の分量を見れば一目瞭然ですがEJB/JPAは今回使っていないのであまり詳しく触れていません。そちらも含め、JavaEE7.0の機能については以下にとてもよくまとまっているので、ご参考ください。
JavaEE7.0のフレームワーク
JavaEE7におけるアプリケーションは、大体以下のような構成になります。
JSF/Backing Bean
昔のJSP/Servletに代わり、JSF/Backing Beanを使うのがJavaEE7.0ではスタンダードです(もちろんServlet/JSPも使えます)。
JSF/Backing BeanはちょうどViewModel型のJavaScriptフレームワークのような感じで、Backing Beanで定義したオブジェクトを簡単にJSF、具体的にはxhtmlで作成された画面にバインドさせることができます。
JSF側
<h:dataTable value="#{IndexBean.hotels}" var="h">
<h:column>#{h.hotelName}</h:column>
<h:column>#{h.latitude}</h:column>
<h:column>#{h.longitude}</h:column>
</h:dataTable>
Backing Bean側
@Named("IndexBean")
@RequestScoped
public class IndexBean implements Serializable{
private ArrayList<Hotel> hotels = new ArrayList<Hotel>();
public ArrayList<Hotel> getHotels() {
return hotels;
}
public void setHotels(ArrayList<Hotel> hotels) {
this.hotels = hotels;
}
}
これで画面とサーバー上のオブジェクトを簡単に対応してバインドさせることもできます。サーバー側から送るだけでなく、フォームなどから受け取る内容もBackingBeanにひも付けることができます。
JSFに関する内容は新旧混在していてかなり見つけづらいですが、こちらにまとめてくださっています。
ここでJavaってまだGetter/Setterいちいち書かないといけないの?超めんどい!という方にはLombokがあるのでご安心を。Lombokを使って書くと、以下のように書けます。
import lombok.Getter;
import lombok.Setter;
@Named("IndexBean")
@RequestScoped
public class IndexBean implements Serializable{
@Getter @Setter private ArrayList<Hotel> hotels = new ArrayList<Hotel>();
}
アノテーションを付けることで自動的に生成をしてくるのです。ちゃんと、Eclipseなどの統合開発環境上でもコード補完はgetHotels
などと出してくれます。これでモデルに使うPOJO(Plain Old Java Object、要するに普通のJavaクラス)もシンプルになります。
@Data
public class Hotel {
private String hotelNo = "";
private String hotelName = "";
private double latitude = 0;
private double longitude = 0;
}
単純な構造として使うようなクラスは、もはやGetter/Setterを付ける必要すらありません。@Data
、これで終了。
Lombokは当然JavaEEとは何も関係ないですが、2015年にJavaを書くならぜひ使いたいライブラリです。
JAX-RS
JAX-RSは、RESTfulなサービスを実装するための仕組みです。JSFは画面を作るには便利なのですが、画面コンポーネントで組み立てていくような形になるのでJavaScript側の処理と連携させようとすると面倒なこともあります。
そんな時はJAX-RSでサーバーサイドの処理をWebサービス化し、JavaScript側とうまく連携できるようにすることができます。
以下は、ホテルの一覧を取得する処理(find
)と、個々のホテルの詳細を取得するための処理(get
)をイメージしたサンプルコードです。
@Path("/hotels")
public class HotelService {
@GET
@Path("/find")
@Produces({ "application/json" })
public Hotel[] find(
@DefaultValue("0.0") @QueryParam("lat") double lat,
@DefaultValue("0.0") @QueryParam("lng") double lng){
ArrayList<Hotel> hotels = RakutenTravelApi.findHotels(lat, lng);
return hotels.toArray(new Hotel[hotels.size()]);
}
@GET
@Path("/{hotelNo}")
@Produces({ "application/json" })
public Hotel get(@PathParam("hotelNo") String hotelNo){
return RakutenTravelApi.getHotelInfo(hotelNo).orElse(new Hotel());
}
}
いかがでしょうか。見ただけでも、なんとなく処理がイメージできると思います。
アノテーションにより対応するリクエスト種別(@GET
)、サービスのパス(@Path
)、レスポンスタイプ(@Produces
)を指定すればあとは中の処理を書くだけです。引数はクエリ引数であれば@QueryParam
、パスから取得するなら@PathParam
とこちらもアノテーションで指定し、@DefaultValue
でデフォルト値までつけることができます。
returnに際しては特別な変換をする必要はなく、上記の例では普通にJavaオブジェクトを返していますが、リクエストを送るとちゃんとJSONオブジェクトになって返ってきます。これは、作っていてかなり快適でした。
JAX-RSはWebサービスを作るだけではなく、呼び出すクライアント側の実装も含んでいます。これにより、サーバー内でWeb APIを呼び出すといった処理も以下のようにずいぶん簡単に書けるようになりました。
String url = "http://xxxxx";
Client client = ClientBuilder.newClient();
WebTarget target = client.target(URI.create(url));
String response = target.request().get(String.class);
JAX-RSの詳細については、以下が分かりやすいです。
- RESTful な Web サービスを Java 技術で作成する (2010年と少し古め)
- Chapter 3. JAX-RS Application, Resources and Sub-Resources
EJB
サービス、ビジネスロジックを書いておくのに良い仕組みです。非同期で実行したい処理などを簡単に書くことができます。
JPA
これはJava版O/Rマッパ―のような機能で、これによりJDBCを使っていたあの頃は去りオブジェクトの取得/保存が非常に容易になりました。
開発環境
JavaEEの開発環境について触れておきます。
開発環境は普通のJavaと変わらないのでEclipse/NetBeans/IDEAがスタンダードですが、IDEAは無償版の場合JavaのWebアプリケーション開発のサポートが弱いので、EclipseかNetBeansが良いと思います(Java8対応も含めると若干NetBeansに軍配が上がるかもしれません)。
プロジェクトの形態としてはMavenかGradle・・・と行くのが通常だと思いますが、個人的には初めて、初めてでなくとも久々にやるなら普通にWebプロジェクトから始めた方がいいと思います。なぜなら、Maven/Gradleに触れたらあなたは高い確率でJavaを嫌いになると思うからです。この辺りのパッケージ管理はまだ他の言語のように進歩しておらず、きっとその手間に愕然とすると思います。
最初にWebプロジェクトから始めてもEclipseであれば途中からMaven/Gradleプロジェクトに変換可能なので、必要に迫られたら変換すればいいと思います。JavaEE7はそれ単体で十分開発が可能なので、いろいろライブラリを入れないと進まない、ということはありません。
今回は最終的にGradleプロジェクトに切り替えましたが、JavaEE7開発を行うに当たっての最小限のスクリプトにしてありますので、参考にしてもらえればと思います。
稼働環境
JavaEE7を動かすことができるのは、今のところJBossが開発しているWildflyかOracleのGlassfishになります。
JavaEEを落としに行くと頼んでもいないのにGlassfishが落ちてきて、おいおいなんだよと思うかもしれません。これはOracleの策略・・・ではなく、JavaEE7は実態としては仕様であり、その実装がWildflyやGlassfish、という関係になっているので、参照実装の一つであるGlassfishが落ちてくるのはOracleとしては当然なのです。
よって、最初に戻りますがJavaEE7の開発にはその実装であるWildflyかGlassfishどちらかが必要になります。初めてJavaEE7に触れる場合は、公式の実装であるGlassfishの方がよいと思います。ただ、GlassfishはCommercial Editionが打ち切られており、商用サポートを受けるならWebLogicにしなさいというのがOracle様のスタンスです。
個人的にはOracle様にはDB面でもお世話になったので、当然開発環境はEclipseで稼働環境はWildflyにしています。ただ、公式参照実装というだけありGlassfishで動いてWildflyで動かない、ということもありました(今回のサンプルもjax-rsのClientにプロキシ設定を渡すところがうまく動かず、最終的には断腸の思いでGlassfishにて稼働の確認をしています)。
さて、Javaを書きたくなったでしょうか。
最近はやっぱり型がある言語で作りたい、ということもあると思うので、その勇でありここにきて進化を遂げたJavaに今一度触れてみるのも良いと思います。