gi_dor

목록 에서 해당글을 삭제 못하고 첫번째 글을 삭제한다고 ? 본문

First/Error

목록 에서 해당글을 삭제 못하고 첫번째 글을 삭제한다고 ?

기돌 2023. 7. 29. 17:57

 

  @PostMapping("faqRemove")
    public String remove(Integer faqNo,FaqDTO faqDTO,SearchCondition sc, Model m , RedirectAttributes rattr,@SessionAttribute int mbrId){
        try {

            faqDTO.setRegrId(mbrId);

            m.addAttribute("sc",sc);
            System.out.println("faqNo = " + faqNo);


            faqService.remove(faqNo,faqDTO.getRegrId());
            rattr.addFlashAttribute("msg","DEL_OK");
        } catch (Exception e) {
           e.printStackTrace();
            rattr.addFlashAttribute("msg","DEL_ERR");
        }
        return  "redirect:/bos/faqList";
    }

 

 

👀문제 

24번 글에 삭제 버튼을 누르면 ’삭제 하시겠습니까 ‘ 라는 메세지가 뜬후 맨위에 글인 8 번이삭제가 되고있다.

어떤 번호의 글을 삭제 하든 맨위에 글이 삭제가 되고 있다.

 

🤦‍♂️관련된 사실 수집 & 원인 추론

<%--
  Created by IntelliJ IDEA.
  User: Han
  Date: 2023-07-10
  Time: 오전 10:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>


<head>
  <style>
    @import url(${cssUrlBos}/cs/BOS_FaqList.scss);
  </style>
</head>

<div class = all-board>

  <div class="fb__bbs__header">
    <h3 class="title-t ty3 mb-30"><a href="<c:url value="/bos/faqlist"/>"> 관리자 FAQ 관리 </a></h3>
  </div>

  <form id="form" class="frm" action="" method="post">
    <div class="notice-list">FAQ 글 목록
      <%--    게시글 갯수 카운팅--%>
      <span class="notice_count">
                (총 ${ph.totalCnt}개)
       </span>
		  </div>

    <table class="table table-hover">

      <tr class="table-dark">
        <th scope="col">번호</th>
        <th scope="col">FAQ 종류</th>
        <th scope="col">제목</th>
        <th scope="col">글 등록 일자</th>
        <th scope="col"> 수정 </th>
        <th scope="col"> 삭제 </th>

      </tr>

      <c:forEach var="faqDTO" items="${list}">

        <input type="hidden" name="faqNo" value="${faqDTO.faqNo}">

        <tr class="table-light">
          <td scope="row">${faqDTO.faqNo}</td>        <%---공지사항 번호---%>
          <td><c:out value="${faqDTO.faqTpNm}"/></td>   <%---공지사항 타입---%>
          <td><a href = "<c:url value="/bos/faqRead${ph.sc.queryString}&faqNo=${faqDTO.faqNo}"/>"> ${faqDTO.title}</a></td> <%---공지사항 제목---%>


            <%---FAQ 등록날짜---%>
          <td><fmt:formatDate value="${faqDTO.regDttm}" pattern="yyyy-MM-dd" type="date"/></td>


          <td><button type="button" id="modifyBtn" class="modifyBtn">수 정</button></td>

          <td><button type="button" id="removeBtn" class="removeBtn">삭 제</button></td>


        </tr>
      </c:forEach>


    </table>


    <%--페이지 이동 페이지 핸들링--%>
    <%--  << <  1 2 3 4 5 6 7 8 9 10 > >>  --%>
    <br>


    <div id="devPageWrap">
      <div class="wrap-pagination">
        <c:if test="${ph.totalCnt==null || ph.totalCnt==0}">
          <div> 게시물이 없습니다.</div>
        </c:if>

        <c:if test="${ph.totalCnt!=null && ph.totalCnt!=0}">

          <c:if test="${ph.showFirst}">
            <a class="page" href="<c:url value='/bos/faqList${ph.sc.getQueryString(ph.beginPage)}'/>"><i class="fa-solid fa-angles-left"></i></a>
          </c:if>

          <c:if test="${ph.showPrev}">
            <a class="page"
               href="<c:url value='/bos/faqList${ph.sc.getQueryString(ph.beginPage-1)}'/>"><i class="fa-solid fa-angle-left"></i></a>
          </c:if>


          <c:forEach var="i" begin="${ph.beginPage}" end="${ph.endPage}">
            <a class="page ${i==ph.sc.page? "paging-active" : ""}"
               href="<c:url value='/bos/faqList${ph.sc.getQueryString(i)}'/>">${i}</a>
          </c:forEach>


          <c:if test="${ph.showNext}">
            <a class="page" href="<c:url value='/bos/faqList${ph.sc.getQueryString(ph.endPage+1)}'/>"><i class="fa-solid fa-angle-right"></i></a>
          </c:if>

          <c:if test="${ph.showLast}">
            <a class="page"
               href="<c:url value='/bos/faqList${ph.sc.getQueryString(ph.totalPage)}'/>"><i class="fa-solid fa-angles-right"></i></a>
          </c:if>

        </c:if>

      </div>
    </div>

  </form>
</div>

 

 

❓ 원인

  1. <c:forEach var="faqDTO" items="${list}"> , faqDTO 객체를 삭제하기 위해 <form> 태그를 사용하고, 반복문을 통해 여러 글에 대한 삭제 버튼을 생성하고 있지만, 모든 버튼이 하나의 <form> 태그 안에 들어가 있는 문제가 있다고 한다.
  2. 이로 인해 삭제 버튼을 클릭하면 form에 있는 가장 첫 번째 faqNo 값을 서버로 전송하게 된다 . 따라서 모든 삭제 버튼이 가장 첫 번째 글의 **faqNo**를 전송하므로, 맨 앞에 숫자에 해당하는 글이 삭제되는 현상이 발생하는 것이다.
  3. 해결 방법은 각각의 삭제 버튼이 별도의 form으로 구성되도록 수정하는 것입니다. 이렇게 하면 각 버튼이 자신이 속한 <form>faqNo 값을 전송하게 되므로 올바르게 해당 글을 삭제할 수 있습니다.

 

✔해결방법

버튼 마다 별도의**<form>** 태그로 감싸는 방법은 추천 하지않는다

왜냐하면 HTML의 유효한 구조에서는 중첩된 <form> 태그를 사용할 수 없다

<form> 태그 안에 또 다른 <form> 태그를 포함시키는 것은 잘못된 문법이며, 브라우저에서 예상치 못한 동작을 일으킬 수 있습니다.

그렇다면 식별자를 사용해 특정글을 삭제 해야 하기 때문에 특정글의 번호를 서버에 전달해야한다.

서버는 해당 식별자를 가진 글을 DB에서 찾아 삭제한다.

버튼 태그에 
data-faq-no="${faqDTO.faqNo}  추가

 

<td><button type="button" id="modifyBtn" class="modifyBtn" data-faq-no="${faqDTO.faqNo}">수 정</button></td>
<td><button type="button" id="removeBtn" class="removeBtn" data-faq-no="${faqDTO.faqNo}">삭 제</button></td>

 

<script>
  // 삭제 버튼(.removeBtn)이 클릭되었을 때의 이벤트 핸들러 설정
  $('.removeBtn').on("click", function() {
    // 삭제하기 전에 확인 메시지를 표시하고, 취소를 선택한 경우 함수 종료
    if (!confirm("삭제 하시겠습니까 ?")) return;

    // 삭제 버튼이 속한 form 태그를 선택
    let form = $('#form');

    // 클릭한 삭제 버튼에 연결된 faqNo 값(data-faq-no 속성으로 저장)을 가져옴
    const faqNo = $(this).data("faq-no");

    // 삭제 요청을 보낼 URL 생성
    let url = "/bos/faqRemove?faqNo=" + faqNo;

    // form 태그의 action 속성을 변경하여 삭제 요청을 보낼 URL로 설정
    form.attr("action", url);

    // form 태그의 method 속성을 POST로 설정 (faqNo를 서버로 전달하기 위해 POST 방식 사용)
    form.attr("method", "post");

    // form 태그를 서버로 제출하여 삭제 요청을 보냄
    form.submit();
  });
</script>

이렇게 JS코드를 사용해 삭제 버튼을 클릭하면 해당 글의 faqNo 를 서버로 전달하여 삭제 요청을 보내는 기능을 완성 할수 있다.

728x90