🌱

SpringBootでwebAPIサーバーを作るハンズオン(Java, Maven)

2021/11/02に公開
6

概要

SpringBoot を学んだので CRUD ができる Web API サーバを作ります。
repository と service はインタフェースと実行クラスを分けています。
最終的なソースコードの URL です。

https://github.com/Msksgm/springboot_web_api_demo

ディレクトリ構成は以下のようになりました。

.
├── HELP.md
├── demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── demo
│   │   │               ├── DemoApplication.java
│   │   │               ├── configuration
│   │   │               │   ├── DataSourceConfiguration.java
│   │   │               │   └── DataSourceConfigurationProperties.java
│   │   │               ├── controller
│   │   │               │   └── MovieRestController.java
│   │   │               ├── domain
│   │   │               │   ├── Director.java
│   │   │               │   ├── Movie.java
│   │   │               │   └── MovieList.java
│   │   │               ├── repository
│   │   │               │   ├── MovieRepository.java
│   │   │               │   ├── MovieRepositoryImpl.java
│   │   │               │   └── mybatis
│   │   │               │       ├── MovieMapper.java
│   │   │               │       └── MovieMapper.xml
│   │   │               └── service
│   │   │                   ├── MovieService.java
│   │   │                   └── MovieServiceImpl.java
│   │   └── resources
│   │       ├── application.yml
│   │       ├── static
│   │       └── templates
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── demo
│                       └── DemoApplicationTests.java
└── target
    ├── classes
    │   ├── application.yml
    │   └── com
    │       └── example
    │           └── demo
    │               ├── DemoApplication.class
    │               ├── configuration
    │               │   ├── DataSourceConfiguration.class
    │               │   └── DataSourceConfigurationProperties.class
    │               ├── controller
    │               │   └── MovieRestController.class
    │               ├── domain
    │               │   ├── Director.class
    │               │   ├── Movie.class
    │               │   └── MovieList.class
    │               ├── repository
    │               │   ├── MovieRepository.class
    │               │   ├── MovieRepositoryImpl.class
    │               │   └── mybatis
    │               │       ├── MovieMapper.class
    │               │       └── MovieMapper.xml
    │               └── service
    │                   ├── MovieService.class
    │                   └── MovieServiceImpl.class
    ├── generated-sources
    │   └── annotations
    ├── generated-test-sources
    │   └── test-annotations
    └── test-classes
        └── com
            └── example
                └── demo
                    └── DemoApplicationTests.class

39 directories, 35 files

下準備

環境

項目 環境
OS macOS
IDE Intellij IDEA
DB MySQL

フレームワーク作成

Spring Initializr を使用して demo.zip をダウンロードして適当な場所で解凍します。
設定は以下のようにしました。

項目 設定
Project Maven
Language Java
Spring Boot 2.4.5
Project Metadata Java 8(それ以外はデフォルト)
Dependencies Spring Web MySQL Driver MyBatis Framework

MySQL の準備

以下の構成で作成します。

認証関係

項目 設定
ユーザー root
パスワード password

DB 関係

新しい DB を作成

CREATE DATABASE moviedb;

moviedb を選択

USE moviedb;

外部キーを持った テーブル を作成

director テーブルを作成。

CREATE TABLE director
(director_id char(10) PRIMARY KEY ,
director_name varchar(20));

movie テーブルを作成。

CREATE TABLE movie
(movie_id CHAR(10) PRIMARY KEY,
movie_name VARCHAR(50),
director_id CHAR(10),
CONSTRAINT director_id_fk FOREIGN KEY (director_id) REFERENCES director(director_id));

tabel に値を挿入

director に挿入。

INSERT INTO director VALUES('D01', '新海誠');
INSERT INTO director VALUES('D02', '藤井道人');
INSERT INTO director VALUES('D03', 'クリストファー・ノーラン');

movie に挿入。

INSERT INTO movie VALUES('M01', '君の名は。', 'D01');
INSERT INTO movie VALUES('M02', '天気の子', 'D01');
INSERT INTO movie VALUES('M03', '言の葉の庭', 'D01');
INSERT INTO movie VALUES('M04', '新聞記者', 'D02');
INSERT INTO movie VALUES('M05', 'デイアンドナイト', 'D02');
INSERT INTO movie VALUES('M06', 'ダークナイト', 'D03');
INSERT INTO movie VALUES('M07', 'インセプション', 'D03');

手順

1. プロジェクトの新規作成

  1. Intellij -> ファイル -> 新規 -> 既存のソースからプロジェクト -> demo を選択して Open をクリックします
  2. "既存プロジェクトから作成する"をチェックして完了を押下します

2. pom.xml を編集

dependencies タグに以下を追加。

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-dbcp2</artifactId>
</dependency>

また build タグに resources タグを追加。

<resources>
   <resource>
      <directory>src/main/java</directory>
      <includes>
         <include>**/*.xml</include>
      </includes>
   </resource>
   <resource>
      <directory>src/main/resources</directory>
   </resource>
</resources>

追加後、pom.xml を右クリック->Maven->"プロジェクトの再ロード"を選択。

3. application.yml を作成

まず、demo/src/main/java/resources/application.properties の名前を変更します。右クリックして"リファクタリング"を選択し、application.yml にします。
記述する設定は以下になります。

  • JDBC の接続設定
    • ドライバ
    • MySQL
      • password, username、文字コード
    • コネクションプール
      • 初期コネクション数、アイドル時間
  • MyBatis の設定
    • mapper-locations
      • MapperXML の場所を指定
ソースコード
# JDBCの接続設定
dbcp2.jdbc:
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://localhost:3306/moviedb?characterEncoding=UTF-8
  username: root
  password: password
  initial-size: 1
  max-idle: 3
  min-idle: 1

# mybatisの設定
mybatis:
  mapper-locations: classpath:com/example/demo/repository/mybatis/*.xml

4. domain を作成

demo/src/main/java/com/example/demo/に domain パッケージを作成します。
domain パッケージ配下に Director クラス, Movie クラス, MovieList クラスを作成します。

Director クラス

package com.example.demo.domain;

public class Director {
    private String directorId;

    private String directorName;

    public Director() {
    }

    public Director(String directorId, String directorName) {
        this.directorId = directorId;
        this.directorName = directorName;
    }

    public String getDirectorId() {
        return directorId;
    }

    public void setDirectorId(String directorId) {
        this.directorId = directorId;
    }

    public String getDirectorName() {
        return directorName;
    }

    public void setDirectorName(String directorName) {
        this.directorName = directorName;
    }
}

Movie クラス

package com.example.demo.domain;

public class Movie {
    private String movieId;

    private String movieName;

    private Director director;

    public Movie() {
    }

    public Movie(String movieId, String movieName) {
        this.movieId = movieId;
        this.movieName = movieName;
    }

    public String getMovieId() {
        return movieId;
    }

    public void setMovieId(String movieId) {
        this.movieId = movieId;
    }

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public Director getDirector() {
        return director;
    }

    public void setDirector(Director director) {
        this.director = director;
    }
}

MovieList

package com.example.demo.domain;

import java.util.List;

public class MovieList {
    private List<Movie> movieList;

    public List<Movie> getMovieList() {
        return movieList;
    }

    public void setMovieList(List<Movie> movieList) {
        this.movieList = movieList;
    }
}

5. Repository を作成

demo/src/main/java/com/example/demo/に repository パッケージを作成します。
repository と mybatis によって、MySQL と java の接続ができます。

5-1 Mapper.xml を作成

repository パッケージ配下に mybatis パッケージを作成します。
mybatis パッケージ配下に MyBatis の設定ファイルである、MovieMapper.xml を作成します。
#{}は Java から渡された変数を表示します。

タグの解説。

  • mapper タグ
    • namespace="Mapper のパス"を指定
  • resultMap タグ
    • MySQL のテーブルと Java クラスのフィールドを対応付ける
      • type=""で Java のオブジェクトとの関連付け
      • id タグの property で Java のフィールドを記述し、column で MySQL の列名を記述
    • association タグで複数のテーブルとの関連付けをする
  • SQL を記述するタグ(id の意味は後述)
    • select タグ
      • CRUD の READE に該当
    • insert タグ
      • CRUD の CREATE に該当
    • update タグ
      • CRUD の UPDATE に該当
    • delete タグ - CRUD の DELETE に該当
ソースコード
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC
        "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.repository.mybatis.MovieMapper">
    <resultMap id="Director" type="com.example.demo.domain.Director">
        <id property="directorId" column="DIRECTOR_ID"/>
        <result property="directorName" column="DIRECTOR_NAME"/>
    </resultMap>

    <resultMap id="Movie" type="com.example.demo.domain.Movie">
        <id property="movieId" column="MOVIE_ID"/>
        <result property="movieName" column="MOVIE_NAME"/>
        <association property="director" resultMap="Director"/>
    </resultMap>

    <select id="find" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        <where>
            <if test="movieName != null">
                M.MOVIE_NAME LIKE CONCAT('%', #{movieName}, '%')
            </if>
            <if test="directorName != null">
                AND D.DIRECTOR_NAME LIKE CONCAT('%', #{directorName}, '%')
            </if>
        </where>
        ORDER BY M.MOVIE_ID ASC
    </select>

    <select id="get" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        WHERE MOVIE_ID = #{movieId}
    </select>

    <select id="lock" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        WHERE MOVIE_ID = #{movieId}
        FOR UPDATE
    </select>

    <insert id="add" parameterType="com.example.demo.domain.Movie" keyProperty="movieId">
        <!-- selectKeyによってmovieIdを新しく設定する -->
        <selectKey keyProperty="movieId" resultType="string" order="BEFORE">
            <!-- MOVIE_IDのAUTO INCREMENTを実装 -->
            SELECT COALESCE(CONCAT('M', LPAD(RIGHT(MAX(MOVIE_ID), 2) + 1, 2, '0')), 'M01') FROM MOVIE
        </selectKey>
        INSERT INTO MOVIE (MOVIE_ID , MOVIE_NAME, DIRECTOR_ID) VALUES (#{movieId}, #{movieName}, #{director.directorId});
    </insert>

    <update id="set" parameterType="com.example.demo.domain.Movie">
        UPDATE MOVIE
        <set>
            <if test="movieName != null">
                MOVIE_NAME = #{movieName},
            </if>
            <if test="director.directorId != null">
                DIRECTOR_ID = #{director.directorId},
            </if>
        </set>
        WHERE MOVIE_ID = #{movieId}
    </update>

    <delete id="remove" parameterType="com.example.demo.domain.Movie">
        DELETE FROM MOVIE
        WHERE MOVIE_ID = #{movieId}
    </delete>
</mapper>

5-2 Mapper インタフェースを作成

mybatis パッケージ配下に MovieMapper インタフェースを作成します。
抽象メソッドを定義します。
メソッド名は MovieMapper.xml で SQL を記述するタグの id="" で定義した名前になっています。
@Param が MovieMapper.xml の引数との関連付けをします。

package com.example.demo.repository.mybatis;

import com.example.demo.domain.Movie;
import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface MovieMapper {
    List<Movie> find(@Param("movieName") String movieName, @Param("directorName") String directorName);

    Movie get(@Param("movieId") String movieId);

    Movie lock(@Param("movieId") String movieId);

    int add(Movie movie);

    int set(Movie movie);

    int remove(Movie movie);
}

5-3 Repository インタフェースを作成

repository パッケージ配下に MovieRepository インタフェースを作成します。
抽象メソッドを定義します。

package com.example.demo.repository;

import com.example.demo.domain.Movie;
import java.util.List;

public interface MovieRepository {
    List<Movie> findList(String movieName, String directorName);

    Movie findOne(String movieId);

    Movie lock(String movieId);

    void insert(Movie movie);

    void update(Movie movie);

    void delete(Movie movie);
}

5-4 RepositoryImpl クラスを作成

repository パッケージ配下に MovieRepository インタフェースを実装した、実行クラスである RepositoryImpl クラスを作成します。
@Repository アノテーションによって、repository に DI をします。
SqlSessionTemplate クラスによって、Mapper インタフェースを読み込み、MySQL を操作するメソッドを利用できます。

package com.example.demo.repository;

import com.example.demo.domain.Movie;
import com.example.demo.repository.mybatis.MovieMapper;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class MovieRepositoryImpl implements MovieRepository {
    private final SqlSessionTemplate sqlSessionTemplate;

    public MovieRepositoryImpl(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<Movie> findList(String movieName, String directorName) {
        List<Movie> movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).find(movieName, directorName);
        return movie;
    }

    @Override
    public Movie findOne(String movieId) {
        Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).get(movieId);
        if (movie == null){
            throw new RuntimeException("movie not found");
        }
        return movie;
    }

    @Override
    public Movie lock(String movieId) {
        Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).lock(movieId);
        if (movie == null){
            throw new RuntimeException("movie not found");
        }
        return movie;
    }

    @Override
    public void insert(Movie movie) {
        this.sqlSessionTemplate.getMapper(MovieMapper.class).add(movie);
    }

    @Override
    public void update(Movie movie) {
        int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).set(movie);
        if (affected != 1){
            throw new RuntimeException("failed");
        }
    }

    @Override
    public void delete(Movie movie) {
        int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).remove(movie);
        if (affected != 1){
            throw new RuntimeException("failed");
        }
    }
}

6 Service を作成

demo/src/main/java/com/example/demo/配下に、service パッケージを作成します。
ビジネスロジックとトランザクション管理をします。

6-1 Service インタフェースを作成

service パッケージ配下に MovieService インタフェースを作成する。

package com.example.demo.service;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;

public interface MovieService {
    MovieList find(String movieName, String directorName);

    Movie get(String movieId);

    void add(Movie movie);

    void set(Movie movie);

    void remove(String  movieId);
}

6-2 ServiceImpl クラスを作成

Service インタフェース(6-1)を実装したクラスを作成します。
@Service アノテーションによって DI します。
@Transactional アノテーションによって、DB 操作にエラーが発生したときにロールバックします。

package com.example.demo.service;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.repository.MovieRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MovieServiceImpl implements MovieService{
    private final MovieRepository repository;

    public MovieServiceImpl(MovieRepository repository) {
        this.repository = repository;
    }

    @Override
    public MovieList find(String movieName, String directorName) {
        MovieList movieList = new MovieList();
        movieList.setMovieList(this.repository.findList(movieName, directorName));
        return movieList;
    }

    @Override
    public Movie get(String movieId) {
        Movie movie = this.repository.findOne(movieId);
        return movie;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void add(Movie movie) {
        this.repository.insert(movie);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void set(Movie movie) {
        this.repository.lock(movie.getMovieId());
        this.repository.update(movie);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void remove(String movieId) {
        this.repository.delete(this.repository.findOne(movieId));
    }
}

7 RestController を作成

demo/src/main/java/com/example/demo/配下に、controller パッケージ作成します。

RestController を作成

controller パッケージ配下に MovieRestController クラスを作成します。

アノテーションについて。

Controller クラスに付与するアノテーション。

  • @RestController
    • RestController の DI する
    • フロントエンドの@Controller とは異なり、戻り値をテキストコンテンツで返すために使用する
  • @RequestMapping
    • localhost:8080 以下に、/api/movie のパスを割り当てています。

メソッドに付与するアノテーション。

  • @GetMapping
    • get メソッド時の動作を指定する
  • @PostMapping
    • post メソッド時の動作を指定する
  • @PatchMapping
    • patch メソッド時の動作を指定する
  • @DeleteMapping
    • delete メソッド時の動作を指定する

メソッド内の引数に付与するアノテーション。

  • @RequestParam
    • HTTP リクエストパラメータを取得する
  • @RequestBody
    • HTTP リクエストボディのデータを引数のクラスにマッピングする
  • @PathVariable
    • URI パスのパラメータを取得する
package com.example.demo.controller;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.service.MovieService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/movie")
public class MovieRestController {
    private final MovieService service;

    public MovieRestController(MovieService service) {
        this.service = service;
    }

    @GetMapping(path = "", produces = "application/json")
    public MovieList find(@RequestParam(name = "movieName", required = false) String movieName,
                          @RequestParam(name = "directorName", required = false) String directorName){
        return this.service.find(movieName, directorName);
    }

    @GetMapping(path = "/{movieId}", produces = "application/json")
    public Movie get(@PathVariable String movieId){
        return this.service.get(movieId);
    }

    @PostMapping(path = "", produces = "application/json")
    public void add(@RequestBody Movie movie){
        this.service.add(movie);
    }

    @PatchMapping(path = "/{movieId}", produces = "application/json")
    public void update(@PathVariable String movieId, @RequestBody Movie movie){
        movie.setMovieId(movieId);
        this.service.set(movie);
    }

    @DeleteMapping(path = "/{movieId}", produces = "application/json")
    public void remove(@PathVariable String movieId){
        this.service.remove(movieId);
    }
}

8 configuration を作成

MySQL との接続設定を作成します。
demo/src/main/java/com/example/demo/配下に、configuration パッケージ作成します。

DataSourceConfigurationProperties を作成

configuration パッケージ配下に DataSourceConfigurationProperties を作成します。
application.yml の読み込みをすることで、独自プロパティの設定をします。

package com.example.demo.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

@ConstructorBinding
@ConfigurationProperties(prefix = "dbcp2.jdbc")
public class DataSourceConfigurationProperties {
    private final String url;

    private final String driverClassName;

    private final String username;

    private final String password;

    private final int initialSize;

    private final int maxIdle;

    private final int minIdle;

    public DataSourceConfigurationProperties(String url, String driverClassName, String username, String password,
                                             int initialSize, int maxIdle, int minIdle) {
        this.url = url;
        this.driverClassName = driverClassName;
        this.username = username;
        this.password = password;
        this.initialSize = initialSize;
        this.maxIdle = maxIdle;
        this.minIdle = minIdle;
    }

    public String getUrl() {
        return url;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public int getInitialSize() {
        return initialSize;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }
}

DataSourceConfiguration を作成

DataSourceConfigurationProperties の読み込むことで、設定の反映します。

package com.example.demo.configuration;

import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(DataSourceConfigurationProperties.class)
public class DataSourceConfiguration {
    private final DataSourceConfigurationProperties properties;

    public DataSourceConfiguration(DataSourceConfigurationProperties properties) {
        this.properties = properties;
    }

    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();

        dataSource.setDriverClassName(this.properties.getDriverClassName());

        dataSource.setUrl(this.properties.getUrl());
        dataSource.setUsername(this.properties.getUsername());
        dataSource.setPassword(this.properties.getPassword());
        dataSource.setInitialSize(this.properties.getInitialSize());
        dataSource.setMaxIdle(this.properties.getMaxIdle());
        dataSource.setMinIdle(this.properties.getMinIdle());
        return dataSource;
    }
}

以上で完成です。

動作確認

起動

demo/src/main/java/com/example/demo/配下の実行クラス、DemoApplication クラスを Intellij を使って実行します。

http://localhost:8080/api/movie にアクセスして MySQL に格納されているデータが表示されたら成功です。

CRUD

curl コマンドを用いて動作確認をします。

READ(get)

単一検索

入力。

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M01"

出力。

{
  "movieId": "M01",
  "movieName": "君の名は。",
  "director": { "directorId": "D01", "directorName": "新海誠" }
}

全検索

入力。

curl -H "Content-Type: application/json" "localhost:8080/api/movie"

出力。

{
  "movieList": [
    {
      "movieId": "M01",
      "movieName": "君の名は。",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M02",
      "movieName": "天気の子",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M03",
      "movieName": "言の葉の庭",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M04",
      "movieName": "新聞記 者",
      "director": { "directorId": "D02", "directorName": "藤井道人" }
    },
    {
      "movieId": "M05",
      "movieName": "デイアンドナイト",
      "director": { "directorId": "D02", "directorName": "藤井道人" }
    },
    {
      "movieId": "M06",
      "movieName": "ダークナイト",
      "director": {
        "directorId": "D03",
        "directorName": "クリストファー・ノーラン"
      }
    },
    {
      "movieId": "M07",
      "movieName": "インセプション",
      "director": {
        "directorId": "D03",
        "directorName": "クリストファー・ノーラン"
      }
    }
  ]
}

CREATE(post)

映画を追加する

入力。

curl -X POST \
-H "Content-Type: application/json" "localhost:8080/api/movie" \
-d '{"movieName":"テネット", "director": {"directorId":"D03"}}'

確認。

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

結果。

{
  "movieId": "M08",
  "movieName": "テネット",
  "director": {
    "directorId": "D03",
    "directorName": "クリストファー・ノーラン"
  }
}

UPDATE(patch)

映画を更新する

入力。

curl -X PATCH \
-H "Content-Type: application/json" "localhost:8080/api/movie/M08" \
-d '{"movieName":"秒速5センチメートル", "director": {"directorId":"D01"}}'

確認。

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

結果。

{
  "movieId": "M08",
  "movieName": "秒速5センチメートル",
  "director": { "directorId": "D01", "directorName": "新海誠" }
}

DELETE(delete)

映画を削除する

入力。

curl -X DELETE -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

確認。

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

出力。

{
  "timestamp": "2021-05-02T22:17:32.490+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "",
  "path": "/api/movie/M08"
}

Discussion

yukimaruyukimaru

こんにちは。記事ありがとうございます!

movie に挿入。のレコードに重複レコードがあるためPKエラーになってしまいます。
INSERT INTO movies VALUES('M07', 'インセプション', 'D03');

お手すきの際に修正いただければと思います。

mskmsk

@yukimaru さん

ご指摘のほどありがとうございます。
こちら、SQL の修正と合わせて movies を movie に統一する対応を実施しました。

yukimaruyukimaru

DDLではテーブル名が movies ですが、 xmlのSELECT文では movie になっております