是你的思緒把我想的太美好
上一篇已經實作的TodoLidt [新增代辦事項]與[顯示代辦事項列表],今天要實作[更新代辦事項狀態]與[刪除代辦事項]
TodoService.java
Service在service層增加3個方法,分別是updateTodo
、findById
、deleteTodo
updateTodo
透過todoDao 的save()方法操作資料庫,deleteTodo
則透過todoDao 的deleteById(id)方法刪除資料庫物件。findById
可以先確定資料庫是否有這筆值,再進行更新或刪除資料。
public Todo updateTodo(Integer id,Todo todo) {
try {
Todo resTodo = findById(id);
Integer status = todo.getStatus();
resTodo.setStatus(status);
return todoDao.save(resTodo);
}catch (Exception exception) {
return null;
}
}
public Todo findById(Integer id) {
Todo todo = todoDao.findById(id).get();
return todo;
}
public Boolean deleteTodo(Integer id) {
try {
Todo resTodo = findById(id);
todoDao.deleteById(id);
return true;
} catch (Exception exception) {
return false;
}
}
TodoController.java
Controller新增@PutMapping("/todos/{id}")
更新資料的方法與@DeleteMapping("/todos/{id}")
刪除資料的方法,而參數中的@PathVariable
對應到url的 {id}
, @RequestBody
前端請求過來的body。
@ResponseBody
@PutMapping("/todos/{id}")
public void upadteTodo(@PathVariable Integer id, @RequestBody Todo todo) {
todoService.updateTodo(id ,todo);
}
@ResponseBody
@DeleteMapping("/todos/{id}")
public void deleteTodo(@PathVariable Integer id) {
todoService.deleteTodo(id);
}
更新todo項目的狀態時,會呼叫 js 的updateTodo()
利用fetch將資料HTT PUT至Controller做資料庫的更新,待成功後, 更新<li>
節點的css改成"checked,就可以看到代辦事項顯示綠色。
刪除todo項目時,會呼叫 js 的deleteTodo()
利用fetch將資料HTT DELETE至Controller做資料庫的移除,並將畫面代辦事項的節點移除。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" th:href="@{/style.css}">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h2>To Do List</h2>
<form class="header" th:action="@{/todos}" method="post" th:object="${todoObject}">
<input type="text" id="input" placeholder="New Item..." th:field="*{task}">
<button type="submit" class="addBtn">Add</button>
</form>
<ul th:each="todo: ${todolist}">
<li th:class="${todo.status} == 2 ? 'checked': '' "
th:onclick="'javascript:updateTodo(this,' + ${todo.id} + ','+${todo.status} +')'">
<span th:text="${todo.task}"></span>
<span class="close" th:onclick="'javascript:deleteTodo(event,this,' + ${todo.id} + ')'">x</span>
</li>
</ul>
</div>
<script>
const updateTodo = (element, id, status) => {
console.log("status", status);
const notDone = 1;
const done = 2;
const data = {
status: status === done ? notDone : done
}
fetch('todos/'+ id, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
}).then(function(response) {
if (status === done) {
element.classList.remove("checked");
} else {
element.classList.add("checked");
}
})
location.reload();
}
const deleteTodo = (event, element, id) => {
event.stopPropagation();
fetch('todos/'+ id, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
}).then(function(response) {
element.parentNode.parentNode.parentNode.removeChild(element.parentNode.parentNode);
})
}
</script>
</body>
</html>
在實作的過程中有遇到一些問題,以下條列遇到的問題以及該如何解決。問題一
我透過POST提交了表單。提交了表單後,重新刷新頁面時,瀏覽器會詢問「確認重新提交表單」按確定之後就會重新POST /todos一模一樣的內容,這樣畫面列表會多一列,Web表單通過HTTP POST請求提交給server而刷新頁面時會導致內容重複提交,可以採取Post / Redirect / Get 設計模式,為的是轉換POST請求,避免二次提交。
要在TodoController.java
檔案的createTodo()
做一個修正
原本:
@PostMapping("/todos")
public String createTodo(@ModelAttribute Todo todo, Model model) {
Iterable<Todo> allTodoList = todoService.createTodo(todo);
Todo emptyTodo = new Todo();
model.addAttribute("todolist", allTodoList);
model.addAttribute("todoObject", emptyTodo);
return "todolist";
}
改成:
@PostMapping("/todos")
public String createTodo(@ModelAttribute Todo todo, Model model) {
Iterable<Todo> allTodoList = todoService.createTodo(todo);
Todo emptyTodo = new Todo();
model.addAttribute("todolist", allTodoList);
model.addAttribute("todoObject", emptyTodo);
return "redirect:/todos";
}
要將POST的請求完後,去重新Redirect到/todos
形成GET /todos,讓畫面重新取值。
今天的實作有點卡住了,加上趕趕的情形下,不太能靜下心,有幾個問題待釐清,會再更新此篇文章,讓學習更加完整。
雖然遇到問題在所難免,有點灰心的是,基礎觀念在一開始就沒有弄清楚,問題出現時,無從判斷起,今天晚晚回家時,室友們的溫暖歌聲治癒了我現在這種無力感
說到"基礎觀念在一開始就沒有弄清楚"這跟我學習剪片狀況很像,但我相信狀況會越來越好的!
學習永無止盡,願意挑戰就是一件很值得欽佩的事了~
謝謝你的鼓勵:))
透過不斷的學習探索,會漸漸找到節奏的
妳好,跟著妳實作的過程中,不知道我理解有沒有錯
似乎沒有看到setStatus為2的地方
目前都是null的狀態
在controller的updateTodo方法中
我加入了todo.setStatus(2)
DB這邊才會把status狀態update為2
你好:
很感謝您提出疑問,我嘗試理解一下您提出的問題,
你敘述到:沒有看到setStatus為2的地方,需要在controller裡將todo.setStatus(2)才能將狀態改為2。
這是一支 update todo 的api
api的格式如下:
- Request
PUT
url: /todos/{id}
body: {status:2}
所以前端(template)js用fetch 呼叫api時,會在body裡放{status: 2},傳至後端,並在TodoService.java
的updateTodo()
方法處理,將資料庫這筆資料的status設為前端傳進來的值,如下:
Integer status = todo.getStatus();
resTodo.setStatus(status);
前端template裡js的部份代碼
const data = {
status: status === done ? notDone : done
}
fetch('todos/'+ id, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
}).then(function(response) {
if (status === done) {
element.classList.remove("checked");
} else {
element.classList.add("checked");
}
})
希望這樣解釋有解決你的疑問。
謝謝妳~解決了!