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이다.
[ 참고자료 ]
'항해99 개발 일지 > [7주차] 클론 프로젝트' 카테고리의 다른 글
[07] Swagger (0) | 2023.01.01 |
---|---|
[06] Spring 이메일 인증 구현 (1) | 2023.01.01 |
[04] OAuth 2.0 카카오 로그인 구현 (0) | 2022.12.28 |
[03] S3 이미지파일 다중업로드 (0) | 2022.12.27 |
[02] Airbnb Clone Coding (Main CRUD) (0) | 2022.12.27 |