API/실습

78. [JAVA] API 문서 문제 : JDBC -> JPA 진행 (2)

천재단미 2025. 1. 15. 15:43
728x90
반응형

 

 

 

문제

 

1.2. 음식점 상세 조회

특정 음식점의 상세 정보와 메뉴 목록을 조회하는 API입니다.

  • URL: /api/v1/restaurants/{id}
  • Method: GET
  • 설명:
    • 음식점의 기본 정보를 제공합니다.
    • 해당 음식점의 전체 메뉴 목록을 함께 반환합니다.
    • 평균 평점과 총 리뷰 수를 포함합니다.
    • 각 메뉴별 리뷰 수도 함께 제공됩니다.
    • 존재하지 않는 음식점 ID인 경우 404 에러를 반환합니다.
  • Response:
{
		"restaurant": {
		    "id": 1,
		    "name": "맛있는 식당",
		    "category": "한식",
		    "address": "서울시 강남구",
		    "phone": "02-1234-5678",
		    "description": "전통 한식집",
		    "avgRating": 4.5,
		    "reviewCount": 100,
		    "createdAt": "2024-12-27T10:00:00",
	  },
    "menus": [
        {
            "id": 1,
            "name": "김치찌개",
            "price": 8000,
            "description": "돼지고기 김치찌개",
            "category": "찌개",
            "reviewCount": 50
        }
    ]
}

 

2. 메뉴 API

2.1. 음식점별 메뉴 목록 조회

특정 음식점의 메뉴 목록을 조회하는 API입니다.

  • URL: /api/v1/restaurants/{restaurantId}/menus
  • Method: GET
  • 설명:
    • 특정 음식점의 전체 메뉴를 페이징 처리하여 제공합니다.
    • 카테고리별 필터링을 지원합니다.
    • 각 메뉴의 리뷰 수를 포함합니다.
    • 메뉴는 카테고리별, 가격순으로 정렬 가능합니다.
    • 존재하지 않는 음식점 ID인 경우 404 에러를 반환합니다.
  • Query Parameters:
page: 페이지 번호 (기본값: 1)
size: 페이지 크기 (기본값: 10)
category: 메뉴 카테고리 필터 (선택)
sort: 정렬 기준 (price_asc, price_desc, name_asc)

 

 

 

 

  • Response:
{
    "content": [
        {
            "id": 1,
            "name": "김치찌개",
            "price": 8000,
            "description": "돼지고기 김치찌개",
            "category": "찌개",
            "reviewCount": 50,
            "createdAt": "2024-12-27T10:00:00"
        }
    ],
    "pageable": {
        "page": 1,
        "size": 10,
        "totalElements": 50,
        "totalPages": 5
    }
}

 

 

 

풀이

 

1.2. 음식점 상세 조회

특정 음식점의 상세 정보와 메뉴 목록을 조회하는 API입니다.

  • URL: /api/v1/restaurants/{id}
  • Method: GET

 

Postman

 

  • 설명:
    • 음식점의 기본 정보를 제공합니다.
    • 해당 음식점의 전체 메뉴 목록을 함께 반환합니다.
    • 평균 평점과 총 리뷰 수를 포함합니다.
    • 각 메뉴별 리뷰 수도 함께 제공됩니다.
    • 존재하지 않는 음식점 ID인 경우 404 에러를 반환합니다.

intelliJ

 

 

    @GetMapping("/api/v1/restaurants/{id}")
    getRestaurantsId(@PathVariable long id) {

            restaurantService.getRestaurantsId(id);

    }

 

 

  public RestaurantDetailListResponse getRestaurantsId(long id){

      //  if (!restaurantRepository.existsById(id)){
        Optional<Restaurant> restaurant = restaurantRepository.findById(id);
        if (restaurant.isEmpty()){
            throw new RuntimeException();
        }

        // averageRating, reviewCount 를 구한다

    // double avgRating = reviewRepository.findAvgRatingByRestaurantId(id);
    // 위와 같이  Repository 에서 직접 구하는 방법도 있지만, 아래와 같이 직접 구하는 방법도 있다.

        // 리뷰 카운트를 구한다.
        int reviewCount = restaurant.get().reviewList.size();
        int total = 0;
        for(Review review : restaurant.get().reviewList){
            total = total + review.rating;
        }
        double averageRating = (double) total / reviewCount;
        // 정수 / 정수 = 정수 이기 때문에 double 로 형변환을 해준다.

 

 

 service 의 개발 방법 

 

1. JPQL 로 하는 방법

2.  for 반복문으로 진행 

 

위 두가지 방법이 있습니다. 위의 방식은 for 반복문으로 진행 하였습니다. JPQL 로 하는 방법로도 사용하는 방법에 대하여 

전달 해 드리겠습니다. 

 

 

@Data
@Entity
@Table(name = "restaurant")
public class Restaurant {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column(length = 100)
    public String  name;

    @Column(length = 200)
    public String address;

    @Column(length = 50)
    public String phone;

    @Column(length = 50)
    public String category;

    @Column(length = 200)
    public String description;

    @Column(length = 10)
    public Instant createdAt;

    @PrePersist
    public void prePersist() {
        createdAt = Instant.now();
    }

 

@Data
@Entity
@Table(name = "restaurant")
public class Restaurant {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column(length = 100)
    public String  name;

    @Column(length = 200)
    public String address;

    @Column(length = 50)
    public String phone;

    @Column(length = 50)
    public String category;

    @Column(length = 200)
    public String description;

    @Column(length = 10)
    public Instant createdAt;

    @PrePersist
    public void prePersist() {
        createdAt = Instant.now();
    }
    @OneToMany(mappedBy = "restaurant")
    public List<Menu> menuList;

    @OneToMany(mappedBy = "restaurant")
    public List<Review> reviewList;

}

 

  • Response:
{
		"restaurant": {
		    "id": 1,
		    "name": "맛있는 식당",
		    "category": "한식",
		    "address": "서울시 강남구",
		    "phone": "02-1234-5678",
		    "description": "전통 한식집",
		    "avgRating": 4.5,
		    "reviewCount": 100,
		    "createdAt": "2024-12-27T10:00:00",
	  },
    "menus": [
        {
            "id": 1,
            "name": "김치찌개",
            "price": 8000,
            "description": "돼지고기 김치찌개",
            "category": "찌개",
            "reviewCount": 50
        }
    ]
}

 

 

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MenuResponse {

    public Long id;
    public String name;
    public Integer price;
    public String description;
    public String category;
    public String createdAt;

}

 

 

 

 

 

 

Postman

 

IP로컬로도 테스트 하여 봅니다.

 

 

1.1. 음식점 목록 조회

 

다양한 조건으로 음식점 목록을 검색하고 조회할 수 있는 API입니다.

  • URL: /api/v1/restaurants
  • Method: GET
  • 설명:
    • 페이징 처리된 음식점 목록을 반환합니다.
    • 카테고리 필터링과 키워드 검색을 지원합니다.
    • 음식점의 평균 평점과 리뷰 수를 포함합니다.
    • 최신 등록순으로 정렬됩니다.
  • Query Parameters:
page: 페이지 번호 (기본값: 1)
size: 페이지 크기 (기본값: 10)
category: 카테고리 필터 (선택) - 한식, 중식, 일식, 양식 등
keyword: 검색어 - 이름, 주소 검색 (선택, 최소 2글자 이상)

 

 

Postman

 

 

 

intelliJ

 

 

    @GetMapping("/api/v1/restaurants")
    getRestaurants(@RequestParam int page, 
    @RequestParam int size,
    @RequestParam(value = "category", required = false) String category,
    @RequestParam(value = "keyword",required = false) String keyword) {

     restaurantService.getRestaurants(page, size, category, keyword);
     

 

    public RestaurantListResponse getRestaurants(int page, int size, String category, String keyword) {

        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));

        // 레파지 토리 생성 및 페이징 처리
        Page<Restaurant> restaurantPage;

 

 

 

조건문 사용시 반복을 구문 줄이는 방법 

 

1. 예시 구문 

Page <restaurantPage> restaurantPage의 반복 

 

if (category == null && keyword == null) {
Page<Restaurant> restaurantPage =

restaurantRepository.findByCategoryAndKeyword(category, keyword, pageable);

//2. 키워드만 있는 경우 (키워드로 필터링)

} else if (category != null && keyword == null) {

Page<Restaurant> restaurantPage =

restaurantRepository.findByKeyword(keyword, pageable);

//3. 카테고리만 있는 경우 (카테고리로 필터링)

} else if (category == null && keyword != null) {

Page<Restaurant> restaurantPage =

 

2. 수정 구문 

 

Page <restaurantPage> restaurantPage;   // 또는 Page restaurantPage = null ;  로도 가능  

 

if (category == null && keyword == null) {
restaurantPage =

restaurantRepository.findByCategoryAndKeyword(category, keyword, pageable);

//2. 키워드만 있는 경우 (키워드로 필터링)

} else if (category != null && keyword == null) {

restaurantPage =

restaurantRepository.findByKeyword(keyword, pageable);

//3. 카테고리만 있는 경우 (카테고리로 필터링)

} else if (category == null && keyword != null) {

restaurantPage =

 

 위와 같이 보다 효율적으로 구문 작성이 가능합니다. 

 

 

 

  • Response:
{
    "content": [
        {
            "id": 1,
            "name": "맛있는 식당",
            "category": "한식",
            "address": "서울시 강남구",
            "phone": "02-1234-5678",
            "description": "전통 한식집",
            "avgRating": 4.5,
            "reviewCount": 100,
            "createdAt": "2024-12-27T10:00:00"
        }
    ],
    "pageable": {
        "page": 1,
        "size": 10,
        "totalElements": 100,
        "totalPages": 10
    }
}

 

RestaurantResponse 클래스의 경우  상세 조회 시  사용한  클래스 사용가능 합니다. 

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageableResponse {
    public Integer page;
    public Integer size;
    public Long totalElements;
    public Integer totalPages;
}

 

public class RestaurantListResponse {

    public List<RestaurantResponse> content;

    public PageableResponse pageable;

}

 

 

   public RestaurantListResponse getRestaurants(int page, 
   int size, String category, String keyword) {

     PageRequest pageRequest = PageRequest.of(page - 1, size);


        // 레파지 토리 생성 및 페이징 처리
     Page<Restaurant> restaurantPage;
        // 조건에 따라 검색
        //1. 카테고리와 키워드가 모드 있는 경우 (카테고리와 키워드로 필터링)
     if (category != null && keyword != null) {
        restaurantPage = 
        restaurantRepository.findByCategoryAndKeyword(category, keyword, pageRequest);
       
       //restaurantPage = 
         restaurantRepository.findByCategoryAndKeyword(category, keyword, pageable);
            //2. 카테고리만 있는 경우 (카테고리로 필터링)
        } else if (category != null&& keyword == null) {
            restaurantPage = 
            restaurantRepository.findByCategory(category, pageRequest);
            //3. 키워드만 있는 경우 (키워드로 필터링)
        } else if ( category == null && keyword != null ) {
       //   restaurantPage = 
      restaurantRepository.findByNameContainingOrAddressContaining(category, pageable);
        //위와래 같이 적용가능합니다. 하지만, 아래와 같이 적용하는 것이 더 직관적입니다.
        restaurantPage = restaurantRepository.findByKeyword(keyword, pageRequest);
            //4. 카테고리가 없는 경우
        } else {
            restaurantPage = restaurantRepository.findAll(pageRequest);
        }
        // entity 를 dto 로 변환
        ArrayList<RestaurantResponse> restaurantResponseArrayList =
                new ArrayList<>();

 

 

    @GetMapping("/api/v1/restaurants")
    public ResponseEntity<RestaurantListResponse> getRestaurants(@RequestParam("page") int page,
                                                                 @RequestParam("size") int size,
                                                                 @RequestParam(value = "category", required = false) String category,
                                                                 @RequestParam(value = "keyword", required = false) String keyword){
        try {
            RestaurantListResponse ListResponse =
                    restaurantService.getRestaurants(page, size, category, keyword);
            return ResponseEntity.status(200).body(ListResponse);

        } catch (Exception e) {
            return ResponseEntity.status(400).build();
        }
    }

 

 

Postman

 

if (category != null && keyword != null)

 

else if (category != null&& keyword == null) 

else if ( category == null && keyword != null ) 

else

728x90
반응형
home top bottom
}