SIerっぽいWEBアプリをAngularJS+JavaEEで組んでみた(その2) マスタメンテナンス画面

SIerっぽいWEBアプリをAngularJS+JavaEEで組んでみたですが
今回はよくあるマスタメンテナンス画面について。

よくある内容を目指していて、ざっくり以下の仕様です。

  • 画面上部が検索条件、モーダルダイアログのコード参照ボタンがある。
  • 画面下部に検索結果の明細が表示される、明細行中のボタンで次画面遷移。

こんな感じの画面ですね。

mntMstUsr.png

ソースはこちらです。
https://github.com/ko-aoki/angularJS_practice/tree/forQiita

設定(的なもの)

  • main.js

$routeProviderで、マスタメンテナンス画面で使用するコントローラと、URLに対応するテンプレート情報を記述しています。
(RequireJSを使用しています。)
※設定としているのですが、実際は初期化処理なんかも$routeProviderで記述できます。

main.js

require.config({
    paths: {
//略
    },
    shim: {
//略
    }
});

require([
        'angular',
        'app',
        'domReady',
        //ファイルを追加したらここに追記
//略
        'controllers/mntMstUserCtrl',
        'controllers/mntMstUserRegCtrl',
        'controllers/mntMstUserRegConfirmCtrl',
        'controllers/codeDeptCtrl',
        'directives/csngPage',
        'directives/csngCodeDept'
    ],
    function (angular, app, domReady) {
        'use strict';
        app.config(['$routeProvider',
            function($routeProvider) {
//ルートの定義。画面を追加したらここで追記
//略
                //ユーザマスタメンテナンス画面
                $routeProvider.when('/mntMstUser', {templateUrl: 'partials/mntMstUser.html', controller: 'MntMstUserCtrl'});
                //ユーザマスタメンテナンス画面(登録)
                $routeProvider.when('/mntMstUserReg', {templateUrl: 'partials/mntMstUserReg.html',
                    controller: 'MntMstUserRegCtrl'
                });
                //ユーザマスタメンテナンス画面(修正)
                $routeProvider.when('/mntMstUserReg/:mstUserId', {templateUrl: 'partials/mntMstUserReg.html',
                    controller: 'MntMstUserRegCtrl'
                });
                //ユーザマスタメンテナンス画面(確認)
                $routeProvider.when('/mntMstUserRegConfirm', {templateUrl: 'partials/mntMstUserRegConfirm.html',
                    controller: 'MntMstUserRegConfirmCtrl'
                });
                //部門コード参照画面
                $routeProvider.when('/codeDept', {templateUrl: 'partials/codeDept.html',
                    controller: 'CodeDeptCtrl'
                });
                $routeProvider.otherwise({redirectTo: '/login'});
            }
        ]);
        domReady(function() {
            angular.bootstrap(document, ['MyApp']);

            $('html').addClass('ng-app: MyApp');
        });
    }
);

テンプレートファイル

  • mntMstUser.html

検索条件のng-modelは”cond”と1階層、情報を付与しています。これにより、明細とのデータを区別しています。
明細はng-repeatで。JSTLのc:forEachで可能なことはいける感じ。
明細内のボタンで、ng-click="delete(rec)"なんて書き方で明細情報を渡せるのは驚きました。
※登録、削除は未実装です。。

mntMstUser.html

コントローラファイル

  • mntMstUserCtrl.js

最初の2行はRequireJSの定義で、依存関係を明確化しています。
1行目でmain,jsで定義したファイル、2行目でその変数化。

$scope.recs = [];以下、$scope.findまでベタで初期化処理書いてますが、多分もっといい書き方あるんでしょうね。。
初期化処理でやりたいことは、コンボボックスの内容取得と、遷移後画面から戻ってきた場合の値復帰です。
コメント//戻る以下でサービスを利用して、自画面の値をすでに持っていたら使用する、といったロジックになります。
コントローラ間のデータ受け渡しに自前のサービスdtoSrvを使用しています。
そもそも検索-選択-入力-確認-登録といった1ユースケースにつき、1コントローラにしたほうがいいのかもしれません。

「検索」ボタン押下の$scope.findではJAX-RSリソースにアクセスして明細行を取得しています。

明細行内の「変更」ボタン押下処理$scope.modifyでは画面遷移前の画面情報の保持と、画面遷移処理です。

検索条件内の「部門検索」ボタン押下処理の$scope.findDeptはjQueryでコード検索のdivにクラスの付け替えをして、コード検索画面の表示をしています。z-index指定のdivでモーダルダイアログとしたのですが、本当に別ウィンドウを起動したい場合は、別途考慮が必要ですね。。

$scope.$on('CodeDeptOK', function (event, rec)はコード参照画面の「OK」押下処理で、コード参照画面から自画面への値渡し処理です。
その3で紹介しているカスタムディレクティブのコントローラからイベント通知されています。

mntMstUserCtrl.js

サービスファイル

  • dtoSrv.js

コントローラ間の値受け渡し用のサービス。
コントローラでも述べたのですが、そもそもコントローラ作成の粒度を画面単位にしているのがどうなのかという疑問はあります。sastrutsなんかとは一致するので移植しやすいかもですが。
内容はJavaでいうところのPOJOですね。

dtoSrv.js

JAX-RSリソースファイル

  • MntMstUserResource.java

ここからサーバサイド=Javaソースです。

リクエストを受け付けてビジネスロジック(サービス)を呼び出しています。
@Produces指定で、呼び出し元のJavaScriptファイル(mntMstUserCtrl.js)にJSONを返しています。

MntMstUserResource.java

  • MntMstUserServiceImple.java

リポジトリを使用してデータ取得し、formに値を設定しています。

MntMstUserServiceImple.java

  • MstUserRepositoryImpl.java

検索条件からJPQLのクエリ文字列を作成しています。
検索結果は他表と結合しているのですが、それはEntityクラス間の関係で表現しています。
改めて見返して、JPQL面倒ですね。。
勉強のためにnativeQuery、JPQL、Criteriaを試しましたが、
できるだけCriteriaを使用したい感じ。

MstUserRepositoryImpl.java

  • MstUser.java

ユーザマスタのエンティティクラス。
ロールマスタ、部門マスタに外部キー指定した状態で、NetBeansの自動生成を行うとそれぞれのエンティティクラスがメンバになります。
MstUserのエンティティを取得すると、紐づくロールマスタ、部門マスタのエンティティも取得されることになります。

ここで、現場で外部キーなんて使ってないよ!結合するには必ずリレーション作成しないといけないのかと思ったのですが、そうでもなく。

MstUser.java

  • SampleRepository.java

Criteraの場合、こんな感じで内部結合できるみたい。
MUser.deptId = MDept.deptIdの関係です。
ここは、もうちょっと突っ込んで調べたいですな。
(2014/09/04 やや関連の別記事を書きました)

SampleRepository.java

まとめ

まずは動かしたというレベルですが、フロントの要求が複雑になるほど、AngularJS使用のメリットは活かせそうです。
むしろ、JPAで実装するにあたって日本語情報が少ないことに手間取りました。
AngularJSは初めから諦めて英語圏の情報収集するのですが、JPA2.0ってJavaEE6のタイミングだから2009年リリースなのに、なんでここまでと。
それで、軽く調べるとJPAは表結合したかったらリレーションの作成が前提になっているように見えてしまう。
正直、自分が関わったプロジェクトで外部キーを使用していたのは1割に満たないので、移行するとなったら大変だ。。と思いながらコーディングしてました。
最後に記述したように、Entity間にリレーション持たせなくても結合する術はあるようなので、そっちを採用することになりそうです。

つづきます。次はコード参照画面/ページ検索

元のサイトへ