4/12/2018

(구버전) 스프링 게시판 만들기 #4. 수정/삭제 기능 구현

'(구버전) 스프링 게시판 만들기'는 내용이 부족하다고 판단하여
스프링 게시판 만들기를 새로 작성하였습니다.

링크 및 참조용으로 현재 게시물은 남겨두겠지만,
가급적이면 새로운 스프링 게시판 만들기를 참조해주시기 바랍니다.

게시판의 내용을 수정하고, 삭제하는 기능을 추가하겠습니다.
수정과 삭제는 조회 페이지에서 사용되며, 각각 별도의 페이지로 이동되어 작업이 이루어집니다.

제이쿼리를 사용할것이므로 헤드 태그, 즉 <head> 와 </head> 사이에 제이쿼리를 불러오는 CDN 코드를 입력합니다

 <!-- 제이쿼리 -->
 <script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>

그리고 수정 버튼과 삭제 버튼을 추가합니다.

 <p>
  <button id="modity_btn">수정</button>
  <button id="delete_btn">삭제</button>
 </p>

버튼의 아이디(ID) 또는 클래스(CLASS) 뒤에 _btn(button)을 넣어서, 구분하기 쉽도록 합니다.

그리고 스크립트를 추가합니다.

 <script>
 
 // 폼을 변수에 저장
 var formObj = $("form[role='form']");
 
 // 수정 버튼 클릭
 $("#modity_btn").click(function(){
  
  formObj.attr("action", "/board/modify");
  formObj.attr("method", "get");  
  formObj.submit();     
  
 });
 
 
 // 삭제 버튼 클릭
 $("#delete_btn").click(function(){
  
  formObj.attr("action", "/board/delete");
  formObj.attr("method", "get");  
  formObj.submit();
  
 });
 </script>

버튼의 타입을 submit으로 하면 현재 페이지에서 값이 전송 되기 때문에, 스크립트를 이용하여 액션(action)과 메서드(method)로 경로와 형태를 설정하여 전송할 수 있습니다.

조회 페이지에 접속해보면 버튼이 2개 생겼습니다.

버튼을 클릭 해보면, 아직 컨트롤러나 jsp 작업을 하지 않았기 때문에 404 에러가 발생합니다.

그전에 봐야할건, 전송되는 주소의 형태입니다.
bno, title, content, writer가 전송되고 있는데 수정과 삭제하는 작업엔 글번호(bno)만 필요하기 때문에 나머지 값은 전송할 필요가 없습니다.

조회 페이지에서, 닫는 폼 태그인 </form>의 위치를 옮겨줍니다. 이제 폼 태그에는 글번호(bno)만 들어가 있습니다.

이렇게 하는 방법 말고도, bno만 따로 뽑아 스크립트에서 작업하는 방법도 있습니다.

이제 글번호만 전송됩니다.

스프링 게시판 만들기 #1에서 CRUD는 이미 만들었기 때문에, 매퍼에서 따로 작업할 필요는 없습니다.

DAO와 Service 또한 미리 만들어두었기 때문에 별도의 작업은 필요 없습니다.

컨트롤러에 수정 페이지와 삭제 페이지의 GET 메서드 코드를 추가합니다.

 // 글 수 정
 @RequestMapping(value = "/modify", method = RequestMethod.GET)
 public void getModify(@RequestParam("bno") int bno, Model model) throws Exception {
  logger.info("get modify");
  
  BoardVO vo = service.read(bno);
  
  model.addAttribute("modify", vo);
  
 } 
 
 // 글 삭제
 @RequestMapping(value = "/delete", method = RequestMethod.GET)
 public void getDelete(@RequestParam("bno") int bno, Model model) throws Exception {
  logger.info("get delete");
    
  model.addAttribute("delete", bno);
  
 }

글 수정의 코드는 글 조회와 똑같습니다. 왜냐하면 게시물을 수정하려면 기존에 작성된 게시물을 모두 가져와야하기 때문입니다. 이때 model의 명칭은 역할에 맞게 modify로 했습니다.

글 삭제는 게시물을 구분할 수 있는 글 번호(bno)만 있으면 되며, model의 명칭은 역할에 맞게 delete로 했습니다.

이번엔 값을 전송할 때 처리할 POST 메서드 코드를 추가합니다.

 // 글 수정  POST 
 @RequestMapping(value = "/modify", method = RequestMethod.POST)
 public String postModify(BoardVO vo) throws Exception {
  logger.info("post modify");
  
  service.update(vo);
  
  return "redirect:/board/list";
  
 }

 // 글 삭제  POST
 @RequestMapping(value = "/delete", method = RequestMethod.POST)
 public String postDelete(@RequestParam("bno") int bno) throws Exception {
  logger.info("post delete");
    
  service.delete(bno);
  
  return "redirect:/board/list";
 }

수정과 삭제 모두 서비스 작업을 끝내면 리스트 페이지로 이동하게 되어있습니다.

read.jsp파일을 복사(Ctrl+C) 후 붙여넣기(Ctrl+V)한 뒤, 이름을 modify.jsp로 변경합니다. read와 modify의 내용은 거의 같기 때문에 미리 작성된 코드를 사용하는게 좋습니다.

기존에 사용했던 EL문법인 ${read.bno} 등등을 컨트롤러에서 작업한 model의 명칭대로 ${modify.bno} 등등으로 변경합니다.

또한 조회 페이지에서 수정할 수 없도록 readonly="readonly"를 사용했지만, 글 수정을 하려면 글 제목과 글 내용의 readonly="readonly"를 지워줍니다.

마지막으로 수정 버튼과 조회 페이지로 이동할 수 있는 버튼을 추가합니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<html>
<head>
 <title>kuzuro 게시판</title>
 
 <!-- 제이쿼리 -->
 <script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>
 
</head>
<body>

<div id="root">
 <header>
  <h1>kuzuro 게시판</h1>
 </header>

<hr />
 
 <nav>
  처음화면 - 글쓰기 - 로그인
 </nav>

<hr />

 <section id="container">
 
  <form role="form" method="post" autocomplete="off">
  
   <p>
    <label for="bno">글 번호</label>
    <input type="text" id="bno" name="bno" value="${modify.bno}" readonly="readonly" />
   </p>
   
   
   <p>
    <label for="title">글 제목</label>
    <input type="text" id="title" name="title" value="${modify.title}" />
   </p>
   <p>
    <label for="content">글 내용</label>
    <textarea id="content" name="content" >${modify.content}</textarea>
   </p>
   <p>
    <label for="writer">작성자</label>
    <input type="text" id="writer" name="writer" value="${modify.writer}" readonly="readonly"/><br />
    <label>작성 날짜</label>
    <span><fmt:formatDate value="${modify.regDate}" pattern="yyyy-MM-dd" /></span>
   </p>
   <p>
    <button type="submit">수정</button><button id="cancel_btn">취소</button>
    
    <script>
    // 폼을 변수에 저장
    var formObj = $("form[role='form']"); 
    
    // 취소 버튼 클릭
    $("#cancel_btn").click(function(){   
     formObj.attr("action", "/board/read?bno=" + $("#bno").val());
     formObj.attr("method", "get");  
     formObj.submit();
    });
    </script>
   </p> 
   
  </form>

 </section>

<hr />

 <footer>
  <p>만든이 : kuzuro</p>  
 </footer>

</div>

</body>
</html>

수정 페이지와 마찬가지로 read.jsp파일을 복사해서 delete.jsp로 이름을 바꾼 뒤 코드를 수정합니다.

글 삭제에는 글 번호(bno)만 필요하기 때문에 폼 태그 안에 글 번호만 있습니다. 삭제전 메시지와 삭제 버튼, 조회 페이지로 이동할 수 있는 버튼을 추가했습니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<html>
<head>
 <title>kuzuro 게시판</title>
 
 <!-- 제이쿼리 -->
 <script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>
 
</head>
<body>

<div id="root">
 <header>
  <h1>kuzuro 게시판</h1>
 </header>

<hr />
 
 <nav>
  처음화면 - 글쓰기 - 로그인
 </nav>

<hr />

 <section id="container">
 
  <form role="form" method="post" autocomplete="off">
  
   <p>
    <label for="bno">글 번호</label>
    <input type="text" id="bno" name="bno" value="${delete}" readonly="readonly" />
   </p>
   
   <p>정말로 삭제하시겠습니까?</p>
   
   <p>
   
    <button type="submit">예, 삭제합니다.</button><br />
    <button id="cancel_btn">아니오, 삭제하지 않습니다.</button>
    
    
    <script>

    // 폼을 변수에 저장
    var formObj = $("form[role='form']"); 
    
    // 취소 버튼 클릭
    $("#cancel_btn").click(function(){   
     formObj.attr("action", "/board/read?bno=" + $("#bno").val());
     formObj.attr("method", "get");  
     formObj.submit();     
     
    });
    </script>
   
   </p>
   
  </form>
   
 </section>

<hr />

 <footer>
  <p>만든이 : kuzuro</p>  
 </footer>

</div>

</body>
</html>

글 수정이 제대로 작동되나 확인하기 위해, 제목과 내용을 수정했습니다.

수정 버튼을 클릭하면 리스트 페이지로 이동하며, 수정이 잘 된걸 확인할 수 있습니다.

이번엔 삭제 기능을 확인하겠습니다.

여기서 삭제 버튼을 누르면

리스트 페이지로 이동하며, 글이 삭제된걸 확인할 수 있습니다.

게시물 수정
  1. 안녕하세요
    질문이 있습니다..
    첫번쨰는 소스에는 form을 role로 묶어서 사용하시는데
    form을 id로 지정해서 사용해도 괜찮은가 이구요.

    두번쨰는 form 의 값들을 controller의 url이 아닌 jsp로 바로 보내서 사용도 하는지가 궁금합니다

    답글삭제
    답글
    1. 아 생각해보니 두번째 질문은 mvc프로젝트니까 jsp파일로 바로접근이 불가능해서 controller를 꼭 거쳐야 겠네요 ..
      스크립트 수업내용과 자바를 동시에하니 머리속에서 꼬여버렸습니다..ㅎ

      삭제
    2. 안녕하세요.

      폼(form)을 선택할 때$("form[role='form']") 처럼하는 이유는 특별히 없습니다;
      말씀하신대로 아이디 또는 클래스 그외에 특정 지을 수 있는 조건만 있다면(버튼에 this → parents라던가) 상관없습니다.

      삭제
  2. 안녕하세요? 덕분에 잘 보고 있습니다.
    질문이 있는데요.
    read.jsp와 modify.jsp 파일에 보면 "${read.bno}"라든지 "${modify.bno}" 같은 것이 있는데 여기서
    read. modify. 은 무엇을 나타내는건가요? contoller에 있는 model.Attribute()에 있는 그것인가요!?
    감사합니다..

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.
      말씀하신대로 read와 modify는 컨트롤러에서 보내준 모델의 이름입니다.

      model.Attribute([모델 이름], [데이터]) 로 보내주면, [모델 이름]으로 데이터를 제어할 수 있습니다.

      삭제
  3. MY 게시판
    처음화면 - 글쓰기 - 로그인
    글 목록
    글 번호 글 제목 작성자 작성일자
    26 가,안녕 다 2019-00-13

    다른 기능들은 전부 다 잘 작동합니다 글내용수정도 잘 되고
    근대 글제목 수정에서 가->안녕으로 수정했는대
    기존값 가와 안녕이 같이 출력됩니다 가,안녕
    콘솔에서도 안보이고 어떻게해야할까요

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      이전 글의 제목과 수정했던 글 제목이 동시에 나타난다는건데, 여기서 의심해야할 건
      1. 글 제목과 동일한 name속성을 가진 input이 hidden으로 숨겨져 있는 경우
      2. 주소창에 동일한 name으로 데이터가 있는 경우 (예 : [주소]?title=글제목)

      이렇게 두가지가 있습니다.
      jsp파일을 확인해보시고, 컨트롤러가 어떤 값을 받는지 확인해보셔야할 것 같습니다.

      삭제
  4. 작성자가 댓글을 삭제했습니다.

    답글삭제
  5. 안녕하세요 너무 잘 보고 공부하고있어요
    몇가지 질문이있어서 질문드려요
    1. form태그를 bno까지만 한정지은 이유를 알고싶어요 제대로 이해가안가서 ㅠ
    2. script함수 짜신거 설명좀 부탁드릴게요. attr. 이부분이요
    3. 컨트롤러에서 수정get과 삭제 get에는 파라미터를 int bno와 모델 로 받았잖아요
    이 의미를 좀 알고싶고 왜 post에서는 수정은 boardvo vo로 하고 삭제는 bno로 받았는지 궁금합니다.

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      1. 아마 read.jsp 내부에 있는 form태그에 대해서 말씀하시는것 같네요.

      꼭 bno만 form으로 묶어줄 필요는 없으나, bno는 꼭 form내부에 있어야합니다.
      왜냐하면, 수정/삭제를 할 경우, 게시물의 고유 번호인 bno를 이용하여 수정/삭제하기 때문입니다. 게시물의 다른 컬럼들, 즉 제목과 내용과 작성자는 변경될 수 있으며, 작성날짜는 그날 작성된 모든 게시물을 잡아버리기 때문에, 원하는 게시물 하나만 지정할 수 있는 bno를 form에 넣어주는것 입니다.


      2. formObj.attr("action", "/board/modify"); formObj.attr("method", "get"); 이 부분과 formObj.attr("action", "/board/delete"); formObj.attr("method", "get"); 이부분 말씀하시는것 같네요.

      attr([속성명], [속성값])으로 되어있습니다. 위의 코드를 보시면 form에 들어가야할 속성중 action속성이 없는걸 확인하실 수 있습니다. action 속성을 넣지 않은 이유는, 폼은 하나인데 버튼에 따라서 두가지 이상의 동작을 할 가능성이 있기 때문에 아예 넣지 않은겁니다.

      수정 버튼을 누르게되면, formObj.attr("action", "/board/modify"); formObj.attr("method", "get"); 코드에 의하여 form에 action="/board/modify" method="get"의 속성을 넣어주고, submit() 코드를 이용하여 폼의 데이터를 action에 있는 컨트롤러로 전송합니다.

      즉, 자바스크립트로 form의 action과 method를 바로바로 제어하기 위해 넣은 코드입니다.


      3. 항상 그런것은 아니지만, get은 페이지를 처음 불러올 경우에 사용되며 post는 페이지에 있는 데이터를 컨트롤러에 전송할 때 사용합니다.

      위에서 게시물을 구분할 수 있는 고유값은 bno라고 했는데요. 이 bno를 이용하면 데이터베이스에 있는 해당 bno의 데이터를 모두 가져올 수 있습니다.

      게시물 목록에서 특정 게시물을 클릭했을 때 사용한것도 bno하나였지요? 이처럼 게시물을 구분할 수 있는 bno만 있다면 나머지 데이터도 가져올 수 있습니다.

      이때 게시물을 수정하고 저장할 때는 조금 달라집니다.
      게시물을 수정하고 저장할 때, title, content등의 다른 데이터는 변경되었으므로 이 변경된 데이터를 데이터베이스에 전달해주어야합니다.

      어느 게시물이 수정된건지 알아야하므로 bno가 필요하고, 변경된 데이터를 전송하기 위해선 게시물을 수정하는 BoardVO 전체를 전송해야할 필요가 있습니다. (BoardVO에 bno, title, content등의 모든 데이터가 있으니까요)
      그렇기 때문에 게시물을 수정했을 땐 BoardVO를 이용하는것 입니다.

      게시물 삭제의 경우 게시물의 제목이나 내용은 필요 없이 삭제하고자하는 게시물의 고유 번호인 bno만 알면 되기 때문에, BoardVO가 아닌 bno만 전송해도 삭제가 가능합니다.

      삭제
  6. 안녕하세요.delete jsp에서 아니오 삭제하지 않겠습니다 이 버튼을 위한 script를 form 안에 넣으면 아니오 를 눌러도 삭제가 되더라구요. 이걸 form 태그 밖으로 빼버리니까 정상작동 되네요

    답글삭제
    답글
    1. 혹시 안에 들어있을때와 어떤 차이가 있는지 알수 있을까요

      삭제
  7. 안녕하세요 질문이 있는데 Request method 'POST' not supported 이게 왜 뜨는지 모르겠습니다.

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      해당 에러는.. 프론트와 백단에서 서로 보내는 전송방식이 달라서 생기는 에러입니다.
      프론트에서 get으로 보냈는데 컨트롤러엔 post로 있다던가하는 경우에 이런 에러가 발생합니다.

      삭제