@GetMapping("detail")
public String todoDetail(@RequestParam("todoNo") int todoNo, Model model, RedirectAttributes ra) {
Todo todo = service.todoDetail(todoNo);
String path = null;
if(todo != null) { // 조회 결과 있을 경우
// forward : todo/detail
path = "todo/detail";
// request scope 값 세팅
model.addAttribute("todo", todo);
} else { // 조회 결과 없을 경우
path = "redirect:/"; // 메인 페이지로 리다이렉트
// RedirectAttributes :
// - 리다이렉트 시 데이터를 request scope -> (잠시) session scope로
// 전달할 수 있는 객체(응답 후 reqeust scope로 복귀)
ra.addFlashAttribute("message", "해당 할 일이 존재하지 않습니다.");
}
return path;
}
// 할 일 상세 조회
@Override
public Todo todoDetail(int todoNo) {
return mapper.todoDetail(todoNo);
}
<!-- 할 일 상세 조회 -->
<select id="todoDetail" parameterType="_int" resultType="Todo">
SELECT TODO_NO, TODO_TITLE, TODO_CONTENT, COMPLETE,
TO_CHAR(REG_DATE, 'YYYY-MM-DD HH24:MI:SS') REG_DATE
FROM TB_TODO
WHERE TODO_NO = ${todoNo}
</select>


/** 완료 여부 변경
* @param todo : 커맨드 객체 (@ModelAttribute 생략)
* - todoNo, complete 두 필드가 세팅된 상태
* @return redirect:detail?todoNo=할 일 번호(상대경로)
*/
@GetMapping("changeComplete")
public String changeComplete(Todo todo, RedirectAttributes ra) {
// 변경 서비스 호출
int result = service.changeComplete(todo);
// 변경 성공 시 : 변경 성공 메시지
// 변경 실패 시 : 변공 실패 메시지
String message = null;
if(result > 0) message = "변경 성공!!";
else message = "변경 실패..";
// 현재 요청 주소 : /todo/changeComplete
// 원하는 응답 주소 : /todo/detail
ra.addFlashAttribute("message", message);
return "redirect:detail?todoNo=" + todo.getTodoNo();
}
<!-- 완료 여부 변경 -->
<update id="changeComplete" parameterType="Todo">
UPDATE TB_TODO SET
COMPLETE = #{complete}
WHERE TODO_NO = ${todoNo}
</update>
// 완료 여부 변경 버튼 동작
const completeBtn = document.querySelector(".complete-btn");
completeBtn.addEventListener("click", (e) => {
const todoNo = e.target.dataset.todoNo;
// Y <-> N 변경
let complete = e.target.innerText; // 버튼 속성 중 th:text="${todo.complete}" -> 기존 완료 여부 값 얻어오기
complete = (complete === 'Y') ? 'N' : 'Y';
// 완료 여부 수정 요청하기
location.href
= `/todo/changeComplete?todoNo=${todoNo}&complete=${complete}`;
});
th:data-todo-no="${todo.todoNo}"
e.target.dataset.todoNo;


// 목록으로 버튼 동작
const goToList = document.querySelector("#goToList");
goToList.addEventListener("click", () => {
location.href = "/"; // 메인 페이지 요청
});

/** 수정 화면 전환
* @return
*/
@GetMapping("update")
public String todoUpdate(@RequestParam("todoNo") int todoNo, Model model) {
// 상세 조회 서비스 호출 -> 수정 화면에 출력할 이전 내용
Todo todo = service.todoDetail(todoNo);
model.addAttribute("todo", todo);
return "todo/update";
}
/** 할 일 수정
* @param todo : 커맨드 객체(전달 받은 파라미터가 자동으로 DTO의 필드에 세팅된 객체
* @param ra
* @return
*/
@PostMapping("update")
public String todoUpdate(Todo todo, RedirectAttributes ra) {
// 수정 서비스 호출
int result = service.todoUpdate(todo);
String path = "redirect:";
String message = null;
if(result > 0) {
// 상세 조회 페이지로 리다이렉트
path += "/todo/detail?todoNo=" + todo.getTodoNo();
message = "수정 성공!!";
} else {
path += "/todo/update?todoNo=" + todo.getTodoNo();
message = "수정 실패..";
}
ra.addFlashAttribute("message", message);
return path;
}
<!-- 할 일 수정 -->
<!-- 파라미터가 DTO인 경우 : #{필드명}, ${필드명} -->
<!-- 파마미터가 Map인 경우 : #{key}, ${key} -->
<update id="todoUpdate" parameterType="Todo">
UPDATE TB_TODO SET
TODO_TITLE = #{todoTitle},
TODO_CONTENT = #{todoContent}
WHERE TODO_NO = ${todoNo}
</update>

// 수정 버튼 동작
const updateBtn = document.querySelector("#updateBtn");
updateBtn.addEventListener("click", e => {
// data-todo-no 얻어오기
const todoNo = e.target.dataset.todoNo;
location.href = `/todo/update?todoNo=${todoNo}`;
});


/** 할 일 삭제
* @param todoNo : 삭제할 할 일 번호
* @param ra
* @return 메인페이지 / 상세페이지
*/
@GetMapping("delete")
public String todoDelete(@RequestParam("todoNo") int todoNo, RedirectAttributes ra) {
int result = service.todoDelete(todoNo);
String path = null;
String message = null;
if(result > 0) { // 성공
path = "/";
message = "삭제 성공";
} else { // 실패
path = "/todo/detail?todoNo=" + todoNo;
message = "삭제 실패";
}
ra.addFlashAttribute("message", message);
return "redirect:" + path;
}
<!-- 할 일 삭제 -->
<delete id="todoDelete" parameterType="_int">
DELETE FROM TB_TODO
WHERE TODO_NO = ${todoNo}
</delete>
// 삭제 버튼 동작
const deleteBtn = document.querySelector("#deleteBtn");
deleteBtn.addEventListener("click", e => {
if(confirm("정말 삭제하시겠습니까?")) {
location.href = `/todo/delete?todoNo=${e.target.dataset.todoNo}`;
}
});

