LoginSignup
6
7

More than 5 years have passed since last update.

Spring BootとAngularUI UI-Routerを使ってみる

Last updated at Posted at 2016-04-14

はじめに

Spring BootとAngularUI UI-Routerを使った、最も簡単なWebアプリケーションを作成します。

参考

Spring Security and Angular JS
https://spring.io/guides/tutorials/spring-security-and-angular-js/

In-Depth Guide
https://github.com/angular-ui/ui-router/wiki

前提条件

下の記事の後の状態を前提にしています
AngularJSのControllerから、SpringのRestControllerにアクセスしてみる

環境

JVM: 1.8.0_45 (Oracle Corporation 25.45-b02)
OS: Mac OS X 10.11.3 x86_64

Spring Tool Suite

Version: 3.7.3.RELEASE
Build Id: 201602250940
Platform: Eclipse Mars.2 (4.5.2)
(こちらから入れました https://spring.io/tools/sts/all)

Buildship: Eclipse Plug-ins for Gradle 1.0.13.v20160411-1723
(Help -> Eclipse marketplaceから入れました)

手順

UI-Routerを追加する

UI-Routerが使えるように、ビルドスクリプトの依存物として、// Addを追記します。

build.gradle
dependencies {
    compile 'org.webjars:jquery:2.2.3'
    compile 'org.webjars:angularjs:1.5.3'
    // Add
    compile 'org.webjars:angular-ui-router:0.2.18'
    compile 'org.webjars:bootstrap:3.3.6'

    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test') 
}

参考

WebJars http://www.webjars.org/

追記を反映するために、Package ExplorerでSSP37(プロジェクトルート)を選び右クリック、
Gradle -> Refresh Gradle Project
をクリックします。
Package ExplorerのProject and External Dependenciesに、追記したJarあるか確認します。

index.htmlを書き換える

コンテンツが変えられるように、index.htmlを書き換えます。
とりあえずコンテンツの切替が分かるように、blueとgreenというコンテンツを追加しました。
コンテンツを切替えるためのリンクを<ul>の下に追記しました。
<a>のui-srefは、state名を指定すると自動的にhref属性を準備してくれる、UI-Routerの便利なディレクティブです。
コンテンツ表示先としてui-viewディレクティブを指定した<div>を追記しました。
先ほどの<a>をクリックすると、この<div>中身が、後で作成するhtmlのTemplateに書き換えられます。
UI-Routerを参照する<script>も追記します。

src/main/resources/static/index.html
<html ng-app="ssp37App">
<head>
<meta charset="utf-8">
<title>SSP37</title>
<link rel="stylesheet" href="webjars/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
    <!-- Change -->
    <div class="container">
        <ul class="nav nav-pills" role="tablist">
            <li><a ui-sref="hello"  >hello</a></li>
            <li><a ui-sref="blue"   >blue</a></li>
            <li><a ui-sref="green"  >green</a></li>
        </ul>
    </div>
    <!-- Add -->
    <div ui-view class="container"></div>
    <script src="webjars/jquery/2.2.3/jquery.min.js"></script>
    <script src="webjars/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script src="webjars/angularjs/1.5.3/angular.min.js"></script>
    <!-- Add -->
    <script src="webjars/angular-ui-router/0.2.18/angular-ui-router.min.js"></script>
    <script src="js/app.js"></script>
</body>
</html>

app.jsを書き換える

UI-Routerによってコンテンツが変わるように、app.jsへstateやcontrollerを指定します。

詳しくはUI-RouterのDocumentsの下を参考にして下さい。

In-Depth Guide
https://github.com/angular-ui/ui-router/wiki

src/main/resources/static/js/app.js
angular.module('ssp37App', ['ui.router'])
    .config(function($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/hello")
        $stateProvider
            .state('hello', {
                url: "/hello",
                templateUrl: "templates/hello.html",
                controller: "HelloCtrl"
            })
            .state('blue', {
                url: "/blue",
                templateUrl: "templates/blue.html",
                controller: "BlueCtrl"
            })
            .state('green', {
                url: "/green",
                templateUrl: "templates/green.html",
                controller: "GreenCtrl"
            })
            ;
    })
    .controller('HelloCtrl', function($http, $scope) {
        $http.get('/helloOrBad?bad=false')
        .then(function(response) {
             $scope.hello = response.data;
         })
         .catch(function(response) {
             $scope.status = response.status;
             $scope.statusText = response.statusText;
         })
    })
    .controller('BlueCtrl', function($scope) {
        $scope.color = "blue"
    })
    .controller('GreenCtrl', function($scope) {
        $scope.color = "green"
    })
    ;

Templateを導入する

Templateを使ってViewを表示します。
src/main/resources/staticの下にtemplatesディレクトリを作り、
その下に、helloとblue、greenのTemplateを新規作成します。
stateに指定している、templateUrlに対応しています。

src/main/resources/static/templates/hello.html
<h1>Check Controller</h1>
<p>The ID is {{hello.id}}</p>
<p>The text is {{hello.text}}</p>
<p>The status is {{status}}</p>
<p>The statusText is {{statusText}}</p>
src/main/resources/static/templates/blue.html
<p>{{color}} sky</p>
src/main/resources/static/templates/green.html
<p>{{color}} land</p>

動作確認する

http://localhost:8080/index.html を開き、<ul>の下に置いたリンクの、hello、blue、greenをクリックして、コンテンツが変わるのを確認します。

RestControllerへのアクセスをfactoryにする

HelloCtrlで直接アクセスしていた/helloOrBadを、factoryに括りだし、HelloCtrlに注入するように変更します。
ブラウザを再読み込みして、動作確認をします。

src/main/resources/static/js/app.js
angular.module('ssp37App', ['ui.router'])
    // Omit
    // Add
    .factory('hello', function($http) {
        return {
            get: function() {
                return $http.get('/helloOrBad?bad=false');
            }
        };
    })
    // Change
    .controller('HelloCtrl', function($scope, hello) {
        hello.get()
        .then(function(response) {
            $scope.hello = response.data
        })
        .catch(function(response) {
            $scope.status = response.status;
            $scope.statusText = response.statusText;
        })
        ;
    })
    // Omit
    ;

stateのresolveを使ってみる

stateのresolveを導入してみます。
stateのresolveで、先ほどのfactoryにしたhelloを利用し、その結果をHelloCtrlに注入するように変更します。
ブラウザを再読み込みして、動作確認をします。

src/main/resources/static/js/app.js
angular.module('ssp37App', ['ui.router'])
    .config(function($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/hello")
        $stateProvider
            .state('hello', {
                url: "/hello",
                templateUrl: "templates/hello.html",
                controller: "HelloCtrl",
                // Add
                resolve: {
                    helloRsl: function(hello) {
                        return hello.get();
                    } 
                }
            })
            .state('blue', {
                url: "/blue",
                templateUrl: "templates/blue.html",
                controller: "BlueCtrl"
            })
            .state('green', {
                url: "/green",
                templateUrl: "templates/green.html",
                controller: "GreenCtrl"
            })
            ;
    })
    .factory('hello', function($http) {
        return {
            get: function() {
                return $http.get('/helloOrBad?bad=false');
            }
        };
    })
    // Change
    .controller('HelloCtrl', function($scope, helloRsl) {
        $scope.hello = helloRsl.data
    })
    .controller('BlueCtrl', function($scope) {
        $scope.color = "blue"
    })
    .controller('GreenCtrl', function($scope) {
        $scope.color = "green"
    })
    ;

先ほどのhello factoryをcontrollerに、注入するのと、resolveを介して注入するのには、違いがあります。
hello factoryの場合は\$http.getが解決する前に、controllerがインスタンス化されますが、resolveの場合は\$http.getが解決したあとに、インスタンス化されます。
resolveでは例のhelloRslようにキーを指定して、\$http.getのようなpromiseを返す関数を複数指定できます。それらの全てが解決したところで、controllerの中を実行するような処理が行えます。
例えば、2つのREST APIにアクセスして、応答が両方揃ったときにcontrollerを実行したいようなときに便利です。

参考

Sample Repository
https://github.com/quwahara/SSP37/tree/410-ui-router

6
7
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
6
7