ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ Spring Boot + JPA + Thymeleaf ] 게시판 만들기 - 3
    Spring Boot 2021. 2. 10. 19:54

    * 게시판 CRUD


    저번 포스팅에서는 수동으로 내가 넣어논 데이터를 단순히 뿌려주기만 하는 기능을 구현해보았는데, 이번에는 내가 직접 글을 작성하고, 수정, 삭제까지 가능하도록 기능을 구현해보겠다.

     

    우선 글 작성을 위한 페이지를 만들기위해 이번에도 역시 BootStrap에서 참고하여 레이아웃을 잡아주었다.

     

    이제 글 작성 페이지로 넘겨주는 컨트롤러를 작성해야하는데, 이번에는 해당 페이지에서 폼을 전송하여 데이터를 저장해주는 작업이 필요하기 때문에 Board 객체를 생성해주었다.

    // 내용 입력 폼
    @GetMapping("/form")
    public String form(Model model){
    
      // 신규 폼
      model.addAttribute("board", new Board());
    
    return "board/form";
    }

     

    그리고 form.html에서 submit을 해주면 내가 작성한 데이터를 Board객체로 넘겨받아 저장할 수 있다.

    @Valid 애노테이션은 파라미터를 검증해주는 것인데, @Valid 어노테이션을 통해 유효한 객체인지 검사한 후 객체가 유효하지 않으면 bindingResult.hasErrors() 메소드에서 true 값이 반환된다.

     

    // 내용 저장
    @PostMapping("/form/save")
    public String saveForm(@Valid Board board, BindingResult result){
      if (result.hasErrors()) {
         return "board/form";
      }
      
      boardRepository.save(board);
      return "redirect:/board/list";
    }

    !! 위와같이 코드를 짜보니 오류가 났다. 해당 코드는 신규등록이랑 수정시 같이 사용되는 메서드인데 휴효성 체크를 하게되어 글 신규 작성시 id값이 null이라 오류가 나는것같다. if문을 삭제해주니 정상적으로 작동되었다.

     

     

    그 다음으로 작성한 글을 수정하기 위해 우선 저장되어있는 데이터를 폼에 알맞게 뿌려주는 부분을 구현해볼것이다.

    우선, 해당 게시물의 키값을 넘겨 주어야 데이터를 가져올 수 있기 때문에 th:href="@{/board/form(id=${board.id})}" 방식으로 id값을 넘겨 준 후 Controller에서 

    // 수정 시 내용 가져오기
    Board board = boardRepository.findById(id).orElse(null);
    model.addAttribute("board", board);

    위와같이 findById를 사용하여 데이터를 객체에 담아 준 후 form.html페이지로 넘겨주면 데이터가 알맞게 뿌려지는것을 볼 수 있다.

     

    그리고 글 작성시와 동일하게 작동되는데 id값을 가지고 있으므로 자동으로 업데이트가 실행이 된다. 아주 편리하다.

    해당 key값이 존재하면 업데이트, 없으면 신규생성이 된다. 하지만 내가 알기론 save()를 실행하면 select 후 insert 또는 update를 하는것이라 나중에 많은 데이터를 처리할 경우에는 불필요한 select시 속도가 느려질수도 있을거라는 생각이 든다..

     

    이제 마지막으로 글 삭제 기능을 구현해보겠다.

    위의 코드들과 딱히 다를것은 없고, deleteById()를 이용하여 데이터 삭제 기능을 구현해주면 된다.

     

    삭제는 신중해야하므로? 스크립트로 확인창 한번 띄워주고 삭제하도록 구현했다.

     

     

    - BoardController.java

    package com.example.myhome.controller;
    
    
    import com.example.myhome.model.Board;
    import com.example.myhome.repository.BoardRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import javax.validation.Valid;
    import java.util.List;
    
    @Controller
    @RequestMapping("/board")
    public class BoardController {
    
        @Autowired
        private BoardRepository boardRepository;
    
        // 리스트 출력
        @GetMapping("/list")
        public String list(Model model){
            List<Board> boards = boardRepository.findAll();
            model.addAttribute("boards", boards);
            return "board/list";
        }
    
        // 내용 입력 폼
        @GetMapping("/form")
        public String form(Model model, @RequestParam(required = false) Long id){
            if(id == null){
                // 신규 폼
                model.addAttribute("board", new Board());
            }else{
                // 수정 시 내용 가져오기
                Board board = boardRepository.findById(id).orElse(null);
                model.addAttribute("board", board);
            }
    
            return "board/form";
        }
        @PostMapping("/form/save")
        public String saveForm(@Valid Board board, BindingResult result){
            
            boardRepository.save(board);
            return "redirect:/board/list";
        }
    
        @PostMapping("/form/delete")
        public String deleteForm(@RequestParam(required = true) Long id){
            boardRepository.deleteById(id);
            return "redirect:/board/list";
        }
    }
    

     

     

     

    - form.html

    <!doctype html>
    <html xmlns:th="http://www.thymelef.org">
    <head th:replace="fragments/common :: head('게시판')">
    </head>
    <body>
    <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top" th:replace="fragments/common :: menu('list')">
    </nav>
    
    <div class="container">
        <h2>게시판</h2>
        <form name="globalform" action="#" th:action="@{/board/form}" th:object="${board}" method="post">
            <input type="hidden" th:field="*{id}">
            <div class="mb-3">
                <label for="exampleFormControlInput1" class="foboardrm-label">제목</label>
                <input type="text" class="form-control" id="exampleFormControlInput1" th:field="*{title}">
            </div>
            <div class="mb-3">
                <label for="exampleFormControlTextarea1" class="form-label">내용</label>
                <textarea class="form-control" id="exampleFormControlTextarea1" rows="3" th:field="*{content}"></textarea>
            </div>
            <div class="text-right">
                <a type="button" class="btn btn-primary" th:href="@{/board/list}">이전</a>
                <a type="submit" class="btn btn-primary" th:href="'javascript:saveForm('+*{id}+')'">저장</a>
                <a type="submit" class="btn btn-primary" th:href="'javascript:delForm('+*{id}+')'">삭제</a>
            </div>
        </form>
    
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
    </body>
    <script>
    
        // 저장
        function saveForm(id){
            var frm = document.globalform;
            frm.action = "/board/form/save?id="+id;
            frm.method = "post";
            frm.submit();
        }
    
        // 삭제
        function delForm(id){
            if(confirm("삭제하시겠습니까?")){
             var frm = document.globalform;
             frm.action = "/board/form/delete?id="+id;
             frm.method = "post";
             frm.submit();
            }
    
        }
    
    </script>
    </html>

     

     

    - list.html

    <!doctype html>
    <html xmlns:th="http://www.thymelef.org">
    <head th:replace="fragments/common :: head('게시판')">
    </head>
    <body>
    <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top" th:replace="fragments/common :: menu('list')">
    </nav>
    
    <div class="container">
        <h2>게시판</h2>
        <div>총 건수 : <span th:text="${#lists.size(boards)}"></span></div>
        <table class="table">
            <thead>
            <tr>
                <th scope="col">번호</th>
                <th scope="col">제목</th>
    
            </tr>
            </thead>
            <tbody>
            <tr th:each="board : ${boards}">
                <th th:text="${board.id}">1</th>
                <td><a th:text="${board.title}" th:href="@{/board/form(id=${board.id})}" >Mark</a></td>
    
            </tr>
            </tbody>
        </table>
        <div class="text-right">
            <a type="button" class="btn btn-primary" th:href="@{/board/form}">글쓰기</a>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
    </body>
    </html>
Designed by Tistory.