Controller

 

//숙소 전체 조회
    @GetMapping("/rooms") // size '/api/rooms?page=0&size=3'
    public ResponseEntity<List<RoomResponseDto>> getRooms(@AuthenticationPrincipal UserDetailsImpl userDetails,
                                                          @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
                                                          @RequestParam(required = false, defaultValue = "-1") int minPrice,
                                                          @RequestParam(required = false, defaultValue = "-1") int maxPrice,
                                                          @RequestParam(required = false) String type) {
        return ResponseEntity.ok(roomService.getRooms(userDetails.getUser(), pageable, minPrice, maxPrice, type));
    }

    // 비회원 숙소 전체 조회
    @GetMapping("/rooms/main")
    public ResponseEntity<List<UnClientResponseDto>> getnoclientRooms(@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
                                                                      @RequestParam(required = false, defaultValue = "-1") int minPrice,
                                                                      @RequestParam(required = false, defaultValue = "-1") int maxPrice,
                                                                      @RequestParam(required = false) String type) {
        return ResponseEntity.ok(roomService.getnoclientRooms(pageable, minPrice, maxPrice, type));
    }

    //숙소 키워드 조회
    @GetMapping("/rooms/search") // '/api/rooms/search?keyword=제목&page=0&size=2'
    public ResponseEntity<List<UnClientResponseDto>> search(@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
                                                            String keyword){
        return ResponseEntity.ok(roomService.search(keyword, pageable));
    }

 

  • @PageableDefault 어노테이션으로 글작성 순서에 따라 페이지를 sorting 해준다. 기본 설정 페이지는 10개의 게시글이다.
  • @RequestParam 어노테이션을 이용해 최젓가, 최댓가, 숙소타입을 필터링 할 수 있도록 설정하였다.
  • required = false 를 적용하여 Service 단에서 다양한 필터링 경우를 if문을 통해 사용하도록 하였다.
  • defaultValue = -1 로 설정한 이유는 최젓가와 최댓가가 0원부터 시작할 수 있기 위함이다. (서비스단 if문 참조)
  • 키워드 검색 부분엔 기본 조회 기능에서 String keword 인자를 추가해 주었다.

 

Repository

 

@Repository
public interface RoomRepository extends JpaRepository<Room, Long> {
    Page<Room> findByTitleContaining(String keyword, Pageable pageable);          // 키워드 검색
    Page<Room> findByType(String type, Pageable pageable);                        // 타입별 필터링
    Page<Room> findByPriceBetween(int minPrice, int maxPrice, Pageable pageable); // 가격별 필터링
    @Query(countQuery = "select count(*) from room r where (r.price between :minPrice and :maxPrice) and r.type = :type", nativeQuery = true)
    Page<Room> findByPriceBetweenAndType(@Param("minPrice") int minPrice,
                                         @Param("maxPrice") int maxPrice,
                                         @Param("type") String type,
                                         Pageable pageable);                      // 타입+가격별 필터링
}

 

  • 키워드 검색은 Cotaining()을 사용하였다. title 컨테이닝이기 때문에 키워드검색은 제목 부분만 해당된다.
  • 타입+가격별 필터링은 Spring JPA Data 에서 제공하는 쿼리문만으로는 적용되지 않아, nativeQuery를 사용하였다. 
  • 구글링으로 찾은 블로그를 참조하여 그 중에서 countQuery를 사용하였는데, count(*) 부분의 동작 원리는 잘 모르겠다...^^
  • 기술 매니저님이  QueryDSL을 사용해 보라는 피드백을 주셨다 ! 

 

Service

 

//숙소 페이징, 필터링
    @Transactional(readOnly = true)
    public Page<Room> addFilter(Pageable pageable, int minPrice, int maxPrice, String type) {
        // pageable은 필수, type, price(기본값 -1)별 필터링
        Page<Room> roomList = roomRepository.findAll(pageable);         // RequestParam page, size만 있을 때
        if (type != null && minPrice == -1 && maxPrice == -1) {         // RequestParam type만 있을 때
            roomList = roomRepository.findByType(type, pageable);
        } else if (type == null && minPrice != -1 && maxPrice != -1) {  // RequestParam price만 있을 때
            roomList = roomRepository.findByPriceBetween(minPrice, maxPrice, pageable);
        } else if (type != null && minPrice != -1 && maxPrice != -1) {  // RequestParam type, price 둘 다 있을 때
            roomList = roomRepository.findByPriceBetweenAndType(minPrice, maxPrice, type, pageable);
        }
        return roomList;
    }

    //숙소 정보 전체 조회
    @Transactional(readOnly = true) //회원 전체 조회
    public List<RoomResponseDto> getRooms(User user, Pageable pageable, int minPrice, int maxPrice, String type) {
        List<RoomResponseDto> roomResponseDto = new ArrayList<>();
        for (Room room : addFilter(pageable, minPrice, maxPrice, type)) {
            List<String> imageFileList = new ArrayList<>();
            for (ImageFile imageFile : room.getImageFileList()) {
                imageFileList.add(imageFile.getPath());
            }
            roomResponseDto.add(new RoomResponseDto(
                    room,
                    (checkLike(room.getId(), user)),
                    imageFileList));
        }
        return roomResponseDto;
    }

    @Transactional(readOnly = true) //비회원 전체 조회
    public List<UnClientResponseDto> getnoclientRooms(Pageable pageable, int minPrice, int maxPrice, String type) {
        List<UnClientResponseDto> unClientResponseDto = new ArrayList<>();
        for (Room room : addFilter(pageable, minPrice, maxPrice, type)) {

            // path를 객체로 받아올 경우 주석부분 사용,
//            List<ImageFileResponseDto> imageFileResponseDtoList = new ArrayList<>();
//            for (ImageFile imageFile : room.getImageFileList()) {
//                imageFileResponseDtoList.add(new ImageFileResponseDto(imageFile));
//            }

            // path를 String 타입으로 받올 경우
            List<String> imageFileList = new ArrayList<>();
            for (ImageFile imageFile : room.getImageFileList()) {
                imageFileList.add(imageFile.getPath());
            }
            unClientResponseDto.add(new UnClientResponseDto(room, imageFileList));
        }
        return unClientResponseDto;
    }

    //숙소 키워드 검색
    @Transactional(readOnly = true)
    public List<UnClientResponseDto> search(String keyword, Pageable pageable) {
        Page<Room> roomList = roomRepository.findByTitleContaining(keyword, pageable);

        List<UnClientResponseDto> roomResponseDtos = new ArrayList<>();
        for (Room room : roomList) {
            List<String> imageFileList = new ArrayList<>();
            for (ImageFile imageFile : room.getImageFileList()) {
                imageFileList.add(imageFile.getPath());
            }
            roomResponseDtos.add(new UnClientResponseDto(room, imageFileList));
        }

        return roomResponseDtos;
    }

 

  • 필터링 기능은 if문을 사용하여 구현하였다.
  • 처음에 이미지파일 url (path라는 변수 사용)을 프론트쪽으로 객체타입으로 보내주었는데, String 타입이 더 가공하기 편하다고 하여 주석처리하고 List<String>을 이용하여 반환타입을 문자열로 바꿔주었다.
  • 참고로, UnClientResponseDto는 비회원 전용 Dto이다.

[ 참고자료 ]

+ Recent posts