[Spring] 응답 DTO 만들기

류재성's avatar
Apr 01, 2024
[Spring] 응답 DTO 만들기
 

1. 회원 정보 조회 DTO

 
notion image
💡
DB에서 ID, 유저네임과 이메일을 가지고 온다.
 
package shop.mtcoding.blog.user; import lombok.Data; public class UserResponse { // 엔티티를 dto로. 그래서 응답은 풀생성자가 필요함 @Data public static class DTO{ private int id ; private String username; private String email; public DTO(User user) { this.id = user.getId(); this.username = user.getUsername(); this.email = user.getEmail(); } } }
 
💡
만약 Lazy Loading 이 발생한다면 getter 가 호출될 때 발생한다.
 
public UserResponse.DTO 회원조회(int id){ User user = userJPARepository.findById(id) .orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다.")); return new UserResponse.DTO(user) ;//엔티티 생명 종료, 여기서 레이지 로딩 종료 }
 
 
@GetMapping("/api/users/{id}") public ResponseEntity<?> userinfo(@PathVariable Integer id){ UserResponse.DTO responseDTO = userService.회원조회(id); return ResponseEntity.ok(new ApiUtil(responseDTO)); }
 
 
notion image
 

2. 게시글 목록 조회 DTO

 
notion image
💡
DB에서 ID, title 을 가지고 온다.
 
package shop.mtcoding.blog.board; import lombok.Data; import shop.mtcoding.blog.user.User; public class BoardResponse { @Data public static class MainDTO{ private int id; private String title; public MainDTO(Board board) { this.id = board.getId(); this.title = board.getTitle(); } } }
 
 
public List<BoardResponse.MainDTO> 글목록조회() { Sort sort = Sort.by(Sort.Direction.DESC, "id"); List<Board> boardList = boardJPARepository.findAll(sort); return boardList.stream().map(board -> new BoardResponse.MainDTO(board)).toList(); }
 
 
@GetMapping("/") public ResponseEntity<?> main(){ List<BoardResponse.MainDTO> responseDTO = boardService.글목록조회(); return ResponseEntity.ok(new ApiUtil(responseDTO)); }
 
 
notion image
 
 
💡
DTO 를 사용하면 원하는 데이터만 가지고 통신을 할 수 있다.
 

3. 상세보기 DTO

 
boardId, title content boarUserId username replyId comment replyUserId replyUsername
 
 
{ "id":1, "title":"제목1", "content":"내용1", "user":{ "id":1, "username":"ssar" } "re }
 
💡
DTO 에는 화면에 보이는 정보와 보이지 않더라도 ID를 함께 담아야 한다. 페이지의 권한 여부는 페이지에서 보이지 않기 때문에 ID가 있다면 프론트에서 권한 처리 할 수 있다.
 
 
 
@Data public static class DetailDTO{ private int id; private String title; private String content ; private int userId ; private String usernaem; // 게시글 작성자 private boolean isOwner ; private List<ReplyDTO> replies = new ArrayList<>(); // new 를해서 초기화해야 값이 없을 때 0의 빈 배열을 리턴함. null 이면 터짐 public DetailDTO(Board board, User sessionUser) { this.id = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); this.userId = board.getUser().getId(); this.usernaem = board.getUser().getUsername(); this.isOwner = false; if(sessionUser!=null){ if(sessionUser.getId()==userId){ isOwner =true ; } } //List 타입을 api 스트림으로 DTO 타입으로 담는다. this.replies = board.getReplies().stream().map(reply -> new ReplyDTO(reply,sessionUser)).toList(); } @Data public class ReplyDTO{ private int id ; private String content ; private int userId ; private String username ; // 댓글 작성자 private boolean isOwner ; public ReplyDTO(Reply reply,User sessionUser) { this.id = reply.getId(); this.content = reply.getComment(); this.userId = reply.getUser().getId(); this.username = reply.getUser().getUsername(); //lazy loading 발동 this.isOwner = false; if(sessionUser!=null){ if(sessionUser.getId()==userId){ isOwner =true ; } } } }
 
public BoardResponse.DetailDTO 글상세보기(int boardId, User sessionUser) { Board board = boardJPARepository.findByIdJoinUser(boardId) .orElseThrow(() -> new Exception404("게시글을 찾을 수 없습니다")); return new BoardResponse.DetailDTO(board,sessionUser); }
 
 
@GetMapping("/api/boards/{id}/detail") public ResponseEntity<?> detail(@PathVariable int id){ User sessionUser = (User) session.getAttribute("sessionUser"); BoardResponse.DetailDTO responseDTO = boardService.글상세보기(id,sessionUser); return ResponseEntity.ok(new ApiUtil(responseDTO)); }
 
notion image
 
notion image
 
💡
처음
 
 
notion image
 
 

4. 예외 경우

 
 
 
select * from board_tb ; select count(id) from reply_tb where board_id = 4; select id, title, content, user_id, (select count(id) from reply_tb where board_id = bt.id) reply_count from board_tb bt;
 
 
notion image
 
💡
만약 이런 서브 쿼리로 댓글의 갯수를 포함한 데이터를 DTO로 받고 싶다면 ?
 
 
public class BoardResponse { @AllArgsConstructor @Data public static class CountDTO { private Integer id ; private String title ; private String content; private Integer userId ; private Long replyCount ; } }
 
 
@Query("select new shop.mtcoding.blog.board.BoardResponse$CountDTO(b.id, b.title, b.content, b.user.id, (select count(r.id) from Reply r where r.board.id = b.id)) from Board b") List<BoardResponse.CountDTO> findAllWithReplyCount(); //<> 내부는 원래 Board 타입만 받을 수 잇음 // 클래스 내부에 static 으로 DTO를 만든다면 $ 를 사용해서 클래스$DTO 로 표시해야 한다.
 
 
@Test public void findAllWithCount_test(){ List<BoardResponse.CountDTO> CountDTOList = boardJPARepository.findAllWithReplyCount(); for(int i=0;i<CountDTOList.size();i++){ System.out.println(CountDTOList.get(i)); } }
 
notion image
 
 
notion image
Share article
RSSPowered by inblog