SpringBoot 프로젝트

Spring Boot - Q&A 페이지 구현하기 (2)

orin602 2024. 11. 25. 13:09

이번 글에서는 질문 작성에 이어서 작성한 질문의 수정 및 삭제에 대해서 포스팅 하겠습니다.

부족하더라도 좋게 봐주세요 :)

 

1. Html - 수정, 삭제 버튼

<!-- 수정 버튼 -->
<button class="qna-edit-btn" type="button" th:attr="data-qna_seq=${qna.qna_seq},
    data-qna_writer=${qna.member.id}, data-answer_status=${qna.answer_status},
    data-qna_viewer=${loginUser.id}" onclick="editQna(this)">수정</button>
<!-- 삭제 버튼 -->
<button class="qna-delete-btn" type="button" th:attr="data-qna_seq=${qna.qna_seq},
    data-qna_writer=${qna.member.id}, data-qna_viewer=${loginUser.id}"
    onclick="deleteQna(this)">삭제</button>

 

  • data-qna_seq=${qna.qna_seq}  : 이 속성은 현재 질문의 고유 시퀀스 번호 (qna.qna_seq)를 저장합니다.
  • data-qna_writer=${qna.member.id} : 질문 작성자의 ID (qna.member.id)를 저장합니다.
  • data-answer_status=${qna.answer_status} : 답변 상태 (qna.answer_status)를 저장합니다.
  • data-qna_viewer=${loginUser.id} : 현재 로그인한 사용자의 ID (loginUser.id)를 저장합니다.

 

수정, 삭제 버튼

 

2. JavaScript - 수정,삭제 버튼 함수 작성

 - 수정 함수

function editQna(button) {
	var qna_seq = button.getAttribute('data-qna_seq');
    var qnaWriter = button.getAttribute('data-qna_writer');
    var answer_status = button.getAttribute('data-answer_status');
    var qnaViewer = button.getAttribute('data-qna_viewer');
    
    if (qnaWriter === qnaViewer && answer_status === '0') {
        // 작성자이면서 답변이 달리지 않은 경우 수정 가능
        window.location.href = '/qnaEdit?qna_seq=' + qna_seq;
    } else if (qnaWriter !== qnaViewer) {
        // 작성자가 아닌 경우 경고 메시지
        swal.fire({
            title: 'QnA 수정 불가',
            text: '작성자만 수정이 가능합니다.',
            icon: 'warning',
            confirmButtonText: '확인'
        });
    } else if (answer_status === '1') {
        // 답변 완료된 경우 수정 불가 메시지
        swal.fire({
            title: 'QnA 수정 불가',
            text: '답변이 완료된 질문은 수정할 수 없습니다.',
            icon: 'error',
            confirmButtonText: '확인'
        });
    }
}
  • button.getAttribute(...); 를 통해 필요한 각 속성 값을 가져온다.
  • 작성자이며 답변이 없는 경우 (qnaWriter === qnaViewer && answer_status === '0') : 수정 가능 상태이므로, 해당 질문의 수정 페이지window.location.href = '/qnaEdit?qna_seq=' + qna_seq;로 이동합니다. 
  • 작성자가 아닌 경우 else if (qnaWriter !== qnaViewer) : 수정 권한이 없으므로 경고 메시지를 표시합니다.
  • 답변이 완료된 경우 else if (answer_status === '1') : 답변이 달린 질문은 수정할 수 없도록 오류 메시지를 표시합니다.

 - 삭제 함수

function deleteQna(button) {
	var qna_seq = button.getAttribute('data-qna_seq');
    var qnaWriter = button.getAttribute('data-qna_writer');
    var qnaViewer = button.getAttribute('data-qna_viewer');
    
    if (qnaWriter === qnaViewer) {
        swal.fire({
            title: 'QnA 삭제',
            text: '정말로 삭제하시겠습니까?',
            icon: 'warning',
            showCancelButton: true,
            confirmButtonText: '삭제',
            cancelButtonText: '취소'
        }).then((result) => {
            if (result.isConfirmed) {
                window.location.href = '/deleteQna?qna_seq=' + qna_seq;
            }
        });
    } else {
        swal.fire({
            title: '삭제 불가',
            text: '작성자만 삭제할 수 있습니다.',
            icon: 'error',
            confirmButtonText: '확인'
        });
    }
}
  • button.getAttribute(...); 를 통해 필요한 각 속성 값을 가져온다.
  • 작성자일 경우 (qnaWriter === qnaViewer) : 삭제 권한이 있으므로 SweetAlert2를 통해 경고창을 띄웁니다. 확인 버튼을 누르면 isConfirmed가 true로 설정되며, window.location.href = '/deleteQna?qna_seq=' + qna_seq; 으로 리디렉션됩니다.
  • 작성자가 아닌 경우 : 삭제 권한이 없으므로 오류 메시지를 표시합니다.

3. Controller 구현

 - 질문 수정

@GetMapping("/qnaEdit")
public String qnaEditView(@RequestParam("qna_seq") int qna_seq, Model model,
                            HttpSession session) {
    Member loginUser = (Member)session.getAttribute("loginUser");

    Qna qna = qnaService.findQnaBySeq(qna_seq);

    if(loginUser == null) {
        model.addAttribute("message", "로그인 페이지로 이동");
        model.addAttribute("text", "질문 수정은 로그인 후 이용 가능합니다.");
        model.addAttribute("messageType", "info");

        return "login/login";
    }
    model.addAttribute("qna", qna);

    return "customer/qna_edit";
}
  • @RequestParam("qna_seq") int qna_seq : URL에서 qna_seq 파라미터를 받아 qna_seq 변수에 저장합니다.
  • Qna qna = qnaService.findQnaBySeq(qna_seq); : qna_seq에 해당하는 질문 데이터를 조회합니다.
  • model.addAttribute("qna", qna); : 조회된 Qna 객체를 model에 추가합니다.
  • return "customer/qna_edit"; : qna_edit.html 파일을 렌더링합니다.

 -- 렌더링 할 qna_edit.html

<div class="qna_edit_container">
	<h2>QnA 수정</h2>
	<form class="qna_edit_form" id="qna_edit_form" method="post">
		<input type="hidden" name="qna_seq" th:value="${qna.qna_seq}" />
		<label>제목</label>
		<input type="text" name="title" id="title" th:value="${qna.title}" />
		<label>내용</label>
		<textarea name="content" id="content" th:text="${qna.content}"></textarea>
	</form>
	<button class="before-page-btn" type="button" onclick="window.history.back()">이전 페이지</button>
	<button class="qna_update_btn" type="button" onclick="qna_update()">질문 수정</button>
</div>

 

 -- qna_update() 함수 작성

function qna_update() {
	if($("#title").val() == "") {
		swal.fire({
			title: '제목을 입력해주세요.',
			text: '제목은 필수 입력 항목입니다.',
			icon: 'warning',
			confirmButtonText: '확인'
		});
		$("#title").focus();
		return false;
	} else if($("#content").val() == "") {
		swal.fire({
			title: '내용을 입력해주세요.',
			text: '내용은 필수 입력 항목 입니다.',
			icon: 'warning',
			confirmButtonText: '확인'
		});
		$("#content").focus();
		return false;
	} else {
		swal.fire({
			title: '질문 수정 성공!',
			text: '질의응답 페이지로 이동합니다.',
			icon: 'success',
			confirmButtonText: '확인'
		}).then((result) => {
			if(result.isConfirmed) {
				$("#qna_edit_form").attr("action", "/qna-edit-action").submit();
			}
		});
	}
}

각 필수 입력 항목(제목, 내용)을 입력했는지 확인하고, 모두 입력되어 있을 때는 "질문 수정 성공!" 이라는 알림창이 나옵니다. 알림창의 확인을 클릭 하면 $("#qna_edit_form").attr("action", "/qna-edit-action").submit(); 를 통해 controller에 url을 요청합니다.

 -- controller 구현

@PostMapping("/qna-edit-action")
public String qnaUpdateAction(HttpSession session, Model model, Qna qna,
        @RequestParam("qna_seq") int qna_seq) {
    Member loginUser = (Member) session.getAttribute("loginUser");

    Qna updateQna = qnaService.findQnaBySeq(qna_seq);

    if(loginUser == null) {
        model.addAttribute("message", "로그인 페이지로 이동");
        model.addAttribute("text", "질문 수정은 로그인 후 이용 가능합니다.");
        model.addAttribute("messageType", "info");

        return "login/login";
    }
    updateQna.setTitle(qna.getTitle());
    updateQna.setContent(qna.getContent());
    qnaService.updateQna(updateQna);

    return "redirect:/myqna";
}
  • qnaService.findQnaBySeq(qna_seq); : qna_seq에 해당하는 기존 질문 데이터를 데이터베이스에서 조회하고, 이를 updateQna객체에 저장합니다.
  • qna.getTitle() , qna.getContent() : 폼에서 전달된 수정된 제목과 내용을 받아옵니다.
  • updateQna.setTitle(qna.getTitle()); , updateQna.setContent(qna.getContent()); : 제목과 내용을 수정된 데이터로 업데이트합니다.
  • qnaService.updateQna(updateQna); : updateQna 객체를 데이터베이스에 저장(업데이트)합니다.

수정 테스트

 

- 질문 삭제

@GetMapping("/deleteQna")
public String deleteQna(@RequestParam("qna_seq") int qna_seq, Model model, HttpSession session) {
    Member loginUser = (Member) session.getAttribute("loginUser");

    if (loginUser == null) {
        model.addAttribute("message", "로그인 페이지로 이동");
        model.addAttribute("text", "질문 삭제는 로그인 후 이용 가능합니다.");
        model.addAttribute("messageType", "info");
        return "login/login";
    }

    try {
        // QnA 삭제 메소드 호출
        qnaService.deleteQna(qna_seq); // qna_seq 전달
        model.addAttribute("message", "QnA가 성공적으로 삭제되었습니다.");
        model.addAttribute("messageType", "success");
    } catch (IllegalArgumentException e) {
        // 삭제 실패 시 메시지 처리
        model.addAttribute("message", e.getMessage());
        model.addAttribute("messageType", "error");
    }

    // 삭제 후 목록 페이지로 리다이렉트
    return "redirect:/myqna";
}

 

  • 로그인 상태인 경우, qnaService.deleteQna(qna_seq); 메서드를 호출하여 삭제 작업을 수행합니다. 삭제가 성공하면, model에 성공 메시지를 추가하여 사용자에게 삭제가 성공적으로 이루어졌음을 알립니다.
  • 삭제 과정에서 문제가 발생하면 IllegalArgumentException 예외가 발생할 수 있습니다. 예외가 발생하면, 해당 예외 메시지를 model에 에러 메시지로 추가하여 사용자에게 알립니다.
  • 모든 과정이 종료되면 return "redirect:/myqna"; 로 "내 QnA 목록" 페이지(/myqna)로 리다이렉트합니다.