はじめに
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を追記します。
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>も追記します。
<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
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に対応しています。
<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>
<p>{{color}} sky</p>
<p>{{color}} land</p>
動作確認する
http://localhost:8080/index.html を開き、<ul>の下に置いたリンクの、hello、blue、greenをクリックして、コンテンツが変わるのを確認します。
RestControllerへのアクセスをfactoryにする
HelloCtrlで直接アクセスしていた/helloOrBadを、factoryに括りだし、HelloCtrlに注入するように変更します。
ブラウザを再読み込みして、動作確認をします。
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に注入するように変更します。
ブラウザを再読み込みして、動作確認をします。
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