✅ 템플릿
삭제버튼
✅ 서비스
delete 메소드(GETMAPPING)
✅ 컨트롤러
삭제버튼과 매핑
✅ 수정버튼 우측에 삭제버튼을 추가해보자!
<a href="javascript:void(0);" th:data-uri="@{|/question/delete/${question.id}|}"
class="delete badge rounded-pill bg-dark text-white" sec:authorize="isAuthenticated()"
th:if="${question.author != null and #authentication.getPrincipal().getUsername() == question.author.username}"
th:text="삭제"></a>
🔴 수정 버튼 : th:href="@{|/question/modify/${question.id}|}"
🔵 삭제 버튼 : href="javascript:void(0);" th:data-uri="@{|/question/delete/${question.id}|}"
삭제 버튼은 수정 버튼과는 달리 href 속성 값을 javascript:void(0)
로 설정했다. 그리고 삭제를 실행할 URL을 얻기 위해 th:data-uri
속성을 추가하고, <삭제> 버튼이 눌리는 이벤트를 확인할 수 있도록 class 속성에 "delete" 항목을 추가해 주었다.
data-uri 속성은 클릭 이벤트 발생시 this.dataset.uri와 같이 사용하여 그 값을 얻을 수 있다.
why? href에 삭제 URL을 직접 사용하지 않는 이유?
버튼을 클릭했을 때 "정말로 삭제하시겠습니까?"와 같은 확인 절차가 필요하기 때문에
✅ 삭제 버튼을 누르면 "정말로 삭제하시겠습니까?"라는 확인창이 뜨는 자바스크립트 추가하기!
<!-- 가장 아래에 <script>엘리먼트를 삽입한다 -->
<script layout:fragment="script" type='text/javascript'>
const delete_elements = document.getElementsByClassName("delete");
Array.from(delete_elements).forEach(function(element) {
element.addEventListener('click', function() {
if(confirm("정말로 삭제하시겠습니까?")) {
location.href = this.dataset.uri;
};
});
});
</script>
<!-- 가장 아래에 <script>엘리먼트를 삽입한다 -->
</html>
delete라는 클래스를 포함하는 컴포넌트를 클릭하면 "정말로 삭제하시겠습니까?"라는 질문을 하고, true일 때 data-uri(@{|/question/delete/${question.id}|}
)를 호출 하고 false일때는 아무런 일도 발생하지 않는다.
✅ 가장 하단에 script 블록 구현
<!doctype html>
<html lang="ko">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" th:href="@{/bootstrap.min.css}">
<!-- sbb CSS -->
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<title>Hello, sbb!</title>
</head>
<body>
<!-- 기본 템플릿 안에 삽입될 내용 Start -->
<nav th:replace="~{navbar :: navbarFragment}"></nav>
<th:block layout:fragment="content"></th:block>
<!-- 기본 템플릿 안에 삽입될 내용 End -->
<script th:src="@{/bootstrap.min.js}"></script>
<th:block layout:fragment="script"></th:block>
</body>
</html>
✅ 추가 : <th:block layout:fragment="script"></th:block>
가장 아래에 엘리먼트를 추가했다. 왜냐하면 화면 렌더링이 완료된 후에 자바스크립트가 실행되기 때문이다. 화면 렌더링이 완료되지 않은 상태에서 자바스크립트를 실행하면 오류가 발생할수도 있고 화면 로딩이 지연되는 문제가 발생할 수도 있다.
✅ delete 메소드 추가
public void delete(Question question) {
this.questionRepository.delete(question);
}
✅ delete 메소드 추가
@PreAuthorize("isAuthenticated()")
@GetMapping("/delete/{id}")
public String questionDelete(Principal principal, @PathVariable("id") Integer id) {
// id를 통해 질문정보를 저장한다.
Question question = this.questionService.getQuestion(id);
// 질문의 작성자의 이름과 접속한 객체의 이름이 동일하지 않으면 에러 발생
if(!question.getAuthor().getUsername().equals(principal.getName())) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "삭제권한이 없습니다.");
}
// 작성자와 접속한 객체가 동일하면 삭제메소드 실행
this.questionService.delete(question);
return "redirect:/"; // 루트페이지로 리다이렉트
}
삭제 버튼이 생성되었다!
"정말로 삭제하시겠습니까?" 팝업창이 생성된다! 확인을 눌러보자!
삭제되었고, 루트페이지로 리다이렉트 된다!
✅ 답변 수정버튼 우측에 삭제버튼을 추가해보자!
<a href="javascript:void(0);" th:data-uri="@{|/answer/delete/${answer.id}|}"
class="delete badge rounded-pill bg-dark text-white"
sec:authorize="isAuthenticated()"
th:if="${answer.author != null and #authentication.getPrincipal().getUsername() == answer.author.username}"
th:text="삭제"></a>
매핑 주소를 제외하고 질문 삭제 버튼과 유사하다.
✅ delete 메소드 추가
public void delete(Answer answer) {
this.answerRepository.delete(answer);
}
질문 delete메소드와 유사하다
✅ delete 메소드 추가
@PreAuthorize("isAuthenticated()")
@GetMapping("/delete/{id}")
public String answerDelete(Principal principal, @PathVariable("id") Integer id) {
// 입력받은 id로 답변을 조회한 뒤 저장한다.
Answer answer = this.answerService.getAnswer(id);
// 현재 uesr와 답변의 작성자가 동일하지 않을경우 예외 발생
if (!answer.getAuthor().getUsername().equals(principal.getName())) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "삭제권한이 없습니다.");
}
// 동일할 경우 delete 메소드 실행
this.answerService.delete(answer);
// 삭제하게 된 후 현재 질문 상세 페이지로 리다이렉트한다.
return String.format("redirect:/question/detail/%s", answer.getQuestion().getId());
}
삭제 버튼이 생성되었다!
"정말로 삭제하시겠습니까?" 팝업창이 생성된다! 확인을 눌러보자!
삭제되었고, 상세페이지로 리다이렉트 된다!
✅ 자바 스크립트를 통해 click event 발생 시키기
✅ layout 상속
✅ 자바 스크립트 click event 공부하기
✅ layout 상속 복습