[Spring Boot] Eclipse で REST API を作る 1 – API 作成編

JavaREST,SpringBoot

Eclipse で Spring Boot を使った REST API を作ってみる。ここでは、 GETPOST の API サンプルを作成する。

前提

  • DB はローカルに MySQL がインストール済
  • Gradle プロジェクトで作成 ( Maven ではない)
  • DB 操作は JPA 使用
  • Spring Boot バージョン:2.6.3
  • Lombok 使用

セットアップがまだの場合はこちら。

Spring Boot REST API 概要

まず REST API は、フロントから Json データを受け取り、 Json データを返す。( MVC モデルとは異なり、バックエンドで画面側の実装は行わない。)
よって、 Json データを受け取り、 Json データを返すまでの処理を記述することとなる。

概要

プロジェクト構成としては、おおまかに、 ControllerServiceRepository/MapperEntity が作成されることとなる。

Overview for Spring Boot REST API Project

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/xxxxxx 部分となる。

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 findByIdfindAll などは実装しなくても使用可能。

@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 ディレクトリになるだろうが、EntityService 、さらに 共通クラスをどのような構成にするかはこれといった決まりはないように思われる。チームで決まりを作ったり、プロジェクトごとの決まりに沿うことになるだろう。

起動

作成したアプリケーションを実行してみる。

プロジェクト名 (ここでは ago-sample ) を右クリック -> 実行 (またはデバッグ) -> Spring Boot アプリケーションを選択する。

run Spring Boot app

動作確認は、curl から POST リクエストしてみたり、 ブラウザから localhost:8080/studentslocalhost:8080/students/id でアクセスすると、 Json データを確認することができる。

Posted by Agopeanuts