Blog-v3(리팩토링), 댓글기능

댓글
홍윤's avatar
Sep 05, 2024
Blog-v3(리팩토링), 댓글기능
 

1. boardPackage

1. BoardController

@GetMapping("/v2/api/board/{id}/update-form") public @ResponseBody BoardResponse.DTO updateForm(@PathVariable("id") int id) { User sessionUser = (User) session.getAttribute("sessionUser"); BoardResponse.DTO model = boardService.게시글수정화면V2(id, sessionUser); return model; }
  • 코드 설명
💡
주어진 코드는 Spring Boot 애플리케이션에서 사용되는 RESTful API 엔드포인트입니다. 이 메소드는 특정 게시글의 수정 화면 데이터를 제공하는 역할을 합니다.
  1. @GetMapping("/v2/api/board/{id}/update-form"):
      • 이 어노테이션은 HTTP GET 요청을 처리하는 메소드를 정의합니다.
      • "/v2/api/board/{id}/update-form" 경로는 클라이언트가 특정 게시글의 수정 폼 데이터를 요청할 때 사용됩니다.
      • {id}는 URL 경로 변수로, 수정하려는 게시글의 ID를 나타냅니다.
  1. @ResponseBody:
      • 이 어노테이션은 메소드의 리턴 값이 HTTP 응답 본문으로 직렬화되어 전송됨을 나타냅니다.
      • 따라서 BoardResponse.DTO 객체는 JSON 형식으로 변환되어 클라이언트에게 응답됩니다.
  1. @PathVariable("id") int id:
      • @PathVariable 어노테이션은 URL 경로에 포함된 변수를 메소드 매개변수로 매핑합니다.
      • 여기서는 {id} 경로 변수를 int id로 받아 사용합니다.
  1. User sessionUser = (User) session.getAttribute("sessionUser");:
      • 이 코드는 현재 세션에서 sessionUser라는 이름으로 저장된 User 객체를 가져옵니다.
      • 이 객체는 현재 로그인한 사용자의 정보를 담고 있을 것입니다.
  1. BoardResponse.DTO model = boardService.게시글수정화면V2(id, sessionUser);:
      • boardService.게시글수정화면V2 메소드를 호출하여 게시글의 수정 화면에 필요한 데이터를 가져옵니다.
      • 이 메소드에는 게시글의 ID(id)와 현재 세션 사용자(sessionUser)가 인자로 전달됩니다.
      • 게시글수정화면V2 메소드는 수정 화면에 필요한 데이터를 가공하거나 권한 검사를 수행할 수 있습니다.
  1. return model;:
      • BoardResponse.DTO 객체를 클라이언트에게 반환합니다.
      • 이 객체는 게시글 수정 화면에 필요한 데이터를 포함하고 있을 것입니다.

요약

이 메소드는 특정 게시글의 수정 화면 데이터를 반환하는 역할을 합니다. 클라이언트는 이 데이터를 받아 수정 화면을 구성할 수 있습니다. 메소드는 현재 세션에서 사용자 정보를 가져와, 해당 사용자가 수정하려는 게시글에 접근할 수 있는지 검증하는 데 사용될 수 있습니다.
 
@GetMapping("/v2/board/{id}") public @ResponseBody BoardResponse.DetailDTO detailV2(@PathVariable("id") Integer id){ User sessionUser = (User) session.getAttribute("sessionUser"); BoardResponse.DetailDTO model = boardService.게시글상세보기(sessionUser, id); return model; } @GetMapping("/v3/board/{id}") public @ResponseBody Board detailV3(@PathVariable("id") Integer id) { User sessionUser = (User) session.getAttribute("sessionUser"); Board model = boardService.게시글상세보기V3(sessionUser, id); return model; }
  • 코드설명
💡
Board model = boardService.게시글상세보기V3(sessionUser, id);:
  • boardService.게시글상세보기V3 메소드를 호출하여 특정 게시글의 상세 정보를 가져옵니다.
  • 이 메소드에는 게시글의 ID(id)와 현재 세션 사용자(sessionUser)가 인자로 전달됩니다.
  • 게시글상세보기V3 메소드는 상세 정보 조회 시 필요한 권한 검사를 수행하거나, 데이터를 가공하여 반환할 수 있습니다.

요약

이 메소드는 특정 게시글의 상세 정보를 조회하여 클라이언트에게 반환하는 역할을 합니다. 클라이언트는 이 데이터를 사용하여 게시글의 상세 화면을 구성할 수 있습니다. 또한, 현재 세션에서 사용자 정보를 가져와, 해당 사용자가 게시글에 접근할 수 있는지 검증하는 데 사용될 수 있습니다.
이 메소드는 사용자와의 세션 정보를 활용하여, 사용자 맞춤형 데이터를 제공하거나 보안 관리를 강화할 수 있는 구조를 가지고 있습니다.

2. BoardResponse

 
@Data public static class DTO { private Integer id; private String title; private String content; public DTO(Board board) { this.id = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); } }
  • 코드설명
💡
이 코드는 DTO라는 데이터 전송 객체(Data Transfer Object)를 정의하는 것입니다. DTO 클래스는 특정 엔티티(여기서는 Board 클래스)의 필요한 일부 컬럼만 선택적으로 포함하기 위해 사용됩니다.

간단한 설명

  • 목적: DTO 클래스는 클라이언트에게 전달할 데이터 중 필요한 컬럼만 선택하여 전송하기 위해 만들어졌습니다.
  • 구성 요소:
    • id, title, content 필드를 가지고 있으며, 이는 Board 엔티티의 일부 정보만 담고 있습니다.
  • 생성자: DTO(Board board) 생성자는 Board 객체를 받아 필요한 필드(id, title, content)만 초기화합니다.
이렇게 함으로써 클라이언트에 불필요한 정보를 보내지 않고, 필요한 데이터만 전달할 수 있게 됩니다.
 
@Data public static class DetailDTO { private Integer id; private String title; private String content; private Boolean isOwner; private String username; //댓글들이 들어와야한다. private List<ReplyDTO> replies = new ArrayList<>(); public DetailDTO(Board board, User sessionUser) { this.id = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); this.isOwner = false; if (sessionUser != null) { if (board.getUser().getId() == sessionUser.getId()) { isOwner = true; // 권한체크 } } this.username = board.getUser().getUsername(); for (Reply reply : board.getReplies()) { replies.add(new ReplyDTO(reply, sessionUser)); } } }
  • 코드설명
💡
주어진 코드는 DetailDTO 클래스의 생성자에서 게시글(Board)의 댓글(Reply)을 순회하며 ReplyDTO 객체로 변환해 replies 리스트에 추가하는 부분입니다. 이 부분에 대해 자세히 설명해드릴게요.

코드 설명 (for 문 부분)

for (Reply reply : board.getReplies()) { replies.add(new ReplyDTO(reply, sessionUser)); }
  1. for 루프:
      • for 문은 board.getReplies() 메소드를 호출하여 가져온 댓글 리스트를 순회합니다.
      • board.getReplies()는 해당 Board 객체에 연결된 모든 Reply 객체(댓글)를 반환합니다.
  1. Reply 객체 순회:
      • Reply replyboard.getReplies()로부터 순차적으로 각 댓글 객체를 하나씩 가져옵니다.
      • 이 루프는 board에 연결된 모든 댓글을 순회합니다.
  1. replies.add(new ReplyDTO(reply, sessionUser));:
      • Reply 객체를 ReplyDTO로 변환합니다.
      • new ReplyDTO(reply, sessionUser)는 각 댓글 Reply 객체와 현재 세션 사용자(sessionUser) 정보를 이용해 새로운 ReplyDTO 객체를 생성합니다.
      • 생성된 ReplyDTO 객체는 replies 리스트에 추가됩니다.
  1. ReplyDTO 생성자:
      • ReplyDTO는 댓글에 대한 정보를 담는 데이터 전송 객체입니다.
      • ReplyDTO 생성자에 replysessionUser를 넘겨줌으로써, 댓글의 내용과 현재 사용자와의 관계 등을 고려하여 DTO 객체를 생성하게 됩니다. 예를 들어, 사용자가 댓글의 작성자인지 여부를 판단하는 로직이 있을 수 있습니다.

요약

for 문은 특정 게시글에 달린 모든 댓글을 순회하며, 각 댓글을 ReplyDTO 객체로 변환하여 DetailDTO 객체의 replies 리스트에 추가하는 역할을 합니다. 이렇게 함으로써 클라이언트가 요청할 때마다 게시글과 함께 해당 게시글에 달린 모든 댓글 정보를 손쉽게 전달할 수 있습니다.
이 과정에서 각 댓글의 세부 사항뿐만 아니라, 현재 세션 사용자가 댓글의 작성자인지 여부 등 추가적인 정보도 ReplyDTO를 통해 담을 수 있습니다.
 
@Data public static class ReplyDTO{ private Integer id; private String content; private boolean isOwner; private String username; public ReplyDTO(Reply reply, User sesstionUser) { this.id = reply.getId(); this.content = reply.getComment(); this.username = reply.getUser().getUsername(); this.isOwner = false; if (sesstionUser != null) { if (reply.getUser().getId() == sesstionUser.getId()) { isOwner = true; //권한체크 } }
  • 코드설명
💡
ReplyDTO 클래스는 댓글에 대한 정보를 담는 데이터 전송 객체(Data Transfer Object)로, 특정 댓글(Reply)의 일부 정보를 선택적으로 담기 위해 사용됩니다.

간단한 설명

  • 필드: id, content, isOwner, username 필드가 있으며, 각각 댓글의 ID, 내용, 작성자 여부, 작성자 이름을 저장합니다.
  • 생성자: ReplyDTO(Reply reply, User sessionUser)Reply 객체와 현재 세션 사용자(sessionUser)를 인자로 받아 필요한 정보를 초기화합니다.
    • isOwner: 현재 세션 사용자가 댓글 작성자인지 확인하여 true 또는 false로 설정됩니다.
이 클래스는 클라이언트에게 필요한 댓글 정보만을 제공하기 위해 설계되었습니다. isOwner 필드는 권한 체크를 위해 사용되어, 현재 사용자가 댓글을 작성했는지 여부를 나타냅니다.

 

3. BoardService

public BoardResponse.DTO 게시글수정화면V2(int id, User sessionUser) { Board board = boardRepository.findById(id) .orElseThrow(()-> new Exception404("게시글을 찾을 수 없습니다")); if (board.getUser().getId() != sessionUser.getId()) { throw new Exception403("게시글 수정 권한이 없습니다."); } return new BoardResponse.DTO(board); }
💡
이 코드는 특정 게시글을 수정하기 위한 데이터를 준비하는 서비스 메소드입니다. 이 메소드는 게시글을 찾고, 현재 사용자에게 해당 게시글을 수정할 권한이 있는지 확인한 후, 권한이 있다면 해당 게시글의 정보를 담은 DTO 객체를 반환합니다.
  1. Board board = boardRepository.findById(id):
      • boardRepository.findById(id) 메소드를 호출하여 데이터베이스에서 해당 ID에 해당하는 Board(게시글) 객체를 찾습니다.
      • Optional로 반환된 결과를 orElseThrow를 통해 예외 처리하여, 해당 게시글이 존재하지 않을 경우 Exception404를 발생시킵니다.
      • Exception404: "게시글을 찾을 수 없습니다"라는 메시지를 가진 예외를 던지며, 이는 404 Not Found HTTP 상태 코드를 의미합니다.
  1. if (board.getUser().getId() != sessionUser.getId()):
      • 현재 세션 사용자(sessionUser)의 ID와 게시글 작성자의 ID를 비교합니다.
      • 만약 현재 사용자가 게시글 작성자가 아니라면, 게시글을 수정할 권한이 없다고 판단하여 Exception403 예외를 발생시킵니다.
      • Exception403: "게시글 수정 권한이 없습니다."라는 메시지를 가진 예외를 던지며, 이는 403 Forbidden HTTP 상태 코드를 의미합니다.
  1. return new BoardResponse.DTO(board);:
      • 권한 검사를 통과한 경우, 게시글의 정보를 담은 BoardResponse.DTO 객체를 생성하여 반환합니다.
      • BoardResponse.DTO는 게시글의 ID, 제목, 내용 등 필요한 정보를 담고 있는 데이터 전송 객체로, 클라이언트에 필요한 데이터만을 전송하기 위해 사용됩니다.

요약

이 메소드는 게시글 수정 화면을 준비하는 데 필요한 데이터를 가져오는 역할을 합니다.
  1. 먼저 게시글을 데이터베이스에서 조회하고,
  1. 현재 사용자가 해당 게시글을 수정할 권한이 있는지 확인한 후,
  1. 권한이 있다면 게시글 정보를 담은 DTO 객체를 반환합니다.
이를 통해 클라이언트가 수정할 게시글의 데이터를 안전하게 가져올 수 있도록 보장합니다.
 
public Board 게시글상세보기V3(User sessionUser, Integer boardId){ Board boardPS = boardRepository.mFindByIdWithReply(boardId) .orElseThrow(() -> new Exception404("게시글이 없습니다.")); return boardPS; }
  • 코드설명
💡
이 코드는 특정 게시글의 상세 정보를 조회하는 서비스 메소드입니다. 이 메소드는 게시글과 그에 대한 댓글까지 포함한 상세 정보를 가져오기 위해 사용됩니다. 이전에 설명한 코드와의 차이점도 포함하여 설명하겠습니다.
Board boardPS = boardRepository.mFindByIdWithReply(boardId):
  • boardRepository.mFindByIdWithReply(boardId) 메소드는 데이터베이스에서 특정 ID의 게시글을 조회하며, 해당 게시글에 달린 댓글도 함께 가져옵니다.
  • 이 메소드는 게시글과 관련된 모든 데이터를 한 번에 가져오는 방식입니다.
return boardPS;:
  • 조회된 게시글 객체 boardPS를 반환합니다.
  • 이 객체에는 게시글의 내용뿐만 아니라, 게시글에 달린 모든 댓글 정보도 포함되어 있을 수 있습니다.
 

 

4. detail.mustach

{{>layout/header}} <div class="container p-5"> <!-- 수정삭제버튼 --> {{#model.isOwner}} <div class="d-flex justify-content-end"> <a href="/api/board/{{model.id}}/update-form" class="btn btn-warning me-1">수정</a> <form action="/api/board/{{model.id}}/delete" method="post"> <button class="btn btn-danger">삭제</button> </form> </div> {{/model.isOwner}} <div class="d-flex justify-content-end"> <!-- 컬렉션이면 user로 만들어야한다.--> <b>작성자</b> : {{model.username}} </div> <!-- 게시글내용 --> <div> <h2><b>{{model.title}}</b></h2> <hr/> <div class="m-4 p-2"> {{{model.content}}} </div> </div> <!-- 댓글 --> <div class="card mt-3"> <!-- 댓글등록 --> <div class="card-body"> <form action="/reply/save" method="post"> <textarea class="form-control" rows="2" name="comment"></textarea> <div class="d-flex justify-content-end"> <button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button> </div> </form> </div> <!-- 댓글목록 --> <div class="card-footer"> <b>댓글리스트</b> </div> <div class="list-group"> {{#model.replies}} <!-- 댓글아이템 --> <div class="list-group-item d-flex justify-content-between align-items-center"> <div class="d-flex"> <div class="px-1 me-1 bg-primary text-white rounded">{{username}}</div> <div>{{comment}}</div> </div> {{#isOwner}} <form action="#" method="post"> <button class="btn">🗑</button> </form> {{/isOwner}} </div> {{/model.replies}} </div> </div> </div> {{>layout/footer}}
  • 코드설명
💡
제공된 HTML 코드와 {{ }} 안의 Mustache 템플릿 구문은 서버에서 가져온 데이터와 동적으로 결합하여 클라이언트에 표시하는 방식입니다.

코드 설명 및 연관성

  1. {{model.isOwner}}:
      • 연관된 Java 코드: DetailDTO 클래스의 isOwner 필드.
      • 설명: model.isOwner는 현재 사용자가 해당 게시글의 소유자인지를 나타냅니다. 이 값은 DetailDTO 생성자에서 설정됩니다. 만약 세션 사용자(sessionUser)의 ID와 게시글 작성자의 ID가 같다면 isOwnertrue로 설정됩니다.
      • 적용: 이 부분은 사용자가 게시글의 작성자인 경우에만 "수정"과 "삭제" 버튼을 표시하도록 합니다.
  1. {{model.username}}:
      • 연관된 Java 코드: DetailDTO 클래스의 username 필드.
      • 설명: model.username은 게시글 작성자의 사용자 이름을 나타냅니다. DetailDTO 생성자에서 board.getUser().getUsername()을 통해 설정됩니다.
      • 적용: 이 값은 게시글 작성자의 이름을 표시하는 데 사용됩니다.
  1. *{{model.title}}*와 {{{model.content}}}:
      • 연관된 Java 코드: DetailDTO 클래스의 titlecontent 필드.
      • 설명: model.titlemodel.content는 게시글의 제목과 내용입니다. DetailDTO 생성자에서 Board 객체의 제목과 내용으로 초기화됩니다.
      • 적용: 이 값들은 각각 게시글의 제목과 내용을 화면에 표시하는 데 사용됩니다.
  1. {{#model.replies}} ... {{/model.replies}}:
      • 연관된 Java 코드: DetailDTO 클래스의 replies 리스트.
      • 설명: model.replies는 게시글에 달린 댓글 목록을 나타냅니다. DetailDTO 생성자에서 Board 객체의 댓글 목록을 ReplyDTO로 변환하여 저장합니다.
      • 적용: 이 부분은 댓글 목록을 반복하여 화면에 출력합니다. 각각의 댓글은 ReplyDTO로부터 usernamecomment 정보를 가져와 표시합니다.
  1. {{username}}{{comment}} (댓글 부분):
      • 연관된 Java 코드: ReplyDTO 클래스의 usernamecontent 필드.
      • 설명: 댓글 작성자의 이름과 댓글 내용을 나타냅니다. ReplyDTO 생성자에서 Reply 객체의 데이터를 기반으로 초기화됩니다.
      • 적용: 각 댓글 항목에서 댓글 작성자의 이름과 댓글 내용이 표시됩니다.
  1. {{#isOwner}} ... {{/isOwner}} (댓글 삭제 버튼 부분):
      • 연관된 Java 코드: ReplyDTO 클래스의 isOwner 필드.
      • 설명: isOwner는 현재 세션 사용자가 해당 댓글의 작성자인지를 나타냅니다. 댓글 작성자와 세션 사용자의 ID가 같을 때 true로 설정됩니다.
      • 적용: 이 조건에 따라 현재 사용자가 댓글의 작성자인 경우에만 댓글 삭제 버튼이 나타납니다.

요약

이 HTML 템플릿은 Java에서 생성된 DTO 객체(DetailDTO, ReplyDTO)의 데이터를 이용하여 동적으로 화면을 구성합니다. 각 템플릿 태그({{ }})는 Java 객체의 필드 값을 참조하여 화면에 필요한 정보를 표시하거나 특정 동작(예: 수정/삭제 버튼 표시)을 제어합니다. 이를 통해 서버와 클라이언트 간의 데이터 통신이 원활하게 이루어질 수 있습니다.
 
Share article

Uni