3
1

More than 3 years have passed since last update.

SpringBoot + MySQL でTodoリストを作る!CRUDの実装(Delete編)

Posted at

はじめに

前回はidに応じたTodoのbooleanの値を更新する機能を実装しました。

今回は、「Todoの削除機能の実装」をゴールとしています。

SpringBootを学び始めた方、復習をしたい方に向けて学んだ事を共有します。

開発環境

OS: macOS Mojave(バージョン 10.14.6)
$ java -version
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
$ mvn -version
Maven home: /usr/local/Cellar/maven/3.6.3_1/libexec
Java version: 15.0.2, vendor: N/A, runtime: /usr/local/Cellar/openjdk/15.0.2/libexec/openjdk.jdk/Contents/Home
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.14.6", arch: "x86_64", family: "mac"
$ spring --version
Spring CLI v2.3.1.RELEASE
$ mysql --version
mysql  Ver 8.0.23 for osx10.14 on x86_64 (Homebrew)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>todolist</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>todolist</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>

        <!-- テンプレートエンジン -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- RESTfulを含んだWebアプリケーションライブラリの利用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- ORMのMyBatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <!-- ファイルの変更を検知すると自動で再起動する -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- アノテーションを付与する事でgetter,setter等を自動生成してくれる -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- テスト用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- DBとJavaオブジェクトやり取りを行う。 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- バリデーション用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

削除ボタンの追加

完了済みを削除というテキストでボタンをHTMLに追加します。

home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" type="text/css" th:href="@{css/home.css}">
  <title>SpringTodoList</title>
</head>
<body>

  <div class="form-area">
    <div class="create-todo">
      <form method="POST" th:action="@{/}" th:object="${todo}">
        <p th:errors="*{content}" class="todo-error-message"></p>
        <input type="text" th:field="*{content}">
        <button type="submit">登録</button>
      </form>
    </div>
    <!-- 追加 -->
    <div class="delete-all">
      <form method="POST" th:action="@{/deleteAll}">
        <button type="submit">完了済みを削除</button>
      </form>
    </div>
  </div>

  <div class="flex">      
    <div class="incomplete">
      <h1>未完了</h1>
      <div th:each="todo : ${allTodo}">
        <div th:if="${!todo.done}">
          <form method="POST" th:action="@{/done}">
            <input type="hidden" name="id" th:value="${todo.id}" />
            <button type="submit"></button>
          </form>
          <p th:text="${todo.content}"></p>
        </div>
      </div>
    </div>

    <div class="complete">
      <h1>完了済み</h1>
      <div th:each="todo : ${allTodo}" th:if="${todo.done}">
        <p th:text="${todo.content}"></p>
      </div>
    </div>

  </div>  

</body>

</html>
body {
  padding: 0;
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1.4rem;
}

h1 {
  text-align: center;
  margin: 20px 0 0 0;
}

p {
  display: inline-block;
}

.form-area {
  margin: 20px auto;
  display: flex;
  justify-content: center;
}

.create-todo {
  display: inline-block;
}

.create-todo input {
  font-size: 1em;
  line-height: 1.2;
  border-width: 2px;
  border-style: solid;
  border-radius: 5px;
  padding: 0.5em 0.5em;
  width: 300px;
}

.create-todo button {
  font-size: 1em;
  line-height: 1.2;
  border-width: 2px;
  border-style: solid;
  border-radius: 5px;
  background-color: #008CBA;
  cursor: pointer;
  color: white;
  display: inline-flex;
  justify-content: center; /* コンテンツを水平方向に中央揃え */
  align-items: center; /* コンテンツを垂直方向に中央揃え */
  padding: 0.5em 1.2em;
}

.todo-error-message {
  color: red;
  text-align: center;
  font-size: 1.2rem;
}

.delete-all {
  margin: 10px 10px 10px 10px;
}

.delete-all button {
  color: white;
  background-color: rgb(237, 76, 81);
  border-radius: 5px;
  font-size: 0.8em;
  cursor: pointer;
}

/* 未完了、完了済みタスクエリア */
.flex {
  display: flex;
  justify-content: space-around;
  margin: 30px 0 0 0;
}

.incomplete {
  text-align: center;
  width: 400px;
  background-color: pink;
}

.incomplete form {
  display: inline;
}

.incomplete button {
  background-color: white;
  border-radius: 50%;
  height: 15px;
  width: 15px;
  cursor: pointer;
  display: inline-flex;
  justify-content: center; /* コンテンツを水平方向に中央揃え */
  align-items: center; /* コンテンツを垂直方向に中央揃え */
}

.complete {
  text-align: center;
  width: 400px;
  background-color: green;
}

削除用のメソッドを作成

TodoServiceに削除用のメソッドを実装します。
deleteAll(IterableSE<? extends T> entities)というメソッドがCrudRepositoryにあるので、それを使用します。

TodoService.java
package com.example.todolist.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.example.todolist.Model.Todo;
import com.example.todolist.Repository.TodoRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

// DBとの具体的な処理(データの取得、新規作成など)を記述するクラス
@Service
public class TodoService {

  @Autowired
  TodoRepository todoRepository;

  public List<Todo> searchAll() {
    return todoRepository.findAll();
  }

  // Todoを新たにDBに登録する
  public void addTodo(Todo todo) {
    todoRepository.save(todo);
  }

  // idに応じたTodoを返却する
  public Todo findById(Integer id) {
    Optional<Todo> updateTodo = todoRepository.findById(id);
    return updateTodo.get();
  }

  // 追加(Todoの全件削除)
  public void deleteAllTodo() {
    List<Todo> allTodo = todoRepository.findAll();
    List<Todo> doneList = new ArrayList<>();
    // doneがtrueかどうかを判定。trueのものをdoneListに追加する。
    for (Todo todo : allTodo) {
      if (todo.getDone()) {
        doneList.add(todo);
      }
    }
    todoRepository.deleteAll(doneList);
  }
}

削除ボタン押下時の処理を追加

Controllerに、削除ボタン押下時に呼ばれるメソッドを実装します。

TodoController.java
package com.example.todolist.Controller;

import java.util.List;

import javax.validation.Valid;

import com.example.todolist.Model.Todo;
import com.example.todolist.Service.TodoService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Controller
public class TodoController {

  @Autowired
  TodoService todoService;

  @GetMapping("/")
  public String home(Model model) {
    List<Todo> allTodo = todoService.searchAll();
    model.addAttribute("allTodo", allTodo);
    model.addAttribute("todo", new Todo());
    return "home";
  }

  // 新規登録用
  @PostMapping("/")
  public String createTodo(@Valid Todo todo, BindingResult bindingResult,Model model) {
    // 入力値にエラーがあった時
    if(bindingResult.hasErrors()) {
      List<Todo> allTodo = todoService.searchAll();
      model.addAttribute("allTodo", allTodo);
      model.addAttribute("todo", todo);
      return "home";
    }

    // エラーがなかった時は、Todoを新規登録する
    todoService.addTodo(todo);
    return "redirect:/";
  }

  // 未完了タスク横のボタンが押されたら、doneフラグをtrueに変更する
  @PostMapping("/done")
  public String doneTodo(@RequestParam(name = "id") Integer todoId) {
    Todo updateTodo = todoService.findById(todoId);
    updateTodo.setDone(true);
    todoService.addTodo(updateTodo);
    return "redirect:/";
  }

  // 追加(削除ボタンが押されたら、処理される)
  @PostMapping("/deleteAll")
  public String deleteAll() {
    todoService.deleteAllTodo();
    return "redirect:/";
  }
}

削除ボタンのformにth:action="@{/deleteAll}"としているので、
ControllerのdeleteAll()が呼ばれ、先ほどServiceで実装した、deleteAllTodo()を実行します。

これで完了済みのTodoを削除します。

動作確認

ここまで実装するとこの様になっています。

スクリーンショット 2021-03-18 12.19.41.png

完了済みを削除のボタンを押下すると...

スクリーンショット 2021-03-18 12.20.43.png

完了済みのTodoだけが削除されています!!!

終わりに

全4回に渡って、SpringBootとMySQLを使ってCRUDの実装が完了しました。

非常にシンプルなものですが、フレームワークを用いる事でデータベースの値を画面に表示したり、更新したりなど学ぶ事が出来ました。

編集、日付を設定したりなど機能を追加したいな〜と思うので、日々勉強していこうと思います。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1