본문 바로가기
개발/Spring

[4] 페이지 처리하는 DTO 설계

by 민지기il 2025. 3. 5.

[1] Service 설정

Todo를 get, register, modify하는 구조가 필요하다. 

@Service
@Log4j2
@RequiredArgsConstructor
public class TodoServiceImpl implements TodoService{
    private final TodoRepository todoRepository;
    @Override
    public TodoDTO get(Long tno){
        Optional<Todo> result = todoRepository.findById(tno);
        Todo todo = result.orElseThrow();
        return entityDTO(todo);
    }

    @Override
    public Long register(TodoDTO dto) {
        Todo todo = dtoToEntity(dto);
        Todo result = todoRepository.save(todo);
        return result.getTno();
    }

    @Override
    public void modify(TodoDTO dto) {
        Optional<Todo> result = todoRepository.findById(dto.getTno());
        Todo todo = result.orElseThrow();
        todo.changeTitle(dto.getTitle());
        todo.changeContent(dto.getContent());
        todo.changeComplete(dto.isComplete());
        todo.changeDueDate(dto.getDueDate());

        todoRepository.save(todo);
    }

    @Override
    public void remove(Long tno) {
        todoRepository.deleteById(tno);
    }

}

[2] PageResponseDTO -- 페이지 넘어가는 로직 설계

 

[2-1] start & end & last

ex) 3페이지 조회: 1~10 반환, 11페이지 조회: 11~20 반환

(3 / 10 = 0.3을 올림 ) * 10-> end (10)

end에서 9를 빼면 항상 -> start (1)

ex) 전체 132페이지에서 13 페이지 조회: end 값은 20 , 실제로는 14 까지 밖에 없음 

따라서 end>last면 last로 하기

 

[2-2] prev & next

이전, 다음 페이지가 있는지 bool

 

[2-3]

페이지 목록 ex) 1...10 생성

@Data
public class PageResponseDTO <E>{
    private List<E> dtoList;
    private List<Integer> pageNumberList;
    private PageRequestDTO pageRequestDTO;
    private boolean prev, next; //페이지 이전, 다음
    private int totalCount, prevPage, nextPage, totalPage, current;

    @Builder(builderMethodName = "withAll")
    public PageResponseDTO(List<E> dtoList, PageRequestDTO pageRequestDTO, long total){
        this.dtoList = dtoList;
        this.pageRequestDTO = pageRequestDTO;
        this.totalCount = (int) total;

        //끝 페이지 end
        int end = (int) (Math.ceil(pageRequestDTO.getPage() / 10.0)) * 10;
        int start = end-9;
        //진짜 마지막
        int last = (int)(Math.ceil(totalCount / (double) pageRequestDTO.getSize()));

        end = end > last ? last : end;
        this.prev = start >1;
        this.next = totalCount > end * pageRequestDTO.getSize();

        this.pageNumberList = IntStream.rangeClosed(start, end).boxed().collect(Collectors.toList());
        this.prevPage = prev ? start-1 : 0;
        this.nextPage = next ? end+1:0;
    }
}

상단의 @Builder(builderMethodName = "withAll")로

PageResponseDTO<UserDTO> response = PageResponseDTO.<UserDTO>withAll()
        .dtoList(userList)
        .pageRequestDTO(requestDTO)
        .total(100L)
        .build(); 처럼 설계 가능함

[3] service 설계

[3-1] TodoService interface에 선언

PageResponseDTO<TodoDTO> getList(PageRequestDTO pageRequestDTO);

[3-2] TodoSearch interface에 선언

Page<Todo> search1(PageRequestDTO pageRequestDTO);

[3-3] TodoServiceImpl

    @Override
    public PageResponseDTO<TodoDTO> getList(PageRequestDTO pageRequestDTO) {
        //JPA
        Page<Todo> result = todoRepository.search1(pageRequestDTO);
        //가져온 Todo List -> TodoDTO List로 만들기
        List<TodoDTO> dtoList = result
                .get()
                .map(todo -> entityDTO(todo)).collect(Collectors.toList());

        PageResponseDTO<TodoDTO> responseDTO =
                PageResponseDTO.<TodoDTO>withAll()
                        .dtoList(dtoList)
                        .pageRequestDTO(pageRequestDTO)
                        .total(result.getTotalElements())
                        .build();
        return responseDTO;

    }

- search1(하단)을 통해 Todo 엔티티 목록을 가져온다.

- result.get() → Stream<Todo>을 반환

- .map(todo -> entityDTO(todo)) → 각 Todo 엔티티를 TodoDTO로 변환

- .collect(Collectors.toList()) → 변환된 TodoDTO 리스트를 List<TodoDTO> 형태로 저장

- 최종적으로 PageResponseDTO<TodoDTO>를 반환해서 프론트에서 쓸 수 있음

[3-4] TodoSearchImpl

    @Override
    public Page<Todo> search1(PageRequestDTO pageRequestDTO){
        log.info("search1..............");
        QTodo todo = QTodo.todo; //자동으로 생성한 Q 클래스
        JPQLQuery<Todo> query = from(todo); //QueryDSL을 사용하여 JPQL 쿼리 생성
        //query.where(todo.title.contains("1"));
        //Pageable 실행
        Pageable pageable = PageRequest.of(
                pageRequestDTO.getPage()-1,
                pageRequestDTO.getSize(),
                Sort.by("tno").descending());
        //Querydsl 사용 !
        this.getQuerydsl().applyPagination(pageable, query);

        List<Todo> list = query.fetch(); //데이터 가져옴
        long total = query.fetchCount();
        return new PageImpl<>(list, pageable, total);
    }

Spring Data JPA에서 QueryDSL을 사용할 때 페이징을 적용:

this.getQuerydsl() - QueryDSL 인스턴스를 가져오기,

applyPagination(pageable, query) - 페이징을 자동으로 적용

 

 

'개발 > Spring' 카테고리의 다른 글

[6] Todo get, register, modify, remove  (0) 2025.03.07
[5] 페이지 처리 controller 동작  (0) 2025.03.06
[3] DTO 설정  (0) 2025.03.04
[2] Querydsl  (0) 2025.03.04
[1] Entity Test  (0) 2025.03.04