SpringBootでToDoアプリを作ってみよう【誰でも作れます・初心者向け】

#はじめに
SpringBootを使ってToDoアプリを作っていきます。
一度動くものを作ってみるとイメージしやすいと思うので、
これからSpringBootの学習を始める方、参考にしてみてください。


基本的な機能のみですが、SpringBootの動く感覚をつかめると思います。
エラーや分からない所、コメントしてください。

(OSはwindowsです)

駆け出しなので、おかしな点もあるかもしれません。
教えてもらえたら嬉しいです。

* テンプレートエンジン　Thymeleaf
* データベース　PostgreSQL
* ORマッパー　　Mybatis


勉強始めたばかりの方は、PostgreSQLを使うという事を懸念せず、
SpringBootの勉強だと思って、やってみてください。

同じ方が簡単な気がします。もちろんMySQLでやってもいいです。

#最終的なディレクトリ構成


![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/114933d1-0a2d-c3d9-176b-05452029703f.png)

#流れ#
* PostgreSQLの準備
* SpringBootプロジェクトの作成
* DB接続設定
* ビューからDBまで動かしてみる
 * Entityの作成
 * Mapperの作成
 * XMLファイルの作成
 * Thymeleafの作成
 * Controllerの作成
 * 確認
* 追加機能を加える
* 更新機能を加える
* 完了機能を加える
 * 完了ボタンを作る
 * 未完了のみ表示する
 * 完了も表示する
* 削除機能を加える


#PostgreSQLの準備#
インストールについては、こちらの方の記事を参考にしてください。
[PostgreSQL を Windows にインストールするには](https://qiita.com/tom-sato/items/037b8f8cb4b326710f71)

記事通りに進めるとインストール時にエラーが出てしまったので、
ダウンロードのみは、[ここ](https： //get.enterprisedb.com/postgresql/postgresql-11.2-1-windows-x64.exe)からしました。
あとは、そのまま説明通りに進めてください。

インストールができたら、ToDoアプリで使用するDBを作っていきます。
参考にした記事で使用されていた、「SQL Shell (psql)」を開きます。

ユーザーを作成します。

```sql
postgres=# create role todo_user login password 'todo_pass';
```
ユーザーが作成されたことを確認します。

```sql
postgres=# select usename from pg_user;
  usename
-----------
 postgres
 todo_user
(2 行)
```
作成されていることが確認できました。

データベースを作成します。

```sql
postgres=# create database todo_db with owner = todo_user;
```
データベースが作成された事を確認します。

```sql
postgres=# \l
                                        データベース一覧
   名前    |  所有者   | エンコーディング | 照合順序 | Ctype(変換演算子) |     アクセス権限
-----------+-----------+------------------+----------+-------------------+-----------------------
 postgres  | postgres  | UTF8             | C        | C                 |
 template0 | postgres  | UTF8             | C        | C                 | =c/postgres          +
           |           |                  |          |                   | postgres=CTc/postgres
 template1 | postgres  | UTF8             | C        | C                 | =c/postgres          +
           |           |                  |          |                   | postgres=CTc/postgres
 todo_db   | todo_user | UTF8             | C        | C                 |
(4 行)
```
作成されている事が確認できました。

作成したデータベースに、作成したユーザーで接続してみます。

```sql
postgres=# \connect todo_db todo_user
ユーザ todo_user のパスワード:
データベース "todo_db" にユーザ "todo_user" として接続しました。
```
接続できました。

テーブルを作成します。
今回は、練習なので、簡単にこんな感じにします。

```sql
todo_db=> create table todo_items(
todo_db(> id serial,
todo_db(> title varchar(40),
todo_db(> done_flg numeric(1) default 0,
todo_db(> time_limit date);
CREATE TABLE
```
※どういう時にどのデータ型が適切かがまだわかってないので、大目に見てください。
テーブルの確認してみます。

```sql
todo_db=> \d todo_items
                                      テーブル "public.todo_items"
     列     |          型           | 照合順序 | Null 値を許容 |               デフォルト
------------+-----------------------+----------+---------------+----------------------------------------
 id         | integer               |          | not null      | nextval('todo_items_id_seq'::regclass)
 title      | character varying(40) |          |               |
 done_flg   | numeric(1,0)          |          |               | 0
 time_limit | date                  |          |               |
```
PostgreSQL、DBの準備はこんな感じです。

#SpringBootプロジェクトの作成#
eclipseを起動します。
起動したら、「ファイル(F)」→「新規(N)」→「プロジェクト(R)...」と進み
「Spring スターター・プロジェクト」を選択します。


eclipseのインストールやSpringBootプロジェクト作成方法はこちらの記事も参考にしてみてください。
https://qiita.com/toki_k/items/52c222433823268472a1


今回は、Maven、Jarを選択します。初期値のままです。
名前等は好きにつけて構いません。
ですが、練習なので、同じで大丈夫だと思います。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/f631339e-4821-675f-e135-d86debbef886.png)
依存関係は、Lombok・Mybatis Framework・PostgreSQL Driver・Thymeleaf・Spring Webを選択しました。

選択した依存関係は、pom.xmlで確認できます。依存関係の追加などもこのファイルでできます。
1度確認してみてください。
これで、SpringBootプロジェクトの作成ができました。

#DB接続設定#
先程、作成したDBに接続するために、「application.properties」を編集します。
src/main/resourcesの下のapplication.propertiesを開きます。
今は、何も書かれていないです。
以下の記述を加えることで、DBに接続できるようになります。

```
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/todo_db
spring.datasource.username=todo_user
spring.datasource.password=todo_pass
```
todo_db、todo_user、todo_passは先ほど、自分が作成したものです。

#ビューからDBまで動かしてみる#

##Entityの作成
VO、Entity、Dtoとかの違いについて、あまり理解できていないので、
これから勉強していきます。すみません。
今回はEntityとします。

src/main/java/com/todo/appの下に、「entity」パッケージを作成します。
app(com.todo.app)を右クリックし、「新規(W)」→「パッケージ」と進みます。
名前欄の初期値が「com.todo.app」となっているので、「com.todo.app.entity」とします。
※簡単なアプリケーションではパッケージを分ける必要はないようですが、応用する時のため分けておきます。

パッケージの下にTodo.javaクラスを作成します。
entityを右クリックし、「新規(W)」→「クラス」と進みます。
名前(M)に「Todo」と入力し、完了を押します。

Todo.javaが作成されたので、編集していきます。
これは、テーブルのデータを保持するためのものです。

```Todo.java
package com.todo.app.entity;

import java.sql.Date;

import lombok.Data;

@Data
public class Todo {

	private long id;
	private String title;
	private int done_flg;
	private String time_limit;
}
```
＠Dataは、lombokのGetter・Setter自動生成のためのものです。
以下のようなものを1つずつ記述する必要がなくなります。

```Java
public Long getId() {
        return id;
    }
public void setId(Long id) {
        this.id = id;
    }
```

##Mapperの作成
RepositoryやDAO、Mapperとかの違いについて、あまり理解できていないので、
これから勉強していきます。すみません。
今回はMapperとします。

src/main/java/com/todo/appの下に、「mapper」パッケージを作成します。
作り方は、先程と同様です。

パッケージの下にTodoMapper.javaクラスを作成します。
mapperを右クリックし、「新規(W)→「インターフェース」と進みます。
名前(M)に「TodoMapper」と入力し、完了を押します。

TodoMapper.javaが作成されたので、編集していきます。
これは、DBを操作するメソッドを呼び出すためのインターフェースです。
このインターフェースから、メソッドを呼び出します。
このインターフェースの具象クラスは、 MyBatis が XML の SQL 情報から自動で作成してくれます。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();
}
```
＠Mapperをつけるだけで、Mapperのインターフェースとなります。
今回は、selectAll()に対応するSQL文は、XMLファイルに記載していきます。
※このインターフェースに書いて、SQLを実装する事も可能です。
##XMLファイルの作成
Mapperインターフェースと同じ構成のフォルダを作成し、XMLファイルを作成していきます。

src/main/resourcesを右クリックし、
「新規(W)」→「フォルダー」と進みます。
フォルダー名に、「com/todo/app/mapper」と入力し、完了します。
※パッケージのように、「.」でつなぐとエラーになるようです。

mapperフォルダを右クリックし、
「新規(W)」→「その他」→「XMLファイル」と進みます。
ファイル名は、「TodoMapper.xml」とします。

TodoMapper.xmlファイルが作成されたので、編集していきます。
ここには、SQL文を記述していきます。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>
</mapper>
```
ここでは、todo_items(テーブル)から、すべてのデータをselectしています。
Todoクラス型で返されています。Todoクラスの変数にそれぞれ値が入ります。
idがメソッド名、resultTypeが戻される型です。
##Thymeleafの作成
画面に表示される部分を作っていきます。
src/main/resources/templatesの下に、index.htmlを作成します。
index.htmlが作成できたら、編集していきます。

今は、TodoListという文字と、Todoリストのタイトルを表示させます。

```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <p th:each="todo : ${todos}" th:text="${todo.title}" />
</body>
</html>
```
\${todos}の部分はリストで、Controllerからデータをもってきます。
リストを1つずつ、todoとして格納し、画面に表示させていきます。リストの数だけ、\<p>が表示されます。
th:text="${todo.title}"が実際に表示されるテキストです。Todoのtitleが表示されます。
##Controllerの作成
src/main/java/com/todo/appの下に、「controller」パッケージを作成します。

controllerパッケージの下に、「TodoController.java」を作成します。
TodoController.javaが作成できたら、編集していきます。

このクラスから、Mapperインターフェースのメソッドを呼び出し、
そのメソッドによってDBからデータを取得し、そのデータを埋め込んで、ブラウザに表示します。


```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {
		List<Todo> list = todoMapper.selectAll();
		model.addAttribute("todos",list);
		return "index";
	}
}
```
＠Controllerでコントローラだと認識されます。
＠RequestMappingに対応するURLが入力された時にこのメソッドが呼び出されます。
今回なら、「http://localhost:8080/ 」です。(value="/todo")の場合は、「http://localhost:8080/todo 」です。

todoMapper.selectAll()でインターフェースのメソッドを実行し、
xml内のSQLの結果を戻り値としてlistに格納しています。
listの値にtodosという名前を付けて、ビュー(index.html側)に渡します。
Thymeleafの\${todos}の部分になります。
returnで先程作ったindex.htmlを指定しています。

##確認
プロジェクトを実行します。
todoappを右クリックし、「実行(R)」→「Spring Boot App」を選択します。
実効ができたら、ブラウザを開き、以下のURLを入力します。
「http://localhost:8080/ 」
成功していれば、画面にTodoListが表示されます。

次に、「SQL Shell(psql)」を使って、テーブルにデータを格納してみます。
はじめに行ったように、todo_userでtodo_dbに接続します。
接続できたら、以下のinsert文を実行してみます。
今は、期限の値はなしで、題名の値だけを追加しています。

```sql
todo_db=> insert into todo_items (title) values ('ご飯を食べる![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/0fb055bd-f665-a932-54b6-70949ba92e38.png)
');
```
もう1度ブラウザを開き、以下のURLを入力します。(先ほどのブラウザが開いてあれば、リロードするだけ)
「http://localhost:8080/ 」
TodoListの下に、ご飯を食べるが追加されれば成功です。

成功したら、他にも自分の好きな値を入れてinsert文を実行してみてください。
ブラウザのご飯を食べるの下に、追加されていきます。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/d1a5a762-43cb-8481-72f9-f9742df48c02.png)

#追加機能を加える
タスクの追加機能を追加していきます。

__Mapperを編集します。__
メソッドを定義します。
ビュー側(index.html)で入力したデータをDBに追加するので、引数が必要です。
この引数のtodoはXMLファイルのSQLで使います。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();

	public void add(Todo todo); // ここを追加しました。
}
```
__XMLファイルを編集します。__
addメソッドに対応するSQLを追加します。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>
</mapper>
```
to_date(#{time_limit},'yy-mm-dd')はString型の日付をデータ型で格納しています。

__Controllerを編集します。__

「/add」で呼び出すメソッドを作成します。
呼び出しと同時にビュー側から渡される値を、Mapperのaddメソッドの引数に渡しています。
メソッドを実行した後、indexメソッドにリダイレクトしています。

```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {
		List<Todo> list = todoMapper.selectAll();
		model.addAttribute("todos",list);
		return "index";
	}

	@RequestMapping(value="/add")
	public String add(Todo todo) {
		todoMapper.add(todo);
		return "redirect:/";
	}
}
```
__thymeleafを編集します。__
2つの入力欄と追加ボタンを作成します。
入力欄に入力した値が、コントローラのメソッドの引数(Todo)になります。
name属性の値と同名の(Todoの)フィールドに、それぞれ入力値が入ります。

追加ボタン(submit)を押すと、コントローラの/addが実行されます。


```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <p th:each="todo : ${todos}" th:text="${todo.title}" />

  <form method="post" th:action="@{/add}">
    <input type="text" name="title" />
    <input type="date" name="time_limit"/>
    <input type="submit" value="追加" />
  </form>
</body>
</html>
```
これで、追加できるようになりました。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/c9b6eb7f-d698-91e7-192c-f93d94e80d99.png)

#更新機能を加える
タスクの編集・更新機能を追加していきます。
今回は、1つのタスクごとに更新する事にします。

__Mapperを編集します。__
メソッドを定義します。
ビュー側(index.html)で入力したデータを受け取ってDBを更新するので、引数が必要です。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();

	public void add(Todo todo);

	public void update(Todo todo);　//ここを追加しました。
}
```
__XMLファイルを編集します。__
updateメソッドに対応するSQLを追加します。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>

  <update id="update" parameterType="com.todo.app.entity.Todo">
    update todo_items set
      title = #{title},
      time_limit = to_date(#{time_limit},'yy-mm-dd')
      where id = #{id}
  </update>
</mapper>
```
テーブルのどのデータを更新するのか、whereを使い識別する必要があります。
add()では、title、time_limitだけ充分でしたが、今回は識別に使うidが必要です
このidはindex.htmlから持ってきます。
__Controllerを編集します。__

「/update」で呼び出すメソッドを作成します。
addとほとんど同じです。

```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {
		List<Todo> list = todoMapper.selectAll();
		model.addAttribute("todos",list);
		return "index";
	}

	@RequestMapping(value="/add")
	public String add(Todo todo) {
		todoMapper.add(todo);
		return "redirect:/";
	}

	@RequestMapping(value="/update")
	public String update(Todo todo) {
		todoMapper.update(todo);
		return "redirect:/";
	}
}
```
__thymeleafを編集します。__
ビュー側の編集していきます。
ここでやる事は以下3つです。

* 文字を書き換えられるようにする
* 更新ボタンをつける
* idを取得できるようにする

```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <h3>マイタスク</h3>
  <form method="post" th:action="@{/update}" th:each="todo : ${todos}" >
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" />
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>新しいタスクを追加</h3>
  <form method="post" th:action="@{/add}">
    <input type="text" name="title" />
    <input type="date" name="time_limit"/>
    <input type="submit" value="追加" />
  </form>
</body>
</html>
```
追加の時と同じようにformにしました。
追加と違うのは、以下3点です。

* ループさせる必要がある　　(編集前の一覧と同様)
* 初めから値が入っている　　(編集前の一覧と同様)
* idは隠す　　(type="hidden"で隠せます)

実際には、このformのセットが何個もできる感じです。

タスク一覧と追加の箇所の区別がしづらくなったので、見出しをつけておきました。

これで、更新できるようになりました。
※日付を入力しないとエラーになります。
※更新する場合も、日付を入れてください。


![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/deb90e2f-bf31-b0f5-e122-eea477b79320.png)

#完了機能を加える
##完了ボタンを作る
__thymeleafを編集します。__
タスクの横に、完了したら押すためのボタンを作っていきます。

input(checkbox)を１行だけ追加しました。
完了したら、このボタンを押します。
チェックがついている時に、valueの値(1)を返します。

```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <h3>マイタスク</h3>
  <form method="post" th:action="@{/update}" th:each="todo : ${todos}" >
    <input type="checkbox"name="done_flg" value="1"/>
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" />
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>新しいタスクを追加</h3>
  <form method="post" th:action="@{/add}">
    <input type="text" name="title" />
    <input type="date" name="time_limit"/>
    <input type="submit" value="追加" />
  </form>
</body>
</html>
```
更新ボタンで、完了しているかどうかの値も送信するようになりました。

__XMLファイルを編集します。__
ControllerとMapperインターフェースに変更はないので、
XMLのSQL文だけ編集していきます。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>

  <update id="update" parameterType="com.todo.app.entity.Todo">
    update todo_items set
      title = #{title},
      time_limit = to_date(#{time_limit},'yy-mm-dd'),
      done_flg = #{done_flg}
      where id = #{id}
  </update>

</mapper>
```
done_flgも同時に更新するようにしました。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/98b644a3-b8c5-b466-22a8-43a6cc5b7967.png)

まだ画面に変化は現れないので、確認したければ
SQL Shell psqlで以下を実行してみてください。

```sql
todo_db=> select * from todo_items;
```
##未完了のみ表示する
未完了のみを表示していきます。

__Mapperを編集します。__

未完了のみを検索するselectIncompleteメソッドを定義します。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();

	public List<Todo> selectIncomplete();

	public void add(Todo todo);

	public void update(Todo todo);

}

```
__XMLファイルを編集します。__
selectIncompleteを実装していきます。
select文に、未完了のみを取得するという条件が加わります。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <select id="selectIncomplete" resultType="com.todo.app.entity.Todo">
    select * from todo_items where done_flg = 0
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>

  <update id="update" parameterType="com.todo.app.entity.Todo">
    update todo_items set
      title = #{title},
      time_limit = to_date(#{time_limit},'yy-mm-dd'),
      done_flg = #{done_flg}
      where id = #{id}
  </update>

</mapper>
```

__Controllerを編集します。__
今は、1度、selectAllを消しておきます。(コメントにした)
selectAllの代わりに、selectIncompleteが呼べるようになりました。
表示する件数が変わるだけで、他はほとんど変わっていません。


```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {

//		List<Todo> list = todoMapper.selectAll();

		List<Todo> list = todoMapper.selectIncomplete();
		model.addAttribute("todos",list);
		return "index";
	}

	@RequestMapping(value="/add")
	public String add(Todo todo) {
		todoMapper.add(todo);
		return "redirect:/";
	}

	@RequestMapping(value="/update")
	public String update(Todo todo) {
		todoMapper.update(todo);
		return "redirect:/";
	}

}
```
これで、ブラウザを起動してみると、未完了のタスクのみが表示されるようになりました。
完了ボタンを押して、更新すると画面から消えます。

##完了も表示する

完了したタスクも表示していきます。

__Mapperを編集します。__

完了のみを検索するselectCompleteメソッドを定義します。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();

	public List<Todo> selectIncomplete();

	public List<Todo> selectComplete();

	public void add(Todo todo);

	public void update(Todo todo);

}

```
__XMLファイルを編集します。__
selectCompleteを実装していきます。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <select id="selectIncomplete" resultType="com.todo.app.entity.Todo">
    select * from todo_items where done_flg = 0
  </select>

  <select id="selectComplete" resultType="com.todo.app.entity.Todo">
    select * from todo_items where done_flg = 1
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>

  <update id="update" parameterType="com.todo.app.entity.Todo">
    update todo_items set
      title = #{title},
      time_limit = to_date(#{time_limit},'yy-mm-dd'),
      done_flg = #{done_flg}
      where id = #{id}
  </update>

</mapper>
```

__Controllerを編集します。__

selectIncompleteとselectCompleteを両方読んで、
完了済みのリストと未完了のリストをそれぞれ作りました。
それぞれのリストを、名前を付けてビュー側に渡しています。

```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {

//		List<Todo> list = todoMapper.selectAll();

		List<Todo> list = todoMapper.selectIncomplete();
		List<Todo> doneList = todoMapper.selectComplete();
		model.addAttribute("todos",list);
		model.addAttribute("doneTodos",doneList);

		return "index";
	}

	@RequestMapping(value="/add")
	public String add(Todo todo) {
		todoMapper.add(todo);
		return "redirect:/";
	}

	@RequestMapping(value="/update")
	public String update(Todo todo) {
		todoMapper.update(todo);
		return "redirect:/";
	}

}
```
__thymeleafを編集します。__

```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <h3>マイタスク</h3>
  <form method="post" th:action="@{/update}" th:each="todo : ${todos}" >
    <input type="checkbox"name="done_flg" value="1"/>
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" />
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>完了済み</h3>
   <form method="post" th:action="@{/update}" th:each="todo : ${doneTodos}" >
    <input type="checkbox"name="done_flg" value="1"/>
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" style="text-decoration:line-through"/>
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>新しいタスクを追加</h3>
  <form method="post" th:action="@{/add}">
    <input type="text" name="title" />
    <input type="date" name="time_limit"/>
    <input type="submit" value="追加" />
  </form>

</body>
</html>
```
完了済みのリストを作成しました。
完了した感を出すために、取り消し線を引きます。
style="text-decoration:line-through"で取り消し線を引いています。

これで、完了と未完了分けての表示ができました。
今は、チェックボックスにチェックなしで、更新すると未完了にもどるので、変な感じです（笑）

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/2dfb5279-1867-a318-23cd-967e9b7d69f0.png)
#削除機能を加える
完了済みが増え続けてしまうので、一括で削除できるようにします。

__Mapperを編集します。__

deleteメソッドを定義します。
一括削除なので、引数も戻り値もなしにします。

```TodoMapper.java
package com.todo.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.todo.app.entity.Todo;

@Mapper
public interface TodoMapper {

	public List<Todo> selectAll();

	public List<Todo> selectIncomplete();

	public List<Todo> selectComplete();

	public void add(Todo todo);

	public void update(Todo todo);

	public void delete();
}

```
__XMLファイルを編集します。__
deleteを実装していきます。

```TodoMapper.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.todo.app.mapper.TodoMapper">
  <select id="selectAll" resultType="com.todo.app.entity.Todo">
    select * from todo_items
  </select>

  <select id="selectIncomplete" resultType="com.todo.app.entity.Todo">
    select * from todo_items where done_flg = 0
  </select>

  <select id="selectComplete" resultType="com.todo.app.entity.Todo">
    select * from todo_items where done_flg = 1
  </select>

  <insert id="add" parameterType="com.todo.app.entity.Todo">
    insert into todo_items (title,time_limit)
    values (#{title},to_date(#{time_limit},'yy-mm-dd'))
  </insert>

  <update id="update" parameterType="com.todo.app.entity.Todo">
    update todo_items set
      title = #{title},
      time_limit = to_date(#{time_limit},'yy-mm-dd'),
      done_flg = #{done_flg}
      where id = #{id}
  </update>

  <delete id="delete" parameterType="com.todo.app.entity.Todo">
      delete from todo_items where done_flg = 1
  </delete>

</mapper>
```
__Controllerを編集します。__

「/delete」で呼び出すメソッドを作成します。

```TodoController.java
package com.todo.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.todo.app.entity.Todo;
import com.todo.app.mapper.TodoMapper;

@Controller
public class TodoController {

	@Autowired
	TodoMapper todoMapper;

	@RequestMapping(value="/")
	public String index(Model model) {

//		List<Todo> list = todoMapper.selectAll();

		List<Todo> list = todoMapper.selectIncomplete();
		List<Todo> doneList = todoMapper.selectComplete();
		model.addAttribute("todos",list);
		model.addAttribute("doneTodos",doneList);

		return "index";
	}

	@RequestMapping(value="/add")
	public String add(Todo todo) {
		todoMapper.add(todo);
		return "redirect:/";
	}

	@RequestMapping(value="/update")
	public String update(Todo todo) {
		todoMapper.update(todo);
		return "redirect:/";
	}

	@RequestMapping(value="/delete")
	public String delete() {
		todoMapper.delete();
		return "redirect:/";
	}

}
```
__thymeleafを編集します。__
削除ボタンを作成します。
submitすることで、Controllerの/deleteを実行します。

```index.html
<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>TodoApp</title>
</head>
<body>
  <h1>TodoList</h1>
  <h3>マイタスク</h3>
  <form method="post" th:action="@{/update}" th:each="todo : ${todos}" >
    <input type="checkbox"name="done_flg" value="1"/>
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" />
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>完了済み</h3>
   <form method="post" th:action="@{/update}" th:each="todo : ${doneTodos}" >
    <input type="checkbox"name="done_flg" value="1"/>
    <input type="hidden" name="id" th:value="${todo.id}" />
    <input type="text" name="title"th:value="${todo.title}" style="text-decoration:line-through"/>
    <input type="date" name="time_limit"th:value="${todo.time_limit}" />
    <input type="submit" value="更新" />
  </form>

  <h3>新しいタスクを追加</h3>
  <form method="post" th:action="@{/add}">
    <input type="text" name="title" />
    <input type="date" name="time_limit"/>
    <input type="submit" value="追加" />
  </form>

  <form method="post" th:action="@{/delete}">
    <input type="submit" value="完了済みを削除" />
  </form>

</body>
</html>
```
削除ボタンを作成することができました。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506867/eab32e3e-a5bd-03f0-a680-e1e66cc10db8.png)

ここを押すと、完了済みが一気に消せます。
これで、データベースへの追加・削除・更新・検索の機能は実装することができました。

#まとめ

本当に簡単な機能だけですが、SpringBootで動くものが作れました。

難しい参考書を使ったり、1つずつ全部調べて時間をかけるよりも先に、
動くものを作って、何となく雰囲気を掴むというのがすごい大事だなと思っています。

自分が今からプログラミングの勉強を始めるとして、役に立つようにと思って書いてきました。
これから、SpringBootの勉強を始めるひとの役に立てれば幸いです。

今は、本当に機能を詰め込んだだけの物なので、好きに改造したり、色々遊んでみてください。
こういう機能だけでなく、例外処理やバリデーションなどを実装してみるのも勉強になると思います。


まだ、すごい駆け出しでキータもあまり書いたことないので、
LGTM1つ来るだけでもすごい喜びます。
もしよかったら、LGTMよろしくお願いします。
間違ってるところやおかしなところ、エラーが出たなどがあったらコメントもお願いします。

長くなってしまいましたがありがとうございました！！

↓ソースファイルです
https://github.com/tokio-k/TodoApp-springboot/tree/intermediate

今回作ったものを、jQueryを使って少し改良した記事です↓
https://qiita.com/toki_k/items/e207157c679018579e21

##参考記事
https://www.kakiro-web.com/postgresql/postgresql-create-user.html
https://qiita.com/tom-sato/items/037b8f8cb4b326710f71
https://www.dbonline.jp/postgresql/table/index1.html
https://www.dbonline.jp/postgresql/database/index2.html
https://www.dbonline.jp/postgresql/type/index5.html
https://mam-mam.net/mytech/show.php?cd=112
https://qiita.com/y_ogawa_naaaa/items/26da3b019f090abcfe36
https://www.shookuro.com/entry/2017/11/23/203318

https://qiita.com/tom-sato/items/037b8f8cb4b326710f71