かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その17 )( 図書館一覧取得 WebAPI の作成 )

概要

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その16 )( ログイン画面の作成7 ) の続きです。

参照したサイト・書籍

  1. Spring Framework Reference Documentation - 22.10 Accessing RESTful services on the Client
    http://docs.spring.io/spring/docs/4.1.7.RELEASE/spring-framework-reference/htmlsingle/#rest-client-access

  2. REST in Spring 3: RestTemplate
    https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate

  3. Spring RESTFul Client – RestTemplate Example
    http://howtodoinjava.com/2015/02/20/spring-restful-client-resttemplate-example/

  4. How to Set HTTP Request Timeouts With Spring RestTemplate
    http://springinpractice.com/2013/10/27/how-to-set-http-request-timeouts-with-spring-resttemplate

    • RestTemplate でタイムアウトを設定する方法を参照しました。
    • この記事では HttpComponentsClientHttpRequestFactory を使用していますが、Apache の HttpClient( org.apache.http.client.HttpClient ) が必要になるため、今回は SimpleClientHttpRequestFactory を使用します。
  5. Simple XML SERIALIZATION
    http://simple.sourceforge.net/home.php

    • XML <--> Java オブジェクトのシリアライズ・デシリアライズをするためのライブラリです。
    • Spring Framework にも MarshallingHttpMessageConverter というクラスが提供されているようなのですが、使い方がよく分かりませんでした。。。
    • 他の方法を調べていたところ、Spring for Android というライブラリで XML --> Java オブジェクトに変換するのにこのライブラリが使用されていました。公式サイトの Tutorial を見て試してみたところ簡単に実装できたので、今回はこのライブラリを利用します。
  6. 千年の孤独 - AndroidXML - Spring Andorid -
    http://d.hatena.ne.jp/horafuki_taka/20110619/1308463386

    • Simple を使用する方法を参考にしました。
  7. Unit Test RESTful API with Spring MVC Test Framework
    https://www.jiwhiz.com/blogs/Unit_Test_RESTful_API_with_Spring_MVC_Test_Framework

    • MockMvc を使用して WebAPI のテストをする方法を参考にしました。
  8. jayway/JsonPath
    https://github.com/jayway/JsonPath

  9. コンピュータクワガタ - Spring MVC 3.2のJSONのテスト
    http://kuwalab.hatenablog.jp/entry/2014/04/21/Spring_MVC_3.2%E3%81%AEJSON%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88

    • jsonPath のテストの書き方を参考にしました。

目次

  1. はじめに
  2. 1.0.x-make-webapi-getlibrary ブランチの作成
  3. カーリル図書館API利用のためのアプリケーションキーの取得
  4. アプリケーションキー保存用設定ファイルの作成 ( Git の管理対象外にする )
  5. Simple ライブラリを利用できるようにする
  6. カーリル図書館APIの図書館データベースを呼び出す CalilApiService クラスの作成
  7. CalilApiService クラスのテストクラスの作成、動作確認
  8. 図書館一覧取得 WebAPI の Controller クラスの作成
  9. LibraryController クラスのテストクラスの作成、動作確認
  10. 次回は。。。

手順

はじめに

都道府県名を URLパラメータに受け取り、カーリル図書館APIを呼び出して図書館一覧を取得後 ( この時は XML で受信します )、JSON/JSONP で返す WebAPI を作成します。URL は以下の仕様です。

http://localhost:8080/webapi/library/getLibraryList?pref=[都道府県名(例:東京都)]

Spring Boot で JSON/JSONP のレスポンスを返す WebAPI の実装と、REST クライアントの実装を試します。

1.0.x-make-webapi-getlibrary ブランチの作成

  1. IntelliJ IDEA で 1.0.x-make-webapi-getlibrary ブランチを作成します。

カーリル図書館API利用のためのアプリケーションキーの取得

  1. 図書館API仕様書 の「アプリケーションキーの登録」に表示されている「こちらのページでアプリケーションキーを申請してください。」のリンクをクリックして API ダッシュボード へ移動します。

  2. API ダッシュボード」のページにある「ログインに進む」ボタンをクリックします。

  3. ログイン画面へ移動しますので、Twitter, facebook, Google のいずれかのアカウントでログインします。

  4. ログインすると再び「API ダッシュボード」のページに戻ります。今度は「開発者プロフィールの登録」ボタンをクリックします。

  5. 「開発者プロフィールの登録」のページに遷移しますので、個人名、メールアドレスを入力後「同意して利用する」ボタンをクリックします。

  6. 再び「API ダッシュボード」のページに戻ります。「新しいアプリケーションの追加」ボタンをクリックします。

  7. 「カーリル・図書館API アプリケーション登録」のページに遷移しますので、アプリ名を入力後「登録する」ボタンをクリックします。

  8. 再び「API ダッシュボード」のページに戻ります。登録したアプリケーション名に対応するアプリケーションキーが表示されますので、これを使用します。

アプリケーションキー保存用設定ファイルの作成 ( Git の管理対象外にする )

  1. src/main/resources の下に calilapi.properties を作成します ( この時 Git には Add しません )。作成後、リンク先の内容 に変更します。

  2. .gitignore を リンク先の内容 に変更します。

Simple ライブラリを利用できるようにする

  1. build.gradle を リンク先のその1の内容 に変更します。

  2. Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。

カーリル図書館APIの図書館データベースAPIを呼び出す CalilApiService クラスの作成

  1. src/main/java/ksbysample/webapp/lending/service の下に calilapi パッケージを作成します。

  2. 図書館データベースAPIXML レスポンスを変換して格納するクラスを作成します。src/main/java/ksbysample/webapp/lending/service/calilapi の下に Libraries.java, Library.java を作成します。作成後、リンク先の内容 に変更します。

  3. カーリル図書館APIの図書館データベースAPIを呼び出して結果を返す Service クラスを作成します。src/main/java/ksbysample/webapp/lending/service/calilapi の下に CalilApiService.java を作成します。作成後、リンク先の内容 に変更します。

CalilApiService クラスのテストクラスの作成、動作確認

  1. src/main/java/ksbysample/webapp/lending/service/calilapi の下の CalilApiService.java で「Create Test」ダイアログを表示し、テストクラスを作成します。

    f:id:ksby:20150819100258p:plain

    src/test/java/ksbysample/webapp/lending/service/calilapi の下に CalilApiServiceTest.java が作成されます。

  2. 最初にデータを取得できているか表示して確認してみます。src/test/java/ksbysample/webapp/lending/service/calilapi の下の CalilApiServiceTest.javaリンク先のその1の内容 に変更します。

  3. テストを実行してみます。testGetLibraryList メソッドにカーソルを移動し、コンテキストメニューを表示後「Run 'testGetLibraryList...()' with Coverage」を選択します。

    テストは成功し、取得した図書館のデータも表示されました。

    f:id:ksby:20150819105506p:plain

  4. まずなくならないと思われる「国立国会図書館東京本館」で存在チェックするようテストを変更します。都道府県名が間違っている場合もテストします。src/test/java/ksbysample/webapp/lending/service/calilapi の下の CalilApiServiceTest.javaリンク先のその2の内容 に変更します。

  5. テストを実行します。CalilApiServiceTest のクラス名にカーソルを移動し、コンテキストメニューを表示後「Run 'CalilApiServiceTest' with Coverage」を選択し、テストが成功することを確認します。

    f:id:ksby:20150819142929p:plain

図書館一覧取得 WebAPI の Controller クラスの作成

  1. 最初に /webapi から始まる URL の場合には認証不要にします。src/main/java/ksbysample/webapp/lending/config の下の WebSecurityConfig.javaリンク先の内容 に変更します。

  2. src/main/java/ksbysample/webapp/lending の下に webapi.common パッケージ、webapi.library パッケージを作成します。

  3. src/main/java/ksbysample/webapp/lending/webapi/common の下に CommonWebApiResponse.java を作成します。作成後、リンク先の内容 に変更します。

  4. src/main/java/ksbysample/webapp/lending/webapi/library の下に LibraryController.java を作成します。作成後、リンク先の内容 に変更します。

  5. Tomcat を起動して WebAPI を呼び出してみます。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。

  6. ブラウザを起動して http://localhost:8080/webapi/library/getLibraryList?pref=%e6%9d%b1%e4%ba%ac%e9%83%bd にアクセスします ( %e6%9d%b1%e4%ba%ac%e9%83%bd は "東京都" を UTF-8 で URLエンコードした文字列です )。東京都の図書館データベース一覧が取得できました。

    f:id:ksby:20150819150229p:plain

  7. 返ってきた JSON を整形してみます。src/main/java/ksbysample/webapp/lending/webapi/library の下に data.json というファイルを作成し、表示された JSON メッセージをコピー&ペーストで貼り付けた後、Ctrl+Alt+L で整形します。

    content の中に図書館データが配列で出力されており、問題なさそうです。確認後、data.json は削除します。

    f:id:ksby:20150819150547p:plain

  8. Ctrl+F2 を押して Tomcat を停止します。

LibraryController クラスのテストクラスの作成、動作確認

  1. MockMvc で JSON のテストをする時に使用する jsonpath を使用できるようにします。build.gradle を リンク先のその2の内容 に変更します。

  2. Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。

  3. src/main/java/ksbysample/webapp/lending/webapi/library の下の LibraryController.java で「Create Test」ダイアログを表示し、テストクラスを作成します。

    f:id:ksby:20150819174716p:plain

    • 画面下部の Member 一覧は何もチェックしません。自分でテストメソッドを書きます。

    src/test/java/ksbysample/webapp/lending/webapi/library の下に LibraryControllerTest.java が作成されます。

  4. src/test/java/ksbysample/webapp/lending/webapi/library の下の LibraryControllerTest.javaリンク先の内容 に変更します。

  5. テストを実行します。LibraryControllerTest クラスのクラス名にカーソルを移動し、コンテキストメニューを表示後「Run 'LibraryControllerTes...' with Coverage」を選択します。

    テストが成功することが確認できます。

    f:id:ksby:20150823175531p:plain

次回は。。。

図書館一覧取得 WebAPI の作成の続きです。マージも次回行います。

  • getLibraryList の JSONP 対応をします。
  • RestTemplate の機能をもう少しいろいろ試してみます。XML のレスポンスを処理する方法を調べるのに結構時間がかかりましたが、JSONJSONP の場合はもっと対応が楽なはずなので試してみたいと思います。

ソースコード

calilapi.properties

calil.apikey=(...ここにアプリケーションキーを記述します...)

.gitignore

# built application files
*.apk
*.ap_

# files for the dex VM
*.dex

# Java class files
*.class

# generated files
bin/
gen/

# Local configuration file (sdk path, etc)
local.properties

# Eclipse project files
.classpath
.project

# Proguard folder generated by Eclipse
proguard/

# Intellij project files
*.iml
*.ipr
*.iws
.idea/

#Gradle
.gradletasknamecache
.gradle/
build/
bin/

#カーリル図書館API用設定ファイル
calilapi.properties
  • ファイルの最後に calilapi.properties を追加します。

build.gradle

■その1

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:9.4-1201-jdbc41"

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されるもの
    // Appendix E. Dependency versions ( http://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity3")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-velocity")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-redis")
    compile("org.codehaus.janino:janino")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.springframework.security:spring-security-test:4.0.1.RELEASE")
    testCompile("org.yaml:snakeyaml")

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されないもの
    compile("${jdbcDriver}")
    compile("org.seasar.doma:doma:2.3.1")
    compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
    compile("org.apache.commons:commons-lang3:3.4")
    compile("org.projectlombok:lombok:1.16.4")
    compile("com.google.guava:guava:18.0")
    compile("org.springframework.session:spring-session:1.0.1.RELEASE")
    compile("org.simpleframework:simple-xml:2.7.1")
    testCompile("org.dbunit:dbunit:2.5.1")
    testCompile("com.icegreen:greenmail:1.4.1")
    testCompile("org.assertj:assertj-core:3.1.0")

    // for Doma-Gen
    domaGenRuntime("org.seasar.doma:doma-gen:2.3.1")
    domaGenRuntime("${jdbcDriver}")
}
  • compile("org.simpleframework:simple-xml:2.7.1") を追加します。

■その2

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:9.4-1201-jdbc41"

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されるもの
    // Appendix E. Dependency versions ( http://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity3")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-velocity")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-redis")
    compile("org.codehaus.janino:janino")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.springframework.security:spring-security-test:4.0.1.RELEASE")
    testCompile("org.yaml:snakeyaml")

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されないもの
    compile("${jdbcDriver}")
    compile("org.seasar.doma:doma:2.3.1")
    compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
    compile("org.apache.commons:commons-lang3:3.4")
    compile("org.projectlombok:lombok:1.16.4")
    compile("com.google.guava:guava:18.0")
    compile("org.springframework.session:spring-session:1.0.1.RELEASE")
    compile("org.simpleframework:simple-xml:2.7.1")
    testCompile("org.dbunit:dbunit:2.5.1")
    testCompile("com.icegreen:greenmail:1.4.1")
    testCompile("org.assertj:assertj-core:3.1.0")
    testCompile("com.jayway.jsonpath:json-path:2.0.0")

    // for Doma-Gen
    domaGenRuntime("org.seasar.doma:doma-gen:2.3.1")
    domaGenRuntime("${jdbcDriver}")
}
  • testCompile("com.jayway.jsonpath:json-path:2.0.0") を追加します。

Libraries.java, Library.java

■Libraries.java

package ksbysample.webapp.lending.service.calilapi;

import lombok.Data;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;

import java.util.List;

@Data
@Root(name = "Libraries")
public class Libraries {

    @ElementList(inline = true)
    private List<Library> libraryList;

}

■Library.java

package ksbysample.webapp.lending.service.calilapi;

import lombok.Data;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

@Data
@Root(name = "Library", strict = false)
public class Library {

    @Element
    private String systemid;

    @Element
    private String systemname;

    @Element(name = "formal")
    private String formalName;

    @Element
    private String address;

}
  • 図書館データベースAPIXML レスポンスには上に定義した以外の要素もありますが、全ては使用しません。@Root アノテーションstrict = false を記述して全ての要素を定義していなくてもエラーにならないようにします。

CalilApiService.java

package ksbysample.webapp.lending.service.calilapi;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
@PropertySource("classpath:calilapi.properties")
public class CalilApiService {

    private int CONNECT_TIMEOUT = 5000;
    private int READ_TIMEOUT = 5000;
    
    private final String URL_CALILAPI_LIBRALY = "http://api.calil.jp/library?appkey={appkey}&pref={pref}";

    @Value("${calil.apikey}")
    private String calilApiKey;

    public Libraries getLibraryList(String pref) throws Exception {
        // 図書館データベースAPIを呼び出して XMLレスポンスを受信する
        RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
        ResponseEntity<String> response
                = restTemplate.getForEntity(URL_CALILAPI_LIBRALY, String.class, this.calilApiKey, pref);
        
        // 受信した XMLレスポンスを Javaオブジェクトに変換する
        Serializer serializer = new Persister();
        Libraries libraries = serializer.read(Libraries.class, response.getBody());
        
        return libraries;
    }

    private ClientHttpRequestFactory getClientHttpRequestFactory() {
        // 接続タイムアウト、受信タイムアウトを 5秒に設定する
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(CONNECT_TIMEOUT);
        factory.setReadTimeout(READ_TIMEOUT);
        return factory;
    }
    
}
  • calilapi.properties に記述したアプリケーションキーを利用するために以下のように実装します。
    • クラスに @PropertySource("classpath:calilapi.properties") アノテーションを記述します。
    • クラス内に @Value("${calil.apikey}") private String calilApiKey; を記述し、calilapi.properties 内の calil.apikey の値を calilApiKey フィールドに読み込みます。
  • RestTemplate で受信したレスポンスは一旦 String に保存し、その後に Simple ライブラリを利用して Java オブジェクトに変換します。

CalilApiServiceTest.java

■その1

package ksbysample.webapp.lending.service.calilapi;

import ksbysample.webapp.lending.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class CalilApiServiceTest {

    @Autowired
    private CalilApiService calilApiService;

    @Test
    public void testGetLibraryList() throws Exception {
        Libraries libraries = calilApiService.getLibraryList("東京都");
        libraries.getLibraryList().stream()
                .forEach(s -> System.out.println(s.getSystemid() + "," + s.getFormalName() + "," + s.getAddress()));
    }

}

■その2

package ksbysample.webapp.lending.service.calilapi;

import ksbysample.webapp.lending.Application;
import org.assertj.core.api.ThrowableAssert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simpleframework.xml.core.ValueRequiredException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.StrictAssertions.assertThatThrownBy;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class CalilApiServiceTest {

    @Autowired
    private CalilApiService calilApiService;

    @Test
    public void testGetLibraryList_都道府県名が正しい場合() throws Exception {
        Libraries libraries = calilApiService.getLibraryList("東京都");
        // systemname が "国立国会図書館" のデータがあるかチェックする
        assertThat(libraries.getLibraryList())
                .extracting("systemname")
                .contains("国立国会図書館");
    }

    @Test
    public void testGetLibraryList_都道府県名が間違っている場合() throws Exception {
        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
            @Override
            public void call() throws Throwable {
                Libraries libraries = calilApiService.getLibraryList("東a京都");
            }
        }).isInstanceOf(ValueRequiredException.class);
    }

}

WebSecurityConfig.java

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                // .antMatchers("/country/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/html/**").permitAll()
                .antMatchers("/encode").permitAll()
                .antMatchers("/urllogin").permitAll()
                .antMatchers("/webapi/**").permitAll()
                .anyRequest().authenticated();
        http.formLogin()
                .loginPage("/")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl(WebSecurityConfig.DEFAULT_SUCCESS_URL)
                .failureUrl("/")
                .usernameParameter("id")
                .passwordParameter("password")
                .permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/")
                .deleteCookies("JSESSIONID")
                .deleteCookies("remember-me")
                .invalidateHttpSession(true)
                .permitAll()
                .and()
                .rememberMe()
                .key(REMEMBERME_KEY)
                .tokenValiditySeconds(60 * 60 * 24 * 30);
    }
  • .antMatchers("/webapi/**").permitAll() を追加します。

CommonWebApiResponse.java

package ksbysample.webapp.lending.webapi.common;

import lombok.Data;

@Data
public class CommonWebApiResponse<T> {

    private String errcode;

    private String errmsg;

    private T content;
    
}

LibraryController.java

package ksbysample.webapp.lending.webapi.library;

import ksbysample.webapp.lending.service.calilapi.CalilApiService;
import ksbysample.webapp.lending.service.calilapi.Libraries;
import ksbysample.webapp.lending.service.calilapi.Library;
import ksbysample.webapp.lending.webapi.common.CommonWebApiResponse;
import org.simpleframework.xml.core.ValueRequiredException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;

@RestController
@RequestMapping("/webapi/library")
public class LibraryController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    private CalilApiService calilApiService;
    
    @RequestMapping("/getLibraryList")
    public CommonWebApiResponse<List<Library>> getLibraryList(String pref) throws Exception {
        CommonWebApiResponse<List<Library>> response = new CommonWebApiResponse<>();
        response.setContent(Collections.EMPTY_LIST);
        
        try {
            Libraries libraries = calilApiService.getLibraryList(pref);
            response.setContent(libraries.getLibraryList());
        } catch (ValueRequiredException e) {
            response.setErrcode(-2);
            response.setErrmsg("都道府県名が正しくありません。");
        } catch (Exception e) {
            logger.error("システムエラーが発生しました。", e);
            response.setErrcode(-1);
            response.setErrmsg("システムエラーが発生しました。");
        }

        return response;
    }
    
}

LibraryControllerTest.java

package ksbysample.webapp.lending.webapi.library;

import ksbysample.common.test.SecurityMockMvcResource;
import ksbysample.webapp.lending.Application;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class LibraryControllerTest {

    @Rule
    @Autowired
    public SecurityMockMvcResource mvc;

    @Test
    public void 正しい都道府県を指定した場合には図書館一覧が返る() throws Exception {
        mvc.noauth.perform(get("/webapi/library/getLibraryList?pref=東京都"))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.errcode", is(0)))
                .andExpect(jsonPath("$.errmsg", is("")))
                .andExpect(jsonPath("$.content[0].address", startsWith("東京都")))
                .andExpect(jsonPath("$.content[?(@.formalName=='国立国会図書館東京本館')]").exists());
    }

    @Test
    public void 間違った都道府県を指定した場合にはエラーが返る() throws Exception {
        mvc.noauth.perform(get("/webapi/library/getLibraryList?pref=東a京都"))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.errcode", is(-2)))
                .andExpect(jsonPath("$.errmsg", is("都道府県名が正しくありません。")))
                .andExpect(jsonPath("$.content", hasSize(0)));
    }

}

履歴

2015/08/19
初版発行。
2015/08/23
* LibraryControllerTest のテストの実行結果を書き忘れていたので追記しました。