Spring

Querydsl에서 동적 쿼리와 함께 페이징하기

gogi masidda 2024. 8. 8. 16:36

PageImpl같은거 만들라하는데 잘모르겠어서 그냥 UserInsuranceSearchDto를 만들어서 검색 결과인 contents랑 검색 결과의 총 개수를 나타내는 count를 필드로 만들었다.

 

@Data
public class UserInsuranceSearchDto {

    private List<UserInsurance> content;
    private long count;
}

 

그리고 정렬은 어차피 보험 가입 날짜를 기준으로 내림차순 정렬하고, 보험 가입 날짜가 같은 경우에는 id를 기준으로 오름차순 정렬했다. 그래서 Controller에서는 pageNo만 @RequestParam을 통해 받았다.

@ModelAttribute InsuranceSearch insuranceSearch는 동적 쿼리를 위한 검색 조건들을 입력하기 위한 것이다.

count는 html에서 페이지 버튼 수를 계산하기 위해 사용된다. 

@GetMapping("/insurance/admin/compensation/requests")
    public String compensationRequests(@RequestParam(required = false, defaultValue = "0", value = "page") int pageNo,
                                       @ModelAttribute InsuranceSearch insuranceSearch, HttpSession session, Model model) throws AccessDeniedException {
        if (!checkRole(session)) {
            return "error/403";
        }

        UserInsuranceSearchDto results = userInsuranceService.findAllUserInsurances(insuranceSearch, pageNo);
        List<UserInsurance> userInsurances = results.getContent();
        long count = results.getCount();
        int totalPages = (int) Math.ceil((double) count / (double) 5);

        model.addAttribute("userInsurances", userInsurances);
        model.addAttribute("count", count);
        model.addAttribute("pageNo", pageNo);
        model.addAttribute("totalPages", totalPages);
        return "admin/userInsuranceListForAdmin";
    }

 

Controller가 호출한 UserInsuranceService에서는 검색 조건인 insuranceSearch, 페이징을 위한 pageNo를 받아 검색한다. insuranceSearch에 저장되어 있는 모든 검색 조건들을 꺼내서 userInsuranceRepository에 넘기며 검색한다. 

검색한 이후에는 userInsuranceSearchDto에 검색 결과와 총 검색 결과 수를 가져와서 저장하고 리턴한다. 

public UserInsuranceSearchDto findAllUserInsurances(InsuranceSearch insuranceSearch, int pageNo) {
        Pageable pageable = PageRequest.of(pageNo, 5);

        CompensationStatus compensationStatus = insuranceSearch.getCompensationStatus();
        String insuranceName = insuranceSearch.getInsuranceName();
        String username = insuranceSearch.getUsername();
        CompensationOption option = insuranceSearch.getCompensationOption();

        List<UserInsurance> contents = userInsuranceRepository.findAllUserInsurances(username, insuranceName, compensationStatus, option, pageable);
        long count = userInsuranceRepository.countUserInsurances(username, insuranceName, compensationStatus, option);
        UserInsuranceSearchDto userInsuranceSearchDto = new UserInsuranceSearchDto();
        userInsuranceSearchDto.setContent(contents);
        userInsuranceSearchDto.setCount(count);
        return userInsuranceSearchDto;
    }

 

Service가 호출한 UserInsuranceRepository에서는 Querydsl을 이용해서 동적 쿼리와 페이징을 진행한다. 

각 조건은 BooleanExpression을 사용하여 조건문을 작성한다.

public List<UserInsurance> findAllUserInsurances(String usernameCond, String insuranceNameCond, CompensationStatus statusCond, CompensationOption optionCond, Pageable pageable) {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);

        List<UserInsurance> result = queryFactory
                .selectFrom(userInsurance)
                .join(userInsurance.insurance, insurance)
                .join(userInsurance.user, user)
                .where(
                        usernameEq(usernameCond),
                        insuranceNameEq(insuranceNameCond),
                        compensationOptionEq(optionCond),
                        compensationStatusEq(statusCond)
                )
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .orderBy(userInsurance.registerDate.desc(), userInsurance.id.asc())
                .fetch();

        return result;
    }

    public long countUserInsurances(String usernameCond, String insuranceNameCond, CompensationStatus statusCond, CompensationOption optionCond) {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);

        return queryFactory
                .select(userInsurance.count())
                .from(userInsurance)
                .where(
                        usernameEq(usernameCond),
                        insuranceNameEq(insuranceNameCond),
                        compensationOptionEq(optionCond),
                        compensationStatusEq(statusCond)
                )
                .fetchOne();
    }

    private BooleanExpression usernameEq(String usernameCond) {
        if(usernameCond == null || usernameCond.isEmpty()) {
            return null;
        }

        return user.username.eq(usernameCond);
    }

    private BooleanExpression insuranceNameEq(String insuranceNameCond) {
        if(insuranceNameCond == null || insuranceNameCond.isEmpty()) {
            return null;
        }

        return insurance.name.eq(insuranceNameCond);
    }

    private BooleanExpression compensationOptionEq(CompensationOption compensationOptionCond) {
        return compensationOptionCond != null ? userInsurance.compensationOption.eq(compensationOptionCond) : null;
    }

    private BooleanExpression compensationStatusEq(CompensationStatus statusCond) {
        return statusCond != null ? userInsurance.compensationStatus.eq(statusCond) : null;
    }

 

실행 결과

728x90