[Spring Boot] Eclipse で REST API を作る 1 – API 作成編
Eclipse で Spring Boot を使った REST API を作ってみる。ここでは、 GET
と POST
の API サンプルを作成する。
前提
- DB はローカルに MySQL がインストール済
- Gradle プロジェクトで作成 ( Maven ではない)
- DB 操作は JPA 使用
- Spring Boot バージョン:2.6.3
- Lombok 使用
セットアップがまだの場合はこちら。
Spring Boot REST API 概要
まず REST API は、フロントから Json データを受け取り、 Json データを返す。( MVC モデルとは異なり、バックエンドで画面側の実装は行わない。)
よって、 Json データを受け取り、 Json データを返すまでの処理を記述することとなる。
概要
プロジェクト構成としては、おおまかに、 Controller
、 Service
、 Repository
/Mapper
、 Entity
が作成されることとなる。
Controller
: フロントからのアクセスを受け取る。Service
: ビジネスロジック。具体的な処理を記述する。Repository
/Mapper
: DB (データ層) 操作する処理を記述する。Entity
: DB テーブルやフロントとやり取りする Json データ構造となるモデル。
コードサンプル
Entity
Entity
クラスには @Entity
を付与する。
@Data
は Lombk のアノテーションで、セッターゲッターを自動生成するなどしてくれる。
@NoArgsConstructor
と @AllArgsConstructor
も Lombok のアノテーションで、引数ありと引数なしのコンストラクタを自動生成してくれる。
今回は JPA のテーブル自動生成機能を使用するので、このクラスをもとにしてテーブルが作られる。@Id
や @Column
などはテーブル定義に必要なアノテーション。
package com.sample.demo.domain.entity;
import java.time.ZonedDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private int grade;
@Column(nullable = false)
private String className;
@Column(nullable = false)
private String name;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private ZonedDateTime created;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private ZonedDateTime updated;
}
application.properties
JPA は Entity
から DB テーブルの自動生成を行ってくれる (Auto DDL
)。自動生成の設定をプロパティファイルに追記する。
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=create
Controller
REST API には @RestController
を付与する。 @Controller
も存在するがこれは MVC モデルに使用する。@RestController
を付与すると Entity <-> Json を自動で変換してくれる。
@RequestMapping()
の引数に文字列を指定すると、 http://hoge.com/xxx
の xxx
部分となる。
GET API には @GetMapping
、 POST には @PostMapping
を付与する。ここの引数に文字列を指定すると、 http://hoge.com/xxx/
XXXX
の XXXX
部分となる。
package com.sample.demo.controller;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sample.demo.domain.entity.Student;
import com.sample.demo.domain.service.StudentService;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/students")
@RequiredArgsConstructor
public class StudentController {
private final StudentService service;
@GetMapping("/{id}")
public Student get(@PathVariable Long id) {
return service.getStudentById(id);
}
@GetMapping
public List<Student> getAll() {
return service.getStudents();
}
@PostMapping
public Student create(@RequestBody Student student) {
return service.createStudent(student);
}
}
Service
Service クラスには @Service
を付与する。このアノテーションによって、 DI
(依存性注入)の注入 (Injection) 対象だと印づけることができる。
Service クラスに限った話ではないが、フィールド変数に @Autowired
を付与するサンプルは多くあり、これでも動く。しかし、これはフィールドインジェクションと呼ばれる方法で、現在 DI
においては、フィールドインジェクションよりもコンストラクタインジェクションの方がいいとされている。 Spring 公式でもコンストラクタインジェクションを推奨している。
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null.
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-setter-injection
spring4.3 以降はコンストラクタが 1 つだけの場合には @Autowired
の記述を省略できる。@RequiredArgsConstructor
は Lombok のアノテーションで、 final
フィールドなどを引数に持つコンストラクタを自動生成してくれる。
package com.sample.demo.domain.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.sample.demo.domain.entity.Student;
import com.sample.demo.repository.StudentRepository;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class StudentService {
// フィールドインジェクション
// @Autowired
//private StudentRepository respository;
// コンストラクタインジェクション
private final StudentRepository respository;
// ID から検索
public Student getStudentById(Long id) {
return respository.findById(id).orElseThrow();
}
// 全件検索
public List<Student> getStudents() {
return respository.findAll();
}
// Student 登録
public Student createStudent(Student student) {
return respository.save(student);
}
}
Repository
JpaRepository
を継承することで、 JPA でもとから定義されている基本的なメソッド、例えば、 save
、 findById
、 findAll
などは実装しなくても使用可能。
@Repository
なるものがあるので、ここで付与するように思えるし、そう記述されたサンプルを目にする。しかし、付けなくても動くし、公式チュートリアルでも付与していない。
つけなければならない場面がよく分かっていない。少なくとも、 JpaRepository
を継承しているインターフェイスには付与しなくても問題なさそう。
package com.sample.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.sample.demo.domain.entity.Student;
public interface StudentRepository extends JpaRepository<Student, Long>{
}
プロジェクト構成
プロジェクト構成は最終的にこうなる。
プロジェクト構成は開発チームや人によって異なる。Controller
は Controller ディレクトリになるだろうが、Entity
や Service
、さらに 共通クラスをどのような構成にするかはこれといった決まりはないように思われる。チームで決まりを作ったり、プロジェクトごとの決まりに沿うことになるだろう。
起動
作成したアプリケーションを実行してみる。
プロジェクト名 (ここでは ago-sample ) を右クリック -> 実行 (またはデバッグ) -> Spring Boot アプリケーションを選択する。
動作確認は、curl
から POST
リクエストしてみたり、 ブラウザから localhost:8080/students
、 localhost:8080/students/id
でアクセスすると、 Json データを確認することができる。