본문 바로가기
공부/메모

스프링 심화과정 - 순한맛 2단계 음식등록

by 고구밍 2022. 4. 4.

2단계 음식 등록문제

더보기
  • 음식점 ID 및 음식 정보 입력받아 등록
    1. 음식점 ID (restaurantId)
      1. 음식점 DB 테이블 ID
    2. 음식명 (name)
      1. 같은 음식점 내에서는 음식 이름이 중복될 수 없음 (예. '자담치킨 강남점'에 '후라이드치킨' 이 이미 등록되어 있다면 중복하여 등록할 수 없지만, 다른 음식점인 '맘스터치 강남점'에는 '후라이드치킨' 을 등록 가능)
    3. 가격 (price)
      1. 허용값: 100원 ~ 1,000,000원
      2. 100 원 단위로만 입력 가능 (예. 2,220원 입력 시 에러발생. 2,300원 입력 가능)
      3. 허용값이 아니거나 100원 단위 입력이 아닌 경우 에러 발생시킴
  • 메뉴판 조회
    • 하나의 음식점에 등록된 모든 음식 정보 조회
      1. 등록 시 입력한 음식 정보 (name, price)
      2. DB 테이블 ID (id)

 

API 명세서

  API Path Request Body Sample Response Body Sample
음식 등록 POST /restaurant/{restaurantId}/food/register [
{
name: "쉑버거 더블"
price: 10900
},
{
name: "치즈 감자튀김"
price: 4900
},
{
name: "쉑버거 더블"
price: 5900
}

]
 
메뉴판 조회 GET /restaurant/{restaurantId}/foods   [
{
id: 1
name: "쉑버거 더블"
price: 10900
},
{
id: 2
name: "치즈 감자튀김"
price: 4900
},
{
id: 3
name: "쉑버거 더블"
price: 5900
}

]

 

POST ->

대괄호 [] : 리스트

중괄호 {} -> 3개

각각은 음식명(name)과 음식가격(price)이 있음

 

 

 

문제점

더보기

API의 Controller 부분에서 설계 문제로, 400오류가 발생 -> 설계를 잘못 함

API의 url 주소는 문제가 없지만, public의 registerFood에 들어갈

@RequestBody@Pathvariable(url로 입력받는 restaurantId을 받아 줌)을 넣어주는 부분이 빠져있음

 

해결과정

더보기

1. @RequestBody FoodDto가 어떻게 구성되어 있는지 보자

 

 

우리가 음식을 등록하는데 있어 

ㄱ. 음식명 (name)

ㄴ. 음식가격 (price)

라는 하나의 정보 만을 받고 있다. 

 

FoodDto를 통해서 받아야 할 것이 3개의 음식이기 때문에,

List<FoodDto>으로 바꿔줘야 한다.

 

 


 

 2. restaurantId가 주소값에서 들어오고 있다. -> /{restaurantId}/

 

 이걸 받아주기 위해서는, @RequestBody로 받는게 아니라 @Pathvariable을 넣어줘야함

->@PathVariable Long restaurantId

 

 -> 이때 FoodDto에 입력해 두었던 restaurantId는 필요가 없기 때문에 지워주자

 

 

음식이름 & 음식가격 ->@RequestBody List<FoodDto> requestDto

// 하나가 Fooddto이고, 이것을 여러개 받기 위해서는 List형식으로 받아야 함

 

Url을 통해 받는 restaurantId -> @Pathvariable Long restaurantId

// @PathVariable url을 통해서 값을 받는다

 


 3. Dto의 형태가 바뀌어서 Service도 바꿔줘야 함

 

public Food registerFood 다음에 FoodDto 하나만 들어오는게 아니라 List<Food>로 들어오고,

 

resturantId도 함께 넣어 줘야 함

 

FoodService

또한, restaurantId를 이미 받았기 떄문에, 퍼블릭 내용에서 지워 주었다.

이때, 컨트롤러에서 서비스로 보내주는 값을 추가한다.

foodService.registerFood(requestDto, restaurantId)

 

 

3-1. requestDto가 여러개의 리스트 형식으로 들어가 있는 것을 For문으로 하나씩 뽑아내 줘야 됨

for(int i = 0; i < requestDtos.size(); i++) {
    FoodDto requestDto = requestDtos.get(i);

 

각 이름과 가격은 requestDto.getName();과 getPrice를 통해서 값을 뽑아내 준다.

 

그 다음은 테스트 조건문을 Food registerFood안에 넣어 준다.

 

3-2. 음식 등록이기 때문에, 리턴값이 필요없음 -> public void로 바꾼다

 

 

ㄱ. public void 로 변경

ㄴ. 리턴값이 없기 때문에 Food registerFood에서 Food를 지운다 (반환 타입이 없으므로)

ㄷ. return food 삭제

 

 

4. Food 엔티티 (entity)을 보자

 

public Food(Long restaurantId, String name, Long price) {
    this.restaurantId = restaurantId;
    this.name = name;
    this.price = price;
}

 

 

5. 테스트

 

테스트 결과 음식이 등록이 되었다.

 

그리고 Food의 entity부분에서 

 

@ 부분의 public을 없에주었다.
수정 후

 

 

음식점에 음식을 등록하는 API를 설계하는데 어려움을 느겼습니다. (기초가 부족하여 어떻게 설계하는지 헤맴)

 

 

<추가 내용>

더보기

1. 용도를 알아보자! - 어떨 때 쓰는가?

@RequestBody : 

-> http요청의 본문(body)이 그대로 전달

-> xml이나 json기반의 메시지를 사용하는 요청의 경우에 이 방법이 매우 유용하다.

https://cheershennah.tistory.com/179

 

[Spring] @RequestBody / @ResponseBody 어노테이션 이란?

스프링에서 비동기 처리를 하는 경우 @RequestBody , @ResponseBody를 사용한다. 비동기 처리를 위해 이 어노테이션들은 어떻게 작동할까? 클라이언트와 서버의 비동기 통신  클라이언트에서 서버로 통

cheershennah.tistory.com

 

@Pathvariable : 

 - > URL을 처리할 때는 @PathVariable을 사용

https://2ham-s.tistory.com/290

 

@RequestParam과 @PathVariable?

컨트롤라에서 Requestparam으로 파라미터 값을 넘겨받을 때 아무 생각 없이 사용하곤 했는데, 이번 기회에 이 어노테이션에 대해 정리해 보고자 한다. 스프링에서는 컨트롤러로 사용할 클래스 상단

2ham-s.tistory.com

 

 

2. 파라미터 

순서대로 넣고, 순서대로 받는다.

Food의 entity

위 3가지를 넣었으니, 3가지를 넣어줘야 실행이 됨

 

 

3. JPA

findAll? 이런거는 어떤건가?

Repository

-> extends JpaRepository

extends : 상속이라는 개념 - 누가 미리 만들어 놓을 것을 받는다 / 쉽게 쓰라고 미리 만들어 놈

findAll / findAllbyId 등 미리 만들어져 있고,

기본으로 만들어 져 있기 때문에 생략도 가능함.

 

-> Service에서 save가 근야 쓸 수 있음

 

ㄱ.  RestaurantRepository과 ServiceRestaurant 연결됨

-> @RequiredArgsConstrouctor : private final이라는 접근제한자가 되어있으면,

자동으로 DI(dependency Injection) 외부요소들(만들어 져있는 것을)을 삽입해줌

https://medium.com/@jang.wangsu/di-dependency-injection-%EC%9D%B4%EB%9E%80-1b12fdefec4f

 

[DI] Dependency Injection 이란?

디펜던시 인젝션, 의존성 주입에 대해 간단하게 작성해 봅니다.

medium.com

 

-> 따라서 내가 RestaurantRepository를 만들어 놨기 때문에 이 내용을 Service에서 가져와서 쓸 수 있게 해준다.

@RequiredArgsConstructor
@Service
public class RestaurantService {

    private final RestaurantRepository restaurantRepository;

 

ㄴ.save도 상속으로 사용할 수 있다.

restaurantRepository.save(restaurant);

 

 

정리

더보기

1. 어노테이션의 용도

@RequestBody : 

-> http요청의 본문(body)이 그대로 전달

-> xml이나 json기반의 메시지를 사용하는 요청의 경우에 이 방법이 매우 유용하다.

https://cheershennah.tistory.com/179

 

[Spring] @RequestBody / @ResponseBody 어노테이션 이란?

스프링에서 비동기 처리를 하는 경우 @RequestBody , @ResponseBody를 사용한다. 비동기 처리를 위해 이 어노테이션들은 어떻게 작동할까? 클라이언트와 서버의 비동기 통신  클라이언트에서 서버로 통

cheershennah.tistory.com

 

@Pathvariable : 

 - > URL을 처리할 때는 @PathVariable을 사용

https://2ham-s.tistory.com/290

 

@RequestParam과 @PathVariable?

컨트롤라에서 Requestparam으로 파라미터 값을 넘겨받을 때 아무 생각 없이 사용하곤 했는데, 이번 기회에 이 어노테이션에 대해 정리해 보고자 한다. 스프링에서는 컨트롤러로 사용할 클래스 상단

2ham-s.tistory.com

 


 

 2. 상속

extends : 상속이라는 개념 - 누가 미리 만들어 놓을 것을 받는다 / 쉽게 쓰라고 미리 만들어 놈

findAll / findAllbyId 등 미리 만들어져 있고,

기본으로 만들어 져 있기 때문에 생략도 가능함.

 

-> Service에서 save가 근야 쓸 수 있음

 

 


 

@RequiredArgsConstrouctor : private final이라는 접근제한자가 되어있으면,

자동으로 DI(dependency Injection) 외부요소들(만들어 져있는 것을)을 삽입해줌

https://medium.com/@jang.wangsu/di-dependency-injection-%EC%9D%B4%EB%9E%80-1b12fdefec4f

 

[DI] Dependency Injection 이란?

디펜던시 인젝션, 의존성 주입에 대해 간단하게 작성해 봅니다.

medium.com

 

-> 따라서 내가 RestaurantRepository를 만들어 놨기 때문에 이 내용을 Service에서 가져와서 쓸 수 있게 해준다.