見出し画像

MyBatisを利用してJavaでtodoリスト作ってみた。

メモです。
こんにちは、青のひとりごとです。
今回はMyBatisの便利さを試すために、MyBatisを用いてJavaのSpringBootでtodoリストを作ってみました。

結論としては、

とても便利でした!

特に、

場合分けしてSQL文を実行するのに有用だ

と感じました。


MyBatisを利用する際、マッパーファイル(Daoのようなもの)のアノテーションに直接SQL文を書き込む方法もあるようですが、今回はXMLファイルを用いた方法で記述しました。


今回、MyBatisを試すにあたって、こちらの記事を主に参考にさせていただきました。そのため、バージョンなどの設定はこちらの記事と同じになっています。



XMLファイルには以下のように記述を行いました。

PlaceMapper.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.TaskMapper">
	<resultMap id="taskMap"
		type="com.example.demo.entity.Task">
		<result column="ID" jdbcType="INTEGER" property="taskId" />
		<result column="TASK" jdbcType="VARCHAR" property="task" />
		<result column="MANHOURS" jdbcType="INTEGER" property="manHours" />
		<result column="ALREADY" jdbcType="BOOLEAN" property="already" />
	</resultMap>

	<!-- Todo一覧を取り出す -->
	<select id="selectAll" resultMap="taskMap">
		SELECT ID,TASK,MANHOURS,ALREADY FROM TASK
	</select>

	<!-- 特定のTodoの編集 -->
    <update id="update">
		UPDATE TASK
		SET
			TASK = #{task},
			MANHOURS  = #{manHours}
		WHERE
			ID = #{taskId}
	</update>

	<!-- 特定のTodoの済/未の変換 -->
	<update id="updateAlready">
		UPDATE TASK
		SET
		<choose>
			<when test="already == 'done'">
				ALREADY = 1
			</when>
			<when test="already != 'done'">
				ALREADY = 0
			</when>
		</choose>
		WHERE
			ID = #{taskId}
	</update>

	<!-- 特定のTodoの削除 -->
	<delete id="delete">
		DELETE FROM TASK
		WHERE
			ID = #{taskId}
	</delete>

	<!-- Todoの挿入 -->
	<insert id="insert" >
		INSERT INTO TASK
			(TASK,MANHOURS)
		VALUES
			(#{task}, #{manHours})
	</insert>

	<!-- Todoの検索 -->
	<select id="search" resultMap="taskMap">
		SELECT ID,TASK,MANHOURS,ALREADY FROM TASK
		<where>
			<choose>
				<when test="task != null">
					TASK LIKE concat('%', #{task}, '%')
				</when>
				<when test="already != 'all'">
					ALREADY = #{already}
				</when>
			</choose>
		</where>
	</select>
</mapper>

注目したいのが、一番最後の部分(Todoの検索)。
whenタグで囲ってある部分は、taskやalreadyという変数の値によって、SQL文に追加されるかどうか条件分岐しします。
さらにwhereタグで囲うことで、もし追加される文があるならば、SQL文にWHEREが追加され、追加された文がSELECT文の条件として機能します。


MyBatisを用いないSpringBootでも、PreparedStatementなどを用いて同じように条件分岐したSQL文を書くことはできますが、MyBatisを用いてかなり簡単に書くことができました。
ただ、単純なSQL文の実行ならxmlファイルを作らずにアノテーションに書いてしまう方が便利そうです。



以下に作ったファイルを残します。

今回はMyBatisのお試しのため、Todoリストの使いやすさにはこだわらなかったため、その点はお許しください。
また、実際に使うことは考えていないためh2データベースを使っていて、springbootを実行し直したら、入力したデータが初期状態に戻ってしまうのでご注意ください。

TaskListController.java

package com.example.demo.apps;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

import com.example.demo.entity.Task;
import com.example.demo.mapper.TaskMapper;

@Controller
public class TaskListController {

	@Autowired
	private TaskMapper taskMapper;
	
	@GetMapping("/")
	public ModelAndView listAll() {
		
		ModelAndView mav = new ModelAndView("index");
		
		mav.addObject("tasks", taskMapper.selectAll());
		mav.addObject("search", "all");
		
		return mav;
	}

	@GetMapping("/search")
	public ModelAndView search(Task task) {
		
		ModelAndView mav = new ModelAndView("index");
		
		mav.addObject("tasks", taskMapper.search(task));
		mav.addObject("searchWord", task.getTask());
		if(task.getAlready() != null){
			mav.addObject("search", task.getAlready());
		}else{
			mav.addObject("search", "all");
		}
		
		return mav;
	}

	@GetMapping("/insert")
	public ModelAndView moveInsert() {
		
		ModelAndView mav = new ModelAndView("insertTask");
		return mav;
	}

	@PostMapping("/confirmInsert")
	public String confirmInsert(Task task) {
		
		taskMapper.insert(task);
		return "redirect:/";
	}

	@GetMapping("/update")
	public ModelAndView moveUpdate() {
		
		ModelAndView mav = new ModelAndView("updateTask");
		return mav;
	}

	@PostMapping("/confirmUpdate")
	public String confirmUpdate(Task task) {
		
		taskMapper.update(task);
		return "redirect:/";
	}

	@GetMapping("/delete")
	public ModelAndView moveDelete() {
		
		ModelAndView mav = new ModelAndView("deleteTask");
		return mav;
	}

	@PostMapping("/confirmDelete")
	public String confirmDelete(Task task) {
		
		taskMapper.delete(task);
		return "redirect:/";
	}

	@PostMapping("/done")
	public String done(Task task) {
		taskMapper.updateAlready(task);
		return "redirect:/";
	}
}


TaskMapper.java

package com.example.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.demo.entity.Task;

@Mapper
public interface TaskMapper {

	/**
	 * 全ユーザーを取得
	 * 
	 * @return 全ユーザーの情報
	 * 
	 */
	List<Task> selectAll();

    /**
	 * ユーザーの更新
	 * @param task 更新するユーザーの情報
	 */
	void update(Task task);
	void updateAlready(Task task);
	
	/**
	 * ユーザーの登録
	 * @param task 登録するユーザーの情報
	 */
	void insert(Task task);

	/**
	 * ユーザーの削除
	 * @param task 削除するユーザーの情報
	 */
	void delete(Task task);

	/**
	 * ユーザーの検索
	 * 
	 * @return 入力した情報に一致したユーザーの情報
	 * 
	 */
	List<Task> search(Task task);
}


Task.java

package com.example.demo.entity;

import lombok.Data;

@Data
public class Task {

	private int taskId;
	private String task;
	private int manHours;
    private String already;

    public int getTaskId() {
        return taskId;
    }

    public String getTask() {
        return task;
    }

    public int getManHours() {
        return manHours;
    }

    public void setTaskId(int taskId) {
        this.taskId = taskId;
    }

    public void setManHours(int manHours) {
        this.manHours = manHours;
    }

    public String getAlready() {
        return already;
    }

    public void setAlready(String already) {
        this.already = already;
    }

    public void setTask(String task) {
        this.task = task;
    }

}


schema.sql

DROP TABLE IF EXISTS TASK;

CREATE TABLE TASK (
  ID INT AUTO_INCREMENT,
  TASK VARCHAR(50),
  MANHOURS INT,
  ALREADY BOOLEAN NOT NULL DEFAULT 0,
  PRIMARY KEY(ID)
);


index.html

<!DOCTYPE html>
<html lang="jp" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a th:href="@{/insert}" >タスク追加</a>
	<a th:href="@{/update}" >タスク変更</a>
	<a th:href="@{/delete}" >タスク削除</a>
	<h1>Tasks</h1>
	<form th:action="@{/search}" method="get">
		<input type="text" name="task" th:value="${searchWord}">
		<input type="submit" value="検索"> 
	</form>
	<form th:action="@{/search}" method="get">
		<input type="radio" name="already" value="all" th:checked="${search == 'all'}">すべて
		<input type="radio" name="already" value="false" th:checked="${search == 'false'}">未
		<input type="radio" name="already" value="true" th:checked="${search == 'true'}">済
		<input type="submit" value="検索"> 
	</form>
	<table border="1">
		<thead>
			<tr>
				<th>ID</th>
				<th>タスク</th>
				<th>工数</th>
				<th>済</th>
				<th></th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="task : ${tasks}">
				<form action="/done" method="post">
					<td th:text="${task.taskId}"></td>
					<input name="taskId" th:value="${task.taskId}" type="hidden">
					<td th:text="${task.task}"></td>
					<td th:text="${task.manHours}"></td>
					<block th:if="${task.already}">
						<td><input name="already" value="done" type="checkbox" checked></td>
					</block>
					<block th:if="${!task.already}">
						<td><input name="already" value="done" type="checkbox"></td>
					</block>
					<td><input type="submit" value="更新"></td>
				</form>
			</tr>
		</tbody>
	</table>
</body>
</html>


insertTask.html

<!DOCTYPE html>
<html lang="jp" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Insert Task</h1>
	<form th:action="@{/confirmInsert}" method="post">
		<input name="task" type="text">
		<input name="manHours" type="number">
		<input type="submit" value="送信">
	</form>
</body>
</html>


updateTask.html

<!DOCTYPE html>
<html lang="jp" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Update Task</h1>
	<form th:action="@{/confirmUpdate}" method="post">
		<input name="taskId" type="text">
		<input name="task" type="text">
		<input name="manHours" type="number">
		<input type="submit" value="送信">
	</form>
</body>
</html>


deleteTask.html

<!DOCTYPE html>
<html lang="jp" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Delete Task</h1>
	<form th:action="@{/confirmDelete}" method="post">
		<input name="taskId" type="text">
		<input type="submit" value="送信">
	</form>
</body>
</html>




おまけ

上記のコードを用いたときのUIはこんな感じです。

今回作ったTodoリスト


この記事が気に入ったらサポートをしてみませんか?