MyBatis - Spring Boot

  • 作成日:
  • 最終更新日:2025/10/19

プロジェクトの作成

名前 DbSample
タイプ Gradle-Groovy
パッケージング Jar
Java バージョン 21
言語 Java

依存関係で選択する項目は以下を選択します。

  • Spring Boot DevTools
  • Lombok
  • MyBatis Framework
  • H2 Database
  • Thymeleaf
  • Spring Web

application.properties

src/main/resourcesフォルダの配下にapplication.propertiesファイルはアプリケーションの設定やプロパティを設定するファイルです。

src/main/resources/application.properties

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.dirver-class-name=org.h2.Driver
spring.datasource.username=user
spring.datasource.password=
spring.h2.console.enabled=true

schema.sql と data.sql

特定の名前をもつ SQLファイルをsrc/main/resourcesフォルダ配下に配置するとアプリケーションの起動時に自動的にデータベースの初期化綾データの投入を行うことができます。

  • schema.sql(データベースの構造に関連するSQL文を記述)
  • data.sql(データ登録などの初期データのセットアップに関連するSQL文を記述)

H2などの組み込みデータベースを使用する場合は、自動初期化の設定は有効になっています。

schema.sql

CREATE TABLE books (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL,
    author VARCHAR(255) NOT NULL
);

data.sql

INSERT INTO books (title, author) VALUES ('book A', '太郎');
INSERT INTO books (title, author) VALUES ('book B', '花子');
INSERT INTO books (title, author) VALUES ('book C', '次郎');

H2 コンソールの起動

H2 コンソールを起動するには、まずアプリケーションを起動します。ブラウザからhttp://localhost:8080/h2-consoleを入力し起動します。

「接続」をクリックすると、管理画面が表示されます。

エンティティの作成

データベースの1レコード = 1オブジェクト として扱う必要があり、その役割を担うのが エンティティ です。

  • entity(エンティティ):実在物

src/main/javaフォルダに以下のクラスを作成します。

パッケージ com.example.demo.entity
名前 Book

Book.java

package com.example.demo.entity;

import lombok.Data;

@Data
public class Book {
    private int id;
    private String title;
    private String author;
}

マッパーインターフェースの作成

src/main/javaフォルダにインターフェースを作成します。

パッケージ名 com.example.demo.mapper
名前 BookMapper

BookMapper.java

package com.example.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.demo.entity.Book;

@Mapper
public interface BookMapper {
    List<Book> getAllBooks();
    
    Book getBookById(int id);
    
    void insertBook(Book book);
    
    void updateBook(Book book);
    
    void deleteBookById(int id);
}

マッパーファイルの作成

マッパーファイルとは、SQL と Java のエンティティや Mapperインターフェースを結びつけるための設定ファイル です。

xmlファイルを開き、以下のような表示だとデザインモードです。デザインモードとソースモードを赤色で囲っているタブで切り替えることができます。

ソースモードにした場合、以下のような表示になり、xmlファイルを編集することができます。

BookMapper.xml

<?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.mapper.BookMapper">
    <!-- 【SELECT】全ての書籍を取得するためのSQLを定義 -->
    <select id="getAllBooks" resultType="com.example.demo.entity.Book">
        SELECT id, title, author FROM books ORDER BY id
    </select>
    
    <!-- 【SELECT】特定のIDを持つ書籍を取得するためのSQLを定義 -->
    <select id="getBookById" resultType="com.example.demo.entity.Book">
        SELECT id, title, author FROM books WHERE id = #{id}
    </select>
    
    <!-- 【INSERT】新しい書籍をデータベースに追加するSQLを定義 -->
    <insert id="insertBook" parameterType="com.example.demo.entity.Book">
        INSERT INTO books (title, author) VALUES (#{title}, #{author})
    </insert>
    
    <!-- 【UPDATE】特定のIDを持つ書籍の情報を更新するSQLを定義 -->
    <update id="updateBook" parameterType="com.example.demo.entity.Book">
        UPDATE books SET title = #{title}, author = #{author} WHERE id = #{id}
    </update>
    
    <!-- 【DELETE】特定のIDを持つ書籍の情報を削除するSQLを定義 -->
    <delete id="deleteBookById" parameterType="int">
        DELETE FROM books WHERE id = #{id}
    </delete>
</mapper>

コントローラ

BookController.java

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.example.demo.entity.Book;
import com.example.demo.mapper.BookMapper;

import lombok.RequiredArgsConstructor;


@Controller
@RequestMapping("/books")
@RequiredArgsConstructor
public class BookController {
    // DI
    private final BookMapper bookMapper;

    // メニュー画面を表示する
    @GetMapping
    public String showIndex(Model model) {
        model.addAttribute("books", bookMapper.getAllBooks());
        return "book/index";
    }

    // 特定のIDを持つ書籍を取得する
    @GetMapping("/{id}")
    public String detail(@PathVariable("id") int id, Model model, RedirectAttributes redirectAttributes) {
        Book book = bookMapper.getBookById(id);
        if (book == null) {
            redirectAttributes.addFlashAttribute("message", "指定の書籍が存在しません");
            return "redirect:/books";
        }
        model.addAttribute("book", book);
        return "book/detail";
    }
    
    // create登録処理(GET)
    @GetMapping("/create")
    public String showCreate(Model model) {
        model.addAttribute("book", new Book());
        return "book/create";
    }

    // create登録処理(POST)
    @PostMapping
    public String create(@RequestParam("title") String title, @RequestParam("author") String author, RedirectAttributes redirectAttributes) {
        Book book = new Book();
        book.setTitle(title);
        book.setAuthor(author);
        bookMapper.insertBook(book);
        redirectAttributes.addFlashAttribute("message", "新規登録しました");
        return "redirect:/books";
    }
    
    // 更新画面を表示(GET)
    @GetMapping("/update/{id}")
    public String showUpdate(@PathVariable("id") int id, Model model, RedirectAttributes redirectAttributes) {
        Book book = bookMapper.getBookById(id);
        if (book == null) {
            redirectAttributes.addFlashAttribute("message", "指定の書籍が存在しません");
            return "book/index";
        }
        model.addAttribute("book", book);
        return "book/update";
    }

    // 更新処理(POST)
    @PostMapping("/update")
    public String update(@RequestParam("id") int id,
                         @RequestParam("title") String title,
                         @RequestParam("author") String author,
                         RedirectAttributes redirectAttributes) {

        Book book = bookMapper.getBookById(id);
        if (book == null) {
            redirectAttributes.addFlashAttribute("message", "指定の書籍が存在しません");
            return "redirect:/books";
        }

        book.setTitle(title);
        book.setAuthor(author);
        bookMapper.updateBook(book);

        redirectAttributes.addFlashAttribute("message", "更新しました");
        return "redirect:/books";
    }

    
    @GetMapping("/delete/{id}")
    public String showDelete(@PathVariable("id") int id, Model model, RedirectAttributes redirectAttributes) {
        Book book = bookMapper.getBookById(id);
        if (book == null) {
            redirectAttributes.addFlashAttribute("message", "指定の書籍が存在しません");
            return "book/index";
        }
        model.addAttribute("book", book);
        return "book/delete";
    }
    
    @PostMapping("/delete")
    public String delete(@RequestParam("id") int id, RedirectAttributes redirectAttributes) {
        Book book = bookMapper.getBookById(id);
        if (book == null) {
            redirectAttributes.addFlashAttribute("message", "指定の書籍が存在しません");
            return "redirect:/books";
        }

        bookMapper.deleteBookById(id);
        redirectAttributes.addFlashAttribute("message", "削除しました");
        return "redirect:/books";
    }
}

@RequiredArgsConstructor

@RequiredArgsConstructor は Lombok のアノテーションで、final が付いたフィールド または @NonNull が付いたフィールド を対象にしたコンストラクタを自動生成するためのものです。

@RequestMapping

@RequestMapping は Spring MVC / Spring Boot のコントローラで使われるアノテーションで、クラスに付けると共通URLになります。

@Controller

@Controller は、HTMLなどのビューを返すWebコントローラであることをSpringに知らせるためのアノテーションです。

ビュー

index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>メニュー画面</title>
</head>
<body>
    <h1>書籍管理メニュー</h1>
    <p th:if="${message}" th:text="${message}"></p>
    <ul>
        <li><a th:href="@{/books/create}">新しい書籍を作成</a></li>
    </ul>
    <table th:if="${books}" border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>タイトル</th>
                <th>著者</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="book : ${books}">
                <td th:text="${book.id}">ID</td>
                <td th:text="${book.title}">タイトル</td>
                <td th:text="${book.author}">著者</td>
                <td>
                    <a th:href="@{/books/{id}(id=${book.id})}">詳細</a>
                    <a th:href="@{/books/update/{id}(id=${book.id})}">編集</a>
                    <a th:href="@{/books/delete/{id}(id=${book.id})}">削除</a>
                </td>
            </tr>
        </tbody>
    </table>
</body>
</html>
detail.html
<!doctype html>
<html lang="ja">
<head>
	<meta charset="UTF-8" />
	<title>Document</title>
</head>
<body>
    <h2 th:text="${message}">メッセージ</h2>

    <h3>書籍の詳細</h3>
    <table border="1">
        <tr>
            <th>ID</th>
            <td th:text="${book.id}">1</td>
        </tr>
        <tr>
            <th>タイトル</th>
            <td th:text="${book.title}">タイトル</td>
        </tr>
        <tr>
            <th>著者</th>
            <td th:text="${book.author}">著者</td>
        </tr>
    </table>
    
    <p><a th:href="@{/books}">一覧へ戻る</a></p>
</body>
</html>
create.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>書籍登録</title>
</head>
<body>
<h2>書籍登録</h2>

<form th:action="@{/books}" th:object="${book}" method="post">
    <label>タイトル:</label>
    <input type="text" th:field="*{title}" /><br/>
    <label>著者:</label>
    <input type="text" th:field="*{author}" /><br/>
    <button type="submit">登録</button>
</form>
<p><a th:href="@{/books}">一覧へ戻る</a></p>
</body>
</html>
update.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>書籍更新</title>
</head>
<body>
<h2>書籍更新</h2>

<form th:action="@{/books/update}" th:object="${book}" method="post">
    <!-- IDはhiddenで渡す -->
    <input type="hidden" th:field="*{id}">

    <label>タイトル:</label>
    <input type="text" th:field="*{title}"><br>

    <label>著者:</label>
    <input type="text" th:field="*{author}"><br>

    <button type="submit">更新</button>
</form>
<p><a th:href="@{/books}">一覧へ戻る</a></p>
</body>
</html>
delete.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8" />
	<title>Document</title>
</head>
<body>
    <h1>削除</h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <td th:text="${book.id}">1</td>
        </tr>
        <tr>
            <th>タイトル</th>
            <td th:text="${book.title}">タイトル</td>
        </tr>
        <tr>
            <th>著者</th>
            <td th:text="${book.author}">著者</td>
        </tr>
    </table>
    <form th:action="@{/books/delete}" method="post">
        <input type="hidden" name="id" th:value="${book.id}" />
        <button type="submit">削除する</button>
    </form>
    <p><a th:href="@{/books}">一覧へ戻る</a></p>
</body>
</html>