[스프링 부트] 13. 글 작성하기(Create) 구현

KangHo Lee's avatar
Nov 18, 2024
[스프링 부트] 13. 글 작성하기(Create) 구현
💡
프로그램의 기능을 개발할 때는 View 부터 만드는 게 좋습니다.

1. save-form.mustache (View)

{{> layout/header}} <section> <!-- http body : title=제목6&content=내용6 http header : application/x-www-form-urlencoded key값은 input태그의 name, value값은 input태그에 사용자가 입력하는 값--> <form action="/board/save" method="post" enctype="application/x-www-form-urlencoded"> <input type="text" name="title" placeholder="제목"><br> <input type="text" name="content" placeholder="내용"><br> <button type="submit">글쓰기</button> </form> </section> </body> </html>

placeholder=”제목”

  • 사용자가 필드에 아무것도 입력하지 않았을 때 placeholder내용이 화면에 표시됩니다.

enctype="application/x-www-form-urlencoded"

  • request의 Content-Type을 설정합니다.

2. DTO (Data Transfer Object)

public class BoardRequest { @Data // getter, setter, toString public static class SaveDTO { private String title; private String content; } }

3. Controller

@GetMapping("/save-form") public String saveForm() { return "save-form"; } @PostMapping("/board/save") public String save(BoardRequest.SaveDTO saveDTO) { // System.out.println(saveDTO); boardService.게시글쓰기(saveDTO); return "redirect:/"; }

save 메서드의 매개변수 타입이 객체가 가능한 이유

  • application/x-www-form-urlencoded 타입의 request(요청)이 웹 서버를 통해 WAS(여기서는 tomcat)로 도착합니다.
  • tomcat이 받은 데이터로 DTO 객체를 만듭니다.
  • tomcat이 파싱한 DTO객체를 HttpServletRequest 안에 담아서 DispatcherServlet 에게 전달합니다.
💡
System.out.println(saveDTO); 는 자바 문법 상
System.out.println(saveDTO.toString()); 과 같습니다.

리다이렉션 흐름(RPG 패턴)

  1. 클라이언트가 작성한 글 내용을 담은 POST 요청을 보냅니다.
  1. 서버가 클라이언트에게 302 리다이렉트 응답을 보냅니다.
      • 이 응답은 클라이언트에게 새로운 위치(“/”)로 다시 요청하라고 지시합니다.
      • HTTP 상태 코드는 302(Found)입니다.
  1. 클라이언트가 “/” 로 GET 요청을 보냅니다.
      • 클라이언트는 서버의 지시에 따라 “/” 경로로 GET 요청을 보냅니다.
  1. 서버가 /에 대한 응답을 보냅니다.
      • 이 요청에 대한 응답은 일반적으로 200 OK 상태 코드를 갖습니다.
      • “/” 경로에 해당하는 리소스를 클라이언트에게 반환합니다.
따라서, 최종적으로 클라이언트는 302 리다이렉트를 통해 “/” 경로로 이동하며, 이 경로에 대한 요청에 200 응답을 받습니다.
💡
개발자 도구 Network 탭에서 요청이 302 요청과 200 요청 총 2번 요청이 발생하는 것을 확인할 수 있습니다.

리다이렉션을 해야 하는 이유

  • 글 쓰기 결과가 반영된 화면을 보여주기 위해서입니다.

4. Repository

public void save(String title, String content) { Query q = em.createNativeQuery("insert into board_tb (title, content, created_at) values(?, ?, now())"); q.setParameter(1, title); q.setParameter(2, content); q.executeUpdate(); // commit 하지 않은 상태 }

5. Repository Test

@Test public void save_test() { // given String title = "제목6"; String content = "내용6"; // when boardRepository.save(title, content); // then Board board = boardRepository.findById(6); System.out.println(board.getId()); System.out.println(board.getTitle()); System.out.println(board.getContent()); }

6. Service

@Transactional // commit 완료 public void 게시글쓰기(BoardRequest.SaveDTO saveDTO) { boardRepository.save(saveDTO.getTitle(), saveDTO.getContent()); }

@Transactional 을 Repository가 아니라 Service에 붙이는 이유

  • 게시글쓰기에 메서드가 여러 개 있을 경우 일부 메서드에 오류가 생길 때 rollback 시키기 위해서입니다.
 
Share article

devleekangho