API 개발 JPA 사용

김찬희·2024년 5월 16일

Spring

목록 보기
6/6

1. 이전 API 개발에서 만든 Fruit 기능을 Jpa를 이용하도록 변경하시오

Fruit

@Entity
@Getter
public class Fruit {

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

    @Column(nullable = false, length = 20)
    private String name;

    @Column(nullable = false)
    private LocalDate warehousingDate;

    @Column(nullable = false)
    private long price;

    @Column(nullable = false, columnDefinition = "boolean default false")
    private Boolean purchase;

    public Fruit(String name, LocalDate warehousingDate, long price) {
        this.name = name;
        this.warehousingDate = warehousingDate;
        this.price = price;
        this.purchase = false;
    }

    public Fruit() {

    }
    public void updatePurchase(){
        this.purchase = true;
    }
}

FruitService

@Service
public class FruitService {

    private final FruitRepository fruitRepository;

    public FruitService(FruitRepository fruitRepository) {
        this.fruitRepository = fruitRepository;
    }

    @Transactional
    public void addFruit(FruitCreateRequest request){
        fruitRepository.save(new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice()));
    }

    @Transactional
    public void updateFruit(FruitUpdateRequest request) {
        Fruit fruit = fruitRepository.findById(request.getId())
			        .orElseThrow(IllegalAccessError::new);
        fruit.updatePurchase();
    }

    @Transactional
    public FruitAmountResponse showAmount(String name) {
        long salesAmount = fruitRepository.findAllByNameAndPurchase(name, true)
                .stream()
                .mapToLong(Fruit::getPrice)
                .sum();
        long notSalesAmount = fruitRepository.findAllByPurchase(false)
                .stream()
                .mapToLong(Fruit::getPrice)
                .sum();
        return new FruitAmountResponse(salesAmount, notSalesAmount);
    }
}

FruitRepository

@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
    
    List<Fruit> findAllByNameAndPurchase(String name, boolean b);

    List<Fruit> findAllByPurchase(boolean b);
}

문제 2

우리는 특정 과일을 기준으로 지금까지 우리 가게를 거쳐갔던 과일 개수를 세고 싶습니다.

<문제 1>에서 만들었던 과일 Entity Class를 이용해 기능을 만들어 보세요!

예를 들어

  1. (1, 사과, 5000원, 판매 X)
  2. (2, 배, 6000원, 판매 X)
  3. (3, 바나나, 3000원, 판매 O)
  4. (4, 딸기, 8000원, 판매 O)
  5. (5, 사과, 7000원, 판매 X)

와 같은 데이터가 있고, 사과를 기준으로 과일 개수를 센다면, API는 2를 반환할 것입니다.

구체적인 스펙은 다음과 같습니다.

  • HTTP method : **GET**
  • HTTP path : **/api/v1/fruit/count**
  • HTTP query
    • name : 과일 이름
  • 예시 : **GET /api/v1/fruit/count?name=사과

FruitController

@RestController
public class FruitController {

    @GetMapping("/api/v1/fruit/count")
    public FruitCountResponse showCount(@RequestParam String name) {
        return fruitService.showCount(name);
    }
}

FruitService

@Service
public class FruitService {

    public FruitCountResponse showCount(String name) {
        long count = fruitRepository.findByName(name)
                .stream()
                .count();
        return new FruitCountResponse(count);
    }
}

FruitRepository

@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
    

    List<Fruit> findByName(String name);
}

FruitCountResponse

public class FruitCountResponse {
    private long count;

    public FruitCountResponse(long count) {
        this.count = count;
    }

    public long getCount() {
        return count;
    }
}

문제 3

우리는 아직 판매되지 않은 특정 금액 이상 혹은 특정 금액 이하의 과일 목록을 받아보고 싶습니다.

구체적인 스펙은 다음과 같습니다.

  • HTTP method : **GET**
  • HTTP path : **/api/v1/fruit/list**
  • HTTP query
    • option : “GTE” 혹은 “LTE” 라는 문자열이 들어온다.
      • GTE : greater than equal
      • LTE : less than equal
    • price : 기준이 되는 금액이 들어온다.
  • 예시 1 - GET /api/v1/fruit/list?option=GTE&price=3000
    • 판매되지 않은 3000원 이상의 과일 목록을 반환해야 한다.
  • 예시 2 - **GET /api/v1/fruit/list?option=LTE&price=5000**
    • 판매되지 않은 5000원 이하의 과일 목록을 반환해야 한다.

FruitController

@RestController
public class FruitController {
    @GetMapping("/api/v1/fruit/list")
    public List<FruitListResponse> showList(@RequestParam String option,
                                            @RequestParam long price){
        return fruitService.showList(option, price);
    }
}

FruitService

@Service
public class FruitService {

    public List<FruitListResponse> showList(String option, long price) {
        List<Fruit> fruits = null;

        if(option.equals("GTE")) {
            fruits = fruitRepository.findByPriceGreaterThanEqual(price);
        }
        else if(option.equals("LTE")){
            fruits = fruitRepository.findByPriceLessThanEqual(price);
        }

        if(fruits == null) throw new IllegalArgumentException("검색 결과 없음");

        return fruits.stream().filter(fruit -> !fruit.getPurchase())
                .map(fruit -> new FruitListResponse(fruit.getName(), fruit.getPrice(), fruit.getWarehousingDate()))
                .toList();
    }
}

FruitRepository

@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
    ...
    List<Fruit> findByPriceGreaterThanEqual(long price);

    List<Fruit> findByPriceLessThanEqual(long price);
}

FruitListResponse

public class FruitListResponse {
    private String name;
    private long price;
    private LocalDate warehousingDate;

    public FruitListResponse(String name, long price, LocalDate warehousingDate) {
        this.name = name;
        this.price = price;
        this.warehousingDate = warehousingDate;
    }
    public String getName() {
        return name;
    }

    public long getPrice() {
        return price;
    }

    public LocalDate getWarehousingDate() {
        return warehousingDate;
    }
}

0개의 댓글