Spring Mybatis (3) 게시글 읽기, 삭제 기능

강서진·2024년 1월 25일
0

Spring

목록 보기
14/18
post-custom-banner

2번째 필수강의 ch4. 5~6강 요약

URL과 URI의 차이

URL은 이미지나 텍스트 파일 리소스 경로이고, URN(Name)은 리소스에 유일한 이름을 붙인 것이다. 이 둘을 합친 것이 URI(Identifier)이다.
보통 URL은 전체 경로를 이야기하고, URI는 일부만 적을 때를 이야기한다.

기능별 URI 정의

작업URIHTTP 메서드설명
읽기/board/read?bno=번호GET지정된 번호의 게시물 조회
삭제/board/removePOST게시물 삭제
쓰기/board/writeGET게시물을 작성하기 위한 화면
/board/writePOST작성한 게시물 저장
수정/board/modigy?bno=번호GET게시물을 수정하기 위한 화면
/board/modifyPOST수정된 게시물을 저장

읽기

  @GetMapping("/read")
  public String read(Integer bno, Model m){
    try {
      BoardDto boardDto = boardService.read(bno);
      m.addAttribute(boardDto);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return "board";
  }

게시물 읽기와 수정하기는 같은 board.jsp를 사용한다. 게시물을 조회할 때는 jsp에 readonly 옵션을 주고, 수정할 때는 해당 옵션을 제거하는 식으로 만든다.

// board.jsp 일부
---
<div style="text-align:center">
  <h2>게시물 읽기</h2>
  <form action="" id="form">
    <input type="text" name="bno" value="${boardDto.bno}" readonly="readonly">
    <input type="text" name="title" value="${boardDto.title}" readonly="readonly">
    <textarea name="content" id="" cols="30" rows="10" readonly="readonly">${boardDto.content}</textarea>
    <button type="button" id="writeBtn" class="btn">등록</button>
    <button type="button" id="modifyBtn" class="btn">수정</button>
    <button type="button" id="removeBtn" class="btn">삭제</button>
    <button type="button" id="listBtn" class="btn">목록</button>
</div>

게시글 목록에서 게시글을 클릭하면 게시물 번호를 함꼐 넘겨 해당 게시물을 조회하는 화면이 뜨고, 이 화면에서 게시물 수정 혹은 삭제를 할 수 있다.
또, 목록을 누르면 다시 게시글 목록으로 돌아가는데, 이 때 그냥 돌아가서는 안되고 원래 보고 있던 페이지로 돌아갈 수 있어야 한다. 즉 처음에 게시글을 조회할 때 보고 있던 페이지와 페이지 크기가 함께 전달되어야 한다.

먼저 게시글 목록에서 게시글 조회로 넘어갈 수 있도록 게시물 제목에 조회 페이지로 이동하는 링크를 걸어준다.

<th><a href="<c:url value='/board/read?bno=${boardDto.bno}&page=${page}&pageSize=${pageSize}'/>">${boardDto.title}</a></th>

다음으로, 조회 화면에서 다시 목록으로 이동할 수 있게 /list에 get 요청이 들어올 때 model에 page와 pageSize를 추가하여 보내도록 하고, /read에서도 page와 pageSize를 받도록 수정한다.
버튼을 눌렀을 때 동작을 실행시키려고 하면 js가 필요하다. 기본적인 jQuery를 사용해보자. jsp 파일 헤더에 다음을 추가해준다.

	<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

html을 브라우저가 전부 읽은 후 js가 작동하여 작업을 수행해야 하므로 하단에 script를 작성한다.

<script>
  $(document).ready(function(){
    $('#listBtn').on("click", function(){
      location.href="<c:url value='/board/list'/>?page=${page}&pageSize=${pageSize}";
    });
  });
</script>

이 때 document는 html문서를 의미하고, html 문서가 준비되면 이 함수가 실행된다. js는 css selector를 그대로 사용하기 때문에 #으로 리스트로 돌아가는 버튼 아이디를 가져오고, 이 버튼에 클릭 이벤트가 발생하면 해당 링크로 이동하게 된다.

다음으로 게시글 삭제 기능을 만든다. 게시판 조회 화면에서 삭제 버튼을 누르면 boardController의 /remove로 해당 게시물의 번호가 POST 요청으로 넘겨지고, 해당 게시물이 삭제되도록 한다. + 작성자일때만 해당 게시글을 삭제할 수 있도록 작성자 정보도 함께 넘어가도록 해주어야 한다.
또, 게시글이 삭제되면 다시 게시글 목록으로 이동하도록 redirect 되도록 한다.

  @PostMapping("/remove")
  public String remove(Integer bno, Integer page, Integer pageSize, Model m, HttpSession session){

    String writer = (String) session.getAttribute("id");

    try {
      boardService.remove(bno, writer);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    m.addAttribute("page", page);
    m.addAttribute("pageSize", pageSize);
    return "redirect:/board/list";
  }

model에 page와 pageSize를 추가해서 넘겨주면, redirect 할 때 알아서 쿼리스트링으로 붙는다.
삭제 버튼을 눌렀을 때 작동할 스크립트를 작성해준다. list 버튼과 비슷하지만, 이번에는 post 방식으로 요청을 날려야 하기 때문에 #form 을 받도록 한다.
추가로, 삭제 버튼을 눌렀을 때 다시 한 번 확인하도록 confirm이 뜨도록 한다.

    $('#removeBtn').on("click", function(){
    if(!confirm("게시글을 삭제하시겠습니까?")) return;
      let form = $('#form');
      form.attr("action","<c:url value='/board/remove'/>?page=${page}&pageSize=${pageSize}");
      form.attr("method","post");
      form.submit();
    });

삭제가 잘 되었으면 삭제되었다고 창을 띄워주도록 한다.
다시 BoardController로 가서 remove의 결과를 int로 받고, 이 값이 1과 같으면 msg를 model에 첨부하여 보낸다.
jsp에서 받은 msg가 삭제 메시지일 경우 alert를 띄우도록 스크립트를 작성한다.

<script>
  let msg = "${msg}"
  if(msg=="del_ok") alert("성공적으로 삭제되었습니다.");
</script>

그런데 막상 실행해보니 삭제는 되는데 msg가 전달되고 있지 않았고, 쿼리 스트링으로 전달되고 있었다. GET 방식이라 model에 있는 값이 파라미터로 전달되기 때문에, ${msg}를 ${param.msg}로 값을 바꿔줬더니 정상적으로 alert가 떴다.

만약 삭제가 되지 않는 등 예외가 발생할 경우도 처리해준다. remove의 결과가 1이 나오지 않는다면 예외를 던지고, 이 때는 다른 msg를 넘겨주도록 수정한다.

  @PostMapping("/remove")
  public String remove(Integer bno, Integer page, Integer pageSize, Model m, HttpSession session){

    String writer = (String) session.getAttribute("id");

    try {
      m.addAttribute("pageSize", pageSize);
      m.addAttribute("page", page);

      int count = boardService.remove(bno, writer);

      if (count!=1)
        throw new Exception("board removal error");

      m.addAttribute("msg", "del_ok");
    } catch (Exception e) {
      e.printStackTrace();
      m.addAttribute("msg", "del_err");
    }
    return "redirect:/board/list";
  }

예외가 발생했을 경우의 스크립트도 추가해준다.

<script>
  let msg = "${param.msg}"
  if(msg=="del_ok") alert("성공적으로 삭제되었습니다.");
  if(msg=="del_err") alert("삭제에 실패했습니다.");
</script>

브라우저를 우클릭하고 검사로 들어가서 없는 게시글 번호로 수정한 뒤 삭제 버튼을 누르면 예외가 발생한다. 삭제가 실행되지 않은 것과 삭제 실패 메시지가 뜨는 것을 확인할 수 있었다.

그런데 메시지가 뜨는 것까지는 좋지만, 새로고침을 하면 msg를 계속 받기 때문에 계속 메시지가 뜬다. 이 때 메시지를 model이 아닌 redirectAttributes에 저장하면 한 번만 나오고, 그 중에서도 addFlashAttribute를 사용하면 session에 잠깐 저장했다가 한 번 쓰고 지워버리기 때문에 세션에도 부담이 덜하다.

@PostMapping("/remove")
  public String remove(Integer bno, Integer page, Integer pageSize,
                       Model m, HttpSession session, RedirectAttributes rattr){
...
rattr.addFlashAttribute("msg", "del_ok");
...
rattr.addFlashAttribute("msg", "del_err");       

이 경우에는 jsp 문서에서 param.msg가 아닌 msg로 써도 받아올 수 있다.
다만 이렇게 일회용으로 만들면 삭제 후 다시 redirect된 게시글 목록이 전에 있던 페이지로 가지 않고 첫 페이지로 나온다.

post-custom-banner

0개의 댓글