Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

Spring BootでToDoアプリを作ってみた

$
0
0

こんな感じで作ってみた。

f:id:okazuki:20150720133735p:plain

画面はしょっぱいですが、TODOアプリです。

f:id:okazuki:20150720133842p:plain

pomの準備

とりあえずmavenでプロジェクトを作成したら、pomを編集します。お約束ですね。最近みないで打てるようになってきました。

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>okazuki</groupId><artifactId>todoapp</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>todoapp</name><url>http://maven.apache.org</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.2.5.RELEASE</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>9.4-1201-jdbc41</version></dependency></dependencies></project>

今回はPostgreSQLを使うのでそれのJDBCドライバも追加しています。

application.propertiesの編集

DBの接続関連の情報を追加してます。仮にtodoappという名前のDBにtodoappというユーザーでtodoappというパスワードでつなぐことにします。

spring.datasource.url=jdbc:postgresql://localhost:5432/todoapp
spring.datasource.username=todoapp
spring.datasource.password=todoapp
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true

DBの作成

PostgreSQLに適当にDBを作ります。上のDBを作ります。作成するテーブルは、こんな感じでさくっと。

CREATETABLE todoitems
(
  id serial NOTNULL,
  title text,
  done boolean,
  CONSTRAINT todoitems_pkey PRIMARY KEY (id)
)

idのserialは、todoitem_id_seqというシーケンスからとってくるようになります。(GUIで作ったらそうなった)

Entityの作成

JPAのEntityを作成します。eclipseって自動生成機能ってあるのかな…わからなかったので手書きしました。

package okazuki.todoapp.entities;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity@Table(name = "todoitems")
publicclass TodoItem {
    @Id@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "todoitems_id_seq")
    @SequenceGenerator(name = "todoitems_id_seq", sequenceName = "todoitems_id_seq")
    private Long id;
    private String title;
    private Boolean done;

    public Long getId() {
        return id;
    }

    publicvoid setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    publicvoid setTitle(String title) {
        this.title = title;
    }

    public Boolean getDone() {
        return done;
    }

    publicvoid setDone(Boolean done) {
        this.done = done;
    }

}

リポジトリの作成

今回はTODOが完了してるかしてないかというのを取得したいのでDoneプロパティで絞込できるようにメソッドをはやしたリポジトリを作成します。ここらへん便利ですね。Spring JPA

package okazuki.todoapp.repositories;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import okazuki.todoapp.entities.TodoItem;

publicinterface TodoItemRepository extends JpaRepository<TodoItem, Long> {
    public List<TodoItem> findByDoneOrderByTitleAsc(boolean done);
}

Controllerの作成

次にコントローラを作成します。初期表示、アイテムを完了にする、完了にしたものをもどす、新規に追加するの4つのメソッドを持っています。

package okazuki.todoapp.controllers;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import okazuki.todoapp.entities.TodoItem;
import okazuki.todoapp.forms.TodoItemForm;
import okazuki.todoapp.repositories.TodoItemRepository;

@Controllerpublicclass HomeController {

    @Autowired
    TodoItemRepository repository;
    
    @RequestMappingpublic String index(@ModelAttribute TodoItemForm todoItemForm, @RequestParam("isDone") Optional<Boolean> isDone) {
        todoItemForm.setDone(isDone.isPresent() ? isDone.get() : false);
        todoItemForm.setTodoItems(this.repository.findByDoneOrderByTitleAsc(todoItemForm.isDone()));
        return"index";
    }
    
    @RequestMapping(value = "/done", method = RequestMethod.POST)
    public String done(@RequestParam("id") long id) {
        TodoItem item = this.repository.findOne(id);
        item.setDone(true);
        this.repository.save(item);
        return"redirect:/?isDone=false";
    }
    
    @RequestMapping(value = "/restore", method = RequestMethod.POST)
    public String restore(@RequestParam("id") long id) {
        TodoItem item = this.repository.findOne(id);
        item.setDone(false);
        this.repository.save(item);
        return"redirect:/?isDone=true";
    }
    
    @RequestMapping(value = "/new", method = RequestMethod.POST)
    public String newItem(TodoItem item) {
        item.setDone(false);
        this.repository.save(item);
        return"redirect:/";
    }
    
}

TodoItemFormは、以下のようになっています。

package okazuki.todoapp.forms;

import java.util.List;

import okazuki.todoapp.entities.TodoItem;

publicclass TodoItemForm {
    privateboolean isDone;
    
    private List<TodoItem> todoItems;

    public List<TodoItem> getTodoItems() {
        return todoItems;
    }

    publicvoid setTodoItems(List<TodoItem> todoItems) {
        this.todoItems = todoItems;
    }

    publicboolean isDone() {
        return isDone;
    }

    publicvoid setDone(boolean isDone) {
        this.isDone = isDone;
    }

}

Viewの作成

最後にViewを作成します。見た目適当です。

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><metacharset="UTF-8"/><title>Insert title here</title></head><body><h2>Todo app</h2><a th:unless="${todoItemForm.done}" th:href="@{/?isDone=true}">完了したアイテムの表示</a><a th:if="${todoItemForm.done}" th:href="@{/?isDone=false}">TODOの表示</a><hr /><h3>TODOの追加</h3><formmethod="post" th:action="@{/new}"><inputtype="text"name="title" /><inputtype="submit"value="追加" /></form><h3>TODOリスト</h3><table><thead><tr><th>Title</th><th></th></tr></thead><tbody><tr th:each="todoItem : ${todoItemForm.todoItems}"><td th:text="${todoItem.title}">xxx</td><td><form th:unless="${todoItemForm.done}"method="post" th:action="@{/done}" th:object="${todoItem}"><inputtype="hidden"name="id" th:value="*{id}" /><inputtype="submit"value="Done" /></form><form th:if="${todoItemForm.done}"method="post" th:action="@{/restore}" th:object="${todoItem}"><inputtype="hidden"name="id" th:value="*{id}" /><inputtype="submit"value="Restore" /></form></td></tr></tbody></table></body></html>

これくらいの量のコードでCRUD(Dは厳密にいうと無いけど)の画面ができるって割といい感じじゃないですかね。


Viewing all articles
Browse latest Browse all 1387

Trending Articles