目次


Vaadin を使用してクラウド内でフルスタック Java のアプリを開発する

Bluemix と Vaadin Rich Web Starter ボイラープレートを利用して対話型の注文デスク・アプリを数分で作成する

Comments

Java 開発者が対話型の Web アプリを作成するにあたって、HTML5、CSS、あるいは JavaScript を習得する必要はありません。Vaadin フレームワークと、そのまますぐにデプロイできるアドオンとコンポーネントからなる Vaadin の巨大なライブラリーを使用することで、使い慣れた IDE とサーバー・サイド技術を利用して、100 パーセント・フルスタック Java のアプリを作成することができます。私が developerWorks に寄稿した記事「Vaadin を使用したフルスタック Java の Web 開発」では、Vaadin がその内部でどのように動作するかを説明しており、Vaadin を使って Web アプリの作成を始める際の参考になります。

Bluemix には Vaadin Rich Web Starter ボイラープレートが用意されているので、Vaadin アプリと Bluemix の相性は抜群です。Vaadin アプリを Bluemix にデプロイすれば、業界標準の Liberty Profile アプリケーション・サーバー・ランタイムのサポートを利用することや、リレーショナル・データベースとして IBM DB2 を使用することができます。さらに、Bluemix 上のすべての Vaadin アプリは、種類が豊富で増え続けているサーバー・サイドのサービスを利用することができます。

このチュートリアルでは、単純な注文デスクとして機能する、完全な Vaadin Web アプリを作成する手順をステップ・バイ・ステップで説明します。コンポーネントを組み合わせてアプリを作成する手段としては Vaadin CDI (Contexts and Dependency Injection) を使用し、バックエンドのデータベースにアクセスする手段としては JPA (Java Persistence API) を使用します。お馴染みの Ecipse IDE でコーディングを行って、完成したアプリを Bluemix にデプロイします。

このチュートリアルでは、以下の方法を説明します。

  • Bluemix 上の Vaadin Rich Web Starter ボイラープレートを使って Vaadin アプリの作成を開始する
  • Vaadin CDI アプリを拡張してアクセス制御を追加する
  • Vaadin Add-ons ディレクトリーにある 2 つのサード・パーティー製アドオン UI コンポーネントを Web アプリの中で使用する
  • ログイン・ページをアプリに追加し、顧客データベースに対して認証を行う
  • 注文検索ビューをアプリに追加する

Bluemix 上のすべての Vaadin アプリは、種類が豊富で増え続けているサーバー・サイドのサービスを利用することができます。

必要となるもの

必須:

サンプル・コードを変更または作成する必要がある場合:

  • JDK (Java Development Kit) 1.7 またはそれ以降のバージョン (サンプル・コードの開発で使用したのは 1.7.0_60-b19 です)。
  • Eclipse IDE for Java EE Developers (Luna またはそれ以降のバージョン)
  • Vaadin Plugin for Eclipse (Eclipse マーケットプレースから入手)
  • WebSphere Application Server Liberty Profile の Web Profile v8.5.5.5 またはそれ以降のバージョン (Eclipse マーケットプレースまたは IBM WebSphere Liberty Repository から入手)
  • Apache Derby データベース (ディストリビューションに含まれる derby.jar) 10.11.1.1 またはそれ以降のバージョン

アプリを実行するコードを入手する

ステップ 1. アプリの UI を探る

「アプリを実行する」ボタン (このステップより前に表示されています) をクリックして、注文デスク・アプリを試してください。

  1. 左側のメニュー項目のいずれか (「About (情報)」を除く) をクリックすると、ログイン・ページが表示されます。「About (情報)」ページは Customer データベースにデータをロードするために使用するページです。ログインを機能させるためにはデータをロードしなければならないので、このページで「Fill test data into DB (DB にテスト・データを取り込む)」ボタンをクリックします。
  2. ログイン・ページで、ユーザー名には「brian@robinson.com」、パスワードには「abc123」と入力してログインします。「Login-Logout (ログイン/ログアウト)」ビューのスクリーンショット
    「Login-Logout (ログイン/ログアウト)」ビューのスクリーンショット
  3. 「Analyze (分析)」ビューで、アニメーション化されたグラフを確認します。「Analyze (分析)」ビューのスクリーンショット
    「Analyze (分析)」ビューのスクリーンショット
  4. 「Customer List (顧客リスト)」ビューで顧客のリストをブラウズして、「Map (地図)」ビューで顧客の場所を確認します。 「Map (地図)」ビューのスクリーンショット
  5. 「Search (検索)」ビューを使用して、注文を検索します。「Search (検索)」ビューのスクリーンショット
    「Search (検索)」ビューのスクリーンショット
  6. ブラウザーのページ幅を狭くして、アプリがレスポンシブにサイズを調整する動作を確認します。
  7. 「Login-Logout (ログイン/ログアウト)」ビューを再び選択してログアウトし、ログアウトした後は他のビューにナビゲートできないことを確認します。

ステップ 2. Vaadin Bluemix ボイラープレートを複製してデプロイする

このチュートリアルでは、Bluemix の Vaadin ボイラープレートのコードをベースに、コードを追加していきます。別の方法として、「コードを入手する」ボタン (「ステップ 1. アプリの UI を探る」の前に表示されています) をクリックし、ファイナル版のコードが格納されている Bluemix DevOps Services プロジェクトにアクセスして、そのコードとボイラープレート版を比較しながらチュートリアルに従うこともできます。

  1. Bluemix アカウントにログインします (または、無料トライアルにサインアップしてください)。
  2. 「Cloud Foundry Apps (Cloud Foundry アプリ)」 > 「CREATE APP (アプリの作成)」の順にクリックします。
  3. 「WEB」をクリックし、続いて「Browse Boilerplates (ボイラープレートの参照)」をクリックすると表示される同じ名前のボタンをクリックします。
  4. 「Vaadin Rich Web Starter」をクリックします。「Vaadin Rich Web Starter」アイコンのスクリーンショット
  5. アプリに固有の名前を付けて、「CREATE (作成)」をクリックします。アプリの作成時に、IBM WebSphere Liberty Profile サーバーと、SQL Database サービスの無料のベータ版インスタンス (現在、IBM DB2 によってサポートされています) がプロビジョニングされます。
  6. 以下のコマンドを実行し、ご使用のコンピューター上にボイラープレートのコード・リポジトリーを複製します。

    git clone https://hub.jazz.net/git/vaadin/vaadin-jpa-app

  7. 以下のコマンドを実行し、リポジトリーを複製したディレクトリーに、カレント・ディレクトリーを変更します。

    cd vaadin-jpa-app

  8. 以下のコマンドを実行し、アプリをビルドして WAR ファイルを作成します。

    mvn install

  9. ディレクトリーから manifest.yml を削除します。
  10. 以下のコマンドを実行し、WAR ファイルを Bluemix にデプロイします。

    cf push appname -p target/vaadin-jpa-application.war

  11. デプロイされたボイラープレート Vaadin アプリ (http://<アプリ名>.mybluemix.net/) にアクセスします。現時点で、このアプリには「Login-Logout (ログイン/ログアウト)」ビューも「Search (検索)」ビューもありませんが、「Customer List (顧客リスト)」ビュー、「Analyze (分析)」ビュー、「Map (地図)」のビューは機能しています。

ステップ 3. プロジェクトを Eclipse IDE にロードする

コードに変更を加えて再ビルドするには、コードを Eclipse にロードして WAR を再ビルドするという方法をとることができます。その場合、デフォルトの Eclipse プロジェクトのビルド・ワークフローではなく、Maven ビルドを使用する必要があります。

  1. プロジェクトを Eclipse にインポートします。それには、「File (ファイル)」 > 「Import (インポート)」 > 「Existing Maven Project (既存の Maven プロジェクト)」の順に選択し、プロジェクトのルート・ディレクトリーを選択してインポートを完了します。
  2. pom.xml ファイルを見つけて右クリックし、「Run as (実行)」 > 「Maven install (Maven インストール)」の順に選択します。コンソールで進行状況を観察します。このプロセスでは成果物をダウンロードして、WAR をビルドするために必要なすべてのものをセットアップするため、完了するまでにしばらく時間がかかります。
  3. Apache Derby データベース (derby.jar) を Liberty Profile インスタンスにコピーします。Apache Derby コード・ディストリビューションの derby.jar を「Enterprise Explorer (エンタープライズ・エクスプローラー)」ペインまでドラッグし、WebSphere Application Server Liberty Profile/shared/resources/derby フォルダー内に配置します。このフォルダーがまだ存在していない場合は、作成する必要があります。
  4. Liberty Profile インスタンスの server.xml ファイルに変更を加えて、JNDI (Java Naming and Directory Interface) データ・ソースを含めるようにします。

    <jdbcDriver id="DerbyEmbedded" libraryRef="DerbyLib"/>
    <library filesetRef="DerbyFileset" id="DerbyLib"/>
    <fileset dir="${shared.resource.dir}/derby" id="DerbyFileset" includes="derby.jar"/>
    <!-- Configure an in-memory db for the vaadin app configuration -->
    <dataSource id="jdbc/vaadindb" jdbcDriverRef="DerbyEmbedded" jndiName=
        "jdbc/vaadindb" transactional="true">
      <properties createDatabase="create" databaseName="memory:jpasampledatabase"/>
    </dataSource>
  5. Vaadin CDI (Contexts and Dependency Injection) アプリを正常に実行するには、server.xml ファイルに以下の行も含める必要があります。Vaadin CDI との適合性を最高にするために、Liberty Profile の個々の機能を選択するのではなく、以下のコード行をそのまま使用してください。

    <featureManager>
        <feature>localConnector-1.0</feature>
        <feature>webProfile-6.0</feature>
    </featureManager>
  6. コードの変更が完了したら、プロジェクトを選択して右クリックし、「Run As (実行)」 > 「Maven Build (Maven ビルド)」の順に選択して WAR を再ビルドします。WAR を初めて再ビルドする際には、最終形を入力するよう促されるので、Maven の最終形として「package」と入力します。 Eclipse の「Edit Configuration (構成の編集)」ダイアログ・ボックスのスクリーンショット
    Eclipse の「Edit Configuration (構成の編集)」ダイアログ・ボックスのスクリーンショット
  7. ローカル・サーバーにデプロイするために、プロジェクト内の WAR を右クリックして「Run As (実行)」 > 「Run on server (サーバーで実行)」の順に選択し、Liberty Profile インスタンスを選択します。

ステップ 4. ログイン・ビューを追加する

このボイラープレート・アプリでは、カスタム・ナビゲーションに対処するためと、UI オブジェクトを CDI 管理対象 Bean として注入するために、Vaadin CDI を使用します。Vaadin CDI アドインは、Vaadin Add-ons ディレクトリーにあります。

Bluemix Vaadin ボイラープレート・コードが依存する一連の cdi-helpers UI コンポーネント (ソース・リポジトリーはこちらのリンク先にあります) も、この Vaadin Add-ons ディレクトリーにあります。これらのヘルパーの操作を調べると、このアプリで Vaadin CDI がどのように使用されているのかを理解するのに役立ちます。

  1. 既存のコードを調べて、Vaadin CDI がこのアプリでどのように機能するのかを確認します。アプリの UI 全体が、ViewMenuUI UI のインスタンスとなっています。このインスタンスをアプリのメイン UI にするためのコードは、org.vaadin.presentation.AppUI クラスに含まれています。ビューの変更は、ViewMenu の一部となっている Vaadin Navigator インスタンスによって調整されます。
  2. ログイン・ビューを追加するには、最初に org.vaadin.presentation.views.LoginView という名前の新規クラスを追加します。このクラスは、ソース・リポジトリーからコピーすることができます。ログイン・ビューは、Vaadin Add-ons ディレクトリーにある Vaadin コンポーネント・アドオンを使用しています。具体的には、Ingo Kegel 氏が作成した. LoginForm UI コンポーネントです。

    このコンポーネントをプロジェクトに追加するには、このコンポーネントの Maven 成果物をプロジェクトの pom.xml ファイル内の dependencies セクションに追加する必要があります。


    <dependency>
       <groupId>org.vaadin.addons</groupId>
       <artifactId>loginform</artifactId>
       <version>0.5.2</version>
    </dependency>
  3. LoginView クラス内では、このアドオンがフォームを簡単に表示できるようにします。

    final DefaultVerticalLoginForm loginForm = new DefaultVerticalLoginForm();
        	loginForm.addLoginListener(new LoginListener() {
        	    @Override
        ...
    });
    ...
    add(loginForm);
  4. アイコンとテキスト・ラベル付きのメニュー項目を作成し、その項目がメニューの最後の項目になるようにするには、以下のように @ViewMenuItem() アノテーションを使用します。

    @ViewMenuItem(icon = FontAwesome.SIGN_IN, title = "Login-Logout", order = ViewMenuItem.END)

    ナビゲーターに、このビューがデフォルト・ビューであることを知らせるには、以下のようにビュー名をブランクにした @CDIView() を使用します。

    @CDIView("")

    これまでの手順に従ってボイラープレートに変更を加えている場合、AboutView のアノテーションを @CDIView("") から @CDIView("about") に変更する必要もあります。

この時点でアプリをビルドしてデプロイすると、アプリは新しいログイン・ビューを使用して実行されますが、ログインしようとしても何も起こりません。それは、まだアクセス制御が関連付けられていないためです。

ステップ 5. 認証に対応するように顧客データベースを拡張する

  1. 認証を行うには、password フィールド、role フィールド、そして findByEmail() という名前付きクエリーを顧客データベースに追加する必要があります。まず、org.vaadin.backend.domain.Customer クラスに含まれるドメイン・モデル POJO を以下のように変更します。

    @NamedQueries({
            ...
            @NamedQuery(name="Customer.findByEmail",
            		query="SELECT c FROM Customer c WHERE LOWER(c.email) LIKE :filter")    
    })
        ...
        private String password;
        private String role;
    ...
    public String getPassword() {
    		return password;
    	}
    ...
    	public void setRole(String role) {
    		this.role = role;
    	}
  2. org.vaadin.backend.CustomerService クラスの ensureTestData() メソッドに、定数を設定した以下の 2 つのフィールドを新たに追加します。

    c.setRole("user");
    c.setPassword("abc123");
  3. CustomerListView クラスの adjustTableColumn() メソッド内に、表示させたいフィールドを追加します。

    customerTable.setVisibleColumns("firstName", "lastName", "email",
                 "status", "role", "password");
    customerTable.setColumnHeaders("First name", "Last name", "Email",
                 "Status", "Role", "Password");
  4. LoginView を機能させるために、バックエンドの CustomerService のインスタンスを注入します。このサービスは、データベースからユーザーの e-メールおよびパスワード情報をフェッチするために使用されます。ログインに成功した場合に AboutView へとナビゲートするために、ViewMenuUI.getMenu() ナビゲーターを使用していることに注意してください。

    public class LoginView extends MVerticalLayout implements View {
        @Inject
        private CustomerService service;
    	...
        Customer cust = service.findByEmail(event.getUserName());
    
    	        if(cust != null) {    
     		...
    	        	System.err.println("PASSWORD verified");
        	             ViewMenuUI.getMenu().navigateTo(AboutView.class);
        	        } else {
        	        		System.err.println("PASSWORD invalid");
        	        		loginForm.clear();
        	        	}
        	   
        	        } else {
        	        	System.err.println("no user found");
        	        	loginForm.clear();
        	        }

この時点でアプリをビルドして実行し、ログインを試してみると、AboutView にリダイレクトされるようになっているはずです。ただし、ビューを保護するためのアクセス制御がまだ追加されていないため、前と変わらず顧客リストや地図をクリックして表示することができます。

ステップ 6. CDI アクセス制御を追加する

  1. Vaadin CDI のCDIViewProvider 実装は、ビューへのアクセスを許可する前に、javax.annotation.security.RolesAllowed という名前の特殊なアノテーションに関するチェックを行います。アクセス違反が発生すると、デフォルトのビュー (この例では、LoginView) にリダイレクトされます。このアノテーションをプロジェクトに追加するには、以下の Maven 依存関係を pom.xml ファイルに追加します。

    <dependency>
       <groupId>javax.annotation</groupId>
       <artifactId>javax.annotation-api</artifactId>
       <version>1.2-b01</version>
    </dependency>
  2. RoleAllowed アノテーションを使用してビューを保護するために、それぞれのビュー (LoginViewAboutView を除く) に @RolesAllowed({"user"}) という行を追加します。

    このように変更すると、user ロールが割り当てられたログイン済みユーザーだけが、そのビューにアクセスできるようになります (「ステップ 5. 認証に対応するように顧客データベースを拡張する」で、すべての顧客に user ロールが割り当てられるように設定したことを思い出してください)。

  3. 現在のユーザー詳細を格納するための org.vaadin.presentation.views.UserInfo クラスを作成します。このクラスを UIScope (セッション内の UI インスタンスごとに存在する特殊な Vaadin CDI コンテキスト) に関連付けます。

    @UIScoped
    public class UserInfo implements Serializable {
    private Customer user;
       private List<String> roles = new LinkedList<String>();
       ...

    完全な詳細については、UserInfo のソース・コードを参照してください。

  4. UserInfoLoginView に注入し、ログインに成功した時点でビューに UserInfo を取り込めるようにします。

    public class LoginView extends MVerticalLayout implements View {
        ...	
        @Inject
        private UserInfo user;
       ...    
       public void onLogin(LoginEvent event) {
              ... 	    
               Customer cust = service.findByEmail(event.getUserName());
               if(cust != null) {    
        	 if (cust.getPassword().equals(event.getPassword()))  {
              		user.setUser(cust);
        	        	...
                    }
  5. デフォルトで、アクセス制御が照合される対象となるのは、単一の具体的な JAAS (Java Authentication and Authorization Service) ベースの実装だけを使用した AccessControl 抽象クラスです。このクラスを、注入された UIScoped UserInfo インスタンスに対して照合を行う独自の AccessControl 実装で置き換えます。

    @Alternative
    public class CustomAccessControl extends AccessControl {
    
        @Inject
        private UserInfo userInfo;
        
        @Override
        public boolean isUserSignedIn() {
            return userInfo.getUser() != null;
        }
      ...

    詳細については、org.vaadin.presentation.views.CustomAccessControl のソースを参照してください。

  6. この代わりの CustomAccessControl 実装が Vaadin CDI で使用されるようにするには、以下の行を beans.xml ファイルに追加する必要があります。

    <alternatives>
        <class>org.vaadin.presentation.views.CustomAccessControl</class>
    </alternatives>
  7. ログアウトを実装するには、クリックして「Login-Logout (ログイン/ログアウト)」ページに戻ろうとするログイン済みユーザーがログアウトされるよう、ビューの onEnter() メソッドに注入された UserInfo インスタンスのリセットを使用します。

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) {
      user.setUser(null);
    }

ここでアプリを再ビルドして実行すると、すべてのビュー (「About (情報)」は除く) が保護されるようになっているため、ログインしなければビューにアクセスできなくなっているはずです。ログインした後は、ログイン・ビューをもう一度選択することで、ログアウトすることができます。

ステップ 7. 検索ビューを追加する

検索ビューには、Vaadin Add-ons ディレクトリーにある、オープンソースのサード・パーティー製アドオン UI コンポーネント ― Teppo Kurki 氏が作成した FilteringTable UI コンポーネント (ソース・リポジトリーはこちらのリンク先にあります) ― を使用します。

  1. 以下の依存関係を pom.xml ファイルに追加して、このコンポーネントを使用します。

    <dependency>
       <groupId>org.vaadin.addons</groupId>
       <artifactId>filteringtable</artifactId>
       <version>0.9.13.v7</version>
    </dependency>
  2. ファイナル版のソースにある org.vaadin.presentation.views.SearchView クラスを追加します。このビューの UI の部分は init() メソッドの中で作成され、以下のように単純明快なものです。このビューも、@RolesAllowed({"user"}) によって保護されます。

    @CDIView("search")
    @RolesAllowed({"user"})
    @ViewMenuItem(icon = FontAwesome.SUPPORT)
    public class SearchView extends MVerticalLayout implements View {
        private FilterTable filterTable;
         
       @PostConstruct
        void init() {
            filterTable = buildFilterTable();
           add(filterTable);
            setExpandRatio(filterTable, 1);
            add(buildButtons());
           setMargin(new MarginInfo(false, true, true, true));
            setStyleName(ValoTheme.LAYOUT_CARD);
        }
    ...

    SearchView の残りのコード (org.vaadin.presentation.views.SearchVieworg.tepi.filterable.demo.DemoFilterDecorator、および org.tepi.filterable.demo.DemoFilterGenerator 内に含まれています) は、このデモ・ビューのセットアップでしか使用されないので、手があいているときにこのコードを調べてください。

  3. WAR をビルドしてアプリを実行します。これで、プロジェクトは完成しました。最新の更新については、ソース・リポジトリーにある README を確認してください。以下の cf push コマンドを使用して、Maven プロジェクト・ディレクトリーから完成した WAR を Bluemix に再デプロイすることもできます。

    cf push appname -p target/vaadin-jpa-application.war

まとめ

Java 開発者は Bluemix 上の Vaadin を利用することで、フルスタック Java の手法によって、魅力的な対話型の Web エクスペリエンスを作成できるようになります。また、Bluemix の Vaadin ボイラープレートは、特定のニーズに合わせて簡単に拡張可能な、すぐにデプロイできるアプリを提供しています。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Web development, Cloud computing
ArticleID=1021266
ArticleTitle=Vaadin を使用してクラウド内でフルスタック Java のアプリを開発する
publish-date=11262015