인프런 워밍업 클럽
인프런 워밍업 클럽/ BE 7일차 과제 : JPA 마이그레이션
킹갓홍
2024. 5. 16. 22:19
7일차 과제
문제 1
Fruit 도메인
JPA를 사용하기 위해 Fruit도메인을 만들어서 Entity로 만들었다.
@Entity
public class Fruit {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, name = "warehousing_date")
private LocalDate warehousingDate;
@Column(nullable = false)
private long price;
@Column(nullable = false)
private boolean state;
protected Fruit() {}
public long getId() {
return id;
}
public String getName() {
return name;
}
public LocalDate getWarehousingDate() {
return warehousingDate;
}
public long getPrice() {
return price;
}
public boolean isState() {
return state;
}
public Fruit(FruitRequestDTO request) {
this.name = request.getName();
this.warehousingDate = request.getWarehousingDate();
this.price = request.getPrice();
this.state = false;
}
public void updateFruit() {
this.state = true;
}
}
컨트롤러는 JPA를 사용해도 똑같이 요청과 응답의 기능을 해주기 때문에 기존의 컨트롤러를 그대로 사용한다.
FruitServiceV2
서비스단의 경우는 V2를 새롭게 만들어서 사용했다.
@Service
public class FruitServiceV2 {
private final FruitRepositoryV2 fruitRepositoryV2;
public FruitServiceV2(FruitRepositoryV2 fruitRepositoryV2) {
this.fruitRepositoryV2 = fruitRepositoryV2;
}
public void storeFruit(FruitRequestDTO request) {
Fruit fruit = fruitRepositoryV2.save(new Fruit(request));
}
public void updateFruit(FruitUpdateRequestDTO request) {
Fruit fruit = fruitRepositoryV2.findById(request.getId())
.orElseThrow(IllegalArgumentException::new);
fruit.updateFruit();
}
public FruitAmountResponse getFruitAmount(String name) {
int salesAmount = fruitRepositoryV2.getSalesAmountByName(name);
int notSalesAmount = fruitRepositoryV2.getNotSalesAmountByName(name);
return new FruitAmountResponse(salesAmount,notSalesAmount);
}
Update문의 경우, JPA Persistence를 이용해서 내부에서 로직을 처리하도록 했다.
FruitRepositoryV2
리포지토리도 V2로 새롭게 인터페이스로 만들고, JpaRepository를 상속받았다.
public interface FruitRepositoryV2 extends JpaRepository<Fruit,Long> {
@Query(value = "SELECT sum(price) FROM fruit WHERE state=1 AND name=:name", nativeQuery = true)
int getSalesAmountByName(String name);
@Query(value = "SELECT sum(price) FROM fruit WHERE state=0 AND name=:name", nativeQuery = true)
int getNotSalesAmountByName(String name);
}
JpaRepository를 사용하기 어려운 쿼리문은 새롭게 추상 메서드를 만들어서 사용했다.
문제2
FruitController
//과일 총합
@GetMapping("/api/v1/fruit/stat")
public FruitAmountResponse getFruitAmount(@RequestParam String name) {
return fruitServiceV2.getFruitAmount(name);
}
FruitServiceV2
public FruitCountResponse getCountByName(String name) {
return new FruitCountResponse(fruitRepositoryV2.getCountByName(name));
}
FruitRepositoryV2
@Query(value = "SELECT COUNT(id) FROM fruit WHERE name = :name", nativeQuery = true)
long getCountByName(String name);
결과값
문제3
FruitController
//과일 리스트
@GetMapping("/api/v1/fruit/list")
public List<FruitResponse> getFruitList(@RequestParam String option, long price) {
return fruitServiceV2.getFruitList(option, price);
}
FruitServiceV2
public List<FruitResponse> getFruitList(String option, long price) {
if(option.equals("GTE")) {
List<Fruit> list = fruitRepositoryV2.findAllByGTEPrice(price);
List<FruitResponse> fruitList = list.stream()
.map(fruit -> new FruitResponse(fruit.getName(), fruit.getPrice(),fruit.getWarehousingDate()))
.collect(Collectors.toList());
return fruitList;
}
else if(option.equals("LTE")) {
List<Fruit> list = fruitRepositoryV2.findAllByLTEPrice(price);
List<FruitResponse> fruitList = list.stream()
.map(fruit -> new FruitResponse(fruit.getName(), fruit.getPrice(),fruit.getWarehousingDate()))
.collect(Collectors.toList());
return fruitList;
}
else {
throw new IllegalArgumentException();
}
}
Option이 GTE일 경우와 LTE일 경우를 비즈니스 로직에서 처리해준다.
리포지토리에서 Fruit리스트를 받고 stream을 사용해서 FruitResponse리스트로 매핑해준다.
FruitRepositoryV2
@Query(value = "SELECT * FROM fruit WHERE price >= :price AND state = 0", nativeQuery = true)
List<Fruit> findAllByGTEPrice(long price);
@Query(value = "SELECT * FROM fruit WHERE price <= :price and state = 0", nativeQuery = true)
List<Fruit> findAllByLTEPrice(long price);
결과값