[Spring] 서비스 레이어에서 여러 데이터 리턴이 필요할 때

류재성's avatar
Mar 20, 2024
[Spring] 서비스 레이어에서 여러 데이터 리턴이 필요할 때
 
notion image
 
 
게시글 상세보기 페이지에는 게시글의 권한을 부여하는 버튼이 있다. 이 버튼은 게시글을 작성한 사람에게만 활성화되어야 하는 버튼이다.
 
notion image
 
게시글 버튼의 권한 여부는 컨트롤러에서 했으나, 서비스 레이어를 만들게 되면서 기능이 서비스로 넘어왔다. 하지만 Board 엔티티에는 isOwner 필드가 없기 때문에 서비스 레이어에서는 권한을 컨트롤러로 넘길 수가 없다.
 
Board 엔티티에 isOwner 필드가 없음
notion image
 
💡
서비스 레이어에서 여러 데이터를 리턴할 때는 두 가지 방법이 있다. 1. DTO 를 활용하는 방법 2. 엔티티에 필드를 추가하는 방법

1. DTO 사용한 경우

 
💡
서비스 레이어에서 받은 데이터를 하나의 DTO로 받아서 DTO를 컨트롤러에 리턴한다.
 
BoardResponse
package shop.mtcoding.blog.board; import lombok.Data; import shop.mtcoding.blog.user.User; public class BoardResponse { @Data public static class DetailDTO{ private int id; private String title; private String content; private UserDTO user ; private Boolean isBoardOwner ; // board 객체 정보를 DTO 에 담는다. public DetailDTO(Board board,User sessionUser) { this.id = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); this.user = new UserDTO(board.getUser()); this.isBoardOwner = false; //게시글의 권한 여부를 체크 if(sessionUser !=null){ if(sessionUser.getId()==board.getUser().getId()){ isBoardOwner = true ; } } } //DetailDTO의 UserDTO. 세션의 유저 정보를 DTO에 받음. @Data private class UserDTO{ private int id ; private String username ; public UserDTO(User user) { this.id = user.getId(); this.username = user.getUsername(); } } } }
 
BoardService
public BoardResponse.DetailDTO 글상세보기(int boardId, User sessionUser){ Board board = boardJPARepository.findByIdJoinUser(boardId) .orElseThrow(() -> new Exception404("게시글을 찾을 수 없습니다.")); return new BoardResponse.DetailDTO(board,sessionUser); }
 
로그인한 유저의 sessionUser 정보와 DB에서 조회된 board 정보를 DTO 담아서 리턴한다.
 
BoardJPARepository
package shop.mtcoding.blog.board; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; public interface BoardJPARepository extends JpaRepository<Board,Integer>{ @Query("select b from Board b join fetch b.user where b.id = :id") Board findByIdJoinUser(@Param("id") Integer id); }
 
 
BoardController
@GetMapping("/v2/board/{id}") public @ResponseBody BoardResponse.DetailDTO detailV2(@PathVariable Integer id, HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); BoardResponse.DetailDTO responseDTO = boardService.글상세보기(id, sessionUser); return responseDTO ; }
 
notion image
💡
DTO를 사용한 경우 화면에 필요한 데이터만 가져올 수 있다.
 

2.DTO를 사용하지 않는 경우 @Transient

 
Board
@Transient // 테이블 생성이 안됨. 임시로 사용함 private boolean isOwner ;
 
BoardController
@GetMapping("/board/{id}") public String detail(@PathVariable Integer id,HttpServletRequest request) { // int 를 쓰면 값이 없으면 0, Integer 를 넣으면 값이 없을 때 null 값이 들어옴. User sessionUser = (User) session.getAttribute("sessionUser"); Board board = boardService.글상세보기(id,sessionUser); request.setAttribute("board", board); return "board/detail"; }
 
BoardService
public Board 글상세보기(int boardId, User sessionUser) { Board board = boardJPARepository.findByIdJoinUser(boardId) .orElseThrow(() -> new Exception404("게시글을 찾을 수 없습니다")); boolean isOwner = false; if(sessionUser != null){ if(sessionUser.getId() == board.getUser().getId()){ isOwner = true; } } board.setOwner(isOwner); return board; }
 
notion image
💡
DTO를 사용하지 않는 경우 사용하지 않는 데이터도 함께 가져오게 된다.
 
 

3. 결론

 
💡
서버 사이드 랜더링을 할 때는 DTO 가 아니라 엔티티를 가지고 원하는 데이터만 선택해서 화면에 뿌려도 된다. 하지만 클라이언트 사이드 랜더링을 하면 JSON 데이터만 응답되고 클라이언트 측에서 화면이 그려지기 때문에 정확한 데이터만 전달되어야 한다. 그래서 SSR 은 꼭 DTO 를 만들지 않아도 되지만 CSR 은 DTO가 있어야 한다.
 
 
 
 
 
 
 
 
 
 
Share article

{CODE-RYU};