본문 바로가기

photogram 리팩토링

photogram 리팩토링 일기

728x90

오늘은 메인페이지에 자신이 구독을 한 사용자의 이미지와 댓글을 달 수 있게 할것이다.

 

리팩토링 하기전  서비스로직

 

   @Transactional(readOnly = true)
    public Page<Image> imageStory(long principalId, Pageable pageable){

        Page<Image> images = imageRepository.mStory(principalId,pageable);

        //images에 좋아요 상태 담기
        images.forEach((image)-> {

            image.setLikeCount(image.getLikes().size());

            image.getLikes().forEach((like)->{
                if(like.getUser().getId() == principalId) {
                    image.setLikeState(true);
                }
            });
        });

        return images;

    }

RestapiContoller

@GetMapping("/api/image")
    public ResponseEntity<?> imageStory(@AuthenticationPrincipal PrincipalDetails principalDetails,
                                        @PageableDefault(size=3,sort="id",direction = Sort.Direction.DESC)Pageable pageable){

        Page<Image> images = imageService.imageStory(principalDetails.getUser().getId(),pageable);

        return new ResponseEntity<>(new CMResDto<>(1,"성공",images),HttpStatus.OK);
    }

 

리팩토링 하기전의 문제점:

Entity의 모든 api스팩을 노출시켜 사용자의 비밀번호 뿐만 아니라 불필요하게 쿼리가 여러방이 나간다.

성능에도 좋지못하다고 볼수있다.

 

리팩토링 후

 

 @GetMapping("/api/image")
    public ResponseEntity<?> imageStory(@AuthenticationPrincipal PrincipalDetails principalDetails,
                                        @RequestParam(value="offset",defaultValue = "0") int offset,
                                        @RequestParam(value="limit",defaultValue = "100") int limit,

                                        @PageableDefault(size=3,sort="id",direction = Sort.Direction.DESC)Pageable pageable){

        List<Image> images =  imageService.imageStory(principalDetails.getUser().getId(),offset,limit);
        List<ImageResDto> collect = images.stream().map(i -> new ImageResDto(i)).collect(Collectors.toList());

        return new ResponseEntity<>(new CMResDto<>(1,"성공",collect),HttpStatus.OK);
    }
    @Transactional(readOnly = true)
    public List<Image> imageStory(long principalId, int offset,int limit){

//        Page<Image> images = imageRepository.mStory(principalId,pageable);
//
//        //images에 좋아요 상태 담기
//        images.forEach((image)-> {
//
//            image.setLikeCount(image.getLikes().size());
//
//            image.getLikes().forEach((like)->{
//                if(like.getUser().getId() == principalId) {
//                    image.setLikeState(true);
//                }
//            });
//        });
        List<Image> resultList = em.createQuery("select i from Image i" +
                " join fetch i.user u", Image.class)
                .setFirstResult(offset)
                .setMaxResults(limit)
                .getResultList();


        return resultList;

    }

일단 Lazy전략으로 ToOne 관계는 전부 Lazy 로 바꿔주었다. 또한 ToOne관계는 fetch join으로 끌고왔다.

 

properties:
  hibernate:
    default_batch_fetch_size: 100

그리고 ToMany관계는 전부 batch_fetch로 In절 쿼리를 이용하여 끌고왔다.

 

@Data
public class ImageResDto {

    private long id;
    private String postImageUrl;

    private User user;
    private long likeCount;
    private String caption;
    private List<ImageCommentResDto> comments;


    @Builder
    public ImageResDto(Image image) {
        this.id = image.getId();
        this.postImageUrl = image.getPostImageUrl();
        this.user=image.getUser();
        this.likeCount = image.getLikeCount();
        this.caption = image.getCaption();
        this.comments = image.getComments().stream()
                .map(c->new ImageCommentResDto(c))
                .collect(Collectors.toList());
    }
}

 

@Data
public class ImageCommentResDto {

    private long id;
    @NotBlank
    private String content;
    private String username;
    private long userId;
    public ImageCommentResDto(Comment comment) {
        this.id = comment.getId();
        this.content = comment.getContent();
        this.username=comment.getUser().getUsername();
        this.userId=comment.getUser().getId();
    }
}

 

{
    "code": 1,
    "message": "성공",
    "data": [
        {
            "id": 1,
            "postImageUrl": "8377fc8d-5e5f-4208-bdb3-46c29d23863e_다운로드 (2).jpg",
            "user": {
                "id": 3,
                "username": "cos",
                "password": "$2a$10$cO9cxD8RHyLQqwTARWIlE.2sPINZA.1TuN8aaJw0o0jIV3.47QhoS",
                "name": "코스",
                "website": null,
                "bio": null,
                "email": "cos@nate.com",
                "phone": null,
                "gender": null,
                "profileImageUrl": null,
                "role": "ROLE_USER",
                "images": null,
                "createDate": "2023-02-17T11:51:17.304359"
            },
            "likeCount": 0,
            "caption": "asd",
            "comments": [
                {
                    "id": 2,
                    "content": "asdasd",
                    "username": "ssar",
                    "userId": 1
                },
                {
                    "id": 1,
                    "content": "asdasdas",
                    "username": "ssar",
                    "userId": 1
                }
            ]
        },

 

리팩토링 완료한 부분:

 

메인페이지-

구독한 유저의 이미지,이미지유저정보,댓글정보,좋아요정보,좋아요 카운트 fecth join 및 batch fetch로 변환 및

DTO 반환 완료

 

댓글-수정,삭제 완료

 

좋아요 카운트 및 좋아요 완료

 

앞으로 해야할 것.

 

프로필 사진 업데이트, 이미지업로드 및 모든 Entity 반환 -> Dto로 변환 및 open in view 끄고 서비스 로직에서

DTO 반환

 

 

728x90