SpringBootでストップウォッチアプリを作ってみる

# はじめに
SpringBootで簡単なアプリ作成としてストップウォッチアプリを作ってみます。
自分の手で自分の作りたいものを手を動かしながらしたほうが、
習得早いのかなって思い始めました。
（ずっとインプットばかりだと、細かいところばっかり気になるし、
　インプットしたらしたで結局どう作るの？って感じなので...）

イメージとしては、スタートボタンとストップボタン、その時間何するか入力欄を
おいて、自分用の記録を取っていく感じです。
少しずつこの記事も更新していきます。（目標:2/3完成）



# 画面イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118881/4b6a0438-6b65-cc3c-978d-43086dabadfc.png)

# 実装

おそらくコードの中で無駄な部分が多いと思います。
多めに見てもらうか、優しい方はこうすればいいよと教えていただけれと思います。

**画面**
今回作成したものは1画面のみになりますので、thymeleafでindex.htmlを作成しました。
（ちょっと画面イメージとは異なります。。）

name属性はControllerのものと同じになるよう気を付ける。
（基本的なことですが、この部分ではまってました。。）


```index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ストップウォッチ</title>
</head>
<body>
	<h1>ストップウォッチです</h1>

	<form method="post" th:action="@{/start}">
		<div>
			<span style="border: 1px solid #999">
			今から何するの?
			</span>
			 &nbsp;<input type="text" name="title"><br>
		</div>
		<button>スタート</button>
	</form>
	
	<form method="post" th:action="@{/stop}"  style="margin-top: 100px">
		<button style="display: block">ストップ</button>
		<input type="text" name="title" th:value="${title}"><br>
		<input type="text" name="start_date" th:value="${start_date}"><br>
		<input type="text" name="start_time" th:value="${start_time}"><br>
	</form>
	
	<table style="margin-top: 100px" border="1" width="500">
		<thead>
			<tr>
				<th>やったこと</th>
				<th>日にち</th>
				<th>始めた時間</th>
				<th>終わった時間</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="list : ${lists}" th:object="${list}">
				<td th:text="*{title}"></td>
				<td th:text="*{theDate}"></td>
				<td th:text="*{startTime}"></td>
				<td th:text="*{finishTime}"></td>
		</tbody>
	</table>
	
</body>
</html>
```


**Controller**

画面側に返したい値はModelに格納して返す。
本来はControllerにロジック組むのではなく、Serviceクラスを実装するとのことですが
今回はまとめてしまっています。

今更ですがLocalDateTimeがとても便利ですね！
フォーマット変換したり日付を何日かずらしたりと多くのメソッドが用意されていて変な手間がありません。
使い方が多岐にわたりそうなので、Javadoc見てみよう！

```StopWatchController.java
package com.example.demo.controller;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.demo.entity.StopWatchEntity;
import com.example.demo.mapper.StopWatchMapper;

@Controller
public class StopWatchController {
	
	@Autowired
	StopWatchMapper stopWatchMapper;

	@GetMapping("/")
	public String index(Model model) {
		List<StopWatchEntity> list = stopWatchMapper.selectAll();
		model.addAttribute("lists", list);
		return "index";
	}
	
	@PostMapping("/start")
	public String start(@RequestParam String title, Model model) {
		
		model.addAttribute("title", title);
		
		//startボタンを押した時間を取得
		LocalDateTime now = LocalDateTime.now();
		model.addAttribute("start_date", now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")));
		model.addAttribute("start_time", now.format(DateTimeFormatter.ofPattern("HH:mm:ss")));

		List<StopWatchEntity> list = stopWatchMapper.selectAll();
		model.addAttribute("lists", list);
		
		return "index";
	}
	
	@PostMapping("/stop")
	public String stop(@RequestParam String title
						, @RequestParam String start_date
						, @RequestParam String start_time) {
		
		StopWatchEntity stopWatchEntity = new StopWatchEntity();
		stopWatchEntity.setTitle(title);
		stopWatchEntity.setTheDate(start_date);
		stopWatchEntity.setStartTime(start_time);
		String finish_time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
		stopWatchEntity.setFinishTime(finish_time);
		
		stopWatchMapper.insert(stopWatchEntity);
		return "redirect:/";
	}
}


```

**SQL**

今回DBはpostgreSQL、ORMフレームワークはMyBatisを使用しています。
SQL設定ファイルのxmlファイルは下記のようになりました。

```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.StopWatchMapper">
	<select id="selectAll" resultType="com.example.demo.entity.StopWatchEntity">
		select    id         as "id"
				, title      as "title"
				, the_date   as "theDate"
				, start_time as "startTime"
				, finish_time as "finishTime"
		from stop_watch
		order by id desc
	</select>
	
	<insert id="insert" parameterType="com.example.demo.entity.StopWatchEntity">
		insert into stop_watch (title, the_date, start_time, finish_time)
		values (#{title}
				,to_date(#{theDate}, 'YYYY/MM/DD')
				,cast(#{startTime} as time)
				,cast(#{finishTime} as time)
				)
		
	</insert>
	
</mapper>
```



# できあがったもの

このような画面になりました。
今から何するの？の項目に入力してスタートボタンを押すと、ストップの欄に入力した項目、押した日時が表示されます。
ストップボタンを押すと入力されている項目に加えて、ボタンを押した時間を「終わった時間」としてDBに登録します。
一番下の一覧は初期画面でも表示するようにしています。降順です。


・初期画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118881/d2a0ed0e-915f-e541-85ef-3fe1424f616e.png)

・スタートボタン押下後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118881/6c4a9a9f-2cf8-d67c-2c3b-2cf864a5e703.png)

・ストップボタン押下後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118881/0904df7a-ce01-565b-4059-30d77d1fab75.png)

# 最後に
SpringBootを使って初めてWEBアプリを作成してみました。
html ⇔ Controller ⇔ Entity ⇔ MyBatis ⇔ SQL
と値を渡していくために変数名をそろえる必要があったのですが、そこに詰まってしまって大変でした。
今回書いたコードはエラーチェックの実装など改良の余地ありで、もっと使いやすいもの（どのくらい時間がたったかなど）に
するためにもできることがあるかなと思っています。

ただ実際に自分で作ってみることでどんな課題があるのか、
この実装をするためにはどうやってコードを書けばいいのか具体的に調査できました。
結果的にそれが良いインプットにもつながりました。
アウトプットとインプットのいい循環ができて、楽しくコードを書けたように感じます。
これからも頑張っていこうと思います！