目次
Spring Boot と データベースマイグレーション (1/2) からの続きです。
メインアプリケーションの構築
メインの Spring Boot を使ったアプリケーションを構築します。 下のようにファイルを作成していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
demo/ `- src/ `- main/ |- kotlin/ | `- com/ | `- example/ | `- demo/ | |- domain/ | | `- task | | |- Task.kt | | `- TaskRepository.kt | |- presentation/ | | `- TaskController.kt | `- DemoApplication.kt `- resources/ |- application.properties `- templates/ `- task/ `- index.html |
設定の追加
application.properties
と DemoApplication
クラス を更新します。
データベースの接続設定を application.properties
に追加します
1 2 3 4 5 |
spring.datasource.url=jdbc:postgresql://localhost:5432/demo spring.datasource.username=developer spring.datasource.password=developer spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect |
タイムスタンプの自動更新を有効にするため、 アノテーション @EnableJpaAuditing
を DemoApplication
クラス に付与します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.example.demo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.data.jpa.repository.config.EnableJpaAuditing @SpringBootApplication @EnableJpaAuditing class DemoApplication fun main(args: Array<String>) { runApplication<DemoApplication>(*args) } |
エンティティの作成
データベースのレコードに対応するエンティティを作成します。 Task
クラス を domain/task/Task.kt
として作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.example.demo.domain.task import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate import org.springframework.data.jpa.domain.support.AuditingEntityListener import java.util.* import javax.persistence.* @Entity @EntityListeners(AuditingEntityListener::class) class Task { @Id @SequenceGenerator( name = "task_id_seq", sequenceName = "task_id_seq", allocationSize = 1 ) @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "task_id_seq" ) var id: Long? = null var name: String? = null @CreatedDate @Temporal(TemporalType.TIMESTAMP) @Column(nullable = false, updatable = false) var createdAt: Date? = null @LastModifiedDate @Temporal(TemporalType.TIMESTAMP) @Column(nullable = false, updatable = false) var updatedAt: Date? = null } |
@EntityListeners
, @CreateDate
および @LastModifiedDate
はタイムスタンプ自動更新のために追加しています。
リポジトリ作成
Task
エンティティ をデータベースから取得する TaskRepository
インターフェースを作成します。 ファイル domain/task/TaskRepository.kt
に記述します。
1 2 3 4 5 |
package com.example.demo.domain.task import org.springframework.data.jpa.repository.JpaRepository interface TaskRepository : JpaRepository<Task, Long> |
ビューテンプレートの作成
ビューテンプレート resources/templates/task/index.html
を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Sample Application</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootst rap/4.1.3/css/bootstrap.min.css" crossorigin="anonymous"> </head> <body> <header class="pos-f-t mb-2"> <nav class="navbar navbar-light bg-light"> <a th:href="@{/task}" class="navbar-brand"> Task List </a> </nav> </header> <main class="container"> <div class="row" th:if="${success}"> <div class="col"> <div class="alert alert-success" role="alert" th:text="${success}"></div> </div> </div> <div class="row" th:each="task : ${taskList}"> <div class="col"> <div class="d-flex"> <div class="p-2 w-100 align-self-center" th:text="${task.name}"> </div> <div class="p-2 flex-shrink-1 align-self-center"> <form th:object="${task}" th:action="@{/task/{id}(id=${task.id})}" th:method="delete"> <button class="btn btn-outline-danger btn-sm" type="submit"> X </button> </form> </div> </div> </div> </div> <hr> <div class="row"> <div class="col"> <form th:method="post" th:action="@{/task}" th:object="${newTask}"> <div class="form-group"> <input type="text" name="name" class="form-control" th:field="*{name}"> </div> <div class="form-group"> <button class="btn btn-primary btn-block" type="submit"> Submit </button> </div> </form> </div> </div> </main> </body> </html> |
コントローラ作成
コントローラを作成します。 ファイル presentation/task/TaskController.kt
を作成し、 TaskController
クラス を記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.example.demo.presentation.task import com.example.demo.domain.task.Task import com.example.demo.domain.task.TaskRepository import org.springframework.data.domain.Sort import org.springframework.stereotype.Controller import org.springframework.ui.ModelMap import org.springframework.web.bind.annotation.* import org.springframework.web.servlet.mvc.support.RedirectAttributes @Controller @RequestMapping("task") class TaskController( private val taskRepository: TaskRepository ) { @GetMapping fun list(modelMap: ModelMap): String { modelMap["taskList"] = taskRepository.findAll( Sort.by("id").descending() ) modelMap["newTask"] = Task() return "task/index" } @PostMapping fun create( attributes: RedirectAttributes, @ModelAttribute task: Task ): String { taskRepository.save(task) attributes.addFlashAttribute( "success", "The Task was successfully created." ) return "redirect:/task" } @DeleteMapping("{id}") fun delete( attributes: RedirectAttributes, @PathVariable id: Long ): String { taskRepository.deleteById(id) attributes.addFlashAttribute( "success", "The Task was successfully deleted." ) return "redirect:/task" } } |
アプリケーションの実行
コマンド ./gradlew bootrun
を実行して、 しばらくすると起動が完了します。 その後、 http://localhost:8080/task
にブラウザでアクセスすると確認できます。 画面からタスクを追加・削除できます。
このデモプロジェクトのコードは GitHub にあります。