Spring BootでつくるCRUD API
はじめに
最近はRuby、Railsで開発することが多い自分ですが、使用したいライブラリがJava用に開発されている場合などの選択肢として、JVM上で実行できるフレームワークにも興味を持ち始めました。 いくつかのフレームワークを検討したのですが、その中からSpring Bootを選び、簡単なCRUDのAPIを作ってみました。Spring Bootを選んだ理由は、以下の通りです。
- JVM上で実行できる
- フルスタックフレームワーク
- デプロイが簡単
- ドキュメントが(割と)豊富
Spring Bootについては弊社中村が以前の記事でも書いていますが、今回はSpring Bootの開発環境の構築と、実際に作成したCRUD APIのソースについて書きたいと思います。
開発環境について
1.前提条件
開発マシンとしては、Windows、Macのどちらでも大丈夫です。予めJDK8をインストールしておくのと、Windowsの場合はCURLを使えるようにしておいてください。
2.Eclipse + STS(Spring Tool Suite) + lombok
IDEにはEclipseを使用します。またlombokを使い、Getter、Setter等のJavaの冗長なコードを少なくしたいと思います。lombokについてはJava特有の冗長なコードを簡潔に記述する「Lombok」 などを参考にしてください。
①Eclipseのインストール
Eclipse公式ページより「Eclipse IDE for Java EE Developers」をダウンロードし、インストールしてください。
②STS(Spring Tool Suite)のインストール
Eclipseを起動し、メニューバーの「Help」-「Eclipse Marketplace」を押下します。「Find」に「STS」を入力し、STSを検索してインストールしてください。
③lombokのインストール
lombokより「lombok.jar」をダウンロードしてください。lombok.jarをダブルクリックするか、以下のコマンドでlombok.jarを起動します。
$ java -jar lombok.jar
インストーラーの案内通りにインストール後、Eclipseを終了し、再度起動してください。
3.maven
Mavenのダウンロードページよりmavenの〜.bin.tar.gzをダウンロードしてください。解凍後、binフォルダをパスに設定します。設定後、以下のコマンドでバージョンが表示されればOKです。
$ mvn --version
CRUD APIの実装
1.今回作成するプロジェクトについて
ウィスキーの名称と価格を登録・参照・更新・削除するAPIです。Tomcat、H2データベースを組み込み、Stand-Aloneで動くAPIサーバを作成します。
2.プロジェクトの作成
mavenを使い、以下のコマンドでプロジェクトを作成します。
$ mvn -B archetype:generate -DgroupId=com.sample -DartifactId=springbootWhiskyList -Dversion=1.0.0-SNAPSHOT
3.Eclipseへのインポート
上記で作成したプロジェクトを、Eclipseへインポートします。
Eclipseの「Project Exploler」を右クリックし、「Import」-「Maven」-「Existing Maven Projects」をクリックします。「Import Maven Projects」の「Root Directory」で、先ほど作成したプロジェクトのフォルダを指定します。
4.Main
いよいよプログラムについてです。先ずはアプリケーションのエントリーポイントとなる、mainについてです。
package: com.sample
class名: App
package com.sample; 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); } }
ここでのソースは(今のところは)「お約束」と考えておけばいいかと思います。見ての通り、SpringApplicatinを起動していますね。
5.Entity
Entityには、データベースに登録する項目を定義します。今回はWhiskyテーブルに、name、priceという項目を登録することにしました。
package: com.sample.entity
class名: Whisky
package com.sample.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import lombok.Data; @Entity @Data public class Whisky { @Id @GeneratedValue private Long id; @NotNull @Size(min = 1, max = 255) private String name; @NotNull @Min(0) private Long price; }
このクラスはEntityなので、12行目で@Entityを付けています。 13行目の@Dataはlombokのアノテーションで、これを使う事でGetter、Setterがソース上からはなくなります。(ビルド時に自動的に付与される)
クラスの中では、id、name、priceという項目を定義しています。 idにはプライマリーキーとなることを表す@Id、自動的に採番するための@GeneratedValueを付けています。
@NotNull、@Size、@Minは、値のバリデーションを行う為のアノテーションです。文字通りNullの不許可、値の文字数定義、最小値チェックを行います。
5.Repository
Repositoryインターフェースを用意することで、JPAにて用意されているデータのCRUDに必要なメソッドを使用することができます。 用意されているメソッドについては、以下を参照してください。
package: com.sample.repository
class名: WhiskyRepository
package com.sample.repository; import com.sample.entity.Whisky; import org.springframework.data.jpa.repository.JpaRepository; public interface WhiskyRepository extends JpaRepository<Whisky, Long> { }
JpaRepositoryを継承しているのと、第一引数にEntityクラス、第二引数にプライマリーキーの型を記述していることがポイントとなります。
6.Service
Serviceでは、上記のRepositoryを使い、EntityのCRUDを行うメソッドを用意します。今回のような単純なデータ操作なら、パッケージ名をDaoとしてもいいかもしれません。
package: com.sample.service
class名: WhiskyService
package com.sample.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.sample.entity.Whisky; import com.sample.repository.WhiskyRepository; import java.util.List; @Service @Transactional public class WhiskyService { @Autowired WhiskyRepository whiskyRepository; public List<Whisky> findAll() { return whiskyRepository.findAll(new Sort(Sort.Direction.ASC, "id")); } public Whisky save(Whisky whisky) { return whiskyRepository.save(whisky); } public void delete(Long id) { whiskyRepository.delete(id); } public Whisky find(Long id) { return whiskyRepository.findOne(id); } }
@Autowiredで、上で作成したRepositoryをインジェクションします。
CRUDに対応するため、以下の4つのメソッドを用意しました。
メソッド名 | 役割 |
---|---|
findAll | 全件取得 |
save | データ登録 |
delete | データ削除 |
find | 一件取得 |
更新処理(Update)については、saveを呼び出して行うことにします。が、もしからしたら更新用のメソッドをここに用意したほうがいいかもしれません。
7.Controller
Controllerには、CRUDに対応するURLの定義と、Serviceの呼び出しを実装します。
URLの定義は、以下の通りです。
CRUD | URL | Method | Body(Json形式) | 実行するメソッド |
---|---|---|---|---|
C | api/whiskies | POST | {'name':'名称', 'price':価格} | insertWhisky() |
R(全件) | api/whiskies | GET | getWhiskies() | |
R(一件) | api/whiskies/id | GET | getWhisky() | |
U | api/whiskies/id | PUT | {'name':'名称', 'price':価格} | updateWhisky() |
D | api/whiskies/id | DELETE | deleteWhisky() |
package: com.sample.api
class名: WhiskyController
package com.sample.api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import com.sample.entity.Whisky; import com.sample.service.WhiskyService; import java.util.List; @RestController @RequestMapping("api/whiskies") public class WhiskyController { @Autowired WhiskyService whiskyService; @RequestMapping(method = RequestMethod.GET) List<Whisky> getWhiskies() { return whiskyService.findAll(); } @RequestMapping(method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) Whisky insertWhisky(@Validated @RequestBody Whisky whisky) { return whiskyService.save(whisky); } @RequestMapping(value = "{id}", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.OK) Whisky updateWhisky(@PathVariable("id") Long id, @Validated @RequestBody Whisky whisky) { whisky.setId(id); return whiskyService.save(whisky); } @RequestMapping(value = "{id}", method = RequestMethod.DELETE) @ResponseStatus(HttpStatus.OK) void deleteWhisky(@PathVariable("id") Long id) { whiskyService.delete(id); } @RequestMapping(value = "{id}", method = RequestMethod.GET) Whisky getWhisky(@PathVariable("id") Long id) { return whiskyService.find(id); } }
@RequestMappingにてURLを定義しています。また@Autowiredで、上のServiceをインジェクションしています。また、URLの定義については@RequestMappingにて行っており、上記の表と対比すれば分かりやすいかと思います。
8.DBの永続化
H2データベースに登録したデータを永続化させるための定義を、src/main/resources/application.ymlに記述します。
spring: thymeleaf: cache: false datasource: driverClassName: org.h2.Driver url: jdbc:h2:file:/tmp/springbootWhiskyList username: sa password: jpa: hibernate: ddl-auto: update
CRUD APIの実行
では、アプリを実行してみましょう。「Project Exploer」を右クリックし、「Run As」-「Spring Boot App」を押下して実行します。
データの登録、更新、削除はcurlコマンドにて、登録したデータの参照はブラウザにて行ってみます。登録は複数件、行った方が分かりやすいかと思います。
登録
$ curl http://localhost:8080/api/whiskies -v -X POST -H "Content-Type:application/json" -d "{\"name\":\"laphroaig\", \"price\":3000}"
更新
$ curl http://localhost:8080/api/whiskies/1 -v -X PUT -H "Content-Type:application/json" -d "{\"name\":\"JohnnieWalerRed\", \"price\":1500}"
削除
$ curl http://localhost:8080/api/whiskies/1 -v -X DELETE
参照(全件)
http://localhost:8080/api/whiskies
参照(一件)
http://localhost:8080/api/whiskies/1
次に、Stand-Aloneで動くかの確認です。以下のコマンドでjarを作成し、起動してみましょう。起動できたら、データの登録、更新、削除を試してみてください。
$ mvn package $ java -jar target/springbootWhiskyList-1.0.0-SNAPSHOT.jar
まとめ
かなり駆け足でしたが、Spring Bootにて簡単にCRUDを実装できることが分かるかと思います。フレームワークを選定するときなどの参考になれば幸いです。
謝辞
本エントリにあたり、Grails 3.0先取り!? Spring Boot入門ハンズオンをかなり参考にさせて頂きました。ありがとうございました。
参考サイト
Grails 3.0先取り!? Spring Boot入門ハンズオン
Spring Boot 公式
DAO and Service layers (JPA/Hibernate + Spring)