Spring4勉強会 第六回

# Spring4勉強会 第六回

今回はRESTfulAPIをSpringMVC4で作成するサンプルを紹介します。
REST周りについて、言葉の説明は形式上載せますが、今回、下記「動かしてみよう」で作成するのは以下のようなものです。

1. HTMLではなく、テキストを返却する
2. xmlを返却する
3. JSONを返却する

* RESTとは
* RESTfulとは
* 動かしてみよう
* 解説

# RESTとは
<font color="red">RE</font>presentational <font color="red">S</font>tate <font color="red">T</font>ransferの略
WEBの設計思想の一つ。
WEBアプリケーション中のリソースをURIで示せる。
保守性・拡張性に対応可能な設計。
XMLやJSONを扱うことで、他システムとの連携がしやすい。

細かい話は以下の資料がわかりやすいので、以下を参照で。ここでは割愛します。

※引用・参照下 →http://www.slideshare.net/unsolublesugar/res-tful

# RESTfulとは

RESTの規約に則ったこと

# 動かしてみよう

早速、APIを作成していきます。

## テキストを返却する

まずはテキストから。
これはjsp/Servletでも「contentType="text/plain"」で返せるので馴染みがある人はいるかもしれません。

「jp.co.kenshu.controller.api」パッケージに「RestfulController.java」を作成してください。

```
package jp.co.kenshu.controller.api;

import java.util.List;
import jp.co.kenshu.dto.test.TestDto;
import jp.co.kenshu.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RestfulController {

	// テキストが返る※@RestControllerが付いているので、@ResponseBodyが不要
	@RequestMapping(value = "/api/text/")
	public String getTestMember() {
		return "aaaa";
	}
}
```

テキストを返却する例はこの記述のみで完了です。
では[http://localhost:8080/SpringKenshu/api/text/](http://localhost:8080/SpringKenshu/api/text/)にアクセスしてみましょう。
「aaa」が返却されましたか？？

今まで作成してきたControllerではreturnした文字列にマッチするViewファイルが返却され、結果としてHTMLが表示されていたと思います。

しかし、今回は

```
@RestController
public class RestfulController {
```

こんな記述があります。
「**@RestController**」このアノテーションを付与することで、SpringMVCのControllerはRest基調のControllerとして
認識されます。

これは以下のように、「@Controller + @ResponseBody」を指定した場合と同様の挙動をとります。

```
@Controller
public class RestfulController {

	@RequestMapping(value = "/api/text/")
	@ResponseBody
	public String getTestMember() {
		return "aaaa";
	}
}
```

＠ResponseBodyは戻り値自体がレスポンスであることを示してます。

## xmlをレスポンスとして返却する

RestfulController.javaに以下の記述を追加します。

```
// XMLを返却する例
@RequestMapping(value = "/xml/", produces = "application/xml")
public String xml1() {
	return "<a><b>content</b></a>";
}
```

注目すべきは

```
produces = "application/xml"
```

のみです。produceでメディアタイプを指定してます。
あとは戻り値がそもそもXML形式の文字列である必要があります。

## JSONを返却する

まずはJSONを扱うにあたり、jacksonライブラリを利用します。

pom.xmlに以下の記述を追記します。

```
<!-- JSON -->
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-core</artifactId>
	<version>2.4.1</version>
</dependency>
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.4.1.1</version>
</dependency>
```

jacksonをpomに記述したら、「実行」→「Maven Install」を実行します。
これでこのPJにjacksonがインストールされます。

では実装していきましょう。

まずはRestfulController.javaに以下のフィールド記述を追加します。

```
@Autowired
private TestService service;
```

続いて、以下のメソッドを追記します。

```
// JSON返却する例※jackson.coreとjackson-databindがPOMに必要
@RequestMapping("/api/json/")
public List<TestDto> json() {
	List<TestDto> tests = service.getTestAll();
	return tests;
}
```

最後にTestDtoの作成

jp.co.kenshu.dto.test下に


TestDto.javaを作成

```
package jp.co.kenshu.dto.test;

import lombok.Data;

@Data
public class TestDto {
	private Integer id;
	private String name;
}
```

これで[http://localhost:8080/SpringKenshu/api/json/](http://localhost:8080/SpringKenshu/api/json/)にアクセスしてみましょう。
前回登録したTestテーブルの一覧が以下のようなJSON文字列として返却されました。
※TestService#getTestAll()は前回紹介したTestテーブルからselect allした結果がList<TestDto>として返却されます。

```
[{"id":17,"name":"hogehoge"},{"id":18,"name":"hogehogehoge"},{"id":23,"name":"芳賀"},{"id":27,"name":"ｐｐｐｐｐっぽ"},{"id":28,"name":"五右衛門"}]
```

リスト情報をよしなにjacksonのほうで解析し、JSON文字列を組み立ててくれます。
JSON構造を変更したい場合は、独自にJSON文字列情報を組み立てる必要があります。

今回は以上です。

## APIから返却されたJSONをパースして、画面に表示してみよう

以上じゃないです。嘘です。追加です。
せっかくAPI作成したので、別のControllerからAPIをコールし、受け取ったJSON文字列をパースして画面に表示してみよう。

* Controllerの作成

jp.co.kenshu.controller.api下に以下のControllerを追加

TestReceiveController.java

```
package jp.co.kenshu.controller.api;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;

import jp.co.kenshu.dto.test.TestDto;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
public class TestReceiveController {

	private static final String API_URL = "http://localhost:8080/SpringKenshu/api/json/";

	@RequestMapping(value = "/api/result/", method = RequestMethod.GET)
	public String test(Model model) throws JsonParseException, JsonMappingException, IOException {
		List<TestDto> dtoList = convertTest(executeGet(API_URL));
		model.addAttribute("dtoList", dtoList);
		return "apiresult";
	}

	private List<TestDto> convertTest(String json) throws JsonParseException, JsonMappingException, IOException {
		ObjectMapper mapper = new ObjectMapper();
		List<TestDto> list = mapper.readValue(json, new TypeReference<List<TestDto>>() {
		});
		return list;
	}

	private String executeGet(final String urlStr) {
		StringBuilder sb = new StringBuilder();
		try {
			URL url = new URL(urlStr);
			HttpURLConnection connection = null;
			try {
				connection = (HttpURLConnection) url.openConnection();
				connection.setRequestMethod("GET");
				if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
					try (InputStreamReader isr = new InputStreamReader(connection.getInputStream(),
							StandardCharsets.UTF_8);
							BufferedReader reader = new BufferedReader(isr)) {
						String line;
						while ((line = reader.readLine()) != null) {
							sb.append(line);
						}
					}
				}
			} finally {
				if (connection != null) {
					connection.disconnect();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
}
```

* JSPの作成

WEB-INF/view下に以下のjspを作成

apiresult.jsp

```
<!DOCTYPE html>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head>
	<body>
        <c:forEach items="${dtoList}" var="test">
            <p><c:out value="${test.id}" /></p>
            <p><c:out value="${test.name}" /></p>
        </c:forEach>
	</body>
</html>
```

これで、APIから取得したJSONをdecodeし、TestDtoに変換して、画面に表示されます。

※ビジネスロジックは実際にはServiceなどに記述するようにしてください。
面倒だったので、Controllerに書いちゃってます。