Hello, this time by pressing the button TODO of completion ⇄ incomplete we want to implement the ability to switch.
1: Brief description of MVC 2: I want to make a template with Spring Initializr and make a Hello world 3: Save temporary data in MySQL-> Get all-> Display on top 4: Implementation of posting function 5: Switch the TODO display (here and now)
First of all, the flow of this process ・ Search and obtain TODO from id -Switch TODO status with true ⇄ false ・ Save TODO It will be.
So let's do the part to get TODO from id immediately.
java/com/example/todo/TodoService.java
public TodoEntity findTodoById(Long todoId) {
Optional<TodoEntity> todoResult = todoRepository.findById(todoId);
//Check for null
return todoResult.get();
}
It should be like this.
The Optional type used here is a type that explicitly indicates that the type contained in it may be null.
//nullチェックする I will leave the part that is marked as it will be done in a future article.
This time it is of type Optional
Now you can get TODO by id!
Next, we will implement the logic to switch the TODO state.
java/com/example/todo/TodoService.java
public void switchTodo(Long todoId) {
TodoEntity todoEntity = findTodoById(todoId);
todoEntity.setStatus(!todoEntity.isStatus());
todoRepository.save(todoEntity);
}
First, get the TODO by calling the previous function. And I switch the status, but by doing! TodoEntity.isStatus (), it is in the opposite state to the current state. (This is a common writing style when switching booleans.)
java/com/example/todo/TodoController.java
@PatchMapping("/toggle-status/{id}")
public String switchStatus(@PathVariable("id") Long todoId) {
todoService.switchTodo(todoId);
return "redirect:/top";
}
Let's write like this.
@PathVariable is an annotation that gets the {id} embedded in the URL.
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<!--Post form-->
<div class=" w-75 h-auto my-1 mx-auto pt-5">
<p class="pl-5">Create a new task</p>
<form th:action="@{/register}" th:object="${ToDoForm}" method="POST" class="container d-flex w-auto my-0 mx-auto">
<div class="w-100">
<label class="row">
<span class="col-2 text-center">ToDo name</span>
<input type="text" name="title" placeholder="Enter ToDo within 30 characters" class="col-9">
</label>
<label class="row my-0">
<span class="col-2 text-center">Deadline</span>
<input type="date" id="date" name="deadline" class="col-9 my-0">
</label>
</div>
<button class="btn btn-primary w-25 col-2 mr-3" type="submit">Add ToDo</button>
</form>
</div>
<div th:each="todo: ${todoList}" class=" w-75 h-25 my-1 mx-auto pt-5">
<div class="container">
<div class="row">
<div class="col-5 pl-5">
<p th:text="${todo.title}" class="mb-1"></p>
<p class="mb-1">Deadline:<span th:text="${todo.deadline}"></span></p>
<p class="mb-1">Creation date:<span th:text="${todo.createTime}"></span></p>
</div>
<div class="col-2 d-flex justify-content-start align-items-center px-0">
<a class="h-100 w-75 btn btn-info pt-4">
Edit
</a>
</div>
<!--〜〜〜〜〜〜 Contents to be added this time〜〜〜〜〜〜-->
<div th:if="${todo.status}" class="col-3 d-flex px-0">
<form th:action="@{/toggle-status/{id}(id=${todo.id})}" method="post" class="w-100 container d-flex my-0 mx-auto p-0 mr-2">
<input type="hidden" name="_method" value="patch">
<button type="submit" class="h-100 w-75 btn btn-success text-white">
Done
</button>
</form>
</div>
<div th:unless="${todo.status}" class="col-3 d-flex px-0">
<form th:action="@{/toggle-status/{id}(id=${todo.id})}" method="post" class="w-100 container d-flex my-0 mx-auto p-0 mr-2">
<input type="hidden" name="_method" value="patch">
<button type="submit" class="h-100 w-75 btn btn-danger text-white">
Incomplete
</button>
</form>
</div>
<!--〜〜〜〜〜〜 Contents to be added this time 〜〜〜〜〜〜-->
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>
th:if="${todo.status}"
However, this means that if the status is true, that is, it has been completed. It is displayed as completed in green.
Also, although method = "post" is set, @PatchMapping was used in the previous controller editing.
In fact, HTML doesn't support the ability to request a patch. So if you want to make a request with Patch, you need to devise something.
In Thymeleaf
<input type="hidden" name="_method" value="patch">
If you want to
in application.property
spring.mvc.hiddenmethod.filter.enabled=true
If you add, type = "hidden" can be used and Patch requests can be sent.
Contoller
package com.example.todo;
import com.example.todo.dao.TodoEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class TodoController {
private final TodoService todoService;
@GetMapping("/top")
public String top(Model model){
List<TodoEntity> todoEntityList = todoService.findAllTodo();
model.addAttribute("todoList", todoEntityList);
return "top";
}
@PostMapping("/register")
public String register(@ModelAttribute TodoForm formData) {
todoService.setTodo(formData);
return "redirect:/top";
}
@PatchMapping("/toggle-status/{id}")
public String switchStatus(@PathVariable("id") Long todoId) {
todoService.switchTodo(todoId);
return "redirect:/top";
}
}
Service
package com.example.todo;
import com.example.todo.dao.TodoEntity;
import com.example.todo.dao.TodoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class TodoService {
private final TodoRepository todoRepository;
public List<TodoEntity> findAllTodo() {
return todoRepository.findAll();
}
public void setTodo(TodoForm formData) {
TodoEntity todo = new TodoEntity();
todo.setTitle(formData.getTitle());
todo.setDeadline(formData.getDeadline());
todoRepository.save(todo);
}
public TodoEntity findTodoById(Long todoId) {
Optional<TodoEntity> todoResult = todoRepository.findById(todoId);
//Exception handling
return todoResult.get();
}
public void switchTodo(Long todoId) {
TodoEntity todoEntity = findTodoById(todoId);
todoEntity.setStatus(!todoEntity.isStatus());
todoRepository.save(todoEntity);
}
}
Entity
package com.example.todo.dao;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Entity
@Getter
@Setter
@Table(name="todo")
public class TodoEntity {
@Id
@Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="title")
private String title;
@Column(name="deadline")
private LocalDate deadline;
@Column(name="status")
private boolean status;
@CreationTimestamp
@Column(name="create_time")
private LocalDateTime createTime;
@UpdateTimestamp
@Column(name="update_time")
private LocalDateTime updateTime;
}
The current TODO app looks like the one above.
Recommended Posts