LoginSignup
62
68

More than 5 years have passed since last update.

SIerっぽいWEBアプリをAngularJS+JavaEEで組んでみた(その1)

Last updated at Posted at 2014-08-12

seasar2とかで実装しているWEBアプリをAngularJS+JavaEE(JPA、JAX-RS)でリプレイスしたい!なんて話をちらほら聞くので、実際どんな感じになるのか作成してみました。
バックエンドだけ開発していた人間が考えると、こうなってしまうんだなという結果に終わってます。。

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

参考にした書籍は以下でした。

実際に作り始めると、やはり書籍の情報だけでは全然不足していて、しんどかった。
OracleはJavaEEにかなり力入れている感じだけど、JavaEE6以降、特にJPAの日本語情報が不足しているなあと。

機能概要

ざっくり動くレベルで、以下の機能を実装。

  • ログイン
  • メニュー
  • 条件検索画面(検索結果明細を表示)
  • データ登録画面
  • コード照会画面(ページ検索)

使用アプリ

  • NetBeans8
    業務だとeclipseを10年以上使用しているのですが、JavaEEならNetBeansかなと採用。
    自動生成機能が強力でした。

  • WebStorm8
    AngularJSのコード補完があったり。NetBeansも対応していたかな?
    まだ使いこなせてないです。。

フォルダ構成


+---src //Javaソース
| \---java
| +---base
| | \---bean
| +---bean
| +---entity
| +---form
| +---repository
| +---resource
| +---service
| \---util
+---test //テストソース。karmaなどもここ。
\---web
+---css
+---data
+---images
+---img
+---js
| +---controllers //AngularJSコントローラ
| +---directives //AngularJSディレクティブ
| +---services //AngularJSサービス
| \---vendor //AngularJS,jQueryなどライブラリファイル
+---partials //AngularJSテンプレート
+---templates //AngularJSテンプレート(ディレクティブ用)
\---WEB-INF

設定ファイル(的なもの)

JavaScript

  • main.js

RequireJSを使用していて、ファイルが増えたらこちらに追記。

main.js
require.config({
    paths: {
        'jquery': 'vendor/jquery/jquery',
        'jquery.treeview': 'vendor/jquery/jquery.treeview',
        'angular': 'vendor/angular/angular',
        'angularRoute': 'vendor/angular/angular-route',
        'angularResource': 'vendor/angular/angular-resource',
        'angularMocks': 'vendor/angular-mocks/angular-mocks',
        'domReady': 'vendor/requirejs/domReady'
    },
    shim: {
        'jquery' : {'exports' : 'jquery'},
        'jquery.treeview' :['jquery'],
        'angular' : {'exports' : 'angular'},
        'angularRoute': ['angular'],
        'angularResource': { deps:['angular'] },
        'angularMocks': {
            deps:['angular'],
            'exports':'angular.mock'
        }
    }
});

require([
        'angular',
        'app',
        'domReady',
        //ファイルを追加したらここに追記
        'services/dtoSrv',
        'controllers/loginCtrl',
        'controllers/menuCtrl',
        '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('/login', {templateUrl: 'partials/login.html', controller: 'LoginCtrl'});
                $routeProvider.when('/menu/:roleId', {templateUrl: 'partials/menu.html', controller: 'MenuCtrl'});
//中略
                $routeProvider.otherwise({redirectTo: '/login'});
            }
        ]);
        domReady(function() {
            angular.bootstrap(document, ['MyApp']);
            $('html').addClass('ng-app: MyApp');
        });
    }
);

JavaEE

  • persistence.xml

寺田さんの記事とか参考にしてNetBeansで自動生成。

実装

ログイン

ユーザID、パスワードを入力して「ログイン」を押下すると
サーバアクセスし、ユーザマスタを参照して次画面遷移するか、エラーメッセージを出力。

AngularJS

テンプレートファイルと、それに対応したコントローラファイルを作成する。

  • login.html
login.html
<h1>ログイン</h1>
<ul>
   <li ng-repeat="message in messages">
          <p>{{message}}</p>
   </li>
</ul>
<br>
<span>ユーザID :</span><input type="text" ng-model="loginUserId"/>
<br>
<span>パスワード:</span><input type="text" ng-model="password"/>
<br>
<button class="btn" ng-click="login()">ログイン</button>
  • loginCtrl.js

コントローラファイルではJAX-RSにアクセスし、結果次第でエラー出力するか、画面遷移しています。
$resourceでresourceオブジェクトを生成し、getでサーバアクセス。
$location.pathを使用すると、HTTPリクエストは発生しません。

loginCtrl.js
define(['controllers','angularResource'],
    function(controllers) {
        controllers.controller('LoginCtrl', ['$scope', '$http', '$location', '$resource',
            function ($scope, $http, $location, $resource) {
                $scope.login = function login() {
                    var login = $resource('webresources/login/:loginUserId,:password',
                                    {
                                        'loginUserId': '@loginUserId',
                                        'password': '@password'
                                    }
                                );
                    login.get(
                        {'loginUserId': $scope.loginUserId, 'password': $scope.password},
                        function (data) {
                            if (data.result === "error") {
                                $scope.messages = data.messages;
                            } else {
                                $location.path("menu/" + data.roleId);
                            }
                        }
                    );
                };
            }]);
    });

JavaEE

  • LoginResource.java

AngularJSのアクセス先となるリソースクラス。
@Pathで示されるリクエストURLのフォーマットにより、対応するクラス、メソッドが決定。
loginCtrl.jsの'login で"webresources/login/ユーザ,パスワード"の形式でリクエストされると、
loginメソッドが実行される。
@InjectでDI。
@Produces("application/json")で、戻り値のJavaオブジェクトをJSONに変換してくれる。

LoginResource.java

@Path("login")
public class LoginResource {

    @Inject
    private LoginService loginService;

    public LoginResource() {
    }

    @GET
    @Path("{userId},{password}")
    @Produces("application/json")
    public LoginForm login(@PathParam("userId") String userId, @PathParam("password") String password) {
       return loginService.login(userId, password);
    }

}
  • LoginServiceImpl.java

リソースクラスから呼び出されるサービスクラス。
既存Javaアプリの移行という観点で、戻り値にformクラスを指定することにしました。
Repositoryクラスを利用し、Entityクラスを取得し、Formクラスに転記。

LoginServiceImpl.java
public class LoginServiceImpl implements LoginService{

    @Inject
    private MstUserRepository mstUserRep;

    public LoginForm login(String userId, String password) {

        List<MstUser> rec = mstUserRep.findByUserId(userId);
        LoginForm form = new LoginForm();
        if (rec.isEmpty()) {
            form.setMessages(Arrays.asList("ユーザが存在しません"));
            form.setResult("error");
        } else {
            if (password.equals(rec.get(0).getPassword())) {
                form.setRoleId(rec.get(0).getRoleId().getRoleId());
                form.setResult("ok");
            } else {
                form.setMessages(Arrays.asList("パスワードが一致しません"));
                form.setResult("error");
            }
        }
        return form;

    }

}
  • MstUserRepositoryImpl.java

エンティティを操作するリポジトリクラス。
正直、DAOとの違いが理解できてないです。。

@PersistenceContextでpersistence-unitを指定。ここは共通化できそうな。。
findByUserIdではNamedQueryを利用しています。

MstUserRepositoryImpl.java

public class MstUserRepositoryImpl implements MstUserRepository{
    @PersistenceContext(name = "common-app-javaee7PU")
    private EntityManager em;

    /**
     * ユーザIDでユーザを検索します.
     * @param userId
     * @return 
     */
    @Override
    public List<MstUser> findByUserId(String userId) {
       Query query = em.createNamedQuery("MstUser.findByUserId", MstUser.class);
       query.setParameter("userId", userId);
       List<MstUser> rec = query.getResultList();
       return rec;
    }
//中略
    /**
     * ユーザ情報を更新します.
     * @param user 
     */
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public void update(MstUser user) {
        em.merge(user);
    }

}

  • MstUser.java

こちらも、NetBeansで、テーブルを指定して自動生成。

まとめ

旧来のJavaフレームワークでは、JSP+アクションクラスで実装していた箇所がAngularJSで置き換えられることになります。
実際に書いてみると、以前より画面-ロジックの見通しが良くなった印象を受けました。JSPは表示できるようになるまで時間がかかるので、それがなくなるのも大きい。
JAX-RSはアノテーションだけでやりたいことができてしまう。昔作成したソースを思い出して遠い目をしちゃう感じです。
JPAはMyBatisとか、生SQLベースのフレームワークを使用していたので、かなり理解し辛かったです。

続きます

62
68
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
68