<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>技術ブログ &#124; 株式会社クラウディア &#187; プログラム</title>
	<atom:link href="https://cloudear.jp/blog/?cat=21&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://cloudear.jp/blog</link>
	<description>クラウド専門の業務システム・社内ツール開発</description>
	<lastBuildDate>Fri, 12 Nov 2021 05:00:35 +0000</lastBuildDate>
	<language>ja</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.0.1</generator>
	<item>
		<title>JPAを深掘りする〜Criteria APIで型安全な検索を追求しよう！【応用編】</title>
		<link>https://cloudear.jp/blog/?p=2143</link>
		<comments>https://cloudear.jp/blog/?p=2143#comments</comments>
		<pubDate>Fri, 18 Mar 2016 03:11:58 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[O/Rマッパー]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=2143</guid>
		<description><![CDATA[JPAを深掘りするシリーズの応用編です。 前回はCriteria APIの基本と利点をご紹介しました。今回はCriteria APIの実戦的な機能をいろいろとご紹介します。 準備・エンティティクラスとメタモデルクラスのサ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>JPAを深掘りするシリーズの応用編です。</p>
<p>前回はCriteria APIの基本と利点をご紹介しました。今回はCriteria APIの実戦的な機能をいろいろとご紹介します。</p>
<p><span id="more-2143"></span></p>
<h2>準備・エンティティクラスとメタモデルクラスのサンプル</h2>
<p>次のようなエンティティクラスとメタモデルクラスが存在することを前提に進めていきます。</p>
<p>まずはUserエンティティクラスです。</p>
<pre class="lang:java decode:true" title="User.java">package sandbox.entity;

import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long      id;

    @Column(length = 150, unique = true, nullable = false)
    String    name;

    // getter/setterは省略
}
</pre>
<p>次にUserエンティティのプロパティの型を表すメタモデルクラスです。</p>
<pre class="lang:java decode:true " title="User_.java">package sandbox.entity;

import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@Generated(value="Dali", date="2016-02-12T22:59:19.623+0900")
@StaticMetamodel(User.class)
public class User_ {
	public static volatile SingularAttribute&lt;User, String&gt; name;
	public static volatile SingularAttribute&lt;User, Long&gt; id;
}
</pre>
<p>それではCriteria APIを見ていきましょう。</p>
<h2>Where条件にメタモデルクラスを使う</h2>
<p><strong>メタモデルクラス</strong>は、Criteria APIによるクエリの型安全性を高めるという重要な役割を持っています。</p>
<p>冒頭で示したUserというエンティティクラスをnameプロパティの値で絞り込むクエリを作ってみましょう。</p>
<pre class="lang:java decode:true ">private static void selectUsersByName(final EntityManager em, final String pUserName) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;User&gt; query = builder.createQuery(User.class);
    final Root&lt;User&gt; root = query.from(User.class);
    query.where( //
            // メタモデルクラスを使ってカラムを指定する
            builder.equal(root.get(User_.name), pUserName) //
    );
    final List&lt;User&gt; result = em.createQuery(query).getResultList();
    for (final User user : result) {
        System.out.println(user);
    }
}
</pre>
<p>eclipseの入力補完の様子を見ると、fromに指定したエンティティクラスに応じたメタモデルクラスが候補として表示されることが分かると思います。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/jps-typesafe-query.png"><img class="alignnone size-full wp-image-2123" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/jps-typesafe-query.png" alt="jps-typesafe-query" width="593" height="170" /></a></p>
<p>&nbsp;</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/jps-typesafe-query-2.png"><img class="alignnone size-full wp-image-2124" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/jps-typesafe-query-2.png" alt="jps-typesafe-query-2" width="644" height="135" /></a></p>
<h2>Where句に複雑な条件を設定する</h2>
<p>検索画面のようにWhere句が動的かつ複雑になる時に、Criteria APIは威力を発揮します。例えば入力のある条件はWhere句に加えるが、入力のない条件はWhere句に加えない、という処理をJPQLで書くのは割と大変です。</p>
<pre class="lang:java decode:true">private static void selectUsersByName(final EntityManager em, final String name) {
    final StringBuilder s = new StringBuilder("select e from User e where 1 = 1");
    if (name != null) {
        s.append(" and e.name = :name");
    }

    final TypedQuery&lt;User&gt; query = em.createQuery(new String(s), User.class);

    if (name != null) { // 存在しないパラメータを設定すると例外が生じるため、再度チェックせざるを得ない！
        query.setParameter("name", name);
    }

    final List&lt;User&gt; result = query.getResultList();
    for (final User user : result) {
        System.out.println(user);
    }
}
</pre>
<p>これをCriteria APIで書き直すと、とても素直なプログラムになります。</p>
<pre class="lang:java decode:true ">private static void selectUsersByName(final EntityManager em, final String name) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;User&gt; query = builder.createQuery(User.class);
    final Root&lt;User&gt; root = query.from(User.class);

    final List&lt;Predicate&gt; where = new ArrayList&lt;&gt;();
    if (name != null) {
        where.add(builder.equal(root.get(User_.name), name));
    }

    query.where(where.toArray(new Predicate[where.size()]));

    final List&lt;User&gt; result = em.createQuery(query).getResultList();
    for (final User user : result) {
        System.out.println(user);
    }
}
</pre>
<h2> 関連クラスを同時に取得する</h2>
<p>JPAの強みの１つにエンティティクラスの関連をコードで表現出来ることがあります。下記はUserを親に持つTagというエンティティを作っています。</p>
<pre class="lang:java decode:true">package sandbox.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Tag {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long   id;

    @Column(length = 50, unique = false, nullable = false)
    String name;

    @ManyToOne(fetch = FetchType.LAZY)
    User   user;

    @Column(nullable = false)
    long   starCount;

    // getter/setterは省略
}</pre>
<p>Tagを取得する際、親のUserも同時に取ってくるようなクエリを作ってみましょう。</p>
<pre class="lang:java decode:true">private static void selectTagWithUser(final EntityManager em) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;Tag&gt; query = builder.createQuery(Tag.class);
    final Root&lt;Tag&gt; root = query.from(Tag.class);

    root.fetch(Tag_.user, JoinType.LEFT); // 関連エンティティを同時に取ってくるように指定

    final List&lt;Tag&gt; result = em.createQuery(query).getResultList();
    for (final Tag tag : result) {
        System.out.println(tag.getUser());
    }
}
</pre>
<p>9行目がポイントです。実はこの行がなくても関連エンティティは取得できるのですが、SQLの実行回数が格段に変わってきます。俗に言う「N+1問題」を回避する手法です。</p>
<h2>関連先のエンティティの条件を指定する</h2>
<p>JPAの強力な機能の１つに、関連先エンティティの条件指定がとても簡単な点があります。</p>
<pre class="lang:java decode:true">private static void selectTagByUserName(final EntityManager em, final String pUserName) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;Tag&gt; query = builder.createQuery(Tag.class);
    final Root&lt;Tag&gt; root = query.from(Tag.class);

    query.where(builder.equal(root.get(Tag_.user).get(User_.name), pUserName));

    final List&lt;Tag&gt; result = em.createQuery(query).getResultList();
    for (final Tag tag : result) {
        System.out.println(tag);
    }
}</pre>
<p>6行目がポイントです。「Tagクラス#userプロパティ」→「Userクラス#nameプロパティ」とたどって条件指定しています。SQLで同じことをしようとするとJOINを書く必要があり手間がかかるところですが、JPAではかなりシンプルに書けることが分かります。</p>
<h2>Where句に IN条件を指定する</h2>
<p>IN条件は少し特殊な書き方をするのでハマることがあります。</p>
<pre class="lang:java decode:true">private static void selectUsersByNames(final EntityManager em, final String... names) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;User&gt; query = builder.createQuery(User.class);
    final Root&lt;User&gt; root = query.from(User.class);

    if (names != null &amp;&amp; names.length &gt; 0) {
        query.where(root.get(User_.name).in(names));
    }

    final List&lt;User&gt; result = em.createQuery(query).getResultList();
    for (final User user : result) {
        System.out.println(user);
    }
}
</pre>
<p>7行目でIN条件を指定しています。CriteriaBuilderを使わない点に注意してください。</p>
<p>また要素数が0の時の挙動は、残念ながらDB製品依存となるようなので、プログラムで明示的にチェックするのが無難でしょう。</p>
<h2>Tupleを使って柔軟な結果を得る</h2>
<p>Tupleという汎用クラスを使えばエンティティにとらわれない形でデータを取得できます。例えば、JOINを使って複数のテーブルからデータを取得しつつ集計するような用途に有用です。</p>
<p>ただし、型安全性が失われる点には注意が必要です。</p>
<pre class="lang:java decode:true">private static void selectTupleWithJoin(final EntityManager em) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();

    // Tupleで結果を受け取る
    final CriteriaQuery&lt;Tuple&gt; query = builder.createTupleQuery();

    // Tagを主テーブルにする
    final Root&lt;Tag&gt; root = query.from(Tag.class);

    // JOINする
    final Join&lt;Tag, User&gt; join = root.join(Tag_.user);

    final Path&lt;String&gt; userName = join.get(User_.name);

    // ユーザ名で集計する
    query.groupBy(userName);

    // Userから特定のカラムのみ取得しつつTagのstarCountを合計する
    // 後で取り出しやすいように、カラムには別名を付けておく
    query.multiselect( //
            userName.alias("user_name") //
            , builder.sum(root.get(Tag_.starCount)).alias("tag_count") //
    );

    final List&lt;Tuple&gt; result = em.createQuery(query).getResultList();
    for (final Tuple e : result) {
        System.out.println(e.get("user_name") + " " + e.get("tag_count"));
    }
}</pre>
<h2>任意のデータクラスをクエリの結果の型にする</h2>
<p>Tupleの弱点は、Tupleが汎用的すぎて「どんなデータがいくつ入っているか分かりにくい」ことです。これを補うために、任意の型をクエリの結果とすることができます。</p>
<p>Tupleの例を書き直してみます。まずは結果を受け取るためのクラスを作ります。コンストラクタで全ての値を受け取るようにする必要があります。</p>
<pre class="lang:java decode:true">public class StarSummary {

    private final String userName;
    private final long   tagCount;

    public StarSummary(final String pUserName, final long pTagCount) {
        this.userName = pUserName;
        this.tagCount = pTagCount;
    }

    // getterは省略
}</pre>
<p>作ったクラスをクエリの結果とするには、<code>CriteriaBuilder#construct(Class, Selection&lt;?&gt;...)</code>を使ってクエリを組み立てます。</p>
<pre class="lang:java decode:true">    private static void selectStartSummary(final EntityManager em) {
        final CriteriaBuilder builder = em.getCriteriaBuilder();
        final CriteriaQuery&lt;StarSummary&gt; query = builder.createQuery(StarSummary.class);
        final Root&lt;Tag&gt; root = query.from(Tag.class);

        final Join&lt;Tag, User&gt; join = root.join(Tag_.user);

        query.select( //
                builder.construct(StarSummary.class //
                , join.get(User_.name) //
                , builder.sum(root.get(Tag_.starCount)) //
        ));
        query.groupBy(join.get(User_.name));

        final List&lt;StarSummary&gt; result = em.createQuery(query).getResultList();
        for (final StarSummary e : result) {
            System.out.println(e);
        }
    }
</pre>
<p>9〜11行目でデータクラスを扱っています。</p>
<p>Tupleに比べ扱いやすい型で結果を得られますが、一方でコンストラクタ引数の順番に依存するプログラムとなってしまうのが弱点です。ですがTupleの「どんなデータがいくつ入っているか分かりにくい」という欠点はとても重大ですので、できれば、こちらのデータクラスを使う方が望ましいです。</p>
<h2>型安全になりきれていない箇所</h2>
<p>ここまで見てきたように、Criteria APIは型安全にクエリを組み立てられる非常に便利な機能なのですが、残念ながら型安全になりきれていない箇所があります。代表的なのは<code>CriteriaBuilder#equal(Expression&lt;?&gt; exp, Object value)</code>メソッドです。</p>
<p>例えば次のコードを見てください。</p>
<pre class="lang:java decode:true">    query.where( //
        builder.equal(root.get(User_.name), pUserName) //
    );
</pre>
<p>これを次のように書き間違えたとしても、コンパイルエラーにはならないのです。</p>
<pre class="lang:java decode:true">    query.where( //
        builder.equal(root.get(User_.id), pUserName) //
    );
</pre>
<p>このケースでは実行時例外がスローされますが、場合によっては例外がスローされず普通に実行されてしまうため、分かりにくいバグの原因となる可能性があります。</p>
<p>このメソッドのシグニチャが</p>
<pre class="lang:java decode:true ">&lt;C&gt; Predicate equal(Expression&lt;C&gt; exp, C value)</pre>
<p>となっていればよかったのに・・・と思えてなりません。頻繁に使うメソッドだけに残念です。</p>
<h2>JPAのその他の機能</h2>
<p>最後に、ちょっとした便利機能をいくつか紹介しておきます。</p>
<h3>ページングに使える２つのメソッド</h3>
<p>Webアプリケーションでは検索結果が大量になる場合、ページング表示するのが普通です。JPAには簡単にページングを実装するためのメソッドがあります。</p>
<p><code>setFirstResult()/setMaxResults()</code>です。</p>
<pre class="lang:java decode:true">private static List&lt;User&gt; selectUsersWithPaging(final EntityManager em, final int pPageIndex, final int pCountPerPage) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;User&gt; query = builder.createQuery(User.class);
    query.from(User.class);
    return em.createQuery(query) //
            .setFirstResult(pPageIndex * pCountPerPage) //
            .setMaxResults(pCountPerPage) //
            .getResultList();
}
</pre>
<p>7行目と8行目でページングを指定しています。</p>
<h3>結果が必ず1件と分かっている場合に使えるメソッド</h3>
<p>結果が必ず1件と分かっている時には<code>getSingleResult()</code>メソッドが使えます。</p>
<pre class="lang:java decode:true">private static void countAllUsers(final EntityManager em) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;Long&gt; query = builder.createQuery(Long.class);
    final Root&lt;User&gt; root = query.from(User.class);

    query.select(builder.count(root));

    final long count = em.createQuery(query).getSingleResult().longValue();
    System.out.println(count);
}
</pre>
<p>ただし、結果が1件でなかった時は例外がスローされますので、絶対に1件と確信が持てる場合にのみ使ってください。</p>
<h2> まとめ</h2>
<p>Criteria APIを中心に、２回に渡ってJPAの様々な機能を解説してきましたがいかがでしたでしょうか。</p>
<p>JPAには他にも便利で重要な機能がたくさんあります。特にエンティティクラスの設計は工夫のしがいがあり、別の機会でご紹介したいところです。</p>
<p>非常にパワフルなJPA。JavaEEを使う場合はぜひJPAを使って効率的かつ安全にDBアクセスを実装していただきたいと思います。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=2143</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JPAを深掘りする〜Criteria APIで型安全な検索を追求しよう！【基本編】</title>
		<link>https://cloudear.jp/blog/?p=2101</link>
		<comments>https://cloudear.jp/blog/?p=2101#comments</comments>
		<pubDate>Mon, 22 Feb 2016 02:10:59 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[O/Rマッパー]]></category>
		<category><![CDATA[データベース]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=2101</guid>
		<description><![CDATA[今回はJavaEEの中でも特に重要な「JPA（Java Persistence API）」を深掘りしてみます。基本編と応用編の２回に渡ってじっくりとJPAをご紹介します。 JPAとは JPAは一言で言えば「高機能なDBア [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>今回はJavaEEの中でも特に重要な<strong>「JPA（Java Persistence API）」</strong>を深掘りしてみます。基本編と応用編の２回に渡ってじっくりとJPAをご紹介します。</p>
<h2>JPAとは</h2>
<p>JPAは一言で言えば「高機能なDBアクセスフレームワーク」です。DBアクセスフレームワークは実に様々なものがありますが、JPAの特徴は</p>
<p><span id="more-2101"></span></p>
<ul>
<li>エンティティクラスへの操作を通してDB操作を実現する（DBの都合はプログラマから極力隠される）</li>
<li>型安全を追求するための様々な機能を備える</li>
</ul>
<p>が挙げられます。Javaの良さを引き出す工夫に満ちたフレームワークと言えるでしょう。</p>
<p>様々な機能を備えたJPAですが、本エントリでは、検索、中でもCriteria APIを使った型安全な検索を中心にご紹介します。コードをしっかり載せていきますので、Criteria APIのコンセプトを感じ取っていただけると思います。</p>
<p>なお、JPAを動作させる環境を構築する方法は「<a title="JavaEEだけでここまで出来る！GlassFish+Eclipseで高速Webアプリ開発【環境構築編】" href="https://cloudear.jp/blog/?p=1375">JavaEEだけでここまでできる！GlassFish+Eclipseで高速Webアプリ開発【環境構築編】</a>」をご覧下さい。</p>
<h2>準備１・メタモデルクラスを自動生成する設定</h2>
<p>メタモデルクラスとは、エンティティクラスのプロパティに関する情報を表すクラスであり、型安全にJPAを使うためには欠かせないクラスです。</p>
<p>例えば次のようなエンティティクラスがあったとしましょう。</p>
<pre class="lang:java decode:true" title="User.java">package sandbox.entity;

import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long      id;

    @Column(length = 150, unique = true, nullable = false)
    String    name;

    // getter/setterは省略
}
</pre>
<p>このエンティティクラスに対するメタモデルクラスは次のようになります。</p>
<pre class="lang:java decode:true " title="User_.java">package sandbox.entity;

import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@Generated(value="Dali", date="2016-02-12T22:59:19.623+0900")
@StaticMetamodel(User.class)
public class User_ {
	public static volatile SingularAttribute&lt;User, String&gt; name;
	public static volatile SingularAttribute&lt;User, Long&gt; id;
}
</pre>
<p>メタモデルクラスはeclipseのような開発環境に自動で作ってもらうことができますので、有効にしておきましょう。</p>
<p>ecliseの場合の手順を紹介しておきます。プロジェクトのプロパティを開き、「プロジェクト・ファセット」から「Convert to faceted form&#8230;」をクリックします。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/convert-to-faceted-form.png"><img class="alignnone size-full wp-image-2107" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/convert-to-faceted-form.png" alt="convert-to-faceted-form" width="833" height="348" /></a></p>
<p>&nbsp;</p>
<p>プロジェクト・ファセットが有効になったので、JPAサポートを有効にします。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/project-facets-jpa.png"><img class="alignnone size-full wp-image-2109" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/project-facets-jpa.png" alt="project-facets-jpa" width="806" height="408" /></a></p>
<p>ここで「 OK」を押していったんプロパティ画面を閉じます。</p>
<p>再びプロパティ画面を開くと「JPA」という設定項目が増えていますので、メタモデルクラスの自動生成を有効にします。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/eclipse-jpa-metamodel.png"><img class="alignnone size-full wp-image-2110" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/eclipse-jpa-metamodel.png" alt="eclipse-jpa-metamodel" width="834" height="713" /></a></p>
<p>これで、エンティティクラスに変更が入る度にメタモデルクラスが自動生成されます。メタモデルクラスの名前はエンティティクラスの名前の後ろに _ を付けたものになります。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/entity-metamodel.png"><img class="alignnone size-full wp-image-2113" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/entity-metamodel.png" alt="entity-metamodel" width="268" height="81" /></a></p>
<p>&nbsp;</p>
<h2>準備２・SQLをコンソールに出力する設定</h2>
<p>JPAを使いこなすコツはJavaコードを中心に考えることですが、さすがにSQLが見えないと辛すぎます。せめてコンソールにSQLを出力するようにしておきましょう。JPAの設定ファイルであるpersistence.xmlにプロパティを追記します。</p>
<h3>EclipseLinkの場合</h3>
<pre class="lang:xhtml decode:true">&lt;property name="eclipselink.logging.level.sql" value="FINE" /&gt;
&lt;property name="eclipselink.logging.parameters" value="true" /&gt;
&lt;property name="eclipselink.logging.logger" value="org.eclipse.persistence.logging.DefaultSessionLog"/&gt;</pre>
<h3>OpenJPAの場合</h3>
<pre class="lang:xhtml decode:true">&lt;property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"/&gt;
&lt;property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" /&gt;</pre>
<p>APサーバにGlassFishを使っているのであれば、EclipseLinkの方を設定してください。</p>
<h2>スキーマ定義をエンティティクラスで行う</h2>
<p>JPAの良さを引き出すコツは、Javaコードを中心に考えることです。まずはスキーマ定義をエンティティクラスで行うようにしてみましょう。</p>
<p>ただ、実はJPAの仕様にはエンティティクラスからDDLを作る機能は含まれていません。JPAの実装であるEclipseLinkやOpenJPAの機能を使います。通常、persistence.xmlにプロパティを追記します。</p>
<h3>EclipseLinkの場合</h3>
<pre class="lang:xhtml decode:true" title="persistence.xml">&lt;property name="eclipselink.ddl-generation" value="create-tables" /&gt;</pre>
<h3>OpenJPAの場合</h3>
<pre class="lang:default decode:true">&lt;property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" /&gt;</pre>
<p>APサーバにGlassFishを使っているのであれば、EclipseLinkの方を設定してください。</p>
<h2>Criteria APIによる検索</h2>
<p>JPAの検索には、JPQLとCriteria APIの２つのやり方があります。JPQLは文字列でクエリを記述するため、コンパイル時に型チェックが全く働きません。</p>
<p>例えば以下のコードは実行時にClassCastExceptionがスローされてしまいます。</p>
<pre class="lang:java decode:true">private static void selectByJPQL(final EntityManager em) {
    final String q = "select e from Tag e";
    for (final User user : em.createQuery(q, User.class).getResultList()) {
        System.out.println(user);
    }
}
</pre>
<p>よく見ると、クエリ文字列が<code>from Tag</code>となっています。結果のエンティティは<code>User</code>型で受けていますから、型が異なっていおり、<strong>実行時に</strong>ClassCastExceptionがスローされるのです。</p>
<p>しかしCriteria APIを使うと、このようなミスは<strong>コンパイル時に</strong>検出できるようになります。上のJPQLをCriteria APIで描き直してみましょう。</p>
<pre class="lang:java decode:true">private static void selectByCriteria(final EntityManager em) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    final CriteriaQuery&lt;Tag&gt; criteria = builder.createQuery(Tag.class);
    criteria.from(User.class);

    final TypedQuery&lt;User&gt; query = em.createQuery(criteria);
    for (final User user : query.getResultList()) {
        System.out.println(user);
    }
}</pre>
<p>eclipseでこのコードを書くと、以下のようにコンパイルエラーとしてミスを教えてくれます。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/02/jpa-criteria-error.png"><img class="alignnone size-full wp-image-2116" src="https://cloudear.jp/blog/wp-content/uploads/2016/02/jpa-criteria-error.png" alt="jpa-criteria-error" width="708" height="104" /></a></p>
<p>&nbsp;</p>
<p>このように、Criteria APIを使うと<span style="font-size: 12pt;"><strong>クエリのミスをコンパイル時にチェックできる</strong></span>ようになります。これがCriteria APIの最大の利点です。</p>
<p>また、副次的な効果ですが<strong>変なクエリが書かれない</strong>ようになります。実際の開発現場では、変態的なSQLが横行してチューンングの足枷になったり、特定のDB製品でしか実行できない書き方がされていたりと、SQL周りの問題が起きやすいです。しかしCriteria APIを使えばクエリの記述方法がある程度統一されるため、問題が起きにくく、またレビューしやすくなります。</p>
<h2>Criteria APIによるクエリの基本形</h2>
<p>Criteria APIはJPQLの構造をJavaクラスで表現したものと考えることができます。JPQLの構成要素の基本は次の３つです。</p>
<ol>
<li>from句：どのエンティティ（≒テーブル）からデータを取得するか</li>
<li>where句：抽出条件</li>
<li>select句：どのエンティティ、あるいはプロパティなどを取得するか</li>
</ol>
<p>この３つを踏まえると、Criteria APIを使ったプログラムの基本形は次のようになります。</p>
<pre class="lang:java decode:true">private static void selectUsersByName(final EntityManager em, final String pUserName) {
    // クエリを組み立てるためのオブジェクトを得る
    final CriteriaBuilder builder = em.getCriteriaBuilder();

    // クエリ全体を表現するオブジェクトを作成.
    // 引数として、クエリ結果の型を指定する.
    final CriteriaQuery&lt;User&gt; query = builder.createQuery(User.class);

    // from句指定
    final Root&lt;User&gt; root = query.from(User.class);

    // where句指定
    query.where( //
            builder.equal(root.get(User_.name), pUserName) //
            , builder.isNotNull(root.get(User_.name)) //
    );

    // select句指定.
    // ここではプロパティではなくエンティティそのものを指定.
    // ただしfromと同じエンティティを指定する場合はこの行は省略可能.
    query.select(root);

    // クエリ実行
    final List&lt;User&gt; result = em.createQuery(query).getResultList();
    for (final User user : result) {
        System.out.println(user);
    }
}
</pre>
<p>結果の型を指定できるのがとても強力です。例えば全件数を得るクエリは次のように書けます。</p>
<pre class="lang:java decode:true ">private static void countAllUsers(final EntityManager em) {
    final CriteriaBuilder builder = em.getCriteriaBuilder();

    // 件数なので結果は数値で得るようにする
    final CriteriaQuery&lt;Long&gt; query = builder.createQuery(Long.class);
    final Root&lt;User&gt; root = query.from(User.class);

    // count関数を使う
    query.select(builder.count(root));

    final long count = em.createQuery(query).getSingleResult().longValue();
    System.out.println(count);
}</pre>
<hr />
<p>基本編はここまでです。次回の応用編では、Criteria APIの実戦的な機能をご紹介します。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=2101</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaEEで簡単WebSocketサーバ</title>
		<link>https://cloudear.jp/blog/?p=2053</link>
		<comments>https://cloudear.jp/blog/?p=2053#comments</comments>
		<pubDate>Tue, 19 Jan 2016 08:07:37 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=2053</guid>
		<description><![CDATA[本エントリでは近代的なWebアプリケーションでは欠かせないWebSocketをJavaEEで実現する方法を説明します。 前段・WebSocketはなぜ生まれたか 伝統的なWebアプリケーションは、HTTPというプロトコル [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本エントリでは近代的なWebアプリケーションでは欠かせない<strong>WebSocket</strong>をJavaEEで実現する方法を説明します。</p>
<h2>前段・WebSocketはなぜ生まれたか</h2>
<p><span id="more-2053"></span></p>
<p>伝統的なWebアプリケーションは、HTTPというプロトコルで成立していました。HTTPとは単純なリクエスト・レスポンスモデルであり「クライアントであるWebブラウザがWebサーバに対してリクエストを投げ、返って来たレスポンスを処理する」というモデルで成り立っていました。あくまでクライアントが処理の起点となっているのです。</p>
<p>一方、Webアプリケーションであっても「サーバ側で起きた何らかの出来事を、Webブラウザに通知したい」というニーズは常にありました。これを「サーバプッシュ」と言います。これまで、HTTPを使って擬似的なサーバプッシュを実現するために技術者は様々な工夫を凝らしてきました。しかしやはり、リクエスト・レスポンスモデルの下では無理があったのです。</p>
<p>このような経緯があり、Webブラウザでの真のサーバプッシュを実現するべく策定されたのが<strong>WebSocket</strong>というプロトコルです。</p>
<p>もちろんJavaEEでもWebSocketはサポートされています。</p>
<p>本エントリではJavaEE7で導入されたWebSocketサーバを簡単に実現する機能をご紹介します。</p>
<h2>最小のサンプル</h2>
<p>これまで紹介してきたように、JavaEEでは、ある機能を使うのにアノテーションを付与したクラスを単に作成するだけで良い、というスタイルが広く採用されています。WebSocketも例外ではありません。</p>
<p>下記は最小のサンプルです。</p>
<pre class="lang:java decode:true">package sandbox.websocket.minimum;

import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/ws/min")
public class MinimumEndpoint {

    @OnMessage
    public String onMessage(final String pText) {
        System.out.println(pText);
        return "Re: " + pText;
    }
}
</pre>
<p>@ServerEndpointアノテーションを付けたクラスはWebSocketサーバとなります。このようなクラスを<strong>Endpointクラス</strong>と呼びます。</p>
<p>さらに@OnMessageアノテーションでクライアントから送信されたメッセージを処理するメソッドを指定しています。メッセージの処理内容は、送信されたメッセージの頭に「Re: 」を付けて送り返しています。</p>
<p>このクラスのテストのために、次のようなHTMLを作ってみましょう。</p>
<pre class="lang:xhtml decode:true">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;WebSocket最小のサンプル&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;input type="text"&gt;
    &lt;button type="button" class="btn btn-primary form-control"&gt;送信&lt;/button&gt;
    &lt;script src="https://code.jquery.com/jquery-2.2.0.min.js"&gt;&lt;/script&gt;
    &lt;script&gt;
       var ws = null;
       var onOpen = function() {
           $('button').click(function() {
               ws.send($('input').val());
           });
       };
       var onMessage = function(e) {
           alert(e.data);
       };
       var connect = function() {
           ws = new WebSocket('ws://localhost:' + location.port + '/ws/min');
           ws.onopen = onOpen;
           ws.onmessage = onMessage;
       };
       connect();
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>テキストフィールドに文字を入力して「送信」ボタンを押すと、先頭に「Re: 」を付けた文字列がアラートで表示されるサンプルです。</p>
<p>&nbsp;</p>
<hr />
<p>&nbsp;</p>
<p>いかがでしょうか。いとも簡単にWebSocketを使ったアプリケーションが作れてしまうことが分かっていただけたかと思います。</p>
<p>ただ、このサンプルはWebブラウザからのリクエストが起点であるため、Ajaxでも実現可能でありWebSocketの旨味がないサンプルです。そこで以降では、WebSocketを使うための実践的な機能を紹介していきます。</p>
<h2>@OnMessage以外のアノテーション</h2>
<p>@OnMessageアノテーションの他にも@OnOpen/@OnError/@OnCloseというアノテーションがあり、これらのアノテーションが付与されたメソッドは、適切なタイミングでJavaEEコンテナから呼び出されるコールバックメソッドとなります。</p>
<p>下記に典型的なEndpointクラスの宣言方法を示します。</p>
<pre class="lang:java decode:true" title="SampleEndpoint.java">package sandbox.websocket.sample;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/ws/sample")
public class SampleEndpoint {

    @OnOpen
    public void onOpen(Session pSession) {
    }

    @OnMessage
    public void onMessage(String pMessage) {
    }

    @OnError
    public void onError(Throwable pError) {
    }

    @OnClose
    public void onClose(Session pSession) {
    }
}
</pre>
<p>各メソッドはpublicである必要があります。</p>
<p>また@OnErrorコールバックメソッドは、Throwableを引数に取る必要があります。</p>
<p>それ以外のメソッドの引数は必要に応じて増減させることが可能です。例えば、@OnMessageのコールバックでSessionが必要なら、引数に追加してください。</p>
<h2>URIテンプレート</h2>
<p>接続先を分類するために、URLにパラメータを含めることが出来ます。</p>
<pre class="lang:java decode:true" title="DescriptorWebSocketServer.java">@ServerEndpoint("/ws/rooms/{room-descriptor}")
public class DescriptorEndpoint {
    ...</pre>
<p>これを使うと、チャットルームの入室管理のようなことが比較的簡単に実装できます。簡単なチャットサーバのコードをご紹介します。</p>
<pre class="lang:java decode:true" title="DescriptorWebSocketServer.java">package sandbox.websocket.descritpor;

import java.io.IOException;

import javax.inject.Inject;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/ws/rooms/{room-descriptor}")
public class DescriptorEndpoint {

    @Inject
    WebSocketSessionManager sessionManager;

    @OnOpen
    public void onOpen(@PathParam("room-descriptor") final String pRoomDescriptor, final Session pSession) {
        this.sessionManager.addSession(pRoomDescriptor, pSession);
    }

    @OnClose
    public void onClose(@PathParam("room-descriptor") final String pRoomDescriptor, final Session pSession) {
        this.sessionManager.removeSession(pRoomDescriptor, pSession);
    }

    @OnMessage
    public void onMessage(@PathParam("room-descriptor") final String pRoomDescriptor, final String pText) {
        for (final Session session : this.sessionManager.getSessions(pRoomDescriptor)) {
            try {
                session.getBasicRemote().sendText("Re: " + pText);
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
    }
}
</pre>
<p>注目していただきたいのは次の２点です。</p>
<ul>
<li>@ServerEndpointの引数に<code>room-descriptor</code>というパラメータを含めている</li>
<li>メソッドの引数に<code>@PathParam("room-descriptor")</code>を指定することでパラメータの値を得ている</li>
</ul>
<p>なおEndpointクラスはCDIによるスコープ管理が効きません。たとえシングルトンな作りにしたくても、それが叶わないのです。</p>
<p>しかしインジェクション対象にすることはできます。ここでは、チャットルーム毎のWebSocket接続を管理するクラス（WebSocketSessionManager）をシングルトンとして作成し、@Injectアノテーションでインジェクションしています。</p>
<p>WebSocketSessionManagerクラスのコードも掲載しておきます。</p>
<pre class="lang:java decode:true" title="WebSocketSessionManager.java">package sandbox.websocket.descritpor;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.enterprise.context.ApplicationScoped;
import javax.websocket.Session;

@ApplicationScoped
public class WebSocketSessionManager {

    private final ConcurrentMap&lt;String, Lock&gt;          locks    = new ConcurrentHashMap&lt;&gt;();
    private final ConcurrentMap&lt;String, List&lt;Session&gt;&gt; sessions = new ConcurrentHashMap&lt;String, List&lt;Session&gt;&gt;() {
        public List&lt;Session&gt; get(final Object key) {
            List&lt;Session&gt; ret = super.get(key);
            if (ret == null) {
                ret = new CopyOnWriteArrayList&lt;&gt;();
                this.put((String) key, ret);
            }
            return ret;
        }
    };

    public void addSession(final String pRoomDescriptor, final Session pSession) {
        synchronized (this.getLock(pRoomDescriptor)) {
            this.sessions.get(pRoomDescriptor).add(pSession);
        }
    }

    public List&lt;Session&gt; getSessions(final String pRoomDescriptor) {
        return this.sessions.get(pRoomDescriptor);
    }

    public void removeSession(final String pRoomDescriptor, final Session pSession) {
        synchronized (this.getLock(pRoomDescriptor)) {
            this.sessions.get(pRoomDescriptor).remove(pSession);
        }
    }

    private Lock getLock(final String pRoomDescriptor) {
        final Lock newLock = new Lock();
        final Lock alreadyLock = this.locks.putIfAbsent(pRoomDescriptor, newLock);
        return alreadyLock == null ? newLock : alreadyLock;
    }

    private static class Lock {
        // nodef
    }

}
</pre>
<p>スレッドセーフにするために少し複雑なコードになっていますが、結局やっていることは部屋毎にWebSocket接続を束ねているだけなので、臆さず読み解いてみてください。</p>
<p>最後に、これをテストするためのHTMLを掲載します。</p>
<pre class="lang:xhtml decode:true">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;WebSocket識別子のサンプル&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;input type="text" name="desc" placeholder="部屋の識別子"&gt;
    &lt;button type="button" class="connector"&gt;接続&lt;/button&gt;
    &lt;hr/&gt;
    &lt;input type="text" name="text" placeholder="送信テキスト"&gt;
    &lt;button type="button" class="sender" disabled="disabled"&gt;送信&lt;/button&gt;
    &lt;hr/&gt;
    &lt;h3&gt;レスポンス&lt;/h3&gt;
    &lt;p class="response"&gt;&lt;/p&gt;
    &lt;script src="https://code.jquery.com/jquery-2.2.0.min.js"&gt;&lt;/script&gt;
    &lt;script&gt;
       var ws = null;
       $('button.connector').click(function() {
           if (ws) ws.close();
           var url = 'ws://localhost:' + location.port + '/ws/rooms/' + $('input[name="desc"]').val();
           ws = new WebSocket(url);
           ws.onmessage = function(e) {
               $('.response').text(e.data);
           };
           ws.onopen = function() {
               $('button.sender').removeAttr('disabled');
           };
           ws.onclose = function() {
               $('button.sender').attr('disabled', 'disabled');
           };
       });
       $('button.sender').click(function() {
            if (!ws || ws.readyState !== WebSocket.OPEN) {
               alert('先に接続して下さい。');
               return;
           }
           ws.send($('input[name="text"]').val());
       });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>動作を見てみるときは、ぜひ複数のWebブラウザを開いてください。誰かの投稿が同じ部屋の全員に配信されることが分かると思います。とてもシンプルですが、チャットアプリケーションができました。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/01/websocket_desc.png"><img class="alignnone size-full wp-image-2075" src="https://cloudear.jp/blog/wp-content/uploads/2016/01/websocket_desc.png" alt="websocket_desc" width="732" height="283" /></a></p>
<h2>DecoderとEncoder</h2>
<p>WebSocketはテキストデータとバイナリデータをやり取りできます。一般的には扱いやすいJSON形式のテキストを使うことが多いでしょう。しかしEndpointクラスを普通に作ると、@OnMessageコールバックの引数や戻り値の型は、単なるString型です。せっかくJavaを使っているのですから、ここはデータクラスに変換して型安全にメッセージを扱いたいものです。</p>
<p>この要求に応えるのが、<strong>Decoder/Encoder</strong>です。</p>
<h3>Decoderクラス</h3>
<p>Decoderクラスにはクライアント（一般的にはWebブラウザ）から送られてきたメッセージ内容を任意のJavaオブジェクトに変換する処理を実装します。このクラスを作成すると、Endpointクラスの@OnMessageコールバックメソッドに引数にString以外の型が使えるようになります。</p>
<p>ここでは ClientMessageというクラスを導入して、Decoderクラスを作ってみます。なおJSONとJavaオブジェクトの変換にはJSONICというライブラリを使っています。</p>
<p>まずはClientMessageクラスです。getterとsetterのみの単なるデータクラスとして作りましょう。</p>
<pre class="lang:java decode:true" title="ClientMessage.java">package sandbox.websocket.json;

import java.util.Date;

public class ClientMessage {
    private Date   date;
    private String body;
    // getter/setterは省略
}
</pre>
<p>次にDecoderです。JsonDecoderという名前で作ります。なお使い方は後で説明します。</p>
<pre class="lang:java decode:true" title="JsonDecoder.java">package sandbox.websocket.json;

import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

import net.arnx.jsonic.JSON;

public class JsonDecoder implements Decoder.Text&lt;ClientMessage&gt; {

    @Override
    public void init(@SuppressWarnings("unused") final EndpointConfig pConfig) {
        // nop
    }

    @Override
    public boolean willDecode(@SuppressWarnings("unused") final String pRequest) {
        return true; // デコード対象としない場合はfalseを返すが、通常はtrueでOK.
    }

    @Override
    public ClientMessage decode(final String pRequestJsonString) throws DecodeException {
        return JSON.decode(pRequestJsonString, ClientMessage.class);
    }

    @Override
    public void destroy() {
        // nop
    }
}</pre>
<p>なおJSON文字列とJavaオブジェクトの変換には<a href="http://jsonic.osdn.jp/index.html">JSONIC</a>というライブラリを使っています。</p>
<h3>Encoderクラス</h3>
<p>次にEncoderクラスを作ってみます。</p>
<p>Encoderクラスには、Javaオブジェクトをクライアントに送信するメッセージに変換する処理を実装します。このクラスを作成すると、Endpointクラスの@OnMessageコールバックメソッドの戻り値にString以外の型が使えるようになります。</p>
<p>ここではServerMessageというクラスを導入して、Encoderクラスを作ってみます。</p>
<p>ServerMessageクラスも、getterとsetterのみの単なるデータクラスとして作ります。</p>
<pre class="lang:default decode:true ">package sandbox.websocket.json;

import java.util.Date;

public class ServerMessage {
    private Date   date;
    private String body;
    private String senderSessionId;
    // getterとsetterは省略
}</pre>
<p>次に、JsonEncoderを作りましょう。これも使い方は後で説明します。</p>
<pre class="lang:default decode:true" title="JsonEncoder.java">package sandbox.websocket.json;

import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;

import net.arnx.jsonic.JSON;

public class JsonEncoder implements Encoder.Text&lt;ServerMessage&gt; {

    @Override
    public void init(@SuppressWarnings("unused") final EndpointConfig pConfig) {
        // nop
    }

    @Override
    public String encode(final ServerMessage pResponse) throws EncodeException {
        return JSON.encode(pResponse);
    }

    @Override
    public void destroy() {
        // nop
    }
}</pre>
<h3 class="p1">DecoderとEncoderを使う</h3>
<p>作成したDecoderとEncoderはEndpointクラスの中で使います。ポイントは次の２点です。</p>
<ul>
<li>Endpointクラスの@ServerEndpointアノテーションのdecodersとencodersに作ったクラスを指定</li>
<li>@OnMessageコールバックメソッドの引数と戻り値にデータクラスを指定</li>
</ul>
<p>それではサンプルコードを見てみましょう。</p>
<pre class="lang:java decode:true" title="DecEncEndpoint.java">package sandbox.websocket.json;

import java.util.Calendar;

import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/ws/dec-enc" //
, decoders = JsonDecoder.class //
, encoders = JsonEncoder.class)
public class DecEncEndpoint {

    @OnMessage
    public ServerMessage onMessage(final Session pSession, final ClientMessage pRequest) {
        final ServerMessage ret = new ServerMessage();
        ret.setBody("Re: " + pRequest.getBody());
        ret.setDate(Calendar.getInstance().getTime());
        ret.setSenderSessionId(pSession.getId());
        return ret;
    }
}
</pre>
<p>String型がなくなり、データクラスを通して型安全にデータ操作ができるようになりました。</p>
<p>テスト用のHTMLも掲載します。</p>
<pre class="lang:xhtml decode:true " title="dec-enc.html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Decoder/Encoderのサンプル&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;input type="text" name="text" placeholder="送信テキスト"&gt;
    &lt;button type="button" class="btn btn-primary form-control"&gt;送信&lt;/button&gt;
    &lt;script src="https://code.jquery.com/jquery-2.2.0.min.js"&gt;&lt;/script&gt;
    &lt;script&gt;
       var ws = null;
       var onOpen = function() {
           $('button').click(function() {
               ws.send(JSON.stringify({ body: $('input[name="text"]').val() }));
           });
       };
       var onMessage = function(e) {
           alert(e.data);
       };
       var connect = function() {
           ws = new WebSocket('ws://localhost:' + location.port + '/ws/dec-enc');
           ws.onopen = onOpen;
           ws.onmessage = onMessage;
       };
       connect();
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>動作させてみると、JSON形式のデータをやり取り出来ていることが分かると思います。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/01/dec-enc.png"><img class="alignnone size-full wp-image-2086" src="https://cloudear.jp/blog/wp-content/uploads/2016/01/dec-enc.png" alt="dec-enc" width="607" height="395" /></a></p>
<p>&nbsp;</p>
<h3>データ変換の流れのまとめ</h3>
<p>登場人物が多くなり少し複雑になったため、データ変換の流れを整理してみました。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2016/01/websocket_dec_enc_flow.png"><img class="alignnone size-full wp-image-2084" src="https://cloudear.jp/blog/wp-content/uploads/2016/01/websocket_dec_enc_flow.png" alt="websocket_dec_enc_flow" width="465" height="496" /></a></p>
<p>&nbsp;</p>
<p>変換処理の流れと、Decoder/Encoderがどのような役割を担っているかを理解いただけたでしょうか。</p>
<h2>最後に</h2>
<p>以上、JavaEEのWebSocketに関する機能をご紹介しました。</p>
<p>実戦ではもっとたくさんのことに気を配る必要があります。例えばエラー処理やスケーリング、認証、リクエスト内容の解析などの処理が必要です。</p>
<p>しかしWebSocketの根幹となる機能は、本エントリでご紹介した機能で充分カバーされていると思います。JavaEEで作るWebアプリケーションにもどんどんWebSocketを取り入れて、新しいユーザ体験を提供していきましょう。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=2053</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaEEでもできる！JAX-RSでお手軽REST開発</title>
		<link>https://cloudear.jp/blog/?p=2005</link>
		<comments>https://cloudear.jp/blog/?p=2005#comments</comments>
		<pubDate>Tue, 22 Dec 2015 01:25:02 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=2005</guid>
		<description><![CDATA[最近のWebアプリケーションはRESTインターフェイスによるAPIを備えることが多くなってきました。 APIはWebアプリケーションの用途を大きく広げる重要な要素であり、また、これをシンプルなインターフェイスであるRES [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>最近のWebアプリケーションはRESTインターフェイスによるAPIを備えることが多くなってきました。</p>
<p>APIはWebアプリケーションの用途を大きく広げる重要な要素であり、また、これをシンプルなインターフェイスであるREST形式で提供することは、より APIを利用しやすくするための重要な手法となっています。</p>
<p>本エントリではJavaEEでRESTインターフェイスを提供するための仕様である<strong>JAX-RS</strong>をご紹介します。</p>
<p><span id="more-2005"></span></p>
<h2>JAX-RSとは</h2>
<p>前述のように、RESTによるAPI提供の重要性は増すばかりです。JavaEEにおいても、JavaEE6からRESTインターフェイスを開発するための仕様である<strong>JAX-RS</strong>が提供されるようになりました。</p>
<p>JAX-RSの特徴として、アノテーションを使ったシンプルな開発スタイルが挙げられます。まずは基本的な使い方を見てみましょう。</p>
<h2>最小のサンプル</h2>
<p>それではJAX-RSの最小のサンプルを作ってみましょう。JavaEEコンテナ環境下であれば、たった２つのファイルを作るだけで済みます。</p>
<h3>JAX-RSの設定クラス</h3>
<p>まずはJAX-RSの設定を持つクラスを作りましょう。</p>
<pre class="lang:java decode:true">package sandbox.web.api;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestApplication extends Application {
    // nodef
}
</pre>
<p>ポイントは２つ。</p>
<ol>
<li><code>@ApplicationPath("/api")</code>というアノテーションにより<code>/api</code>以下がJAX-RSで扱うURLになります</li>
<li><code>javax.ws.rs.core.Application</code>クラスを継承します。</li>
</ol>
<p>クラス名はどんな名前でも構いません。また実装は何も必要ありません。</p>
<h3>リソースクラス</h3>
<p>JAX-RSによる開発の主たる作業は、リソースクラスを作ることです。</p>
<p>リソースというのは情報の断片のことで、URLで識別されるものです。リソースクラスは、リソースに対する操作をリクエストに従って処理するクラスとなります。</p>
<p>ここでは次のような仕様のリソースを、リソースクラスで実装してみましょう。</p>
<ul>
<li><code>Hello, World</code>というテキストをリソースとする</li>
<li><code>/api/hello/text</code>というパスに対するGETメソッドでテキストが得られる</li>
<li>テキストのContent-Typeは<code>text/plain</code></li>
</ul>
<p>クラス名は何でもいいのですが、ここでは分かりやすく<code>HelloResource</code>としましょう。</p>
<pre class="lang:java decode:true">package sandbox.web.api;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class HelloResource {

    @Path("/text")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String asText() {
        return "Hello, World";
    }
}
</pre>
<p>仕様がそのままアノテーションで表現されていますね。</p>
<p>ではブラウザで次のURLにアクセスしてみましょう。</p>
<address><a href="http://localhost:8081/api/hello/text">http://localhost:8081/api/hello/text</a></address>
<p>次のような画面が表示されるはずです。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_first.png"><img class="alignnone wp-image-2031 size-full" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_first.png" alt="jax-rs_first" width="325" height="93" /></a></p>
<h2>リソースクラスのポイント</h2>
<p>JAX-RSの根幹、リソースクラスを詳しく見てみましょう。とはいえ非常に直感的なコードになっていますので、読み解きやすいと思います。</p>
<h3>@PathアノテーションとURLの関係</h3>
<p>クラスとメソッドに<code>@Path</code>アノテーションを付与することで、このリソースクラスにアクセスするためのパス（≒URLの一部）を表現しています。</p>
<p>クラス宣言の<code>@Path</code>アノテーションは、このリソースが<code>/hello</code>というパスで表されることを示しています。</p>
<pre class="lang:java decode:true">@Path("/hello")
public class HelloResource</pre>
<p>メソッド宣言の<code>@Path</code>アノテーションは、このリソースに実際にアクセスするためのパスを示しています。</p>
<pre class="lang:java decode:true ">@Path("/text")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String asText()
</pre>
<p>実際にアクセスするためのパスは、JAX-RSの設定クラスに付与した<code>@ApplicationPath</code>アノテーションにも影響されることに注意してください。</p>
<p><code>/api/hello/text</code>というパスの階層毎に対応するアノテーションをまとめてみましたので、イメージしてみてください。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_url_path_mapping1.png"><img class="alignnone size-full wp-image-2038" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_url_path_mapping1.png" alt="jax-rs_url_path_mapping" width="778" height="197" /></a></p>
<h3>メソッドに付与された@GET/@Producesアノテーション</h3>
<p>リソースクラスのメソッドには、<code>@Path</code>の他にも２つのアノテーションが付いています。いずれも重要なアノテーションです。</p>
<p><code>@GET</code>アノテーションは、メソッドが動作するHTTPメソッドがGETであることを示しています。HTTPメソッドに該当するアノテーションとして、他にも@PUT/@POST/@DELETEなどがあります。</p>
<p><code>@Produces</code>アノテーションは、このメソッドが返す値をどのようなデータ形式で返すかを示していて、HTTP応答ヘッダ内の<code>Content-Type</code>を指定していることに相当します。</p>
<hr />
<p>&nbsp;</p>
<p>このようにJAX-RSによるREST開発は、<strong>HTTPインターフェイスをアノテーションを駆使して表現する</strong>というスタイルになります。</p>
<p>それではJAX-RSが提供する様々な機能を見ていきましょう。多数の機能があるのですが、重要なものに絞ってご紹介します。</p>
<h2>POSTメソッドに対応する</h2>
<p>POSTメソッドでアクセスされた時に動くメソッドには<code>@POST</code>アノテーションを付与します。</p>
<pre class="lang:java decode:true">@Path("text")
@POST
public void postText(@FormParam("text") final String pText) {
    System.out.println(pText);
}
</pre>
<p>パラメータを<code>@FormParam</code>アノテーションで受け取っています。これは後ほど、もっと詳しく解説します。</p>
<p>同じ考え方で、PUTメソッドやDELETEメソッドにも対応できます。単に<code>@PUT</code>や<code>@DELETE</code>アノテーションを付与すればいいのです。直感的ですね。</p>
<h2>@QueryParamアノテーションでクエリパラメータを受け取る</h2>
<p>クエリパラメータとは、URLの?以降の部分を言います。例えば以下のURLのクエリパラメータは<code>format=json</code>です。</p>
<pre class="lang:default decode:true">http://example.com/api/hello/text?format=json</pre>
<p>これをリソースクラスで受け取るには、メソッド引数に<code>@QueryParam</code>アノテーションを付与します。</p>
<pre class="lang:java decode:true">@Path("/text-with-format")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getTextWithFormat(@QueryParam("format") final String pFormat) {
    return "Hello, World" + "(format=" + pFormat + ")";
}
</pre>
<p>ブラウザで次のURLにアクセスしてみてください。</p>
<address><a href="http://localhost:8081/api/hello/text-with-format?format=json">http://localhost:8081/api/hello/text-with-format?format=json</a></address>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_resource-class_queryparameter.png"><img class="alignnone size-full wp-image-2033" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_resource-class_queryparameter.png" alt="jax-rs_resource-class_queryparameter" width="517" height="94" /></a></p>
<p>確かにクエリパラメータが受け取れていますね。</p>
<h2>@FormParamアノテーションでformのパラメータを受け取る</h2>
<p>HTMLのformタグで送信するデータは<code>application/x-www-form-urlencoded</code>という形式であり、次のような書式のデータです。</p>
<pre class="lang:default decode:true">param1=value1&amp;param2=value2</pre>
<p>JAX-RSではこの形式のデータは特別扱いであり、メソッドの引数に<code>@FormParam</code>アノテーションを付与することで値を受け取ることができます。</p>
<pre class="lang:java decode:true">@Path("text")
@POST
@Produces(MediaType.TEXT_PLAIN)
public void postText(@FormParam("text") final String pText) {
    System.out.println(pText);
}</pre>
<h2>少し横道・JAX-RSのクライアントAPIによるテスト</h2>
<p>RESTインターフェイスのテストを実施する際、GETであればブラウザで手軽にテストできますが、POSTやPUT、DELETEはそうはいきません。ところがJAX-RSにはクライアント用のAPIが備わっており、手軽にリソースクラスをテストすることができます。</p>
<p>JAX-RSのクライアント APIを使ってPOSTを送るサンプルを掲載しておきます。</p>
<pre class="lang:java decode:true">public static void main(final String[] pArgs) {
    final Response response = ClientBuilder.newClient() //
            .target("http://localhost:8081/api") // 実行するWeb APIのエントリポイント
            .path("/hello/text") // リクエストを投げるURLのパス部分
            .request(MediaType.TEXT_PLAIN_TYPE) // 受け入れ可能なレスポンス形式(HTTPヘッダでいうAcceptに相当)
            // application/x-www-form-urlencoded形式でデータを作成(HTTPヘッダでいうContent-Typeに相当)し、リクエストを送信.
            .post(Entity.&lt;String&gt; entity("text=hoge", MediaType.APPLICATION_FORM_URLENCODED_TYPE));
    System.out.println(response.getStatusInfo());
}</pre>
<h2>パスパラメータを受け取る</h2>
<p>URLの一部がパラメータになっているケースがよくあります。例えばよくあるブログエントリのURLがこれに相当します。</p>
<p><code>http://example.com/blog/2015/12/17</code></p>
<p>2015年12月17日のエントリという意味ですね。JAX-RSでこのようなパラメータを受け取るには、２つのアノテーションを併用します。</p>
<ol>
<li>メソッドの@PathアノテーションでURLパラメータを表現</li>
<li>メソッド引数に@PathParamアノテーションを付与し値を受け取る</li>
</ol>
<p>以下、サンプルです。</p>
<pre class="lang:java decode:true ">@Path("/date/{year}/{month}/{date}")
@GET
@Produces("text/plain; charset=UTF-8")
public String getDateText( //
        @PathParam("year") final int pYear //
        , @PathParam("month") final int pMonth //
        , @PathParam("date") final int pDate //
) {
    return String.format("%d年%d月%d日", pYear, pMonth, pDate);
}
</pre>
<p><code>@Path</code>アノテーションに<code>{パラメータ名}</code>というスタイルでパラメータを表現しているのが分かると思います。</p>
<p>ブラウザで次のURLにアクセスしてみてください。</p>
<address><a href="http://localhost:8081/api/hello/date/2015/12/17">http://localhost:8081/api/hello/date/2015/12/17</a></address>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_pathparam.png"><img class="alignnone size-full wp-image-2034" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_pathparam.png" alt="jax-rs_pathparam" width="456" height="71" /></a></p>
<h2>HTTPリクエストのヘッダ情報を受け取る</h2>
<p>時にはクライアントから送信されてきたHTTPヘッダの情報が必要な時があります。この場合、<code>HttpHeaders</code>型のメソッド引数を作り<code>@Context</code>アノテーションを付与します。すると<code>HttpHeaders</code>を通してヘッダ情報が得られます。</p>
<pre class="lang:java decode:true ">@Path("/headers/{headerName}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getRequestHeaderValue( //
        @PathParam("headerName") final String pHeaderName //
        , @Context final HttpHeaders pHeaders) {
    return String.valueOf(pHeaders.getRequestHeader(pHeaderName));
}
</pre>
<p>ブラウザで次のURLにアクセスしてみてください。</p>
<address><a href="http://localhost:8081/api/hello/headers/accept">http://localhost:8081/api/hello/headers/accept</a></address>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_header.png"><img class="alignnone size-full wp-image-2035" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_header.png" alt="jax-rs_header" width="526" height="99" /></a></p>
<h2></h2>
<h2>Servlet APIにアクセスする</h2>
<p>リソースクラスの中でServlet APIにアクセスしたい場合、メソッド引数にServlet APIのオブジェクトを指定し、そこに<code>@Context</code>アノテーションを付与します。</p>
<pre class="lang:java decode:true ">@Path("/text")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String asText( //
        @Context final HttpServletRequest pRequest //
        , @Context final ServletContext pContext) {
    System.out.println(pRequest);
    System.out.println(pContext);
    return "Hello, World";
}
</pre>
<p>上記のように、<code>HttpServletRequest</code>と<code>ServletContext</code>は取得可能ですが、<code>HttpSession</code>はこの方法では取得できません。本来、RESTとHttpSessionは相容れないものですのでこの仕様は妥当と言えますが、どうしてもHttpSessionが必要な場合は、次のようにして取得してください。</p>
<pre class="lang:java decode:true">@Path("/session-info")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sessionInfo(@Context final HttpServletRequest pRequest) {
    return String.valueOf(pRequest.getSession());
}</pre>
<h2>CDIの適用</h2>
<p>リソースクラスはJavaEEコンテナ管理であるためCDI連携が可能です。ただ、CDI対象であることをコンテナに示すために、クラス宣言に<code><span class="s1">@</span>Dependent</code>アノテーションを付与する必要があることに注意してください。</p>
<p>このことを踏まえると、リソースクラスは下記のようなコードになります。</p>
<pre class="lang:java decode:true">@Path("/hello")
@Dependent
public class HelloResource {

    @Inject
    HogeService hogeService;
</pre>
<p>なおCDIの詳しいことについては本ブログの「<a title="JavaEE屈指の便利機能、CDIを触ってみよう" href="https://cloudear.jp/blog/?p=1945">JavaEE屈指の便利機能、CDIを触ってみよう</a>」というエントリをご参照ください。</p>
<h2>JSONでデータをやり取りする</h2>
<p>最後に、実践的な内容としてJSONでデータをやり取りする方法をご紹介します。</p>
<p>昨今のWebAPIの多くはJSON形式でデータをやり取りしますが、JAX-RSはデフォルトではJSONを扱えません。多少の設定追加が必要ですので、この章で見て行きましょう。</p>
<h3>データ変換用のクラスを作成する</h3>
<p>JAX-RSには、Content-Typeに応じてJavaオブジェクトを変換する処理を選択／実行する機能が備わっています。</p>
<p>ここではContent-Typeが<code>application/json</code>の時に動作する変換用クラスを作成します。<code>MessageBodyReader</code>と<code>MessageBodyWriter</code>インターフェイスを実装し、<code>@Provider</code>アノテーションを付与するのがポイントです。</p>
<p>実装すべきメソッドは５つあります。各メソッドの意味はコメントに書いておきました。どれも引数が多く見にくいかもしれませんが、実際のメソッドの中身はどれも１行ですので、臆さず読んでみてください。</p>
<pre class="lang:java decode:true">package sandbox.jax_rs;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import net.arnx.jsonic.JSON;

@Provider
@Consumes(MediaType.APPLICATION_JSON) // リクエストのContent-Typeがapplication/jsonの時に当クラスが実行される
@Produces(MediaType.APPLICATION_JSON) // レスポンスのContent-Typeがapplication/jsonの時に当クラスが実行される
public class JsonConverter implements MessageBodyReader&lt;Object&gt;, MessageBodyWriter&lt;Object&gt; {

    /**
     * クライアントに返すデータの長さを返しますが、不明な場合は-1を返します.
     */
    @Override
    public long getSize(final Object pT, final Class&lt;?&gt; pType, final Type pGenericType, final Annotation[] pAnnotations, final MediaType pMediaType) {
        return -1;
    }

    /**
     * クライアントから送られてきたデータのContent-Typeが、このクラスで処理可能かどうかを返します. &lt;br&gt;
     * このクラスの場合、application/jsonを処理するようにします.
     */
    @Override
    public boolean isReadable(final Class&lt;?&gt; pType, final Type pGenericType, final Annotation[] pAnnotations, final MediaType pMediaType) {
        return pMediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE);
    }

    /**
     * クライアントに送り返すデータのContent-Typeが、このクラスで処理可能かどうかを返します. &lt;br&gt;
     * このクラスの場合、application/jsonを処理するようにします.
     */
    @Override
    public boolean isWriteable(final Class&lt;?&gt; pType, final Type pGenericType, final Annotation[] pAnnotations, final MediaType pMediaType) {
        return pMediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE);
    }

    /**
     * クライアントからのデータをJavaオブジェクトに変換して返します. &lt;br&gt;
     * ここではクライアントからのデータをJSONと決め打ちして処理します. &lt;br&gt;
     */
    @Override
    public Object readFrom(final Class&lt;Object&gt; pType, final Type pGenericType, final Annotation[] pAnnotations, final MediaType pMediaType,
            final MultivaluedMap&lt;String, String&gt; pHttpHeaders, final InputStream pEntityStream) throws IOException, WebApplicationException {
        return JSON.decode(pEntityStream, pType);
    }

    /**
     * Javaオブジェクトを変換してクライアントに返します. &lt;br&gt;
     * ここではJSONに変換します. &lt;br&gt;
     */
    @Override
    public void writeTo(final Object pT, final Class&lt;?&gt; pType, final Type pGenericType, final Annotation[] pAnnotations, final MediaType pMediaType,
            final MultivaluedMap&lt;String, Object&gt; pHttpHeaders, final OutputStream pEntityStream) throws IOException, WebApplicationException {
        JSON.encode(pT, pEntityStream);
    }
}
</pre>
<p>なおこJSONとJavaオブジェクトの変換には<a href="http://jsonic.osdn.jp/index.html">JSONIC</a>というライブラリを使っています。</p>
<h3>リソースクラスでJSONレスポンスを返す</h3>
<p>それではリソースクラスにJSON形式でデータを返すメソッドを追加しましょう。</p>
<pre class="lang:java decode:true">@Path("/json")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Map&lt;String, Object&gt; asJson() {
    final Map&lt;String, Object&gt; ret = new HashMap&lt;&gt;();
    ret.put("response", "Hello, World");
    return ret;
}
</pre>
<p><code><span class="s1">@Produces</span><span class="s2">(MediaType.</span>APPLICATION_JSON</code><span class="s2"><code>)</code>というアノテーションにより、レスポンスをJSON形式にすることを示しています。</span></p>
<p>それではブラウザで次のURLにアクセスして下さい。</p>
<address><a href="http://localhost:8081/api/hello/json">http://localhost:8081/api/hello/json</a></address>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_json_01.png"><img class="alignnone size-full wp-image-2043" src="https://cloudear.jp/blog/wp-content/uploads/2015/12/jax-rs_json_01.png" alt="jax-rs_json_01" width="879" height="511" /></a></p>
<p>&nbsp;</p>
<p>レスポンスがJSON形式のデータであることや、レスポンスヘッダのContent-Typeがapplication/jsonになっていることが確認できます。</p>
<h3>リソースクラスでJSONを受け取る</h3>
<p>次にJSON形式のデータをPOSTで受け取るメソッドを作ってみましょう。</p>
<pre class="lang:java decode:true">@Path("/json")
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void postJson(final Map&lt;String, Object&gt; pJson) {
    System.out.println(pJson.get("request"));
}
</pre>
<p class="p1"><code><span class="s1">@Consumes</span><span class="s2">(MediaType.</span>APPLICATION_JSON</code><span class="s2"><code>)</code>というアノテーションで、リクエストのContent-Typeがapplication/jsonである場合にこのメソッドが動作することを示しています。</span></p>
<p class="p1">クライアントAPIで動作確認をしてみましょう。</p>
<pre class="lang:java decode:true ">public static void main(final String[] pArgs) {
    final Response response = ClientBuilder.newClient() //
            .target("http://localhost:8081/api") //
            .path("/hello/json") //
            .request() //
            .post(Entity.&lt;String&gt; entity("{ \"request\": \"This is json request.\" }", MediaType.APPLICATION_JSON));
    System.out.println(response.getStatusInfo());
}
</pre>
<p>このメソッドを実行すると、リソースクラスのpostJson()メソッドが動作することが確認できるはずです。</p>
<h2>まとめ</h2>
<p>駆け足でJAX-RSを見てきました。実にシンプルな上、RESTの考え方にマッチした分かりやすい仕様になっているため、学びやすいと思います。</p>
<p>本エントリでは紹介しきれなかった機能の中には、サブリソースやキャッシュ制御、レスポンスの詳細な制御など重要なものがあります。幸い、<a href="http://www.oreilly.co.jp/books/9784873114675/">オライリーから良いJAX-RSの指南書</a>が出ています。分量が少なく読みやすいため、ぜひご一読をおすすめします。</p>
<p>冒頭に書いたように、Web APIの重要性は増すばかりです。JAX-RSを使ってRESTフルなAPIをどんどん開発し、Webサービスの価値を高めましょう。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=2005</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wicketでオブジェクト指向を楽しみながらWebアプリケーションを作る</title>
		<link>https://cloudear.jp/blog/?p=1755</link>
		<comments>https://cloudear.jp/blog/?p=1755#comments</comments>
		<pubDate>Thu, 22 Oct 2015 02:39:53 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1755</guid>
		<description><![CDATA[今回はJava製Webアプリケーションフレームワークの１つであるWicketをご紹介します。 Wicketとは Wicketはユーザインターフェイス（UI）を担当するフレームワークです。世の中にはJavaEEやPlay  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>今回はJava製Webアプリケーションフレームワークの１つである<strong>Wicket</strong>をご紹介します。</p>
<h2>Wicketとは</h2>
<p><span id="more-1755"></span></p>
<p>Wicketはユーザインターフェイス（UI）を担当するフレームワークです。世の中にはJavaEEやPlay Framework、Ninjaのようにフルスタックなフレームワークも存在しますが、Wicketは、StrutsのようにUI層に特化しています。</p>
<p>事例としては<a title="ピザハット" href="http://pizzahut.jp" target="_blank">ピザハットのサイト</a>があります。</p>
<p>Java製Webアプリケーションフレームワークは数多くありますが、Wicketの特徴はどこにあるのでしょうか。</p>
<p>&nbsp;</p>
<h2>Wicketの大事な２つの特徴</h2>
<h3>1.「Javaらしい」コードでWebアプリケーションを作れる</h3>
<p>Wicket最大の特徴はオブジェクト指向を活用したJavaらしいコードでWebアプリケーションを作れることです。<br />
オブジェクト指向の機能と言えば継承やカプセル化による部品化などでしょうか。Wicketはこれらの機能をうまく活用し、継承による画面レイアウトの共通化や、共通部品のクラス化などを可能にしています。<br />
これにより<strong>Javaによるプログラミングを楽しみながら</strong>Webアプリケーションを作ることが出来るのです。<br />
またほとんど全ての機能をJavaのコードとして記述することから、型安全性やリファクタリングしやすい、などの恩恵もあります。</p>
<h3>2. Ajaxが統合されている</h3>
<p>WicketはAjaxを上手に取り込んでいます。開発者は少しの作法を覚えるだけで、Ajaxを使った応答性の良いWebアプリケーションを作ることが出来るのです。</p>
<h3>その他の特徴</h3>
<ul>
<li>デフォルトでセキュア</li>
<li>データと画面を柔軟に結合するModelの提供</li>
<li>マルチタブやマルチウィンドウへの配慮</li>
<li>宣言的なマークアップ</li>
<li>ユニットテスト用クラスの提供</li>
</ul>
<p>この記事では大事な２つの特徴に絞ってご紹介しますが、更に詳しい情報を得たい方は<a href="http://wicket.apache.org">Wicketの本家Webサイト</a>をご覧下さい。</p>
<p>&nbsp;</p>
<h2>第一章　最初のサンプル</h2>
<h3>1. Mavenによる雛形アプリの作成</h3>
<p>まずはWebアプリ開発プロジェクトの雛形を作ります。<br />
2015年7月にWicketは7系へのメジャーバージョンアップを果たしました。ここでは7系を使ってサンプルを作って行きましょう。<br />
WicketはMavenのarchetypeを提供していますので、これを利用します。<a href="https://maven.apache.org">Maven</a>の導入は事前に済ませておいて下さい。</p>
<p>ターミナル、あるいはコマンドプロンプトで次のコマンドを実行して下さい。</p>
<pre class="lang:sh decode:true">mvn archetype:generate -DgroupId=sandbox -DartifactId=WicketSandbox -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=7.0.0 -DarchetypeRepository=https://repository.apache.org/ -DinteractiveMode=false</pre>
<p>groupIdとartifactIdは適切に変更して下さい。なおこのコマンドは<a title="Wicket Quickstart" href="https://wicket.apache.org/start/quickstart.html" target="_blank">WicketのQuickstartページ</a>で編集出来ます。</p>
<h3>2. 雛形アプリの起動</h3>
<p>mvnコマンドの実行が完了したら、動作する雛形アプリが出来上がっています。早速起動してみましょう。</p>
<pre class="lang:sh decode:true">cd WicketSandbox
mvn jetty:run</pre>
<p>WicketSandboxの部分はご自分のartifactIdに合わせて適切に変更して下さい。</p>
<p>コンソールにテキストがずらずらと表示され、下記のように「Started Jetty Server」と表示されれば起動が完了しています。</p>
<pre class="lang:sh decode:true ">********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
2015-10-07 06:56:47.966:INFO:oejsh.ContextHandler:main: Started o.e.j.m.p.JettyWebAppContext@12d54304{/,file:/Users/jabaraster/Documents/Develop/Java/workspace/projects/WicketSandbox/src/main/webapp/,AVAILABLE}{file:/Users/jabaraster/Documents/Develop/Java/workspace/projects/WicketSandbox/src/main/webapp/}
2015-10-07 06:56:47.967:WARN:oejsh.RequestLogHandler:main: !RequestLog
2015-10-07 06:56:48.001:INFO:oejs.ServerConnector:main: Started ServerConnector@319f9f37{HTTP/1.1}{0.0.0.0:8080}
2015-10-07 06:56:48.303:INFO:oejs.ServerConnector:main: Started ServerConnector@4602f47{SSL-http/1.1}{0.0.0.0:8443}
2015-10-07 06:56:48.304:INFO:oejs.Server:main: Started @8721ms
[INFO] Started Jetty Server
</pre>
<p>次のURLにアクセスして画面を確認してみましょう。</p>
<p><a href="http://localhost:8080">http://localhost:8080</a></p>
<p>次の画面がブラウザに表示されれば起動に成功しています！</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/10/Apache_Wicket_Quickstart.png"><img class="alignnone size-full wp-image-1778" src="https://cloudear.jp/blog/wp-content/uploads/2015/10/Apache_Wicket_Quickstart.png" alt="Apache_Wicket_Quickstart" width="865" height="455" /></a></p>
<p>&nbsp;</p>
<h2>第二章　Wicketによる開発の概念を知る</h2>
<p>雛形アプリの中身を見ていく前に、Wicketによる開発の考え方を押さえておきましょう。</p>
<h3>1. HTMLとぺージクラスで画面を作る</h3>
<p>WicketはHTMLで画面を作り、画面に対しページクラスを作ることでWebアプリケーションを構築します。</p>
<h3>2. ページクラスの中にコンポーネントを配置</h3>
<p>ページクラスの中には様々な種類のコンポーネントを配置します。コンポーネントはHTMLの一部に相当します。例えば<code>&lt;button&gt;&lt;/button&gt;</code>タグに相当するButtonクラスなどがあります。Buttonクラスのような基本的なコンポーネントはもちろん、多くのコンポーネントがWicketから提供されています。また必要であれば自作することも出来ます。コンポーネントを知ることはWicketを使う上で重要なポイントになります。</p>
<h3>3. コンポーネントは入れ子に出来る</h3>
<p>コンポーネントによっては、中に１個以上の子コンポーネントを持つことが出来ます。コンポーネントは入れ子に出来るわけです。<br />
実はページクラスもコンポーネントです。Wicketのページクラスは、ページクラスを根本としたコンポーネントのツリー構造となります。</p>
<p>&nbsp;</p>
<h2>第三章　HTMLとぺージクラスのポイントを押さえる</h2>
<p>Wicketで最も重要なのはHTMLとぺージクラスの作り方です。ここでは雛形アプリを使ってポイントを押さえておきます。<br />
雛形アプリのファイル構成を見ると、「HomePage」から始まるファイルが２つあります。ぺージクラスと、それに対応するHTMLファイルです。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_file_structure_simple.png"><img class="alignnone size-full wp-image-1789" src="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_file_structure_simple.png" alt="WicketSandbox_file_structure_simple" width="320" height="294" /></a></p>
<p>まずはぺージクラスのコードを見てみましょう。</p>
<pre class="lang:java decode:true" title="HomePage.java">package sandbox;

import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.WebPage;

public class HomePage extends WebPage {
    private static final long serialVersionUID = 1L;

    public HomePage(final PageParameters parameters) {
        super(parameters);

        // Labelコンポーネントをぺージクラスに追加z
        add(new Label("version", getApplication().getFrameworkSettings().getVersion()));

        // TODO Add your page's components here

    }
}</pre>
<p>ポイントを挙げておきます。</p>
<ul>
<li>７行目：ぺージクラスはWebPageクラスを継承</li>
<li>14行目：ぺージクラスの子としてLabelコンポーネントを追加</li>
</ul>
<p>次にHTMLを見てみます・・・と言いたいところですが、雛形アプリのHTMLファイルはかなりコード量が多く大事な部分が見えにくいですから、思い切って重要でない部分を落としてしまいましょう。次のようにHTMLを書き換えて下さい。</p>
<pre class="lang:default decode:true" title="HomePage.html">&lt;!DOCTYPE html&gt;
&lt;html xmlns:wicket="http://wicket.apache.org"&gt;
	&lt;head&gt;
		&lt;meta charset="utf-8" /&gt;
		&lt;title&gt;Apache Wicket Quickstart&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Wicketのバージョン: &lt;span wicket:id="version"&gt;ここに使っているWicketのバージョンが入ります&lt;/span&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>&nbsp;</p>
<p>何の変哲もないHTMLですが、１つだけ変な記述がありますね。８行目の<strong>wicket:id</strong>属性です。</p>
<p>wicket:id属性は、HTMLのタグをページクラスで追加したコンポーネントと関連付けるものです。ぺージクラスのコードのコンポーネント追加部分を再掲します。</p>
<pre class="lang:java decode:true">add(new Label("version", getApplication().getFrameworkSettings().getVersion()));</pre>
<p>Labelクラスのコンストラクタの第一引数に注目して下さい。&#8221;version&#8221;となっており、HTMLのwicket:id属性の値&#8221;version&#8221;と一致しています。ここがポイントです。</p>
<p>Wicketでは、コンポーネントの第１引数に必ずIDを取るようになっています。このIDとHTML上のwicket:id属性の値を一致させることで、コンポーネントと関連付けられます。</p>
<p>以上がWicketを使う上で最低限知っておかなければならないことです。</p>
<p>&nbsp;</p>
<h2>第四章　コンポーネントを使う</h2>
<p>実際にWebアプリケーションを作るには、種々のコンポーネントの知識が必要です。Wicketは様々なコンポーネントを提供していますので、うまく使えばあまり深く考えなくてもリッチなUIを実現出来ます。ここからは代表的なコンポーネントの使い方を見てみましょう。</p>
<h3>1. 予備知識・匿名クラスについて</h3>
<p>コンポーネントを使う上でよく使うJavaの機能に<strong>匿名クラス</strong>というものがあります。匿名クラスは簡単に言えばnewしたオブジェクトの一部メソッドをオーバーライドする機能です。<br />
次のように記載します。</p>
<pre class="lang:java decode:true ">final Map&lt;String, List&lt;String&gt;&gt; map = new HashMap&lt;String, List&lt;String&gt;&gt;() {
    @Override
    public List&lt;String&gt; get(final Object pKey) {
        List&lt;String&gt; ret = super.get(pKey);
        if (ret == null) {
            ret = new ArrayList&lt;&gt;();
            put((String) pKey, ret);
        }
        return ret;
    }
};
</pre>
<p>コンストラクタ呼び出しの直後に{}を記載し、中でメソッドをオーバーライドします。上記の例ではHashMapクラスをnewすると同時にgetメソッドをオーバーライドしています。この構文はWicketを使っていると頻出しますので慣れておいて下さい。</p>
<h3>2. Ajaxコンポーネントを使う</h3>
<p>まずはAjaxコンポーネントの使い方を見てみましょう。いきなりAjax？と思われるかもしれませんがWicketはAjaxをとても簡単に扱うことが出来るのです。ここでは、ボタンを押す度にサーバの時刻をAjaxで取得して表示する機能を追加してみましょう。</p>
<p>まずサーバの時刻を表示するコンポーネントを追加します。</p>
<pre class="lang:java decode:true">final Label now = new Label("now", new AbstractReadOnlyModel&lt;String&gt;() {
    @Override
    public String getObject() {
        return DateFormat.getDateTimeInstance().format(new Date());
    }
});
now.setOutputMarkupId(true);
add(now);
</pre>
<p>7行目の<code>now.setOutputMarkupId(true)</code>を忘れないようにして下さい。これはAjaxで書き換えるコンポーネントに対して必要な記述です。</p>
<p>次にリンクコンポーネントを追加します。</p>
<pre class="lang:java decode:true">final AjaxLink&lt;?&gt; nowRefresher = new AjaxLink&lt;Object&gt;("nowRefresher") {
    @Override
    public void onClick(final AjaxRequestTarget pTarget) {
        pTarget.add(now);
    }
};
add(nowRefresher);
</pre>
<p>このコードの意味は、「リンクを押したらnowコンポーネントを再表示しなさい」です。</p>
<p>最後にHTMLを編集します。Javaコードで追加した２つのコンポーネントをHTMLにも追記しましょう。</p>
<pre class="lang:default decode:true">&lt;h2 wicket:id="now"&gt;サーバの時刻がここに表示されます&lt;/h2&gt;
&lt;a wicket:id="nowRefresher"&gt;サーバ時刻表示を更新&lt;/a&gt;</pre>
<p>次のURLにアクセスして画面を確認してみましょう。</p>
<p><a href="http://localhost:8080">http://localhost:8080</a></p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_collection_sample.png"><img class="alignnone size-medium wp-image-1817" src="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_ajax_sample3.png" alt="WicketSandbox_ajax_sample" width="300" height="145" /></a></p>
<p>「サーバ時刻表示を更新」というリンクをクリックする度に時刻表示が更新されるのが分かると思います。</p>
<p>このように、WicketはAjaxを「コンポーネントを再表示する」機能として取り込むことで、プログラマが楽にAjaxを利用出来るようにしているのです。</p>
<p>&nbsp;</p>
<h2>第五章　コレクションを扱う</h2>
<p>次に紹介するコンポーネントはコレクションを扱うものです。一覧表示はWebアプリケーションで欠かせないものですから、コレクションの扱い方を押さえておくのは不可欠です。</p>
<p>コレクションを扱うコンポーネントには様々な種類があるのですが、ここでは最も一般的なListViewを使います。以下、ListViewの生成とページクラスへの追加を行うコードです。</p>
<pre class="lang:java decode:true ">final List&lt;String&gt; nameValues = Arrays.&lt;String&gt; asList("JavaEE6", "Ninja", "Play Framework", "Wicket");
final ListView&lt;String&gt; names = new ListView&lt;String&gt;("names", nameValues) {
    @Override
    protected void populateItem(final ListItem&lt;String&gt; pItem) {
        pItem.add(new Label("name", pItem.getModelObject()));
    }
};
add(names);
</pre>
<p>ここでも匿名クラスが登場しています。オーバーライドしているpopulateItemメソッドは、コレクションの要素毎に呼び出されます。引数のListItemにコンポーネントを追加することで画面を編集出来ます。ここではLabelのみを追加し、シンプルに文字列を表示しています。</p>
<p>併せてHTMLも編集しましょう。</p>
<pre class="lang:default decode:true">&lt;h2&gt;Javaフレームワーク&lt;/h2&gt;
&lt;ul&gt;
    &lt;li wicket:id="names"&gt;&lt;span wicket:id="name"&gt;ここにコレクションの要素が表示されます&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
</pre>
<p>次のURLにアクセスして画面を確認してみましょう。</p>
<p><a href="http://localhost:8080">http://localhost:8080</a></p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_collection_sample1.png"><img class="alignnone size-full wp-image-1818" src="https://cloudear.jp/blog/wp-content/uploads/2015/10/WicketSandbox_collection_sample1.png" alt="WicketSandbox_collection_sample" width="298" height="173" /></a></p>
<p>いかがでしょうか。多少クセがありますが、Wicketでコレクションを扱うときの基本形は以上のようになります。</p>
<p>&nbsp;</p>
<h3>その他のコンポーネント</h3>
<p>他にも数多くの便利なコンポーネントがあるのですが、とてもではありませんが紹介するスペースが足りませんので、重要なものの名前を挙げるに留めます。</p>
<ul>
<li>Form/TextFieldなど：ユーザからの入力を受け取るフォーム部品が提供されています</li>
<li>AjaxButton/IndicatingAjaxButton：Ajaxでサブミットするボタンです</li>
<li>AjaxFallbackDefaultDataTable：Ajaxによるページング機能を持つテーブルです</li>
</ul>
<p>&nbsp;</p>
<h2>第六章　コンポーネントを作る</h2>
<p>最後に、簡単なコンポーネントを作ってみましょう。Ajaxコンポーネントの紹介で作ったサーバ時刻を表示する機能をコンポーネント化してみます。</p>
<p>HTMLを持つコンポーネントを作るには、Panelクラスを継承します。ここではServerTimePanelというクラスを作ってみましょう。</p>
<pre class="lang:java decode:true">package sandbox;

import java.text.DateFormat;
import java.util.Date;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;

public class ServerTimePanel extends Panel {

    public ServerTimePanel(final String pId) {
        super(pId);

        final Label now = new Label("now", new AbstractReadOnlyModel&lt;String&gt;() {
            @Override
            public String getObject() {
                return DateFormat.getDateTimeInstance().format(new Date());
            }
        });
        now.setOutputMarkupId(true);
        add(now);

        final AjaxLink&lt;?&gt; nowRefresher = new AjaxLink&lt;Object&gt;("nowRefresher") {
            @Override
            public void onClick(final AjaxRequestTarget pTarget) {
                pTarget.add(now);
            }
        };
        add(nowRefresher);
    }
}
</pre>
<p>HomePage.javaからコンポーネント生成と追加部分を移植しました。</p>
<p>次にHTMLファイルを作成します。クラスと同名、つまりServerTimePanel.htmlを作りましょう。</p>
<pre class="lang:default decode:true">&lt;wicket:panel&gt;
    &lt;h2 wicket:id="now"&gt;サーバの時刻がここに表示されます&lt;/h2&gt;
    &lt;button type="button" wicket:id="nowRefresher"&gt;サーバ時刻表示を更新&lt;/button&gt;
&lt;/wicket:panel&gt;
</pre>
<p><code>&lt;wicket:panel&gt;〜&lt;/wicket:panel&gt;</code>で囲んだ部分がコンポーネントとして使われるHTMLになります。</p>
<p>これでコンポーネントは完成。使う側のページクラスを修正しましょう。</p>
<p>HomePage.javaは次のようになります。</p>
<pre class="lang:java decode:true">package sandbox;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.request.mapper.parameter.PageParameters;

public class HomePage extends WebPage {

    public HomePage(final PageParameters parameters) {
        super(parameters);
        add(new Label("version", getApplication().getFrameworkSettings().getVersion()));
        add(new ServerTimePanel("serverTime"));
    }
}
</pre>
<p>12行目でServerTimePanelを使っています。ご覧の通り、自作のコンポーネントだからといって特別なことは何もなく、Labelなどのコンポーネントと同じように扱えます。</p>
<p>HomePage.htmlは次のようになります。</p>
<pre class="lang:default decode:true">&lt;!DOCTYPE html&gt;
&lt;html xmlns:wicket="http://wicket.apache.org"&gt;
    &lt;head&gt;
        &lt;meta charset="utf-8" /&gt;
        &lt;title&gt;Apache Wicket Quickstart&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        Wicketのバージョン: &lt;span wicket:id="version"&gt;ここに使っているWicketのバージョンが入ります&lt;/span&gt;
        &lt;hr/&gt;
        &lt;div wicket:id="serverTime"&gt;&lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>10行目でServerTimePanelコンポーネントを使っています。こちらも特別なことは何もないですね。実際にブラウザ上でどう表示されるかは、皆さんの目で確かめて下さい。</p>
<p>&nbsp;</p>
<h2>まとめ</h2>
<p>かなり駆け足でWicketの概要と基本を見てきました。Ajaxの利用や部品化が簡単に行えることが理解していただけたかと思います。</p>
<p>Javaの利点を最大限に発揮することを目指して作られているWicketは、機能や設定項目にうまくJavaの型を当てることで、誤解やミスが生じにくいAPIを提供しています。</p>
<p>簡単かつ安全にWebアプリケーションを作れるWicketにぜひ触れてみて、一味違うフレームワークを味わってみて下さい。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1755</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebookが作ったJavaScriptライブラリ、Reactの威力を体感する</title>
		<link>https://cloudear.jp/blog/?p=1545</link>
		<comments>https://cloudear.jp/blog/?p=1545#comments</comments>
		<pubDate>Thu, 24 Sep 2015 01:03:20 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1545</guid>
		<description><![CDATA[今回のエントリでは、最近注目を浴びているJavaScriptライブラリ「React」を取り上げます。 Reactとは Reactはブラウザで動作するWebアプリケーションのUI（ユーザインターフェイス）を担当するJava [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>今回のエントリでは、最近注目を浴びているJavaScriptライブラリ「React」を取り上げます。</p>
<h2>Reactとは</h2>
<p>Reactはブラウザで動作するWebアプリケーションのUI（ユーザインターフェイス）を担当するJavaScriptライブラリです。DOM操作を通して画面の見た目を変えることに特化しています。</p>
<p>Reactの重要な特徴は３つあります。</p>
<p><span id="more-1545"></span></p>
<h3>JSXによるDOM操作の隠蔽</h3>
<p>本来DOM操作は面倒で誤りやすいプログラムを書く必要があのですが、Reactは、JSXというJavaScriptを拡張した言語を提供することで、面倒なDOM操作をプログラマから隠してくれます。</p>
<p>その代わりJSXをJavaScriptに変換するという開発上の手間が必要ですが、JSXはこの手間を上回る利便性を提供してくれます。</p>
<h3>一方向データバインディング</h3>
<p>Reactでは「データ」→「画面（HTML）」という方向でしかデータが流れません。AngularJSなどは画面でユーザの入力を検出したらデータに反映してくれるようですが、Reactはあくまでデータを画面に反映するのみです。</p>
<p>これはプログラムの見通しが良くなる効果がありますし、またReactを使うために覚えることが少なくなるという利点もあります。</p>
<h3>コンポーネント指向</h3>
<p>Reactは画面の部品化を促進します。HTMLの一部をコンポーネントとして切り出し、プロパティやイベントハンドラをコンポーネントの中にまとめて記述出来ます。</p>
<p>これにより、プログラムの記述方法が統一されるという効果や、いわゆるカプセル化による保守性向上が望めます。</p>
<h2>Reactを使ったプログラム</h2>
<p>さてこれ以降は、実際にReactを使ったプログラムを見て行きましょう。今回はHTMLファイルの中にスクリプトを書く方法を使います。</p>
<h3>最小のサンプル</h3>
<p>まずはReactを使ってHello Worldを書いてみます。</p>
<pre class="lang:js decode:true" title="hello_react.html">&lt;!DOCTYPE html&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8" /&gt;
  &lt;title&gt;Hello, React!&lt;/title&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id="content"&gt;&lt;/div&gt;
  &lt;script type="text/jsx"&gt;

// コンポーネントを定義
var Hello = React.createClass({
    render: function() {
        return (
            &lt;h1&gt;Hello, React!&lt;/h1&gt;
        );
    },
});
// コンポーネントを描画
React.render(&lt;Hello /&gt;, document.getElementById('content'));

  &lt;/script&gt;
&lt;/body&gt;
</pre>
<p>scriptタグのtype属性値が&#8221;text/jsx&#8221;となっていることに注意して下さい。</p>
<p>このサンプルでは、Reactプログラミングで欠かすことの出来ない２つの操作を行っています。</p>
<ul>
<li>コンポーネントを作る：React.createClass関数（&#8221;createClass&#8221;なのに&#8221;コンポーネントを作る&#8221;と表現しているのは大目に見て下さい）</li>
<li>画面に描画する：React.render関数</li>
</ul>
<p>また、Helloコンポーネントのrender関数に注目して下さい。HTMLタグを直接returnしていますね。この書き方を実現しているのが、JSXというJavaScript拡張言語です。</p>
<h2>重要な３つの機能</h2>
<p>驚くべきことに、ReactでWebアプリケーションを作る上で必須なのはたった３つの機能です。</p>
<h3>１．子コンポーネントに属性を指定する</h3>
<p>コンポーネントは入れ子に出来ます。１つのコンポーネントで事が済むことはほとんど無く、いくつかのコンポーネントを組み合わせて画面を作って行くのが通常です。</p>
<p>なおここからのサンプルコードは、HTMLの部分が最小のサンプルと変わりません。ですのでscriptタグの中だけを記載することにします。</p>
<pre class="lang:js decode:true" title="inner.html">// 子コンポーネント
var Child = React.createClass({
    render: function() {
        return (
            &lt;h2&gt;{this.props.text}&lt;/h2&gt;
        );
    }
});
// 親コンポーネント
var Parent = React.createClass({
    render: function() {
        return (
            &lt;div&gt;
                &lt;h1&gt;ここは親です&lt;/h1&gt;
                &lt;Child text="ここは子1です" /&gt;
                &lt;Child text="ここは子2です" /&gt;
            &lt;/div&gt;
        );
    },
});
// 親コンポーネントを描画
React.render(&lt;Parent /&gt;, document.getElementById('content'));
</pre>
<p>ChildとParentという２つのコンポーネントを定義しています。そして親コンポーネントParentのrender関数の中でChildコンポーネントを使っています。render関数の中にはHTMLタグだけでなくコンポーネントを書くことも出来るのです。</p>
<p>重要な機能として、親から子に属性を通して値を渡すことが出来ます。以下の部分です。</p>
<pre class="lang:js decode:true">&lt;Child text="ここは子1です" /&gt;</pre>
<p>Childコンポーネントにtext属性を付けています。一方、Childコンポーネントの中では次のようにしてtext属性値を使っています。</p>
<pre class="lang:js decode:true">return (
    &lt;h2&gt;{this.props.text}&lt;/h2&gt;
);
</pre>
<p>this.propsというオブジェクトを使うことで属性値にアクセス出来ます。</p>
<h3>２．イベントハンドリング</h3>
<p>コンポーネントの属性には関数を渡すことが出来ます。これを利用し、子コンポーネントのイベントを親コンポーネントでハンドリングすることが出来ます。</p>
<pre class="lang:js decode:true" title="event.html">// 子コンポーネント
var Child = React.createClass({
    onClick: function() {
        this.props.onNowButtonClick(new Date());
    },
    render: function() {
        return (
            &lt;div&gt;
                &lt;h2&gt;{this.props.text}&lt;/h2&gt;
                &lt;button onClick={this.onClick}&gt;現在時刻を通知&lt;/button&gt;
            &lt;/div&gt;
        );
    }
});
// 親コンポーネント
var Parent = React.createClass({
    handleNowButtonClick: function(pNow) {
        alert(pNow);
    },
    render: function() {
        return (
            &lt;div&gt;
                &lt;h1&gt;ここは親です&lt;/h1&gt;
                &lt;Child onNowButtonClick={this.handleNowButtonClick} text="ここは子です" /&gt;
            &lt;/div&gt;
        );
    },
});
// 親コンポーネントを描画
React.render(&lt;Parent /&gt;, document.getElementById('content'));
</pre>
<p>親コンポーネントにはイベントをハンドリングする関数handleNowButtonClickが増えました。またChildコンポーネントの属性にイベントハンドリング関数を渡しています。</p>
<p>子コンポーネントは少し複雑です。まずrender関数にbuttonタグを増やしonClick属性に自身のイベントハンドラ関数onClickを渡しています。</p>
<pre class="lang:default decode:true ">&lt;button onClick={this.onClick}&gt;現在時刻を通知&lt;/button&gt;</pre>
<p>そして自身のイベントハンドラ関数の中で、属性に指定された関数onNowButtonClickを実行しています。</p>
<pre class="lang:js decode:true">onClick: function() {
    this.props.onNowButtonClick(new Date());
}</pre>
<h3>３．状態を扱う</h3>
<p>最後の機能は状態を扱うためのものです。次のサンプルではボタンを押す度に画面の時刻表示が変わります。</p>
<pre class="lang:js decode:true" title="state.html">// 子コンポーネント
var Child = React.createClass({
    onClick: function() {
        this.props.onNowButtonClick(new Date());
    },
    render: function() {
        return (
            &lt;div&gt;
                &lt;h2&gt;{this.props.time.toString()}&lt;/h2&gt;
                &lt;button onClick={this.onClick}&gt;現在時刻を通知&lt;/button&gt;
            &lt;/div&gt;
        );
    }
});
// 親コンポーネント
var Parent = React.createClass({
    getInitialState: function() {
        return {
            now: new Date()
        };
    },
    handleNowButtonClick: function(pNow) {
        this.setState({ now: pNow }); // ←ここが重要！状態を更新します
        alert(pNow);
    },
    render: function() {
        return (
            &lt;div&gt;
                &lt;h1&gt;ここは親です&lt;/h1&gt;
                &lt;Child onNowButtonClick={this.handleNowButtonClick} time={this.state.now} /&gt;
            &lt;/div&gt;
        );
    },
});
// 親コンポーネントを描画
React.render(&lt;Parent /&gt;, document.getElementById('content'));
</pre>
<p>親コンポーネントにgetInitialState関数が増えています。この関数はコンポーネントの初期状態を返します。</p>
<pre class="lang:js decode:true">getInitialState: function() {
    return {
        now: new Date()
    };
}</pre>
<p>更にsetState関数を呼び出すことで状態を変更しています。</p>
<pre class="lang:js decode:true ">handleNowButtonClick: function(pNow) {
    this.setState({ now: pNow }); // ←ここが重要！
    alert(pNow);
}</pre>
<p>もう１つ重要な箇所があります。子コンポーネントの属性に親コンポーネントの状態を渡しています。</p>
<pre class="lang:js decode:true">&lt;Child onNowButtonClick={this.handleNowButtonClick} time={this.state.now} /&gt;
</pre>
<p>ReactのすごいところはsetState関数を呼び出すと関連する箇所が自動で書き換わることです。プログラマはコンポーネントを定義し、render関数を書き、setState関数を呼ぶだけ。たったこれだけでWebアプリケーションがきれいに動きます。</p>
<h2>データの更新を伴うサンプル</h2>
<p>最後のサンプルとして、データの更新を伴う画面のコードを載せておきます。画面イメージは次のようになります。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/09/3c793e68ff516233740231bf93e5436d.png"><img class="alignnone size-full wp-image-1582" src="https://cloudear.jp/blog/wp-content/uploads/2015/09/3c793e68ff516233740231bf93e5436d.png" alt="スクリーンショット 2015-09-08 18.41.25" width="767" height="556" /></a></p>
<p>このサンプルはHTMLも変わっていますので全文を載せます。手軽に見栄えを良くするためにBootstrapを使っています。</p>
<pre class="lang:js decode:true" title="input.html">&lt;!DOCTYPE html&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8" /&gt;
  &lt;title&gt;ReactによるCRUDアプリ&lt;/title&gt;
  &lt;link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js"&gt;&lt;/script&gt;
  &lt;style&gt;
    body {
        padding-top: 20px;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id="content"&gt;&lt;/div&gt;
  &lt;script type="text/jsx"&gt;
// テーブルの各行となるコンポーネント
var Rows = React.createClass({
    onDataRemove: function(pIndex) {
        this.props.onDataRemove({ index: pIndex });
    },
    render: function() {
        // 各行のタグを連結
        var rows = this.props.data.map(function(e, idx) {
            return (
                &lt;tr key={e.id}&gt;
                    &lt;td&gt;{e.title}&lt;/td&gt;
                    &lt;td&gt;{e.content}&lt;/td&gt;
                    &lt;td&gt;
                        &lt;button onClick={this.onDataRemove.bind(this, idx)} className="btn btn-danger"&gt;
                            &lt;i className="glyphicon glyphicon-trash" /&gt;
                        &lt;/button&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            );
        }.bind(this));
        // tableタグを作成
        return (
            &lt;table className="table table-striped"&gt;
                &lt;thead&gt;
                    &lt;th&gt;タイトル&lt;/th&gt;
                    &lt;th&gt;内容&lt;/th&gt;
                    &lt;th&gt; &lt;/th&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    {rows}
                &lt;/tbody&gt;
            &lt;/table&gt;
        );
    }
});
// 入力フォームコンポーネント
var Form = React.createClass({
    onAddButtonClick: function(e) {
        // React.findDOMNode関数で入力項目を得ることが出来る
        var title = React.findDOMNode(this.refs.title).value;
        var content = React.findDOMNode(this.refs.content).value;

        // データ追加をイベント通知
        this.props.onDataAdd({ id: (new Date()).getTime(), title: title, content: content });

        e.preventDefault(); // デフォルトの動作をキャンセル
    },
    render: function() {
        return (
            &lt;form&gt;
                &lt;div className="form-group"&gt;
                    &lt;label htmlFor="title"&gt;タイトル&lt;/label&gt;
                    &lt;input ref="title" type="text" className="form-control" id="title" /&gt;
                &lt;/div&gt;
                &lt;div className="form-group"&gt;
                    &lt;label htmlFor="content"&gt;内容&lt;/label&gt;
                    &lt;textarea ref="content" className="form-control" id="content" /&gt;
                &lt;/div&gt;
                &lt;button onClick={this.onAddButtonClick} className="btn btn-primary"&gt;追加&lt;/button&gt;
            &lt;/form&gt;
        );
    }
});
// ルートコンポーネント
var Root = React.createClass({
    getInitialState: function() {
        return {
            data: []
        };
    },
    handleDataAdd: function(e) {
        var data = this.state.data;
        data.push(e);
        this.setState({ data: data });
    },
    handleDataRemove: function(e) {
        var data = this.state.data;
        data.splice(e.index, 1);
        this.setState({ data: data });
    },
    render: function() {
        return (
            &lt;div className="container"&gt;
                &lt;Form onDataAdd={this.handleDataAdd} /&gt;
                &lt;hr/&gt;
                &lt;Rows data={this.state.data} onDataRemove={this.handleDataRemove} /&gt;
            &lt;/div&gt;
        );
    }
});
// ルートコンポーネントを画面に描画
React.render(&lt;Root /&gt;, document.getElementById('content'));
  &lt;/script&gt;
&lt;/body&gt;
</pre>
<p>少し長くなりましたが、各コンポーネントの役割分担がはっきりしている上にHTMLとJavaScriptが１つのコンポーネントの中にまとまっているため、コードの見通しが良く読みやすいと思います。</p>
<p>またJSXのおかげでDOM操作のコードが一切現れていない点に注目して下さい。render関数にテンプレートを書いておけば、DOMを意識する必要がなくなります。</p>
<p>画面は常にデータに対して描画されます。ずれることはありません。またユーザの入力はsetState関数でデータに反映させることで、Reactが文字通りreact（反応）して必要な部分だけが再描画されます。</p>
<p>つまりReactを手にしたプログラマは<span style="color: #ff0000;"><strong>データ操作だけに集中</strong></span>してプログラムすれば良い、ということになります。Reactの真髄はここにあります。</p>
<h2>実戦投入するときには</h2>
<p>本エントリのコードはあくまでサンプルですので、実際にReactを実戦投入するときに、考慮すべきことがあります。</p>
<h3>JSXの事前コンパイル</h3>
<p>本エントリのコードはポータビリティを重視したため、JSXをブラウザでコンパイルしています。しかし実戦では事前にJSXをコンパイルし出力されたJavaScriptをHTMLから参照するようにするべきです。</p>
<p>事前コンパイルにはいくつかの方法がありますが、この解説はまたの機会に譲ることにします。</p>
<h3>サーバサイドレンダリング</h3>
<p>素直にReactを使っていると、HTMLの多くがJavaScriptが実行されるまで描画されないため、体感的にページの描画が遅くなります。そこでReactでは初期画面をサーバサイドでもレンダリング出来る仕組みが備わっています。</p>
<p>サーバサイドレンダリングの詳しい解説もまたの機会に譲ることにします。</p>
<h2>Reactの注意点</h2>
<h3>Reactを通さずDOMを操作するのは厳禁！</h3>
<p>これは、例えばjQueryを使ってDOMを追加／削除／変更することは厳禁！ということです。また、jQueryを通してイベントハンドラを設定することも厳禁です。これはReactが採用している「バーチャルDOM」という仕組みへの配慮です。</p>
<p>DOM操作というのは低速な処理です。そこでReactは、DOMを更新しなければならないときに、バーチャルDOMを使って差分を算出し、実際のDOMは最低限必要な箇所のみ更新する、ということをやっているのです。</p>
<p>ですので、Reactを通さずにDOMを更新してしまうと、バーチャルDOMと実際のDOMに齟齬が出来てしまい、Reactが正しくDOMを更新出来なくなってしまいます。</p>
<p>jQueryに慣れていればいるほど、この制限は辛いものになるでしょう。しかし一度Reactに慣れてしまうと、jQueryの手続き的なDOM操作がとても面倒かつ危険なものに思えてきます。ぜひReactを使ってみてパラダイムシフトを体感していただきたいと思います。</p>
<h2>まとめ</h2>
<p>覚えることが少なくとっつきやすいReact。実績も充分（何せFacebookで使われている！）です。JavaScriptにHTMLを埋め込むのが気持ち悪いと感じる方もいると思いますが、そこを乗り越えればものすごく便利に使えるライブラリです。</p>
<p>SPA（Single Page Application）タイプのWebアプリケーションを作るときは、ぜひ採用を検討してみて下さい。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1545</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>今からでも遅くない！身に付けよう、良いJavaコーディングスタイル</title>
		<link>https://cloudear.jp/blog/?p=1459</link>
		<comments>https://cloudear.jp/blog/?p=1459#comments</comments>
		<pubDate>Sun, 30 Aug 2015 23:53:05 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1459</guid>
		<description><![CDATA[今回はJavaのコーディングスタイルに関する話題です。 スタイルにはいろんな考え方がありますが、本エントリでは「読むときのことを考える」という原則に従ったスタイルを考えて行きます。 「プログラムは書いている時間よりも読ま [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>今回はJavaのコーディングスタイルに関する話題です。</p>
<p>スタイルにはいろんな考え方がありますが、本エントリでは「<em><strong>読むときのことを考える」</strong></em>という原則に従ったスタイルを考えて行きます。</p>
<p><span id="more-1459"></span></p>
<p>「プログラムは書いている時間よりも読まれている時間の方がずっと長い」とFacebookの中の人が言ったとか言わないとか。また「昨日の自分は他人」とも言いますね。たとえ自分が書いたプログラムでも、後から読み返してみると「何でこんなコーディングしてるんだろ・・・」と思うことは良くあります。自分も含めた将来の読み手に対し、適切な情報を与えることで読みやすいプログラムを書くように心がける必要があるでしょう。</p>
<h2>考え方の基本は「読み手に課す前提を減らす」</h2>
<p>「読み手に課す前提」とは何でしょうか。それは、ある箇所のコードを読んでいるときに考慮しなければならない事柄を減らす、ということです。</p>
<p>次のコードを見て下さい。</p>
<pre class="lang:java decode:true" title="多くのケースが考えられるコード">public Object someMethod(String s) {
    String os = cnv(s);
    ...
}

public String cnv(String s) {
    ...
}
</pre>
<p>someMethodを読み解くには、いろんな可能性を考える必要があります。</p>
<ul>
<li>publicだからどこから呼び出されているか分からないな・・・</li>
<li>返り値がObject型なんだけど、実際にはどの型のオブジェクトが返ってるんだろう・・・？</li>
<li>インスタンス変数に手を加えてる可能性ってあるのかな・・・？</li>
<li>cnvメソッドは何をやってるんだろう？副作用はないの？インスタンス変数に手を加えるようなことしてないよね？</li>
<li>cnvメソッドまでpublicなんだけど名前から言ってユーティリティっぽいんだけど、このクラスの外から呼び出している箇所ってあるの？</li>
</ul>
<p>安易なpublic宣言のおかげで、読み解くのがとてもたいへんなことになっています。しかし、このコードが次のようになっているとどうでしょうか。</p>
<pre class="lang:java decode:true" title="可能性を極限まで減らしたコード">void someMethod(final String s) {
    final String os = cnv(s);
    ...
}

private static String cnv(final String s) {
    ...
}
</pre>
<ul>
<li>someMethodはパッケージ外から呼び出されていることはない！→呼び出し元を洗い出す範囲が減った！</li>
<li>戻り値はない！→インスタンス変数に何らかの変更を加えているはず！</li>
<li>cnvメソッドはprivateかつstaticだから、インスタンス変数に手を加えることは無いしこのクラスの外から呼び出されることはない！</li>
</ul>
<p>先のコードに比べ、考慮しなければならない事柄が相当に減ります。</p>
<h2>読み手に課す前提を減らすためのスタイル</h2>
<p>読み手に課す前提を減らすには、以下のようなスタイルを採用すると良いでしょう。</p>
<h3>アクセス修飾子はprivateが基本！</h3>
<p>特にpublicはどこからでも参照可能になり影響範囲が広大です。本当にpublicでないといけないのか、自問しましょう。</p>
<h3>変数のスコープは最小限に</h3>
<p>コードを読む際に考慮すべき変数が少ない方が読みやすいです。グローバル変数よりもインスタンス変数を、インスタンス変数よりもローカル変数を選択しましょう。</p>
<h3>staticメソッドを好む</h3>
<p>staticメソッドの中ではthisが参照出来ません。staticメソッドの中ではインスタンス変数に変更が入らないことが保証されるわけで、考えなければならないことがかなり減ります。</p>
<p>これは後にもう少し詳しく解説します。</p>
<p>ちなみに・・・あくまでstatic<strong>メソッド</strong>が有用なのであって、static<strong>変数</strong>はむやみに使わないように気を付けて下さい。特に<strong>finalでないstatic変数</strong>が必要な局面はほぼありません。finalでないstatic変数を宣言したくなったら「何かがおかしいのでは？」と自問して下さい。</p>
<h3>変数やメソッドの名前の単語を極力省略しない</h3>
<p>書くのは面倒ですが読みやすいです。</p>
<h3>変数の数を少なくする</h3>
<p>ただでさえ変数の中の値は目に見えないため、人間にとって把握が難しい存在です。その上数が増えると飛躍的に複雑さが増し、手に負えなくなります。クラスにまとめるなどして、シンプルに管理出来ないか？などの手法を考えましょう。</p>
<h3>インデントを減らす</h3>
<p>インデントは何らかの条件分岐の結果で生じている場合がほとんどです。よって、インデントが深いということは複数の条件が組み合わされている、ということであり、人間の頭では把握が難しい状況です。</p>
<p>また、インデントを抜ける際には「今までどんな条件の下で処理が実行されてたんだっけ」と考えなおす必要があります。</p>
<p>これは後にもう少し詳しく解説します。</p>
<h3>変数は宣言と同時に初期化し、finalを付ける</h3>
<p>先にも書いたように、変数の値は目にみえないため、人間にとって把握が難しい存在です。ましてや値がどんどん変わって行ってしまうような変数は、相当理解が難しいと言えます。</p>
<p>final変数は、２度と値が変わらないことが保証されています。これは読み手に大きな安心感を与えます。</p>
<p>これは後にもう少し詳しく解説します。</p>
<h2>３つの具体例</h2>
<p>前項で紹介したスタイルのうち、あまり普及していないような気がするけれどもコードの読みやすさへの貢献度の高いスタイルを３つピックアップし、少しだけ掘り下げてみましょう。</p>
<h3>staticメソッドを好む</h3>
<p>スタイル具体例１つ目はstaticメソッドについてです。</p>
<p>メソッドにstaticを付けると、読み手に対し「このメソッドの中ではthisを使っていませんよ！」と知らせていることになります。thisを使っていないということは、少なくとも自クラス内のインスタンス変数やインスタンスメソッドを使っていないということになります。これは読み手にとって、考えなければならないことをかなり減らす効果があります。</p>
<p>以下のコードを見て下さい。</p>
<pre class="lang:java decode:true">private String cnv(String s) {
    if (s == null) {
        return "★";
    }
    return "★" + s;
}
</pre>
<p>このメソッドはthisにアクセスしていないのですが、全てのコードを読むまでそのことが分かりません。しかし次のように書き換えるとどうでしょうか。</p>
<pre class="lang:default decode:true ">private static String cnv(String s) {
    if (s == null) {
        return "★";
    }
    return "★" + s;
}
</pre>
<p>コードを読むまでもなく、thisにアクセスしていないことが明示されます。</p>
<h4>eclipseのコンパイラ設定</h4>
<p>実はeclipseのコンパイラ設定にはthisにアクセスしていないメソッドを「staticを付けることが出来るよ！」と教えてくれる設定があります。ぜひオンにして積極的にstaticを付けるようにしましょう。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/11b52181a2fac8ce39a12051fd049878.png"><img class="alignnone size-full wp-image-1476" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/11b52181a2fac8ce39a12051fd049878.png" alt="Preferences_と_Java_-_Sandbox_src_main_java_sandbox_service_EmployeeService_java_-_Eclipse_-__Users_jabaraster_Documents_Develop_Java_workspace" width="915" height="463" /></a></p>
<h3>変数にfinalを付ける</h3>
<p>スタイル具体例の２つ目は変数にfinalを付けることです。これは手軽で効果が高いスタイルである上にプログラムの腕を向上させる効果もあるため、<strong>強くおすすめ</strong>します。</p>
<p>プログラムを書く側は、変数にfinalを付けなくても、実際に値が変わることはないことを確信出来ます。しかし読み手はその確信を得るのに、変数のスコープにある全てのコードを読む必要があるのです。</p>
<p>しかしfinalの付いた変数は、その変数の宣言を見ただけで、値が変わらないという確信を得ることが出来ます。これは読み手にとってとてもありがたいことなのです。</p>
<p>更に、変数の宣言と共に初期化するように心がけると値に何が入っているか分かりやすくなります。</p>
<p>以下のコードを見て下さい。</p>
<pre class="lang:java decode:true">private Map&lt;String, String&gt; cache;

/**
 * コンストラクタ
 */
public SomeClass() {
    this.cache = new HashMap&lt;&gt;();
    ...
}
</pre>
<p>cacheという変数の値はどこからか書き換えられる可能性があり、読み手はこのことを意識してコードを読む必要があります。また実際にcacheにどんな値が入っているのか、コンストラクタを見るまで分かりません。</p>
<p>しかし次のように書くとどうでしょうか。</p>
<pre class="lang:java decode:true">private final Map&lt;String, String&gt; cache = new HashMap&lt;&gt;();

/**
 * コンストラクタ
 */
public SomeClass() {
    ...
}
</pre>
<p>finalが付いているおかげで、この変数の値が決して書き換えられないことが分かります。また宣言と同時に初期化しているため、値に何が入っているか一目瞭然です。</p>
<h4>finalを忘れがちな変数</h4>
<h5>メソッド/コンストラクタ引数</h5>
<pre class="lang:java decode:true">void someMethod(final String s) {
    ...
}</pre>
<h5>catch</h5>
<pre class="lang:java decode:true">try {
    ...
} catch (final RuntimeException e) {
    ....
}</pre>
<h5> ローカル変数</h5>
<pre class="lang:java decode:true ">void someMethod(final String s) {
    final String os = cnv(s);
    ...
}</pre>
<p>&nbsp;</p>
<p>クラスによっては全ての変数にfinalを付けることが出来ます。</p>
<h4>finalを付けられないこともある、が・・・</h4>
<p>for文のループ変数にはfinalを付けられません。が、forループの多くは拡張for文に置き換え可能であり、拡張for文のループ変数にはfinalを付けられます。</p>
<p>for文を使ってListの全要素にアクセスするコードは以下のようになります。</p>
<pre class="lang:default decode:true">final List&lt;String&gt; ss = getStringList();
for (int i = 0; i &lt; ss.size(); i++) {
    System.out.println(ss.get(i));
}</pre>
<p>ループ変数はインクリメントされていくため、finalを付けることは出来ません。</p>
<p>これを拡張for文に置き換えると次のようになります。</p>
<pre class="lang:default decode:true">for (final String s : getStringList()) {
    System.out.println(s);
}</pre>
<p>拡張for文に置き換えたことで、変数にfinalを付けられる上に変数ssが不要になっています。シンプルになり読みやすくなったと思います。</p>
<h4>eclipseの設定に頼ってはいけない</h4>
<p>実はeclipseには保管アクションの中に「finalを付けられる変数に自動で付けてくれる設定」があります。しかしこの機能に頼ることは<strong>おすすめしません</strong>。なぜなら、finalを付けられない変数には付けてくれないためです。</p>
<p>&nbsp;</p>
<p>保険として設定する分には構いませんが、基本的にはプログラマが意思を持ってfinalを付ける必要があります。</p>
<h3>インデントを減らす</h3>
<p>最後のスタイル具体例はインデントについてです。</p>
<p>インデントが深くなる典型的なケースはif、for、while、tryによるものでしょう。これらはいずれも何らかの条件分岐であると考えられます。つまりインデントを付けられたコードを読む際、読み手は「ここのコードが実行されている条件は何だっけ・・・？」と考えながら読むことになります。</p>
<p>例えば、次のようなコードを目にしたことはありませんか？</p>
<pre class="lang:default decode:true" title="wrong-indent.java">void someMethod(String s) {
    if (s != null) {
        // とても長いコード
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        s = .....;
    } else { // ん？このelseの条件って何だったっけ？
        s = "";
    }
    ...
}
</pre>
<p>長いコードブロックが終わるとおもむろに現れるelse。これを読み手が目にすると、「ん？このelseの条件は何だっけ？」と、ifのコードブロックの一番上まで戻らざるを得ません。</p>
<p>このコードは次のように書くとぐっと読みやすくなります。</p>
<pre class="lang:default decode:true" title="good-indent.java">void someMethod(String s) {
    if (s == null) {
        s = "";
    } else {
        // とても長いコード
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        ...
        s = .....;
    }
    ...
}
</pre>
<p>が、更に工夫して、次のように書けばもっと読みやすくなります。</p>
<pre class="lang:default decode:true" title="best-indent.java">void someMethod(String s) {
    s = cnv(s);
    ...
}

private static String cnv(final String s) {
    if (s == null) {
        return "";
    }
    // とても長いコード
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    return .....;
}
</pre>
<p>インデントがほぼ無くなってしまいました。someMethodメソッドの中を見る限り、条件分岐が無くなっていて、コードを追いやすくなっていると思います。</p>
<p>条件分岐を別メソッドに切り出すようにすると、インデントの多くを無くすことが出来ます。</p>
<h2>まとめ</h2>
<p>ここまで「<em><strong>読むときのことを考える」</strong></em>という原則のもとで、様々なスタイルを考えて来ました。</p>
<p>スタイルを理解するにはその裏にある原則を理解することが必要です。例えば過去のエントリ「<a title="Java @Override アノテーション活用法" href="https://cloudear.jp/blog/?p=332">Java @Override アノテーション活用法</a>」で紹介したスタイルは、読みやすさに加えて「ミスは極力コンパイルエラーとして捕捉する」という原則に沿ったスタイルです。</p>
<p>このエントリでは具体的なスタイルについて解説しましたが、原則を理解することでより良いスタイルを自分で選択出来るようになると思います。ぜひ日々考えながらプログラミングするようにしてみて下さい。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1459</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaEEだけでここまで出来る！GlassFish+Eclipseで高速Webアプリ開発【開発編】</title>
		<link>https://cloudear.jp/blog/?p=1435</link>
		<comments>https://cloudear.jp/blog/?p=1435#comments</comments>
		<pubDate>Mon, 17 Aug 2015 01:09:29 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1435</guid>
		<description><![CDATA[JavaEEでWebアプリを高速開発する手順をご紹介するエントリの第２弾です。前回の記事はこちら。 今回はいよいよWebアプリを作っていきます。 このエントリのゴール 簡単にJavaEE開発環境を構築する手順を説明します [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>JavaEEでWebアプリを高速開発する手順をご紹介するエントリの第２弾です。前回の記事は<a title="JavaEEだけでここまで出来る！GlassFish+Eclipseで高速Webアプリ開発【環境構築編】" href="https://cloudear.jp/blog/?p=1375">こちら</a>。</p>
<p>今回はいよいよWebアプリを作っていきます。</p>
<p><span id="more-1435"></span></p>
<h2>このエントリのゴール</h2>
<ul>
<li>簡単にJavaEE開発環境を構築する手順を説明します<span style="color: #0000ff;">【前回ご紹介】</span></li>
<li>JavaEEを使ったRDBにアクセスする簡単なサンプルを作成する手順を説明します<span style="color: #ff0000;">【今回はこちらの手順をご紹介】</span></li>
</ul>
<h2>前提</h2>
<ul>
<li>前回のエントリに沿って開発環境が構築されていること</li>
</ul>
<h2>アプリケーションの作成</h2>
<p>JavaEEの仕様は重厚長大ですが、Webアプリを作るだけならほんの少しのことを知っているだけでOKです。</p>
<p>ここでは、JPAを使って単一テーブルからのCRUDを実行するシンプルな１画面のみのアプリを作ってみます。画面イメージは以下のようになります。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/8c66225166aca937086df4d28b5ac669.png"><img class="alignnone size-full wp-image-1408" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/8c66225166aca937086df4d28b5ac669.png" alt="スクリーンショット 2015-08-13 14.55.52" width="663" height="384" /></a></p>
<p>それでは、EJB→Servlet→JSPの順番で作成していきます。</p>
<h3>EJB</h3>
<p>EJBといっても大げさに考える必要はなく、DBアクセスを担当するフツーのクラスのことです。</p>
<p>今回は、JavaEE標準のDBアクセス仕様であるJPAを使ってEJBを実装します。まずはJPAの動作に必要な設定ファイルとクラスを作成しましょう。</p>
<h4>JPA設定ファイル（persistence.xml）の作成</h4>
<p>Eclipse上にソースフォルダsrc/main/resourcesが無い場合は作成し、更にその中にMETA-INFフォルダを作って下さい。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/d2acd52ca8e31576bd37b33e581374d2.png"><img class="alignnone size-full wp-image-1397" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/d2acd52ca8e31576bd37b33e581374d2.png" alt="スクリーンショット 2015-08-13 13.46.45" width="316" height="255" /></a></p>
<p>META-INFフォルダの中にpersistence.xmlを次の通りに作成します。</p>
<pre class="lang:xhtml decode:true" title="persistence.xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"&gt;
    &lt;persistence-unit name="pu" transaction-type="JTA"&gt;
        &lt;jta-data-source&gt;jdbc/App&lt;/jta-data-source&gt;
        &lt;exclude-unlisted-classes&gt;false&lt;/exclude-unlisted-classes&gt;
        &lt;properties&gt;
            &lt;property name="eclipselink.ddl-generation" value="create-tables" /&gt;
            &lt;property name="eclipselink.logging.level.sql" value="FINE" /&gt;
            &lt;property name="eclipselink.logging.parameters" value="true" /&gt;
            &lt;!-- eclipseのConsoleビューにSQLを出力するための設定. http://stackoverflow.com/questions/4676705/jpa-2-0-logging-and-tracing-through-with-glassfish-3-0-1-and-netbeans-6-9-1 --&gt;
            &lt;property name="eclipselink.logging.logger" value="org.eclipse.persistence.logging.DefaultSessionLog"/&gt;
        &lt;/properties&gt;
    &lt;/persistence-unit&gt;
&lt;/persistence&gt;
</pre>
<p>&nbsp;</p>
<p class="lang:xhtml decode:true " title="persistence.xml">&lt;property name=&#8221;eclipselink.ddl-generation&#8221; value=&#8221;create-tables&#8221; /&gt;という記述のおかげで、サーバ起動時にテーブルが自動で作られます。</p>
<p class="lang:xhtml decode:true " title="persistence.xml">また、DBデータはプロジェクト内のdbフォルダの中に作られます。このフォルダを削除すれば、再度テーブルが作られます。</p>
<h4>エンティティクラスの作成</h4>
<p>DBのテーブルに対応するクラスを作成しましょう。</p>
<p>src/main/java下のパッケージsandbox.entityに以下の通りにEmployeeクラスを作成します。</p>
<pre class="lang:java decode:true" title="Employee.java">package sandbox.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long   id;

    @Column(nullable = false, unique = true, length = 100)
    String name;

    public Long getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void setId(final Long pId) {
        this.id = pId;
    }

    public void setName(final String pName) {
        this.name = pName;
    }
}
</pre>
<h4>EJBクラスの作成</h4>
<p>src/main/java下のパッケージsandbox.serviceにEmployeeServiceクラスを作成します。INSERT、SELECT、DELETE用に３つのメソッドを作成しましょう。</p>
<pre class="lang:java decode:true " title="EmployeeService.java">package sandbox.service;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;

import sandbox.entity.Employee;

@Stateless
public class EmployeeService {

    @PersistenceContext(unitName = "pu")
    EntityManager em;

    public Employee delete(final long pDeleteEmployeeId) {
        final Employee emp = this.em.find(Employee.class, Long.valueOf(pDeleteEmployeeId));
        this.em.remove(emp);
        return emp;
    }

    public List&lt;Employee&gt; getAll() {
        final CriteriaBuilder builder = this.em.getCriteriaBuilder();
        final CriteriaQuery&lt;Employee&gt; query = builder.createQuery(Employee.class);
        query.from(Employee.class);
        return this.em.createQuery(query).getResultList();
    }

    public Employee insert(final String pName) {
        final Employee newEmp = new Employee();
        newEmp.setName(pName);
        this.em.persist(newEmp);
        return newEmp;
    }
}
</pre>
<p>たったこれだけです。メソッドの前後で自動的にトランザクションが仕込まれます。また以前の記事「<a title="依存性注入（DIコンテナ）について" href="https://cloudear.jp/blog/?p=1247" target="_blank">依存性注入（DIコンテナ）について</a>」で紹介したDI機能によって、JPA用のEntityManagerオブジェクトが良い感じでインジェクトされます。</p>
<p>またSQLが全く登場しないことにも注目して下さい。JPAのCriteria Queryという機能を使うと、SQLを書かずに済むシーンが増えます。文字列に頼らず型を使ってDBアクセス出来るようになることは、Javaの型安全性ととても相性の良い手法だと思います。JPAを使う場合は、ぜひ有効活用してみて下さい。</p>
<p>これら全ての機能がJavaEEによって提供されている点にも注目です。SpringやHibernateなどのライブラリを組み合わせて使う場合、ライブラリ同士をうまく接続するために多少なりとも設定を書く必要がありますが、JavaEEであればライブラリを、それもたった２つのJARを参照するだけ。</p>
<p>このお手軽さがJavaEEを使って開発する際の魅力です。</p>
<h3>Servletの作成</h3>
<p>続いてHTTPリクエストを受け取るためのServletを作成します。今回は、ルート（ / ）へのGETで社員一覧、ルートへのPOSTで社員の追加を行うようにしましょう。</p>
<p>src/main/java下のパッケージsandbox.web.handlerにEmployeeHandlerクラスを作成します。</p>
<pre class="lang:default decode:true" title="EmployeeHandler.java">package sandbox.web.handler;

import java.io.IOException;
import java.util.List;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sandbox.entity.Employee;
import sandbox.service.EmployeeService;

@WebServlet(urlPatterns = "/")
public class EmployeeHandler extends HttpServlet {

    @Inject
    EmployeeService employeeService;

    @Override
    protected void doGet(final HttpServletRequest pReq, final HttpServletResponse pResp) throws ServletException, IOException {
        final List&lt;Employee&gt; emps = this.employeeService.getAll();
        pReq.setAttribute("emps", emps);
        pReq.getRequestDispatcher("WEB-INF/emp.jsp").forward(pReq, pResp);
    }

    @Override
    protected void doPost(final HttpServletRequest pReq, final HttpServletResponse pResp) throws ServletException, IOException {
        final String empName = pReq.getParameter("employee-name");
        this.employeeService.insert(empName);
        pResp.sendRedirect("/");
    }
}
</pre>
<p>もう１つServletを作ります。/deleteへのPOSTで社員一覧を削除するようにしましょう。</p>
<p>src/main/java下のパッケージsandbox.web.handlerにEmployeeDeleteHandlerクラスを作成します。</p>
<pre class="lang:default decode:true" title="EmployeeDeleteHandler.java">package sandbox.web.handler;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sandbox.service.EmployeeService;

@WebServlet(urlPatterns = "/delete")
public class EmployeeDeleteHandler extends HttpServlet {

    @Inject
    EmployeeService employeeService;

    @Override
    protected void doPost(final HttpServletRequest pReq, final HttpServletResponse pResp) throws ServletException, IOException {
        final String employeeIdStr = pReq.getParameter("employee-id");
        try {
            final long employeeId = Long.parseLong(employeeIdStr);
            this.employeeService.delete(employeeId);
        } catch (final NumberFormatException e) {
            // nop
        }
        pResp.sendRedirect("/");
    }
}
</pre>
<p>各メソッドでやっていることは</p>
<ol>
<li>EJBを呼び出してDB操作</li>
<li>JSP呼び出し、または/へのリダイレクト</li>
</ol>
<p>という単純な処理です。</p>
<p>ServletクラスでもDI機能が使えるため、EmployeeServiceオブジェクトが良い感じでインジェクトされます。</p>
<h3>JSPの作成</h3>
<p>最後に、JSPで画面を作成しましょう。</p>
<p>src/main/webapp/WEB-INFの下にemp.jspを作成して下さい。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/82ce28448bfdf72db673788bb3f69aa3.png"><img class="alignnone size-full wp-image-1406" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/82ce28448bfdf72db673788bb3f69aa3.png" alt="スクリーンショット 2015-08-13 14.34.58" width="315" height="327" /></a></p>
<pre class="lang:asp decode:true" title="emp.jsp">&lt;%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;
&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"&gt;
    &lt;title&gt;社員情報&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class="container"&gt;
      &lt;fieldset&gt;
        &lt;legend&gt;社員一覧&lt;/legend&gt;
        &lt;table class="table table-striped"&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;td&gt;#&lt;/td&gt;
              &lt;td&gt;名前&lt;/td&gt;
              &lt;td&gt; &lt;/td&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            &lt;c:forEach  items="${emps}" var="emp"&gt;
              &lt;tr&gt;
                &lt;td&gt;${emp.id}&lt;/td&gt;
                &lt;td&gt;${emp.name}&lt;/td&gt;
                &lt;td&gt;
                  &lt;form method="post" action="${request.contextPath}/delete"&gt;
                    &lt;input type="hidden" value="${emp.id}" name="employee-id" /&gt;
                    &lt;button class="btn btn-danger"&gt;&lt;span class="glyphicon glyphicon-trash"&gt;&lt;/span&gt;&lt;/button&gt;
                  &lt;/form&gt;
                &lt;/td&gt;
              &lt;/tr&gt;
            &lt;/c:forEach&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/fieldset&gt;
      &lt;fieldset&gt;
        &lt;legend&gt;社員登録&lt;/legend&gt;
        &lt;form method="post" action="${request.contextPath}"&gt;
          &lt;div class="form-group"&gt;
            &lt;input type="text" name="employee-name" class="form-control" /&gt;
          &lt;/div&gt;
          &lt;button class="btn btn-primary"&gt;追加&lt;/button&gt;
        &lt;/form&gt;
      &lt;/fieldset&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>
<p>手軽に見栄えを良くするために、Bootstrapを使っています。</p>
<h3>文字化け防止クラスの作成</h3>
<p>実はこのままでは日本語が文字化けします。次のクラスを作成して文字コードをUTF-8に統一します。</p>
<p>src/main/java下のパッケージsandbox.webにCharacterEncodingFilterクラスを作成します。</p>
<pre class="lang:java decode:true" title="CharacterEncodingFilter.java">package sandbox.web;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebFilter(urlPatterns = "/*", dispatcherTypes = DispatcherType.REQUEST)
public class CharacterEncodingFilter implements Filter {

    @Override
    public void destroy() {
        // nop
    }

    @Override
    public void doFilter(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pChain) throws IOException,
            ServletException {
        ((HttpServletRequest) pRequest).setCharacterEncoding(StandardCharsets.UTF_8.name());
        ((HttpServletResponse) pResponse).setCharacterEncoding(StandardCharsets.UTF_8.name());
        pChain.doFilter(pRequest, pResponse);
    }

    @Override
    public void init(final FilterConfig pFilterConfig) throws ServletException {
        // nop
    }
}
</pre>
<p>&nbsp;</p>
<p>以上でコーディングは終了です！おつかれさまでした。</p>
<p>Eclipseプロジェクトは次のような状態になっているはずです。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/b928497fe3d80b633a9e8e70c93941d0.png"><img class="alignnone size-full wp-image-1412" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/b928497fe3d80b633a9e8e70c93941d0.png" alt="スクリーンショット 2015-08-13 15.17.11" width="321" height="584" /></a></p>
<h3>動作確認</h3>
<p>前回作成したJavaEEContainerStarterクラスを起動した上で、以下のURLにアクセスして動作を確認してみて下さい。</p>
<p><a title="http://localhost:8081" href="http://localhost:8081">http://localhost:8081</a></p>
<h2>まとめ</h2>
<p>Eclipse上でJavaEEを使った開発の手順を説明してきました。</p>
<p>RoRほどではないものの、思ったよりも簡単に開発を始められ、割りと少ないコード量でWebアプリが作成出来ることがご理解いただけたかと思います。</p>
<p>フルJavaEEを使って開発する利点は、機能が豊富で、更にそれらの機能が既に統合されている、という点です。新しい機能を使うときにJAR参照を追加したりする必要はありません。RESTfulなWebアプリを作るためのJAX-RSであっても、WebSocketのハンドラクラスであっても、適切なアノテーションを付与したクラスを作れば、それだけで動作します。またビジネスロジックをEJBとして作成すれば、DI機能によってどこからでも利用出来ます。</p>
<p>しかしこう言った利点を享受したくてJavaEEを使おうとしても、環境構築が面倒で挫折した、という人は少なくないと思います。</p>
<p>今回ご紹介した環境構築手順を使えば、簡単高速に開発が始められますので、ぜひJavaEEを体験してその便利さに触れていただきたいと思います。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1435</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaEEだけでここまで出来る！GlassFish+Eclipseで高速Webアプリ開発【環境構築編】</title>
		<link>https://cloudear.jp/blog/?p=1375</link>
		<comments>https://cloudear.jp/blog/?p=1375#comments</comments>
		<pubDate>Fri, 07 Aug 2015 07:21:00 +0000</pubDate>
		<dc:creator><![CDATA[tomo]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[フレームワーク]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1375</guid>
		<description><![CDATA[JavaでのWeb開発と言えばSpringMVC+Hibernate(MyBatis)辺りが人気の組み合わせでしょうか。他にもWicket、Struts、PlayFrameworkなど様々なフレームワークが実用されていま [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>JavaでのWeb開発と言えばSpringMVC+Hibernate(MyBatis)辺りが人気の組み合わせでしょうか。他にもWicket、Struts、PlayFrameworkなど様々なフレームワークが実用されています。</p>
<p><span id="more-1375"></span></p>
<p>そんな中、標準仕様であるJavaEEは人気が今ひとつな気がしますね。仕様が重い、動作が重い、などの悪印象があるのがその原因かもしれません。</p>
<p>しかし実は相当に開発しやすくなっているんです。</p>
<p>このエントリでは、JavaEEを活用してWebアプリを高速開発する手順を２回に分けてご紹介します。</p>
<h2>このエントリのゴール</h2>
<ul>
<li>簡単にJavaEE開発環境を構築する手順を説明します<span style="color: #ff0000;">【今回はこちらの手順をご紹介】</span></li>
<li>JavaEEを使ったRDBにアクセスする簡単なサンプルを作成する手順を説明します <span style="color: #0000ff;">【次回ご紹介】</span></li>
</ul>
<h2>前提</h2>
<ul>
<li>Eclipseをインストールしておいて下さい</li>
<li>Maven3系を導入しておいて下さい</li>
</ul>
<h2>開発環境の構築</h2>
<p>APサーバとDBサーバをインストールせずにEclipseでの開発環境を構築します。具体的には、組み込みGlassFishと組み込みH2 Database Engineを利用します。</p>
<h3>Eclipseプロジェクトの作成</h3>
<p>以下のコマンドでプロジェクトのひな形を作成して下さい。</p>
<pre class="lang:sh decode:true" title="mvn archetype:create">mvn -B archetype:create -DgroupId=sandbox -DartifactId=rapid-javaee -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0</pre>
<p>これでrapid-javaeeというディレクトリが作られ、その中にpom.xmlが作られます。このファイルの中身を次のように書き換えます。設定の意味は極力ファイル内にコメントを付けておきましたので参照して下さい。</p>
<pre class="lang:xhtml decode:true" title="pom.xml">&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;groupId&gt;sandbox&lt;/groupId&gt;
    &lt;artifactId&gt;rapid-javaee&lt;/artifactId&gt;
    &lt;version&gt;1.0&lt;/version&gt;
    &lt;packaging&gt;war&lt;/packaging&gt;
    &lt;name&gt;rapid-javaee&lt;/name&gt;
    &lt;url&gt;http://maven.apache.org&lt;/url&gt;
    &lt;dependencies&gt;
        &lt;!-- JavaEE7のAPI --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax&lt;/groupId&gt;
            &lt;artifactId&gt;javaee-web-api&lt;/artifactId&gt;
            &lt;version&gt;7.0&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;!-- 組み込みGlassFish --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.glassfish.main.extras&lt;/groupId&gt;
            &lt;artifactId&gt;glassfish-embedded-web&lt;/artifactId&gt;
            &lt;version&gt;4.1&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;!-- H2 Database Engine --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.h2database&lt;/groupId&gt;
            &lt;artifactId&gt;h2&lt;/artifactId&gt;
            &lt;version&gt;1.4.181&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    &lt;build&gt;
        &lt;finalName&gt;rapid-javaee&lt;/finalName&gt;
        &lt;!-- JavaEEの仕様に従ってclassファイルを配置するための設定 --&gt;
        &lt;outputDirectory&gt;src/main/webapp/WEB-INF/classes&lt;/outputDirectory&gt;
        &lt;testOutputDirectory&gt;src/main/webapp/WEB-INF/test-classes&lt;/testOutputDirectory&gt;
        &lt;!-- javaファイル以外のファイル格納用ソースフォルダの設定 --&gt;
        &lt;resources&gt;
            &lt;resource&gt;
                &lt;directory&gt;src/main/resources&lt;/directory&gt;
            &lt;/resource&gt;
            &lt;resource&gt;
                &lt;directory&gt;src/main/java&lt;/directory&gt;
                &lt;includes&gt;
                    &lt;include&gt;**&lt;/include&gt;
                &lt;/includes&gt;
                &lt;excludes&gt;
                    &lt;exclude&gt;**/*.java&lt;/exclude&gt;
                &lt;/excludes&gt;
            &lt;/resource&gt;
        &lt;/resources&gt;
        &lt;testResources&gt;
            &lt;testResource&gt;
                &lt;directory&gt;src/test/resources&lt;/directory&gt;
            &lt;/testResource&gt;
            &lt;testResource&gt;
                &lt;directory&gt;src/test/java&lt;/directory&gt;
                &lt;includes&gt;
                    &lt;include&gt;**&lt;/include&gt;
                &lt;/includes&gt;
                &lt;excludes&gt;
                    &lt;exclude&gt;**/*.java&lt;/exclude&gt;
                &lt;/excludes&gt;
            &lt;/testResource&gt;
        &lt;/testResources&gt;
        &lt;plugins&gt;
            &lt;!-- UTF-8のソースを正しくコンパイルしてもらうための設定 --&gt;
            &lt;plugin&gt;
                &lt;inherited&gt;true&lt;/inherited&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.3&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;source&gt;1.7&lt;/source&gt;
                    &lt;target&gt;1.7&lt;/target&gt;
                    &lt;optimize&gt;true&lt;/optimize&gt;
                    &lt;debug&gt;true&lt;/debug&gt;
                    &lt;encoding&gt;UTF-8&lt;/encoding&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
            &lt;!-- WAR作成時にweb.xmlがなくてもOKにする --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
                &lt;version&gt;2.6&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;
&lt;/project&gt;</pre>
<p>さらに、Eclipseで開発できるようにするために、以下のコマンドも実行しておきます。</p>
<pre class="lang:sh decode:true" title="mvn eclipse">mvn eclipse:eclipse</pre>
<p>これでEclipseプロジェクトが作成されました。</p>
<h3>Eclipseプロジェクトのインポート</h3>
<p>作成したプロジェクトをEclipseにインポートして下さい。ただ、この時点ではAppTest.javaにコンパイルエラーがあるはずです。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/d0630b06ba57b5f3f3c55358a1974266.png"><img class="alignnone size-full wp-image-1391" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/d0630b06ba57b5f3f3c55358a1974266.png" alt="スクリーンショット_2015-08-13_13_20_15" width="416" height="253" /></a></p>
<p>このファイル、今回は使わないので削除して下さい。</p>
<h3>JavaEEサーバ（GlassFish）起動クラスの作成</h3>
<p>JavaEEサーバをEclipseから起動出来るようにします。src/test/javaソースフォルダ下のsandboxパッケージに、JavaEEContainerStarterというクラスを次の通りに作成して下さい。コードの意味はコメントを参照して下さい。</p>
<p><a href="https://cloudear.jp/blog/wp-content/uploads/2015/08/43f2591f9e7d4a2dab6c9df857dd439b.png"><img class="alignnone size-full wp-image-1393" src="https://cloudear.jp/blog/wp-content/uploads/2015/08/43f2591f9e7d4a2dab6c9df857dd439b.png" alt="スクリーンショット_2015-08-13_13_30_20_1" width="353" height="161" /></a></p>
<pre class="lang:java decode:true" title="JavaEEContainerStarter.java">package sandbox;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;

import javax.sql.DataSource;

import org.glassfish.embeddable.GlassFish;
import org.glassfish.embeddable.GlassFishProperties;
import org.glassfish.embeddable.GlassFishRuntime;
import org.h2.jdbcx.JdbcDataSource;

public class JavaEEContainerStarter {
    /**
     * 当クラスのソースの参考ページURL. &lt;br&gt;
     * http://www.coppermine.jp/docs/programming/2013/12/glassfish-embedded-server.html
     */
    @SuppressWarnings("nls")
    public static void main(final String[] pArgs) throws Exception {
        final long s = System.currentTimeMillis();
        final GlassFishProperties properties = new GlassFishProperties();

        // HTTPは8081番ポート、HTTPSは8082番ポートでリッスン
        properties.setPort("http-listener", 8081);
        properties.setPort("https-listener", 8082);

        // サーバ起動
        final GlassFish glassfish = GlassFishRuntime.bootstrap().newGlassFish(properties);
        glassfish.start();

        // コネクションプール作成. 組み込みH2 Database Engineを利用する.
        final String connectionPoolName = "AppConnectionPool";
        glassfish.getCommandRunner().run("create-jdbc-connection-pool" //
                , "--datasourceclassname=" + JdbcDataSource.class.getName() //
                , "--restype=" + DataSource.class.getName() //
                , "--property", "url=jdbc\\:h2\\:./db/db" //
                , connectionPoolName //
                );

        // JDBCリソースとしてコネクションプールを、jdbc/Appという名前で登録する.
        glassfish.getCommandRunner().run("create-jdbc-resource" //
                , "--connectionpoolid", connectionPoolName //
                , "jdbc/App" //
        );

        // Webアプリを配備.
        glassfish.getDeployer().deploy( //
                new File("src/main/webapp") //
                , "--name=app" //
                , "--contextroot", "/");

        System.out.println("GlassFishサーバを起動しました.");
        System.out.println(System.currentTimeMillis() - s + " ms");

        // Enterを押せばサーバ停止.
        new BufferedReader(new InputStreamReader(System.in)).readLine();
        glassfish.stop();
        System.out.println("GlassFishサーバを停止.");
    }
}
</pre>
<p>このクラスが本エントリの大きなポイントです。通常、JavaEEサーバは別途インストールして起動、Eclipseで開発するためにアダプタを導入して・・・と面倒な手順を踏む必要がありますが、この方法だと起動は簡単かつスピーディ、環境構築に苦労はなしと良いこと尽くしです。</p>
<p>試しにこのクラスを起動してみて下さい。10秒以内には起動完了するはずです。</p>
<p>以上で開発環境構築は完了！これでJavaEEの全ての機能を使った開発が開始出来ます。びっくりするほど簡単ですね。</p>
<h2>次回予告</h2>
<p>次回はいよいよJavaEEを使ったWebアプリ開発の手順をご紹介します。JavaEEは機能が豊富な上に手軽に利用出来る点が利点です。この利点を活用してWebアプリを簡単高速に作成していきます。</p>
<p>お楽しみに。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1375</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>個人的によく使うVimテクニック5選</title>
		<link>https://cloudear.jp/blog/?p=1352</link>
		<comments>https://cloudear.jp/blog/?p=1352#comments</comments>
		<pubDate>Sun, 19 Jul 2015 13:22:07 +0000</pubDate>
		<dc:creator><![CDATA[masa]]></dc:creator>
				<category><![CDATA[インフラ]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">https://cloudear.jp/blog/?p=1352</guid>
		<description><![CDATA[みなさんこんにちは masa です。今回はエディタネタの中でも Vim テクニックを取り上げてみたいと思います。普段、コンパイラ系の言語を書く場合は IDE を使いますが、それ以外の言語やシェルスクリプトを書く場合は V [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>みなさんこんにちは masa です。今回はエディタネタの中でも Vim テクニックを取り上げてみたいと思います。普段、コンパイラ系の言語を書く場合は IDE を使いますが、それ以外の言語やシェルスクリプトを書く場合は Vim でちゃっちゃっとやることが多かったりします。</p>
<p><span id="more-1352"></span></p>
<p>今回はノーマルの Vim で使えるもので、個人的によく使うテクニックをご紹介。</p>
<p>&nbsp;</p>
<p><span class="hcss1" style="font-size: 14pt;"><strong>　ここからここまでコピー or 切り取りしたい</strong></span></p>
<p>なんといっても一番使う行コピーと行切り取りです。いえいえ <strong>5yy</strong> とか<strong> 10dd</strong> とかじゃないですよ！</p>
<p>5行など行数が少なければ目測で 5yy とかできますが、コピーしたい行数が 127行だったりしたら大変ですね。<br />
あまり Vim に慣れていない方は :set nu で行数を表示して、コピーしたい行を引き算してヤンクするというのを見掛けます。<br />
これは効率が悪いですし、計算違いで関係ない行までコピー or 切り取りしてしまう可能性もあります。</p>
<p>そんなときは以下を使いましょう。</p>
<pre class="theme:dark-terminal lang:default decode:true ">ここは1行目ですよ。    //この行でmsと打つ
ここは2行目ですよ。 
ここは3行目ですよ。
ここは4行目ですよ。
（中略）
ここは126行目ですよ。
ここは127行目ですよ。  //この行でy'sもしくはd'sと打つ</pre>
<p>上の例ではコピーをしたい始めの行でmsと打ち、コピー終わりの行でy&#8217;sと打つと、1~127行がヤンクされます。（d&#8217;sだとヤンクではなく切り取りになります）</p>
<p>これだと始点と終点でコマンドを打つだけなので間違いもないし簡単ですね。知らなかった方はレッツトライ！</p>
<p>&nbsp;</p>
<p><span class="hcss1" style="font-size: 14pt;"><strong>　大文字と小文字を切り替える or どちらかに統一する</strong></span></p>
<p>シェルスクリプトの変数や PHP の定数などは大文字で書くのが慣習ですが、そうなっていないものを直したりするときに使えます。</p>
<p>選択した文字を大文字⇔小文字にトグルさせる場合は~（チルダ）で、選択した文字をすべて小文字に統一したい場合はu（小文字）、大文字に統一したい場合はU（大文字）でできます。</p>
<pre class="theme:dark-terminal lang:default decode:true ">//まずは ctrl+v で対象文字を選択します

this is komoji   //左の文字すべてを選択した状態でUと打つと大文字へ変換されます

THIS IS OMOJI    //左の文字すべてを選択した状態でuと打つと大文字へ変換されます

ThIs Is KoNGoU   //左の文字すべてを選択した状態で~を打つとすべての大文字と小文字が反転します</pre>
<p>&nbsp;</p>
<p><strong><span class="hcss1" style="font-size: 14pt;">　一文字づつもしくは複数文字をリプレイスする</span></strong></p>
<p>わざわざ挿入モードに入らずに1文字だけ修正したいとか、この単語だけ修正したいとかあると思いますが、その際はコマンドモードで以下を実施してください。</p>
<pre class="theme:dark-terminal lang:default decode:true ">understanf   //fの上にカーソルを移動してr、そのまま変換したい文字(d)を入力

disk  //dの上にカーソルを移動してR、そのまま変換したい文字を打ち、最後にESC</pre>
<p>&nbsp;</p>
<p><strong><span class="hcss1" style="font-size: 18.6666660308838px;">　マクロを組んで同じ操作をワンキーで繰り返す</span></strong></p>
<p>なにやら難しい感じですが、めちゃくちゃ簡単です。 Vim では操作を記録して実行するマクロ機能がありますが、それを.（ドット）で繰り返すだけです。</p>
<pre class="theme:dark-terminal lang:default decode:true ">//qaと打ち記録を開始　qの後ろは任意の覚えやすい文字で結構です

This is Macro Test!  //左のように記録したい操作をやりきります　
    1234567          //今回は簡単ですが3行の文字入力をしました
  Test is End

//qと打ち記録を停止します

//@aと打つと1回マクロを実施しますが、.（ドット）だけでも実施できます。

This is Macro Test!
    1234567
  Test is End

//回数指定でマクロを実行したい場合は7@aと押すと7回実行できます</pre>
<p>上の例だとコピーしたほうが早いですが、複雑な操作を再実行したい場合はマクロのほうが良いですね。</p>
<p>&nbsp;</p>
<p><strong><span class="hcss1" style="font-size: 18.6666660308838px;">　大文字小文字に関係なく検索</span></strong></p>
<p>地味ですが検索時は必須ですね。わざわざ大文字で検索して、次に小文字で検索してとやっている人を見掛けました。検索文字列の後ろに\cとつけるだけでOKですw</p>
<pre class="theme:dark-terminal lang:default decode:true ">banana BaNANA Apple
Grape Banana ORANGE
orange PEAR peAR GRAPE

//（スラッシュ）を押して検索文字列banana\cと打つとすべてのバナナが引っ掛かります</pre>
<p>&nbsp;</p>
<p>いかがでしたか？今回はノーマルの Vim で使えるテクニックをご紹介しました。みなさんの作業効率を高める一助にしていただければ幸いです。</p>
]]></content:encoded>
			<wfw:commentRss>https://cloudear.jp/blog/?feed=rss2&#038;p=1352</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
