AngularJSのControllerから、SpringのRestControllerにアクセスしてみる


# はじめに

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

こちらのチュートリアルが元ネタです。
Spring Security and Angular JS
https://spring.io/guides/tutorials/spring-security-and-angular-js/

AngularJSのチュートリアルも参考にしています。
https://code.angularjs.org/1.5.3/docs/tutorial

# 前提条件

下の記事の後の状態を前提にしています
[Spring Tool Suite 3.7.3(Eclipse Mars.2 (4.5.2))でSpring Starter Projectを新規作成](http://qiita.com/quwahara/items/e3eac70425cee1b70454)


# 環境

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から入れました)

# 手順

## JavaScript Libraryを追加する

AngularJSなどのJavaScript Libraryが使えるように、ビルドスクリプトの依存物として、// Addを追記します。

```groovy:build.gradle
dependencies {
	// Add
	compile 'org.webjars:jquery:2.2.3'
	compile 'org.webjars:angularjs:1.5.3'
	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あるか確認します。

## JavaScript Libraryを参照してみる

導入したJavaScript Libraryがhtmlファイルから参照できるか試してみます。
下のindex.htmlファイルを新規作成します。

```html:src/main/resources/static/index.html
<html>
<head>
<meta charset="utf-8">
<title>SSP37</title>
<link rel="stylesheet" href="webjars/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
	<div class="container">
		<div>Check script sources</div>
	</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>
</body>
</html>
```

Webアプリケーションを実行し、ブラウザで http://localhost:8080/index.html を開きます。
ブラウザの開発ツールなどで、参照しているJavaScript Libraryが参照できているか確認します。

## ちょっとだけAngularJSを使ってみる

簡単にAngularJSが動いているかを確認します。
index.htmlの<!-- Change -->とあるところを変更します。
htmlタグにng-app属性を追記。
class="container"の下を変更。

```html:src/main/resources/static/index.html
<html ng-app><!-- Change -->
<head>
<meta charset="utf-8">
<title>SSP37</title>
<link rel="stylesheet" href="webjars/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
	<div class="container">
		<!-- Change -->
		<h1>Check AngularJS</h1>
		<div>{{'AngularJS'}}</div>
	</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>
</body>
</html>
```

\<div\>{{'AngularJS'}}\</div\>のところが、ブラウザでAngularJSとでればOKです。
{{'AngularJS'}}とでたら、 AngularJSが動いてません。

## Controllerを導入してみる

AngularJSのControllerを導入してみましょう。
下のapp.jsを新規作成します。

```js:src/main/resources/static/js/app.js
angular.module('ssp37App', [])
	.controller('HelloCtrl', function($scope) {
		$scope.hello = {id: 'xxx', text: 'Hello'}
	})
	;
```

index.htmlも導入したControllerを使うように<!-- Change -->とあるところを変更します。
htmlタグにng-app属性にモジュール名:ssp37Appを追記。
class="container"のdivタグに、ng-controller属性を追記。
同タグ内もHelloCtrlで指定した値を使うように変更します。
\<!-- Add --\>に先ほどのControllerへの参照を追記します。

```html:src/main/resources/static/index.html
<html ng-app="ssp37App"><!-- Change -->
<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" ng-controller="HelloCtrl">
		<h1>Check Controller</h1>
		<p>The ID is {{hello.id}}</p>
		<p>The text is {{hello.text}}</p>
	</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="js/app.js"></script>
</body>
</html>
```

プレースホルダの{{xxx}}内が、Controllerで指定した値に換わったか確認します。

## RestControllerにアクセスしてみる

AngularJSのControllerから、SpringのRestControllerにアクセスして、値を出してみましょう。
下のRestControllerを新規作成します。

```java:src/main/java/com/example/controllers/MyRestController.java
package com.example.controllers;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyRestController {

	@RequestMapping("/hello")
	public Map<String,Object> hello() {
	    Map<String,Object> model = new HashMap<String,Object>();
	    model.put("id", UUID.randomUUID().toString());
	    model.put("text", "Hello by MyRestController");
	    return model;
	}
}
```

AngularJSのControllerからRestControllerへアクセスするように、app.jsを変更します。

```js:src/main/resources/static/js/app.js
angular.module('ssp37App', [])
	// Change
	.controller('HelloCtrl', function($http, $scope) {
		$http.get('/hello')
		.then(function(response) {
			 $scope.hello = response.data;
		 })
	})
	;
```

プレースホルダの{{xxx}}内が、RestControllerで指定した値に換わったか確認します。

## 400 Bad Requestを応答するRestControllerにアクセスしてみる

RestControllerが400 Bad Requestを応答する場合をAngularJSのControllerで捕捉してみましょう。
先ほどのRestControllerに// Addの部分を追記し、/helloOrBad?bad=trueでアクセスされたら、400 Bad Requestを応答するようにします。

```java:src/main/java/com/example/controllers/MyRestController.java
package com.example.controllers;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.http.HttpStatus;						// Add
import org.springframework.http.ResponseEntity;					// Add
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;	// Add
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyRestController {

	// Omit

	// Add
	@RequestMapping("/helloOrBad")
	public ResponseEntity<Map<String,Object>> helloOrBad(@RequestParam(required=false) Boolean bad) {
		if(bad != null && bad) {
			return new ResponseEntity<Map<String,Object>>(HttpStatus.BAD_REQUEST);
		}
		else {
		    Map<String,Object> model = new HashMap<String,Object>();
		    model.put("id", UUID.randomUUID().toString());
		    model.put("text", "Hello or Bad by MyRestController");
			return new ResponseEntity<Map<String,Object>>(model, HttpStatus.OK);
		}
	}

}
```

AngularJSのControllerから/helloOrBad?bad=trueへアクセスするようにし、200 OK以外の応答を捕捉するように、// Addの部分を追記します。

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

index.htmlにstatusが出るようにも<!-- Add -->とあるところを追記します。

```html: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>
	<div class="container" ng-controller="HelloCtrl">
		<h1>Check Controller</h1>
		<p>The ID is {{hello.id}}</p>
		<p>The text is {{hello.text}}</p>
		<!-- Add -->
		<p>The status is {{status}}</p>
		<p>The statusText is {{statusText}}</p>
	</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>
	<script src="js/app.js"></script>
</body>
</html>
```

The status is 400と出るか確認します。

## 参考

Sample Repository
https://github.com/quwahara/SSP37/tree/310-webjars