Search
📙

#블로그만들기_15 #게시글 수정하기

View 먼저 확인

/board/1/update → 어떤 게시글을 업데이트 하냐라는 로직이 필요하기 때문에 id가 필요하다. 게시글 수정 버튼을 눌렸을 때, 내용과 제목이 있어야 하므로 DB조회가 필요하다.

updateForm.mustache 코드 구현

saveForm.mustache를 복붙해서 updateForm.mustache을 만들어 준다. action 링크 확인 → 1은 변수로 바꿔야 된다. method → post enctype → xform 데이터 키값 확인 → title, content button 타입확인 → submit은 폼태그 안에 있으면 양식을 제출한다.
updateForm.mustache 코드 글 수정화면으로 사용하기 때문에, 메시지도 아래처럼 수정해준다.
{{> layout/header}} <div class="container p-5"> <div class="card"> <div class="card-header"><b>수정하기 화면입니다</b></div> <div class="card-body"> <form action="/board/{id}/update" method="post" enctype="application/x-www-form-urlencoded"> <div class="mb-3"> <input type="text" class="form-control" placeholder="Enter title" name="title" value="제목1"> </div> <div class="mb-3"> <textarea class="form-control" rows="5" name="content">내용 1</textarea> </div> <button type="submit" class="btn btn-primary form-control">수정완료</button> </form> </div> </div> </div> {{> layout/footer}}
HTML
복사

updateForm로직

부가로직을 구현하느라 핵심로직을 잊어버리지 말자!! updateForm의 핵심로직은 board를 조회해서 request에 담아서 view에 전달하는 것이 핵심이다! 반복 숙달이 되면 부가로직은 주석으로만 남겨 놓고, 핵심로직 구현후에 복붙하자. @PathVariable 적극 사용!!
@RequiredArgsConstructor @Controller public class BoardController { private final HttpSession session; private final BoardRepository boardRepository; // 게시글 수정 페이지 정보를 조회해서 뿌리는 책임을 가진다. // @PathVariable 사용해서 동적으로 할당한다. @GetMapping("/board/{id}/updateForm") public String updateForm (@PathVariable int id, HttpServletRequest request) { // 인증 체크 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "redirect:/loginForm"; } // 모델 위임 (id로 board를 조회) // 권한 체크 BoardResponse.DetailDTO detailDTO = boardRepository.findById(id); if (sessionUser.getId() != detailDTO.getUserId()){ request.setAttribute("msg", "권한이 없습니다."); request.setAttribute("status", 403); } // 가방에 담기 // 가방에 담아서 View에 전달하는 것이 핵심로직이다 request.setAttribute("board", detailDTO); return "board/updateForm"; }
Java
복사
Additional Notes DB를 조회하기 위해서 번호가 필요하다. Join을 사용하게 되면 DB부하가 커진다. 조심해서 사용!! 서버부하가 커지는 쿼리 → join, group by, sub쿼리 PK로 조회하면 인덱스로 조회하기 때문에 엄청 빠르다. 평점이라는 기능 역시 사람들의 평가가 필요하므로 스칼라가 아닌 테이블로 만들어야된다.

DetailDTO를 board에 할당하기

BoardResponse.DetailDTO 는 변수 detailDTO라는 변수으로 지정이 되어있다. request.setAttribute로 키 값을 board로 지정하고 필드값으로 detailDTO를 연결한다.
아래 DetailDTO에서 Mustache 문법으로 {{ 변수.필드값 }} 으로 해당 필드값을 가져와 할당할 수 있다. {{board.id}} / {{board.title}} / {{board.content}}
View에 연동하기

수정버튼에 updateForm으로 이동기능 만들기

상세보기 화면에서 수정버튼을 누르면 updateForm으로 이동하는 버튼 만들기 Get요청만 하는 거라면 a태그를 사용해서 링크를 붙여도 된다. {{id}} 는 컨트롤러에서 @PathVariable로 값을 할당받게 될 것이다.
테스트 수정을 클릭하면 URL이 게시글 번호를 받아서 updateForm페이지로 가야된다.
성공! 수정화면의 내부역시 DB로 조회된 내용을 화면에 출력해야 된다. /board/3/update으로 URL 잘 적용이 되었다. 3번 게시물이므로 제목3, 내용3이 표현되었고 잘 적용이 된 것 같다!

게시물 수정기능 구현하기(액션)

DTO만들기

게시물 제목과 내용을 수정하여 버튼을 클릭하면 전달되는 정보는 titlecontent이다. 이를 위한 DTO를 따로 만들어 최대한 SRP원칙을 지키도록 한다.
package shop.mtcoding.blog.board; import lombok.Data; public class BoardResponse { // 게시물 제목과 내용을 적어서 버튼을 클릭하면 // 전달되는 정보는 title과 content이다. @Data public static class UpdateDTO { private String title; private String content; }
Java
복사

컨트롤러>>update() 메소드 핵심로직 먼저 만들기

인증체크랑 권한 체크는 이미 모듈화가 되어있으므로 핵심로직부터 구현한다. redirect로 반환 → PRG 패턴 (중복 Post요청을 방지하기 위함이다) PRG패턴 이란 → Post요청 >> Redirect >> Get요청
@RequiredArgsConstructor @Controller public class BoardController { private final BoardRepository boardRepository; private final HttpSession session; @PostMapping("board/{id}/update") public String update (@PathVariable int id, BoardResponse.UpdateDTO requestDTO){ //1. 인증 체크 //2. 권한 체크 //3. 핵심 로직 // 쿼리 >> update board_tb set title=? , content=? where id=? boardRepository.update(id, requestDTO); return "redirect:/board/" + id; } }
Java
복사

DB연결하기

DB변경이 일어나므로 @Transactional 어노테이션을 붙인다. 위치 BoardRepository>> update() 메소드 쿼리문 = “update board_tb set title=? , content=? where id=?
@Transactional // DB변경이기 때문에 최소작업단위로 묶어야된다. public void update(int id, BoardRequest.UpdateDTO requestDTO) { Query query = em.createNativeQuery("update board_tb set title=? , content=? where id=? "); query.setParameter(1, requestDTO.getTitle()); query.setParameter(2, requestDTO.getContent()); query.setParameter(3, id); query.executeUpdate(); }
Java
복사

테스트 하기

이 수정 완료 버튼에는 폼태그(<form></form>)로 post요청과 submit이 들어가있기 때문에, 브라우저에서 바로 테스트 해볼 수 있다.
TransactionRequiredException에러가 생길경우!
해결방법 펼쳐보기
수정 테스트 확인완료!

update()메소드 부가로직 구현

부가로직은 다음과 같다. 로그인 여부 검사 → 인증 테스트, 401 게시물 주인 판단 검사 → 권한 테스트, 403
@RequiredArgsConstructor @Controller public class BoardController { private final BoardRepository boardRepository; private final HttpSession session; @PostMapping("board/{id}/update") public String update (@PathVariable int id, BoardResponse.UpdateDTO requestDTO, HttpServletRequest request){ //1. 인증 체크 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null){ return "redirect:/loginForm"; } //2. 권한 체크 BoardResponse.DetailDTO board = boardRepository.findById(id); if (board.getUserId()!=sessionUser.getId()){ request.setAttribute("msg", "권한이 없습니다."); request.setAttribute("status", 403); return "error/40x"; } //3. 핵심 로직 // 쿼리 >> update board_tb set title=? , content=? where id=? boardRepository.update(id, requestDTO); return "redirect:/board/" + id; }
Java
복사
Additional Notes - @RequestBody어노테이션
@RequestBody는 Spring Framework에서 사용하는 어노테이션으로, 클라이언트로부터 오는 HTTP 요청의 본문(body)을 Java 객체로 변환해주는 역할을 한다. 이 어노테이션은 주로 POST나 PUT 요청에서 사용되며, JSON, XML 등의 형식으로 전송된 데이터를 해당 메서드의 파라미터로 매핑할 때 사용된다. 여기서는 사용안할 것이기 때문에 알아만 놓자.\
아래 코드에서 @RequestBody 어노테이션의 위치를 살펴보자!
@PostMapping("/board/{id}/update") public void update (@PathVariable int id, @RequestBody BoardRequest.UpdateDTO requestDTO) { System.out.println(requestDTO); }
Java
복사
Postman으로 raw섹션에 JSON타입의 자료를 입력하여 Post요청을 하면 @RequestBody는 해당 원문을 자바 객체로 변환시켜서 저장한다.