Skip to main content
Grails 3.0先取り!?
Spring Boot入門ハンズオン
2014-08-01 日本Grails/Groovyユーザーグループ
G*ワークショップ"Z" 第14弾
槙 俊明(@making)
最初にことわっておきますが
Groovy/Grails/Gradle
使いません(キリ)
Java/Mavenで許して😜
※ GroovyやGradleを使っても勧められますが、
自己責任でお願いします。
自己紹介
• @making
• http://blog.ik.am
• 日本Javaユーザーグループ(JJUG)幹事
• Groovy書けません
• Spring Boot本書いています
http://amzn.to/hajiboo
今日のハッシュタグ
#jggug_boot
今日のコンテンツ
• Spring Boot超概要(5分)
• Spring Bootハンズオン(100分)
• まとめ(5分)
Spring Boot超概要
Spring Bootとは?
• 簡単にいうと、「Spring Boot」
とは「Spring Framework」で
アプリケーションを簡単に作る
た めの仕組み
Grails3のベースになるらしい
Spring Boot以前のSpring Framework
Spring Boot以前のSpring Framework
色々ありすぎて、
組み合わせがわからない!
初期セットアップが大変!
Spring Boot
• あらかじめオススメの組み合わせが決まっ
ている
• 依存ライブラリを同梱するだけで自動で
設定がきまる
• 組み込みサーバーを同梱し、アプリを即
実行可能
Spring Bootで何が変わる?
• アプリの設定が変わる
• アプリのデプロイが変わる
Spring Bootで何が変わる?
• アプリの設定が変わる
• アプリのデプロイが変わる
ほとんど設定不要!
Spring Bootで何が変わる?
• アプリの設定が変わる
• アプリのデプロイが変わる
ほとんど設定不要!
jarを実行するだけ!
Spring Bootに関する詳しい話はまた今度!
• 2014-08-14に日本Springユー
ザー会 勉強会でSpring Bootにつ
いて話します。
• https://atnd.org/events/53770
(今から登録は厳しいかも・・・)
体験してみましょう
Spring Bootハンズオン
ハンズオンの流れ
1.Hello WorldアプリでSpring Bootことはじめ
2.Spring BootでREST APIを作ろう
3.Spring Bootで画面のあるアプリを作ろう
4.Spring Securityで認証認可を追加しよう
ハンズオンの流れ
1.Hello WorldアプリでSpring Bootことはじめ
2.Spring BootでREST APIを作ろう
3.Spring Bootで画面のあるアプリを作ろう
4.Spring Securityで認証認可を追加しよう
100分だと多分ここまで
ハンズオンの流れ
1.Hello WorldアプリでSpring Bootことはじめ
2.Spring BootでREST APIを作ろう
3.Spring Bootで画面のあるアプリを作ろう
4.Spring Securityで認証認可を追加しよう
100分だと多分ここまで
土日にやろう
質問があれば
•#jggug_boot でつぶいや
いてくればいつか回答し
ます
JDK 8のインストール
• http://www.oracle.com/technetwork/java/javase/
downloads/jdk8-downloads-2133151.html
• JAVA_HOMEを設定してね!
Spring Tool Suite(STS)
のインストール
• http://spring.io/tools
Mavenのインストール
• http://maven.apache.org/
• ダウンロードして、PATHに追加
curlのインストール
• http://curl.haxx.se/
• Windowsの人はダウンロードして、PATHに追加
本ハンズオン扱う技術
Webブラウザ
curl
Tomcat
Spring Boot
Spring Framework
SpringSecurity
ThymeLeaf
SpringMVC
Jackson
SpringDataJPA
Hibernate
H2
Database画面のあるアプリ
REST API
題材のアプリ
• 簡易ブックマークシステム
1. Hello Worldアプリで
Spring Bootことはじめ
Mavenアーキタイプでプロジェ
クト雛形生成
$ mvn -B archetype:generate -DgroupId=com.example
-DartifactId=jggug-helloworld -Dversion=1.0.0-
SNAPSHOT -DarchetypeArtifactId=maven-archetype-
quickstart
Spring Bootに関係のない汎用的な手順
http://bit.ly/jggug-01-00
pom.xmlを編集
<parent>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-parent</artifactId>	
<version>1.1.4.RELEASE</version>	
</parent>	
<dependencies>	
<dependency>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-web</artifactId>	
</dependency>	
<dependency>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-test</artifactId>	
<scope>test</scope>	
</dependency>	
</dependencies>	
<build>	
<plugins>	
<plugin>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-maven-plugin</artifactId>	
</plugin>	
</plugins>	
</build>	
<properties>	
<java.version>1.8</java.version>	
</properties>	
 
この設定を追加
http://bit.ly/jggug-01-01
Mavenプロジェクトをインポー
ト
インポート後
いろいろな依存関係が追加され
ている
package com.example;	
!
import org.springframework.boot.SpringApplication;	
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;	
import org.springframework.web.bind.annotation.RequestMapping;	
import org.springframework.web.bind.annotation.RestController;	
!
@RestController	
@EnableAutoConfiguration	
public class App {	
!
@RequestMapping("/")	
String home() {	
return "Hello World!";	
}	
!
public static void main(String[] args) {	
SpringApplication.run(App.class, args);	
}	
}
App.javaの編集
http://bit.ly/jggug-01-02
package com.example;	
!
import org.springframework.boot.SpringApplication;	
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;	
import org.springframework.web.bind.annotation.RequestMapping;	
import org.springframework.web.bind.annotation.RestController;	
!
@RestController	
@EnableAutoConfiguration	
public class App {	
!
@RequestMapping("/")	
String home() {	
return "Hello World!";	
}	
!
public static void main(String[] args) {	
SpringApplication.run(App.class, args);	
}	
}
App.javaの編集
http://bit.ly/jggug-01-02
魔法のアノテーション
まずは実行
• 実行方法は2通り
または
$ mvn spring-boot:run
ログ
組込Tomcatが起動した
http://localhost:8080 にアクセス
実行可能jarを作成
$ mvn package
jarを実行
$ java -jar target/jggug-helloworld-1.0.0-
SNAPSHOT.jar
プロパティを変更して実行
$ java -jar target/jggug-helloworld-1.0.0-
SNAPSHOT.jar --server.port=8888
--(プロパティ名)=(プロパティ値)
予め用意されている沢山のプロ
パティを変更可能
• http://docs.spring.io/spring-boot/docs/
1.1.4.RELEASE/reference/html/common-application-
properties.html
一度作ったjarはそのまま本番環境で使用可能。
配布も可能。
• -Drun.arguments="--(プロパティ名)=(プロパティ値)"
で指定。
[補足] mavenプラグインの場合
$ mvn spring-boot:run -Drun.arguments="--server.port=8888"
http://bit.ly/jggug-01-03
[参考] Spring LoadedでHot Reload
<plugin>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-maven-plugin</artifactId>	
<dependencies>	
<dependency>	
<groupId>org.springframework</groupId>	
<artifactId>springloaded</artifactId>	
<version>1.2.0.RELEASE</version>	
</dependency>	
</dependencies>	
</plugin>
maven pluginに追加
http://bit.ly/jggug-01-04
[参考] Spring LoadedでHot Reload
$ mvn spring-boot:run
[INFO] Attaching agents: [/Users/****/.m2/repository/org/springframework/
springloaded/1.2.0.RELEASE/springloaded-1.2.0.RELEASE.jar]	
objc[11505]: Class JavaLaunchHelper is implemented in both /Library/Java/
JavaVirtualMachines/jdk1.8.0_11.jdk/Contents/Home/jre/bin/java and /Library/
Java/JavaVirtualMachines/jdk1.8.0_11.jdk/Contents/Home/jre/lib/
libinstrument.dylib. One of the two will be used. Which one is undefined.	
!
. ____ _ __ _ _	
/ / ___'_ __ _ _(_)_ __ __ _    	
( ( )___ | '_ | '_| | '_ / _` |    	
/ ___)| |_)| | | | | || (_| | ) ) ) )	
' |____| .__|_| |_|_| |___, | / / / /	
=========|_|==============|___/=/_/_/_/	
:: Spring Boot :: (v1.1.4.RELEASE)
Hot Reload用のagentが自動
的にアタッチされる
アプリ実行中にソースを変更してコンパイル
@RequestMapping("/")	
String home() {	
return "Hello World!";	
}
@RequestMapping("/")	
String home() {	
return "Hello Spring!";	
}
再起動することなく
アプリが更新された
注意
• まだまだSpring Loadedは未熟で、リ
ロードされないケースや副作用による
エラーが発生することもある。
• うまく更新できたらラッキー。
• 開発を暖かく見守りましょう。
Integration Test
@RunWith(SpringJUnit4ClassRunner.class)	
@SpringApplicationConfiguration(classes = App.class)	
@WebAppConfiguration	
@IntegrationTest("server.port:0")	
public class AppTest {	
@Value("${local.server.port}")	
int port;	
!
RestTemplate restTemplate = new TestRestTemplate();	
!
@Test	
public void testHome() {	
ResponseEntity<String> response = restTemplate.getForEntity(	
"http://localhost:" + port, String.class);	
assertThat(response.getStatusCode(), is(HttpStatus.OK));	
assertThat(response.getBody(), is("Hello World!"));	
}	
}
空いているポートを使用
実際に使ったポート番号
テスト用HTTPクライアント
エントリポイントのクラス指定
http://bit.ly/jggug-01-05
Integration Test
組込Tomcatを起動して、
HTTPリクエストを送り、
HTTPレスポンスをチェック
他のJVM言語の例
• https://github.com/making/spring-boot-demo-jvm-
languages
• Java/Groovy/Scala/KotlinそれぞれのGradleプロジェク
トサンプルがあるのでお好みの言語でSpring Bootアプ
リを作りましょう
2. Spring Bootで

REST APIを作ろう
Webブラウザ
curl
Tomcat
Spring Boot
Spring Framework
SpringSecurity
ThymeLeaf
SpringMVC
Jackson
SpringDataJPA
Hibernate
H2
Database画面のあるアプリ
REST API
REST APIでBookmark管理
• 「REST」はクライアントとサーバ間でデータをやりと
りするためのソフトウェアアーキテクチャスタイルの
一つ。
• RESTでは、「リソース」に対するCRUD操作をHTTP
メソッド(POST/GET/PUT/DELETEなど)を使ってWeb
APIとしてクライアントに公開する。
• 今回は「ブックマーク」が「リソース」
実装するAPI
API
HTTP
メソッド
リソースパス
正常時レスポンス
ステータス
ブックマーク
全件取得
GET /api/bookmarks 200 OK
ブックマーク
新規登録
POST

! /api/bookmarks 201 CREATED
ブックマーク
一件削除
DELETE /api/bookmarks/{id} 204 NO CONTENT
Mavenアーキタイプでプロジェ
クト雛形生成
$ mvn -B archetype:generate -DgroupId=com.example
-DartifactId=bookmark -Dversion=1.0.0-SNAPSHOT -
DarchetypeArtifactId=maven-archetype-quickstart	
$ mkdir bookmark/src/main/resources
artifactId以外helloworldのときと同じ
src/main/resourcesを作成しておく
http://bit.ly/jggug-02-00
<parent>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-parent</artifactId>	
<version>1.1.4.RELEASE</version>	
</parent>	
<dependencies>	
<dependency>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-web</artifactId>	
</dependency>	
<dependency>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-data-jpa</artifactId>	
</dependency>	
<dependency>	
<groupId>com.h2database</groupId>	
<artifactId>h2</artifactId>	
</dependency>	
<dependency>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-starter-test</artifactId>	
<scope>test</scope>	
</dependency>	
</dependencies>	
<build>	
<plugins>	
<plugin>	
<groupId>org.springframework.boot</groupId>	
<artifactId>spring-boot-maven-plugin</artifactId>	
<dependencies>	
<dependency>	
<groupId>org.springframework</groupId>	
<artifactId>springloaded</artifactId>	
<version>1.2.0.RELEASE</version>	
</dependency>	
</dependencies>	
</plugin>	
</plugins>	
</build>	
<properties>	
<java.version>1.8</java.version>	
</properties>
pom修正
JPAを使用したい場合は、
spring-boot-starter-data-jpa
を追加するだけ。
JDBCドライバも必要
http://bit.ly/jggug-02-01
必要な依存関係が追加される
Mavenプロジェクトのインポート
出来上がりイメージ
レイヤー化アプリケーション
DI Container
Controller Service Repository
use use
inject inject
レイヤー化アプリケーション
DI Container
Controller Service Repository
use use
inject inject
この順で実装する
ドメインオブジェクト作成
• ブックマークサービスに必要な情報
• ID
• ブックマーク名
• URL
ドメインオブジェクト作成
• com.example.domain.Bookmark
@Entity	
public class Bookmark {	
@Id	
@GeneratedValue	
private Long id;	
@NotNull	
@Size(min = 1, max = 255)	
private String name;	
@NotNull	
@Size(min = 1, max = 255)	
@URL	
private String url;	
// omitted setter & getter	
}
JPAのエンティティとして
アノテーションをつける
デフォルトでは
インメモリ組み込みDBが使用
され、DDLも自動生成&実行
http://bit.ly/jggug-02-02
リポジトリ作成
• 「リポジトリ」は、 ドメインオブジェクト
の保存、取得、検索といった操作をカプセ
ル化し、”コレクションオブジェクト”のよ
うに振る舞う役割をもつ。
• 「リポジトリ」にロジックを含めない。
Spring Data JPAでリポジトリ作成
• com.example.repository.BookmarkRepository
package com.example.repository;	
!
import com.example.domain.Bookmark;	
import org.springframework.data.jpa.repository.JpaRepository;	
!
public interface BookmarkRepository extends JpaRepository<Bookmark, Long>
{	
!
} エンティティクラス、主キークラス
たったこれだけでJPAのEntityManagerを使用した
基本的なDBのCRUD操作を利用できる。(SQL不要)
http://bit.ly/jggug-02-03
サービス作成
• 全件取得、新規作成、一件削除用のメソッ
ドを作成する
• POJOに@Serviceアノテーションを付け
るとDIコンテナに自動登録される(コン
ポーネントスキャン)
サービス作成
• com.example.service.BookmarkService
@Service	
@Transactional	
public class BookmarkService {	
@Autowired	
BookmarkRepository bookmarkRepository;	
!
public List<Bookmark> findAll() {	
return bookmarkRepository.findAll(new Sort(Sort.Direction.ASC, "id"));	
}	
!
public Bookmark save(Bookmark bookmark) {	
return bookmarkRepository.save(bookmark);	
}	
!
public void delete(Long id) {	
bookmarkRepository.delete(id);	
}	
}
リポジトリをインジェクション
宣言的トランザクション管理
IDで昇順に検索
http://bit.ly/jggug-02-04
コントローラー作成
• 基本的にSpring MVCを使ったプログラミン
グを行う
• POJOに@Controllerを付けるとHTTPのリク
エストを受けられる
• @RestControllerを付けると、Controllerの
メソッドの返り値が、シリアライズされ、その
ままHTTPレスポンスのボディになる
コントローラーの
リクエストマッピング
• HTTPリクエストとコントローラーのメソッドのマッ
ピング表
API
HTTP
メソッ
ド
リソースパス メソッド 返り値の型
ブックマー
ク全件取得
GET /api/bookmarks getBookmarks List<Bookmark>
ブックマー
ク新規登録
POST

! /api/bookmarks postBookmarks Bookmark
ブックマー
ク一件削除
DELET
E
/api/
bookmarks/{id}
deleteBookmark void
コントローラー作成
• com.example.api.BookmarkRestController
@RestController	
@RequestMapping("api/bookmarks")	
public class BookmarkRestController {	
@Autowired	
BookmarkService bookmarkService;	
!
@RequestMapping(method = RequestMethod.GET)	
List<Bookmark> getBookmarks() {	
return bookmarkService.findAll();	
}	
@RequestMapping(method = RequestMethod.POST)	
@ResponseStatus(HttpStatus.CREATED)	
Bookmark postBookmarks(@RequestBody Bookmark bookmark) {	
return bookmarkService.save(bookmark);	
}	
@RequestMapping(value = "{id}", method = RequestMethod.DELETE)	
@ResponseStatus(HttpStatus.NO_CONTENT)	
void deleteBookmarks(@PathVariable("id") Long id) {	
bookmarkService.delete(id);	
}	
}
サービスをインジェクション
パスやHTTPメソッド等の組み
合わせとコントローラーのメソッ
ドを結びつける
リクエストボディ
をJavaBeanに
マッピング
プレースホルダの
値を取得
http://bit.ly/jggug-02-05
入力チェックを実施
@RestController	
@RequestMapping("api/bookmarks")	
public class BookmarkRestController {	
@Autowired	
BookmarkService bookmarkService;	
!
@RequestMapping(method = RequestMethod.GET)	
List<Bookmark> getBookmarks() {	
return bookmarkService.findAll();	
}	
@RequestMapping(method = RequestMethod.POST)	
@ResponseStatus(HttpStatus.CREATED)	
Bookmark postBookmarks(@Validated @RequestBody Bookmark bookmark) {	
return bookmarkService.save(bookmark);	
}	
@RequestMapping(value = "{id}", method = RequestMethod.DELETE)	
@ResponseStatus(HttpStatus.NO_CONTENT)	
void deleteBookmarks(@PathVariable("id") Long id) {	
bookmarkService.delete(id);	
}	
}
詳細は割愛・・・
参照URLを後述
http://bit.ly/jggug-02-06
アプリケーションのエントリポイント作成
package com.example;	
!
import org.springframework.boot.SpringApplication;	
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;	
import org.springframework.context.annotation.ComponentScan;	
!
@EnableAutoConfiguration	
@ComponentScan	
public class App {	
!
public static void main(String[] args) {	
SpringApplication.run(App.class, args);	
}	
}
http://bit.ly/jggug-02-07
アプリケーション実行
• リクエストマッピングのログが出力される
ことを確認s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/
bookmarks],methods=[GET],params=[],headers=[],consumes=[],produces=[],cust
om=[]}" onto java.util.List<com.example.domain.Bookmark>
com.example.api.BookmarkRestController.getBookmarks()	
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/
bookmarks],methods=[POST],params=[],headers=[],consumes=[],produces=[],cus
tom=[]}" onto com.example.domain.Bookmark
com.example.api.BookmarkRestController.postBookmarks(com.example.domain.Bo
okmark)	
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/bookmarks/
{id}],methods=[DELETE],params=[],headers=[],consumes=[],produces=[],custom
=[]}" onto void
com.example.api.BookmarkRestController.deleteBookmarks(java.lang.Long)
APIチェック
• ブックマーク新規作成
$ curl http://localhost:8080/api/bookmarks
-v -X POST -H 'Content-Type:application/
json' -d '{"name":"Google", "url":"http://
google.com"}'
http://bit.ly/jggug-02-08
Windowsのコマンドプロンプトだとシングルクオートが効か
ないのでダブルクオートとエスケープしてください
APIチェック
• ブックマーク新規作成
> POST /api/bookmarks HTTP/1.1	
> User-Agent: curl/7.30.0	
> Host: localhost:8080	
> Accept: */*	
> Content-Type:application/json	
> Content-Length: 44	
>	
< HTTP/1.1 201 Created	
< Server: Apache-Coyote/1.1	
< Content-Type: application/json;charset=UTF-8	
< Transfer-Encoding: chunked	
< Date: Sat, 26 Jul 2014 17:44:11 GMT	
<	
{"id":1,"name":"Google","url":"http://google.com"}
APIチェック
• ブックマーク全件取得
$ curl http://localhost:8080/api/bookmarks
-v -X GET
http://bit.ly/jggug-02-09
APIチェック
• ブックマーク全件取得
> GET /api/bookmarks HTTP/1.1	
> User-Agent: curl/7.30.0	
> Host: localhost:8080	
> Accept: */*	
>	
< HTTP/1.1 200 OK	
< Server: Apache-Coyote/1.1	
< Content-Type: application/json;charset=UTF-8	
< Transfer-Encoding: chunked	
< Date: Sat, 26 Jul 2014 17:55:48 GMT	
<	
[{"id":1,"name":"Google","url":"http://google.com"}]
APIチェック
• ブックマーク1件削除
$ curl http://localhost:8080/api/bookmarks/
1 -v -X DELETE
http://bit.ly/jggug-02-10
APIチェック
• ブックマーク1件削除
> DELETE /api/bookmarks/1 HTTP/1.1	
> User-Agent: curl/7.30.0	
> Host: localhost:8080	
> Accept: */*	
>	
< HTTP/1.1 204 No Content	
< Server: Apache-Coyote/1.1	
< Date: Sat, 26 Jul 2014 17:58:02 GMT	
<
課題1
• ブックマーク1件取得APIを実装してみよう
API
HTTP
メソッ
ド
リソースパス メソッド 返り値の型
ブックマー
ク一件取得
GET
/api/
bookmarks/{id}
getBookmark Bookmark
アプリケーションをカスタマイズしよう
• 設定ファイルの設定方法
• JavaConfigでBean定義を行う方法
• ログの設定変更方法
これらを試していきます
JDBCドライバの設定値を変更
• インメモリH2からファイルベースH2へ
• 設定ファイルはクラスパス直下の
application.ymlまたは
application.properties
YAMLが便利
application.yml作成
spring:	
datasource:	
driverClassName: org.h2.Driver	
url: jdbc:h2:file:/tmp/bookmark	
username: sa	
password:	
jpa:	
hibernate:	
ddl-auto: update
インメモリDB使用時はcreate-
dropが指定されており、毎回破
棄・生成が行われていた。今回は
updateを指定し、差分があれば
適用する方式に。
DBの実体のファイルパスを指定
する。なかったら作成される。
src/main/resources/application.yml
http://bit.ly/jggug-02-11
[補足] 設定値一覧(再掲)
• http://docs.spring.io/spring-boot/docs/
1.1.4.RELEASE/reference/html/common-
application-properties.html
Log4JDBCでSQLログを出力しよう
• pom.xmlに以下を追加
<dependency>	
<groupId>org.lazyluke</groupId>	
<artifactId>log4jdbc-remix</artifactId>	
<version>0.2.7</version>	
</dependency>
http://bit.ly/jggug-02-12
• Bean定義を行うJavaConfigクラスを作成
Log4JDBCでSQLログを出力しよう
package com.example;	
!
import org.springframework.context.annotation.Bean;	
import org.springframework.context.annotation.Configuration;	
!
@Configuration	
public class AppConfig {	
!
@Bean	
SomeBean someBean() {	
returen new SomeBean();	
}	
}
JavaConfigの記法
JavaConfig宣言
Bean定義宣言
※この部分は書かなくて良い
com.example.AppConfig
Log4JDBCでSQLログを出力しよう
@Configuration	
public class AppConfig {	
@Autowired	
DataSourceProperties properties;	
DataSource dataSource;	
!
@ConfigurationProperties(prefix = 	
DataSourceAutoConfiguration.CONFIGURATION_PREFIX)	
@Bean(destroyMethod = "close")	
DataSource realDataSource() {	
DataSourceBuilder factory = DataSourceBuilder	
.create(this.properties.getClassLoader())	
.url(this.properties.getUrl())	
.username(this.properties.getUsername())	
.password(this.properties.getPassword());	
this.dataSource = factory.build();	
return this.dataSource;	
}	
@Bean	
DataSource dataSource() {	
return new Log4jdbcProxyDataSource(this.dataSource);	
}	
}
Spring Bootが内部
で行っている、
DataSourceの作成
方法。
難しい場合は気にし
なくて良い。
作成しDataSource
にログ出力処理をラッ
プする。こちらを使
う。
http://bit.ly/jggug-02-13
このメソッド名
(=Bean名)が重要
• src/main/resources/logback.xmlを
作成
<?xml version="1.0" encoding="UTF-8"?>	
<configuration>	
<include resource="org/springframework/boot/logging/logback/base.xml" />	
<logger name="jdbc" level="OFF" />	
<logger name="jdbc.sqltiming" level="DEBUG" />	
</configuration>
Log4JDBCでSQLログを出力しよう
http://bit.ly/jggug-02-14
• アプリケーションを再起動して各APIを実行
Log4JDBCでSQLログを出力しよう
jdbc.sqltiming :
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:
187)	
3. insert into bookmark (id, name, url) values (null, 'Google', 'http://google.com') {executed
in 3 msec}	
jdbc.sqltiming :
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:80)	
4. select bookmark0_.id as id1_0_, bookmark0_.name as name2_0_, bookmark0_.url as url3_0_ from 	
bookmark bookmark0_ order by bookmark0_.id asc {executed in 0 msec}	
jdbc.sqltiming :
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:80)	
5. select bookmark0_.id as id1_0_0_, bookmark0_.name as name2_0_0_, bookmark0_.url as url3_0_0_ 	
from bookmark bookmark0_ where bookmark0_.id=1 {executed in 0 msec}	
jdbc.sqltiming :
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:
187)	
5. delete from bookmark where id=1 {executed in 2 msec}
課題2
• bookmarkアプリケーションのjarを作成
し、実行時にspring.datasource.*プ
ロパティを変更して、接続先DBを変更し
よう(MySQLやPostgreSQLで試してみる
と面白い)。
REST APIを任意のクライアント
からアクセスできるようにする
• Angular.jsで作成したSingle Page
Applicationからアクセスしてみよう
• http://jsfiddle.net/Ca2g2/
作っておきました
REST APIを任意のクライアント
からアクセスできるようにする
REST APIを任意のクライアント
からアクセスできるようにする
XMLHttpRequest cannot load http://localhost:
8080/api/bookmarks. No 'Access-Control-Allow-
Origin' header is present on the requested
resource. Origin 'http://fiddle.jshell.net' is
therefore not allowed access.
Same Origin Policy制限!
REST APIを任意のクライアント
からアクセスできるようにする
• Cross-Origin Resource Sharing (CORS)
の設定を行うServletFilterを作成
• http://spring.io/guides/gs/rest-service-
cors/
• Spring BootではServlet FilterはDIコンテ
ナに登録しておけば自動的に有効になる。
REST APIを任意のクライアント
からアクセスできるようにする
• AppConfigに以下のBean定義を追加
@Bean	
Filter corsFilter() {	
return new Filter() {	
public void doFilter(ServletRequest req, ServletResponse res,	
FilterChain chain) throws IOException, ServletException {	
HttpServletRequest request = (HttpServletRequest) req;	
HttpServletResponse response = (HttpServletResponse) res;	
String method = request.getMethod();	
response.setHeader("Access-Control-Allow-Origin", "*");	
response.setHeader("Access-Control-Allow-Methods",	
"POST,GET,OPTIONS,DELETE");	
response.setHeader("Access-Control-Max-Age",	
Long.toString(60 * 60));	
response.setHeader("Access-Control-Allow-Credentials", "true");	
response.setHeader(	
"Access-Control-Allow-Headers",	
"Origin,Accept,X-Requested-With,"	
+ "Content-Type,Access-Control-Request-Method,"	
+ "Access-Control-Request-Headers,Authorization");	
if ("OPTIONS".equals(method)) {	
response.setStatus(HttpStatus.OK.value());	
} else {	
chain.doFilter(req, res);	
}	
}	
public void init(FilterConfig filterConfig) {	
}	
public void destroy() {	
}	
};	
}
別クラスにして
@Componentを付
ければ定義は不要
FilterRegistra
tionBeanを使え
ばurl-pattern等
の指定もできる。
http://bit.ly/jggug-02-15
• 再起動後に、再アクセス
REST APIを任意のクライアント
からアクセスできるようにする
REST APIのIntegrationTest
@RunWith(SpringJUnit4ClassRunner.class)	
@SpringApplicationConfiguration(classes = App.class)	
@WebAppConfiguration	
@IntegrationTest({ "server.port:0",	
"spring.datasource.url:jdbc:h2:mem:bookmark;DB_CLOSE_ON_EXIT=FALSE"
})	
public class BookmarkRestControllerIntegrationTest {	
// write test code	
}
test用にインメモリDBを使用
http://bit.ly/jggug-02-16