簡単！Spring BootでWebAPIをたたいてJSON形式のレスポンスをjavaオブジェクトに変換

##概要
spring bootを使って世の中に公開されているwebAPIをたたいてみよう！
今回は一例として日本郵便が公開している『郵便番号検索API』を使用してみます。フォームで入力した郵便番号をリクエストURLにGETパラメータとして渡し、json形式のレスポンスを取得後、javaに変換しレスポンスの内容を画面に表示します。

<strong>開発環境</strong>

- macOS Sierra 10.12
- java version 1.8.0_65
- Spring-Boot 1.3.5
 - Thymeleaf
 - Gradle

<strong>参考資料</strong>

- [5.17. RESTクライアント（HTTPクライアント）](http://terasolunaorg.github.io/guideline/5.1.0.RELEASE/ja/ArchitectureInDetail/RestClient.html)
- [Jackson使い方メモ](http://qiita.com/opengl-8080/items/b613b9b3bc5d796c840c)
- [郵便番号検索API - zipcloud](http://zipcloud.ibsnet.co.jp/doc/api)

## 完成図
|入力フォーム|
|:-----------|
|    <img width="321" alt="スクリーンショット 2016-11-19 15.20.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/119288/98748c1b-3f61-6801-d287-473123c262ee.png">    |

|送信結果|
|:-----------|
|     <img width="321" alt="スクリーンショット 2016-11-19 15.21.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/119288/f5c36b33-f2bd-9a6b-1a36-e4c85371b5c4.png">  |



##Controller

/zipcodeにアクセスすると入力フォームの画面を表示します。
送信ボタンを押すと、/zipcode/confirmにアクセスされ、POSTパラメータとして渡されてきた郵便番号を@RequestParamで取得します。
取得してきた郵便番号を引数にAPIを呼んでいるサービスクラスを呼び出します。最後にAPIのレスポンスをmodelに詰めます。
ここではリストをmodelに詰めてthymeleafでリストの情報を表示していますが、controllerで一つずつmodelに詰めてもOK。

```java:ZipCodeController.java
@Controller
public class ZipCodeController {
	
	@Autowired
	ZipCodeService zpcService;
	
	/**
	 * 郵便番号入力フォーム
	 * @return "zipcode"
	 */
	@RequestMapping("/zipcode")
	public String zipcodeForm(HttpSession session, Model model) {
		return "zipcode";
	}
	
	/**
	 * 郵便番号情報表示	
	 * @return "zipcode-confirm"
	 */
	@RequestMapping(value="/zipcode/confirm", method=RequestMethod.POST)
	public String zipcodeConfirm(HttpSession session, Model model, 
			                     @RequestParam("zipcode") String zipcode){
		
		// 一応必須チェックのみ 数字・桁数チェックは省略
		// nullまたは空文字の場合、入力フォームにエラーメッセージを表示
		if (zipcode == null || zipcode.equals("")) {
			model.addAttribute("errorMessage", "郵便番号を入力してください。");
			return zipcodeForm(session, model);
		}
		
		// 郵便番号検索APIサービス呼び出し
		ZipCodeDto zipCodeDto = zpcService.service(zipcode);
		// thymeleafでリストを展開して表示する
        model.addAttribute("zipcodeList", zipCodeDto.getResults());
		return "zipcode-confirm";	
	}
}

```

##Service
Controllerから渡されてきた郵便番号をAPIのリクエストURLと結合させ、RestTemplateのpostForEntityメソッドの第一引数に渡しています。

<strong>RestTemplate</strong>とは？
RestTemplateは、REST API(Web API)を呼び出すためのメソッドを提供するクラスであり、 Spring Frameworkが提供するHTTPクライアントです。
※詳細は[こちら](http://terasolunaorg.github.io/guideline/5.1.0.RELEASE/ja/ArchitectureInDetail/RestClient.html)を参照してください

response.getBody()でJSON文字列を取得します。

|JSON文字列|
|:-----------|
|     <img width="353" alt="スクリーンショット 2016-11-19 15.53.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/119288/aeefaaab-2b3d-776a-b3e2-a767eb566409.png">|

JSON文字列をパースするために、jsonパーサーライブラリのJacksonをインストールします。

```java:build.gradle
dependencies {
compile("com.fasterxml.jackson.core:jackson-databind")
}
```
restTemplateのgetForObjectメソッドを第一引数にAPIのURL、第二引数に受け取りのDTO、第三引数にAPIパラメータを指定して呼び出します。



```java:ZipCodeService.java

@Service
public class ZipCodeService {

	@Autowired
	@Qualifier("zipCodeSearchRestTemplate")
	RestTemplate restTemplate;

	/** 郵便番号検索API リクエストURL */
	private static final String URL = "http://zipcloud.ibsnet.co.jp/api/search?zipcode={zipcode}";

	public ZipCodeDto service(String zipcode) {
		return restTemplate.getForObject(URL, ZipCodeDto.class, zipcode);
	}

}

```

## RestTemplateResolver

追記
コメントに以下の指摘頂き、RestTemplateResolverクラスを作成します。

**RestTemplateは内部でHttpMessageConverterを使ってHTTPのBODYとJavaオブジェクトの変換を行っているのですが、Jackson用のHttpMessageConverterの実装クラス(MappingJackson2HttpMessageConverter)は、content-typeがapplication/jsonとかじゃないとダメなんですよね・・・。**

```RestTemplateResolver.java
@Component
public class RestTemplateResolver {

	@Bean
	public RestTemplate zipCodeSearchRestTemplate() {
		RestTemplate restTemplate = new RestTemplate();
		MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
		List<MediaType> supportedMediaTypes = new ArrayList<>(messageConverter.getSupportedMediaTypes());
		supportedMediaTypes.add(MediaType.TEXT_PLAIN); // text/plainのJacksonの処理対象にくわえる
		messageConverter.setSupportedMediaTypes(supportedMediaTypes);
		restTemplate.setMessageConverters(Collections.singletonList(messageConverter)); // カスタムしたHttpMessageConverterを適用
		return restTemplate;
	}
}

```


##Dto

```java:ZipCodeDto.java
    /** ステータス */
	int status;
	
	/** メッセージ */
	String message;
	
	/** 郵便番号情報リスト */
	List<ZipCodeDataDto> results = new ArrayList<>();
```

```java:ZipCodeDataDto.java
　　 /** 郵便番号 */
	String zipcode;
	
	/** 都道府県コード */
	String prefcode;
	
	/** 都道府県名 */
	String address1;
	
	/** 市区町村名 */
	String address2;
	
	/** 町域名 */
	String address3;
	
	/** 都道府県名カナ */
	String kana1;
	
	/** 市区町村名カナ */
	String kana2;
	
	/** 町域名カナ */
	String kana3;
```
※setter、getterは省略

##Template

テンプレートエンジンはthymeleafを使用。
リストの中の要素を一つずつ取り出したい場合はth:each="変数 : ${コレクション}"で記述できる。th:objectを定義しておくことで、*{変数}でオブジェクトの中の要素を取得できる。他のthymeleafの記法についてはここでは割愛する。

```html:zipcode-confirm.html
th:each="item : ${zipcodeList}" th:object="${item}"
th:text="*{zipcode}"
th:text="*{prefcode}"
th:text="*{address1}"
・
・(省略)
・
th:text="*{kana3}"
```

##使用したコード

https://github.com/keiyonekawa0614/spring-boot_calling_webapi