ちょっと話題の記事

Spring BootでつくるCRUD API

2014.09.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

最近は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を検索してインストールしてください。

参考 第3回 Spring開発環境の整備

③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に必要なメソッドを使用することができます。 用意されているメソッドについては、以下を参照してください。

Interface JpaRepository

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)