Pageable의 map 사용방법

선종우·2023년 4월 26일
1

1. 공부배경

쿼리메소드를 이용할 때 파라미터로 Pageable구현 객체를 전달하면 반환 값으로 Page<> 객체를 반환한다. 문제는 쿼리메소드가 반환하는 Page<>객체와 메소드를 호출한 Service 메소드가 반환해야 하는 Page<>객체가 다를 경우였다. 예를 들어서 아래와 같은 코드를 구성하였다고 하자.

	public Page<EventFormDto> getEventLists(Pageable pageable){
        return eventRepository.findAll(pageable);
    }

위 코드에서 findAll메소드는 Page<Event>를 반환하지만 getEventLists메소드는 Page<EventFormDto>를 반환한다. 이때 사용하는 게 Page 객체의 map메소드인데 동작원리가 잘 이해되지 않아 정리했다.

2. 공부 내용

Pageable 인터페이스에는 <U> Page<U> map(Function<? super T, ? extends U> converter); 가 정의되어 있다. 따라서 Pageable를 구현한 Page 클래스 안에는 아래와 같은 메소드가 정의되어 있어야 한다.

<U> page<U> map(Function<? super T, ? extends U> converter){
List<U> content = new ArrayList<>(getSize());
        for (T element : this) {
            content.add(converter.apply(element));
        }
        return new PageImpl<>(content, getPageable(), getTotalElements());
}

코드를 보면 mapconverter(@FunctionalInterface Function 구현체)를 전달하면 page 객체는 Page<T>의 T를 순회하며 converter의 apply 메소드를 적용하는 것을 알 수 있다. 그리고 PageImpl<>을 이용해 새로 생성된 content를 다시 Page<U> 객체로 만들어 준다. 이를 실제 내 코드에 적용해 보면 아래와 같다.

<EventFormDto> page<EventFormDto> map(Function<? super Event, ? extends EventFormDto> converter){
List<EventFormDto> content = new ArrayList<>(getSize());
        for (Event element : this) {
            content.add(converter.apply(element));
        }
        return new PageImpl<>(content, getPageable(), getTotalElements());
}

결론은 converter를 잘 구현해주면 내가 원하는 조작을 Event객체에 적용할 수 있고, 이를 다시 Page<>객체로 만들어낼 수 있다는 것이다. 많은 경우 Dto에 static method를 구현해서 아래와 같이 사용한다.

    public static EventFormDto from(Event event){
       return new EventFormDto(event.getId(),
               event.getTitle(),
               event.getTitleTag(),
               event.getRecruitDeadline(),
               event.getFee(),
               event.getPeopleLimit(),
               event.getSummary(),
               event.getContent(),
               event.getStatus(),
               event.getHashtag(),
               event.getStartDate(),
               event.getEndDate());
    }
	public Page<EventFormDto> getEventLists(Pageable pageable){
        return eventRepository.findAll(pageable).map(EventFormDto::from);
    }

나는 조금 더 복잡한 작업을 해주고 싶기도 하고 익명클래스와 람다식을 조금 더 연습할 겸 아래와 같이 작성해보았다.(개인적으로 람다식과 익명함수를 길게 사용하는 걸 좋아하진 않는다)

//익명 클래스 이용(apply메소드명은 변경 가능)
public Page<EventFormDto> getEventLists(Pageable pageable) {
    return eventRepository.findAll(pageable).map(new Function<Event, EventFormDto>() {
        @Override
        public EventFormDto apply(Event event) {
            EventFormDto eventDto = EventFormDto.from(event);
            EventImg eventImg = eventImgRepository.findByEvent(event)
                                                  .orElse(new EventImg("default", "default", "/images/event/default.PNG", event));
            EventImgDto eventImgDto = eventImg.toDto();
            eventDto.setEventImgDto(eventImgDto);
            return eventDto;
        }
    });
}
    
//람다식 이용
	public Page<EventFormDto> getEventLists(Pageable pageable){
        return eventRepository.findAll(pageable).map(event -> {
            EventFormDto eventDto = EventFormDto.from(event);
            EventImg eventImg = eventImgRepository.findByEvent(event)
                                                    .orElse(new EventImg("default", "default", "/images/event/default.PNG", event));
            EventImgDto eventImgDto = eventImg.toDto();
            eventDto.setEventImgDto(eventImgDto);
            return eventDto;
        });
    }

3. 정리

Page<T> 형태의 객체를 Page<U>형태로 바꿔야 하는 경우 아래와 같이 구현하면 된다.

Page<T> 객체.map(param(객체 안에 담긴 T형 파라미터를 의미한다) ->{
	U convertedparam = param.~~
	(U는 변환결과로 받고싶은 객체, 과정에서 convertedParam에 대한 다양한 조작 수행)
	return convertedParam(U형 파라미터)
});

0개의 댓글