##概要
spring bootを使って世の中に公開されているwebAPIをたたいてみよう!
今回は一例として日本郵便が公開している『郵便番号検索API』を使用してみます。フォームで入力した郵便番号をリクエストURLにGETパラメータとして渡し、json形式のレスポンスを取得後、javaに変換しレスポンスの内容を画面に表示します。
開発環境
- macOS Sierra 10.12
- java version 1.8.0_65
- Spring-Boot 1.3.5
- Thymeleaf
- Gradle
参考資料
完成図
入力フォーム |
---|
送信結果 |
---|
##Controller
/zipcodeにアクセスすると入力フォームの画面を表示します。
送信ボタンを押すと、/zipcode/confirmにアクセスされ、POSTパラメータとして渡されてきた郵便番号を@RequestParamで取得します。
取得してきた郵便番号を引数にAPIを呼んでいるサービスクラスを呼び出します。最後にAPIのレスポンスをmodelに詰めます。
ここではリストをmodelに詰めてthymeleafでリストの情報を表示していますが、controllerで一つずつmodelに詰めてもOK。
@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メソッドの第一引数に渡しています。
RestTemplateとは?
RestTemplateは、REST API(Web API)を呼び出すためのメソッドを提供するクラスであり、 Spring Frameworkが提供するHTTPクライアントです。
※詳細はこちらを参照してください
response.getBody()でJSON文字列を取得します。
JSON文字列 |
---|
JSON文字列をパースするために、jsonパーサーライブラリのJacksonをインストールします。
dependencies {
compile("com.fasterxml.jackson.core:jackson-databind")
}
restTemplateのgetForObjectメソッドを第一引数にAPIのURL、第二引数に受け取りのDTO、第三引数にAPIパラメータを指定して呼び出します。
@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とかじゃないとダメなんですよね・・・。
@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
/** ステータス */
int status;
/** メッセージ */
String message;
/** 郵便番号情報リスト */
List<ZipCodeDataDto> results = new ArrayList<>();
/** 郵便番号 */
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の記法についてはここでは割愛する。
th:each="item : ${zipcodeList}" th:object="${item}"
th:text="*{zipcode}"
th:text="*{prefcode}"
th:text="*{address1}"
・
・(省略)
・
th:text="*{kana3}"
##使用したコード