📂 TodoController.java
@Controller
@RequestMapping("/todo")
@RequiredArgsConstructor
public class TodoController {
private final TodoService todoService;
@GetMapping("")
public void listGET(Model model) {
model.addAttribute("list", todoService.getList());
}
@PostMapping("/register")
public String registerPOST(TodoDTO todoDTO) {
todoService.register(todoDTO);
return "redirect:/todo";
}
@PostMapping("/remove")
public String removePOST(Long tno) {
todoService.remove(tno);
return "redirect:/todo";
}
@PostMapping("/check")
public String checkPOST(TodoDTO todoDTO) {
todoService.finish(todoDTO);
return "redirect:/todo";
}
}
유의해야 할 점
- 간단한 프로젝트이므로 REST 방식을 사용하여 비동기 전송을 사용하는 대신, 행동을 수행할 때마다
redirect를 이용하여 새로고침 효과가 나도록 했다.@RequiredArgsConstructor:private final과 함게 사용해 Service 객체를 컨트롤러에서 사용할 수 있도록 주입한다(생성자 주입)
📂 todo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/resources/style.css">
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,700i"
rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>Insert title here</title>
</head>
<body>
<div style="position: relative">
<div class="container">
<div class="card card-white">
<div class="card-body">
<input type="text" class="form-control add-task"
placeholder="New Task...">
<ul class="nav nav-pills todo-nav">
<li role="presentation" class="nav-item all-task active"><a
href="#" class="nav-link">All</a></li>
<li role="presentation" class="nav-item active-task"><a
href="#" class="nav-link">Active</a></li>
<li role="presentation" class="nav-item completed-task"><a
href="#" class="nav-link">Completed</a></li>
</ul>
<div class="todo-list">
<c:forEach items="${list}" var="dto">
<div class="todo-item jumbotron ${dto.finished?'complete':'' }"
data-num="${dto.tno }">
<div class="checker">
<span class=""> <input type="checkbox"
${dto.finished?"checked":"" }></span>
</div>
<span><c:out value="${dto.content }" /></span> <a
class="float-right remove-todo-item"><i
class="fa-solid fa-xmark"></i></a>
</div>
</c:forEach>
</div>
</div>
</div>
<form id="todoForm" method="post">
</form>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="/resources/script.js"></script>
<script>
$(document).ready(function() {
//등록
$(".add-task").keypress(function (e) {
if ((e.which == 13)&&(!$(this).val().length == 0)) {
const text = $(this).val();
const textInput = $("<input type='hidden' name='content' value='" + text +"'/>");
$("#todoForm").append(textInput);
$("form").attr("action", "/todo/register").submit();
} else if(e.which == 13) {
alert('Please enter new task');
}
})
//완료or완료취소
$("input[type=checkbox]").change(function() {
const tno = $(this).closest(".todo-item").data("num");
const complete = !$(this).closest(".todo-item").hasClass("complete");
const tnoInput = $("<input type='hidden' name='tno' value='" + tno +"'/>");
const finishedInput = $("<input type='hidden' name='finished' value='" + complete +"'/>");
$("#todoForm").append(tnoInput).append(finishedInput);
$("form").attr("action", "/todo/check").submit();
})
//삭제
$(".remove-todo-item").click(function() {
const tno = $(this).closest(".todo-item").data("num");
const tnoInput = $("<input type='hidden' name='tno' value='" + tno +"'/>");
$("#todoForm").append(tnoInput);
$("#todoForm").attr("action", "/todo/remove").submit();
})
})
</script>
</body>
</html>
유의할 점
- jsp에서 List를 forEach문으로 출력하기 위해
jstl을 사용할 수 있는 태그를 맨 위에 삽입했다.- 각 작업이 수행될 때마다
form 태그에 적절한input 태그를 집어넣어 컨트롤러로 알맞은 값이 갈 수 있도록 했다.



정상적으로 데이터 삽입/삭제/완료 작업이 이루어지는 것을 확인할 수 있다.