볡수의 데이터λ₯Ό λ°˜ν™˜ν•˜λŠ” κ²½μš°μ— νŽ˜μ΄μ§•μ€ ν•„μˆ˜!

μˆ˜μ‹­, 수백만개의 데이터λ₯Ό ν•œλ²ˆμ— λ°˜ν™˜ν•œλ‹€λ©΄..?

APIλ₯Ό κ°œλ°œν•˜λ‹€ 보면 데이터 리슀트λ₯Ό λ°˜ν™˜ν•˜λŠ” 상황이 무쑰건 λ°œμƒν•œλ‹€. 그런데 λ§Œμ•½μ— μ•„λ¬΄λŸ° 쑰치 없이 데이터 리슀트λ₯Ό λ°˜ν™˜ν•œλ‹€κ³  μƒκ°ν•΄λ³΄μž.  λͺ‡μ‹­, λͺ‡λ°±κ°œμ˜ 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ”λ°λŠ” 큰 상관이 μ—†μ§€λ§Œ λͺ‡μ‹­λ§Œ, λͺ‡ 백만개의 데이터λ₯Ό λ°˜ν™˜ν•˜κ²Œ 되면 λ¬Έμ œκ°€ λ°œμƒν•  수 밖에 μ—†λ‹€.  μ΄λŸ¬ν•œ 상황을 λ°©μ§€ν•˜κΈ° μœ„ν•΄ μš°λ¦¬λŠ” API μ„€κ³„μ‹œμ— νŽ˜μ΄μ§• λ‘œμ§μ„ ν•„μˆ˜μ μœΌλ‘œ μ μš©μ‹œμΌœμ•Ό ν•œλ‹€. 

 

νŽ˜μ΄μ§•μ„ μ μš©ν•œ API κ΅¬ν˜„ μ˜ˆμ‹œ 

λ‹€μŒμ€ λ‚˜λ§Œμ˜ 옷μž₯ μ„œλΉ„μŠ€μ—μ„œ νŽ˜μ΄μ§•μ„ μ μš©ν•œ 옷 리슀트λ₯Ό λ°˜ν™˜ν•˜λŠ” API κ΅¬ν˜„ μ˜ˆμ‹œμ΄λ‹€.  

 

@Setter
@Getter
public class ResponseForClothes extends PaginatedResponse {
    private List<ContentForCloth> contents;
}

 

옷 리슀트λ₯Ό λ°˜ν™˜ν•˜κΈ° μœ„ν•œ DTO 이닀. contents ν•„λ“œμ— ContentForCloth 객체듀이 λ‹΄κΈ°κ²Œ λœλ‹€. ContentForClothλŠ” Cloth 정보가 λ‹΄κΈ°λŠ” 객체이고  ResponseForClothesκ°€ μƒμ†λ°›λŠ” PaginatedResponseλŠ” νŽ˜μ΄μ§• μ²˜λ¦¬κ°€ ν•„μš”ν•œ λͺ¨λ“  DTOκ°€ μƒμ†λ°›λŠ” 객체이닀. 

 

@Getter
@Setter
public class PaginatedResponse {
    private Integer _code;
    private String _message;
    private Integer totalPages; // 총 νŽ˜μ΄μ§€ 수
    private Integer pageNumber; // ν˜„μž¬ νŽ˜μ΄μ§€
    private Integer numberOfElements; // ν˜„μž¬ νŽ˜μ΄μ§€μ˜ μ•„μ΄ν…œ 개수
    private Integer size; // ν•œ νŽ˜μ΄μ§€μ˜ μ΅œλŒ€ μ•„μ΄ν…œ 수
    private Long totalElements; // 총 μ•„μ΄ν…œ 수
    private Boolean isLast; // λ§ˆμ§€λ§‰ νŽ˜μ΄μ§€ μ—¬λΆ€
    private Boolean isFirst; // 첫 νŽ˜μ΄μ§€ μ—¬λΆ€

    public void setPageNumber(Integer pageNumber) {
        this.pageNumber = pageNumber + 1;
    }
}

 

PaginatedResponseλŠ” Page에 κ΄€λ ¨λœ 정보λ₯Ό 가지고 μžˆλ‹€. νŽ˜μ΄μ§• 처리λ₯Ό 톡해 데이터λ₯Ό μ „λ‹¬ν•˜λŠ” 만큼 그에 λ”°λ₯Έ νŽ˜μ΄μ§• 정보λ₯Ό ν•¨κ»˜ λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€. (κ·Έλž˜μ•Ό ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 데이터 μ²˜λ¦¬κ°€ κ°€λŠ₯ν•˜λ‹€) 자, 이제 DTO에 데이터λ₯Ό λ‹΄μ•„ λ°˜ν™˜ν•˜κΈ°λ§Œ ν•˜λ©΄ νŽ˜μ΄μ§• μ²˜λ¦¬κ°€ 완성이 λœλ‹€. κ·Έλ ‡λ‹€λ©΄ νŽ˜μ΄μ§• λ‘œμ§μ€ μ–΄λ–€μ‹μœΌλ‘œ κ΅¬ν˜„ν•΄μ•Ό ν• κΉŒ? 

 

    /** WardrobeService **/
    @Transactional
    public ResponseEntity<ResponseForWardrobes> findAll(int pageNumber, int pageSize) {
        PageRequest pageRequest = PageRequest.of(pageNumber-1, pageSize);
        Page<Wardrobe> paginationedWardrobes = wardrobeRepository.findAll(pageRequest);

        return paginationService.convertToPaginatedWardrobes(paginationedWardrobes);
    }
    
    /** PaginationService **/ 
    protected ResponseEntity<ResponseForWardrobes> convertToPaginatedWardrobes(Page<Wardrobe> paginatedWardrobes) {
        List<ContentForWardrobe> wardrobes = new ArrayList<>();
        ResponseForWardrobes responseForWardrobes = new ResponseForWardrobes();

        for(Wardrobe wardrobe : paginatedWardrobes.getContent()) {
            wardrobes.add(new ContentForWardrobe(
                    wardrobe.getId(),
                    wardrobe.getName(),
                    wardrobe.getClothes().size(),
                    wardrobe.getLikeCnt(),
                    wardrobe.getMember().getName())
            );
        }

        responseForWardrobes.set_code(200);
        responseForWardrobes.set_message("OK");
        responseForWardrobes.setContents(wardrobes);
        responseForWardrobes.setTotalPages(paginatedWardrobes.getTotalPages());
        responseForWardrobes.setPageNumber(paginatedWardrobes.getNumber());
        responseForWardrobes.setSize(paginatedWardrobes.getSize());
        responseForWardrobes.setNumberOfElements(wardrobes.size());
        responseForWardrobes.setTotalElements(paginatedWardrobes.getTotalElements());
        responseForWardrobes.setIsLast(paginatedWardrobes.isLast());
        responseForWardrobes.setIsFirst(paginatedWardrobes.isFirst());

        return new ResponseEntity<>(responseForWardrobes, HttpStatus.OK);
    }

 

λ‹€ν–‰νžˆλ„ HibernateλŠ” νŽ˜μ΄μ§• 처리λ₯Ό 직접 μ œκ³΅ν•œλ‹€. PageRequestλ₯Ό 톡해 νŽ˜μ΄μ§€ λ²ˆν˜Έμ™€ νŽ˜μ΄μ§€ λ‹Ή μ΅œλŒ€ 데이터 수λ₯Ό 지정해주고 Repositoryμ—κ²Œ λ„˜κ²¨μ£Όλ©΄ νŽ˜μ΄μ§•μ΄ 된 λ¦¬μŠ€νŠΈκ°€ λ°˜ν™˜ λœλ‹€. μ΄λ•Œ 이 λ°μ΄ν„°λŠ” Page ν˜•νƒœλ₯Ό 가지고 μžˆλŠ”λ° νŽ˜μ΄μ§•κ³Ό κ΄€λ ¨λœ μ „λ°˜μ μΈ 정보도 ν•¨κ»˜ ν¬ν•¨ν•˜κ³  μžˆλ‹€. νŠΉλ³„ν•œ 둜직 κ΅¬ν˜„ 없이 λ°˜ν™˜ν•΄μ€€ νŽ˜μ΄μ§€ 정보와 데이터듀을 DTO에 μ•Œλ§žκ²Œ λ§€ν•‘μ‹œμΌœ λ°˜ν™˜λ§Œ μ‹œμΌœμ£Όλ©΄ 이리 κ°„λ‹¨ν•˜κ²Œ νŽ˜μ΄μ§• λ‘œμ§μ„ API에 μ μš©μ‹œν‚¬ 수 μžˆλ‹€.