Spring BootとH2で学ぶCRUDアプリ開発入門

Spring

はじめに

Spring Bootを使うと、最小限の設定でWebアプリケーションを素早く開発できます。
今回はその中でも、学習用として最もシンプルな構成である 「Spring Boot + H2データベース + Thymeleaf」 を使って、
ランチ情報を管理するCRUDアプリ(登録・一覧・更新・削除)を作成してみましょう。

このチュートリアルを通して、以下のポイントを学ぶことができます。

  • Spring BootによるWebアプリの基本構成
  • H2データベースを使ったデータ永続化(組み込みDBの利用)
  • ThymeleafによるHTMLテンプレートとの連携
  • コントローラ、リポジトリ、エンティティの役割と関係

環境構築からCRUDの実装までを通して、Spring Bootアプリ開発の流れを一通り体験できます!

プロジェクトの作成

  • エクリプスにて新規 > Spring Starter project(名前はLunchApp)
  • Build ToolにMaven
  • 以下の項目にチェックを入れてプロジェクト立ち上げる
  • 各項目の詳細は以下
チェック項目実際のスターター名役割
H2 Databasecom.h2database:h2組み込みDB
Spring Boot DevToolsspring-boot-devtools自動リロードなどの開発支援
Spring Webspring-boot-starter-webMVC構築(Tomcat含む)
Spring Data JDBCspring-boot-starter-data-jdbcJDBCによるデータアクセス
Thymeleafspring-boot-starter-thymeleafHTMLテンプレートエンジン

テーブルの作成

今回は学習用アプリのため、DBはメモリ上に作成しデータの永続化は行わない。(再起動を行うたびに初期データ3件の状態で始まる)

resourcesフォルダの直下に以下の2枚のファイルを作成する

  • schema.sql
CREATE TABLE lunch (
  id INT PRIMARY KEY AUTO_INCREMENT,
  shop VARCHAR(30),
  menu VARCHAR(30)
);
  • data.sql
INSERT INTO lunch (shop, menu) VALUES
('subway', 'チリチキン'),
('はなまる', 'かけうどん(小)'),
('吉野家', '牛丼(並)');

Entityクラスの作成

先ほど作成したテーブル lunches に対応するエンティティクラスを作成する。

demoフォルダを右クリック新規クラス > Lunchクラスを作成する

Lunch.javaの内容は以下

package com.example.demo.entity;

import org.springframework.data.annotation.Id;

public class Lunch {
	@Id
    private int id;
    private String shop;
    private String menu;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getShop() {
        return shop;
    }
    public void setShop(String shop) {
        this.shop = shop;
    }
    public String getMenu() {
        return menu;
    }
    public void setMenu(String menu) {
        this.menu = menu;
    }
}

Spring Data JDBCでは、テーブル名とクラス名、カラム名とフィールド名が自動的に対応するため、
特別なアノテーション指定(@Table, @Columnなど)は不要である。

Repositoryの作成

com.example.demo.repository.LunchRepositoryインターフェイスを作成する

内容は以下

package com.example.demo.repository;

import org.springframework.data.repository.CrudRepository;

import com.example.demo.entity.Lunch;

public interface LunchRepository extends CrudRepository<Lunch,Integer>{

}

Controllerの作成

  • com.example.demo.controller.LunchController.javaを作成
  • 内容は以下
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.example.demo.repository.LunchRepository;

@Controller
public class LunchController {
	private final LunchRepository lunchRepository;
	
	public LunchController(LunchRepository lunchRepository) {
		this.lunchRepository=lunchRepository;
	}
	//一覧
	@GetMapping("/lunches")
	public String list(Model model) {
		model.addAttribute("lunches",lunchRepository.findAll());
		return "lunch/list";
	}
	
}

View(list.html)の作成

  • src/main/resources/templates/lunch/list.htmlを作成
  • 内容は以下
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>ランチ一覧</title>
</head>
<body>
    <h1>ランチ一覧</h1>

    <p>
        <a th:href="@{'/lunches/new'}">新規作成</a>
    </p>

    <table border="1">
        <tr>
            <th>ID</th>
            <th>お店</th>
            <th>メニュー</th>
            <th>操作</th>
        </tr>
        <tr th:each="lunch : ${lunches}">
            <td th:text="${lunch.id}"></td>
            <td th:text="${lunch.shop}"></td>
            <td th:text="${lunch.menu}"></td>
            <td>
                <a th:href="@{'/lunches/edit/' + ${lunch.id}}">編集</a> |
                <a th:href="@{'/lunches/delete/' + ${lunch.id}}"
                   onclick="return confirm('削除してよろしいですか?');">
                   削除
                </a>
            </td>
        </tr>
    </table>
</body>
</html>

アプリの実行

いよいよ実行してみよう。
あらかじめ作成されている、LunchAppApplication.javaを右クリック>実行>Srping Bootアプリケーション

Screenshot

無事に起動したらブラウザから以下のURLを入力

localhost:8080/lunches

以下のように表示されたら成功だ!

新規作成処理

データを新規に挿入する処理を作成する。

LunchControllerに以下を追記する

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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo.entity.Lunch;
import com.example.demo.repository.LunchRepository;

@Controller
public class LunchController {
    private final LunchRepository lunchRepository;

    public LunchController(LunchRepository lunchRepository) {
        this.lunchRepository = lunchRepository;
    }

    // 一覧
    @GetMapping("/lunches")
    public String list(Model model) {
        model.addAttribute("lunches", lunchRepository.findAll());
        return "lunch/list";
    }

    // 新規作成フォーム
    @GetMapping("/lunches/new")
    public String newLunch(Model model) {
        model.addAttribute("lunch", new Lunch());
        return "lunch/new";
    }

    // 登録処理
    @PostMapping("/lunches")
    public String create(@ModelAttribute Lunch lunch) {
        lunchRepository.save(lunch);
        return "redirect:/lunches";
    }
}

new.htmlの作成

  • src/main/resources/templates/lunch/new.htmlを作成
  • 内容は以下
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>新規ランチ作成</title>
</head>
<body>
    <h1>新規ランチ作成</h1>

    <form th:action="@{/lunches}" th:object="${lunch}" method="post">
        <p>お店:<input type="text" th:field="*{shop}"></p>
        <p>メニュー:<input type="text" th:field="*{menu}"></p>
        <p><button type="submit">登録</button></p>
    </form>

    <p><a th:href="@{/lunches}">戻る</a></p>
</body>
</html>

新規作成ボタンを押して、データを入力して登録ボタンを押そう

データが追加されれば成功だ

更新処理

LunchControllerに以下を追記する

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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo.entity.Lunch;
import com.example.demo.repository.LunchRepository;

@Controller
public class LunchController {
    private final LunchRepository lunchRepository;

    public LunchController(LunchRepository lunchRepository) {
        this.lunchRepository = lunchRepository;
    }

    // 一覧
    @GetMapping("/lunches")
    public String list(Model model) {
        model.addAttribute("lunches", lunchRepository.findAll());
        return "lunch/list";
    }

    // 新規作成フォーム
    @GetMapping("/lunches/new")
    public String newLunch(Model model) {
        model.addAttribute("lunch", new Lunch());
        return "lunch/new";
    }

    // 登録処理
    @PostMapping("/lunches")
    public String create(@ModelAttribute Lunch lunch) {
        lunchRepository.save(lunch);
        return "redirect:/lunches";
    }
    
    // 編集フォーム表示
    @GetMapping("/lunches/edit/{id}")
    public String edit(@PathVariable Integer id, Model model) {
        Lunch lunch = lunchRepository.findById(id).orElseThrow();
        model.addAttribute("lunch", lunch);
        return "lunch/edit";
    }
    
    // 更新処理
    @PostMapping("/lunches/update")
    public String update(@ModelAttribute Lunch lunch) {
        lunchRepository.save(lunch); // idが存在すればUPDATE
        return "redirect:/lunches";
    }

}

edit.htmlの作成

src/main/resources/templates/lunch/edit.htmlを作成

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>ランチ編集</title>
</head>
<body>
  <h1>ランチ編集</h1>

  <form th:action="@{/lunches/update}" th:object="${lunch}" method="post">
      <!-- 重要:idをhiddenで送信 -->
      <input type="hidden" th:field="*{id}">

      <p>お店:<input type="text" th:field="*{shop}"></p>
      <p>メニュー:<input type="text" th:field="*{menu}"></p>

      <p><button type="submit">更新</button></p>
  </form>

  <p><a th:href="@{/lunches}">戻る</a></p>
</body>
</html>
  • 編集ボタンを押してみよう
  • 復元されるので編集をして更新ボタンを押す。データが更新されれば成功だ

削除処理

LunchControllerに以下を追記する。

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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo.entity.Lunch;
import com.example.demo.repository.LunchRepository;

@Controller
public class LunchController {
    private final LunchRepository lunchRepository;

    public LunchController(LunchRepository lunchRepository) {
        this.lunchRepository = lunchRepository;
    }

    // 一覧
    @GetMapping("/lunches")
    public String list(Model model) {
        model.addAttribute("lunches", lunchRepository.findAll());
        return "lunch/list";
    }

    // 新規作成フォーム
    @GetMapping("/lunches/new")
    public String newLunch(Model model) {
        model.addAttribute("lunch", new Lunch());
        return "lunch/new";
    }

    // 登録処理
    @PostMapping("/lunches")
    public String create(@ModelAttribute Lunch lunch) {
        lunchRepository.save(lunch);
        return "redirect:/lunches";
    }
    
    // 編集フォーム表示
    @GetMapping("/lunches/edit/{id}")
    public String edit(@PathVariable Integer id, Model model) {
        Lunch lunch = lunchRepository.findById(id).orElseThrow();
        model.addAttribute("lunch", lunch);
        return "lunch/edit";
    }
    
    // 更新処理
    @PostMapping("/lunches/update")
    public String update(@ModelAttribute Lunch lunch) {
        lunchRepository.save(lunch); // idが存在すればUPDATE
        return "redirect:/lunches";
    }
    
    // 削除処理
    @GetMapping("/lunches/delete/{id}")
    public String delete(@PathVariable Integer id) {
        lunchRepository.deleteById(id);
        return "redirect:/lunches";
    }

}

削除してみよう。データが削除されるはずだ。

完成!

これで Spring Boot + H2データベース + Thymeleaf を使った基本的なCRUDアプリが完成しました。
本チュートリアルを通して、Spring Bootの基本的な構成とWebアプリ開発の流れを理解できたと思います。

次のステップとしては、以下のような拡張もおすすめです。

  • MySQLやPostgreSQLなどの外部DBに接続してみる
  • バリデーション(入力チェック)を追加してみる
  • Bootstrapで画面デザインを整える

今回の内容が、Spring Bootを使ったWebアプリ開発の第一歩になれば幸いです!

Spring
スポンサーリンク
シェアする
mjpurinをフォローする

コメント

タイトルとURLをコピーしました