<aside> 👉 우리는 JPA라는 개념을 배우고 유저 테이블에 JPA를 적용해 보았습니다. 몇 가지 문제를 통해 JPA를 연습해 봅시다! 🔥
</aside>
// Fruit.java
package com.inflearn.Inflearn.Study.day07.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Entity
@NoArgsConstructor // JPA는 기본 생성자가 필요하다.
@Getter
public class Fruit {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private LocalDate warehousingDate;
private Long price;
private boolean isSold; // 0 -> false, 1 -> true
public Fruit(String name, LocalDate warehousingDate, Long price) {
this.name = name;
this.warehousingDate = warehousingDate;
this.price = price;
}
public void soldFruit() {
this.isSold = true;
}
}
// FruitService.java
package com.inflearn.Inflearn.Study.day07.service;
import com.inflearn.Inflearn.Study.day07.dto.*;
import com.inflearn.Inflearn.Study.day07.entity.Fruit;
import com.inflearn.Inflearn.Study.day07.repository.FruitRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
@Service // 스프링 빈으로 만들어 줌
@Transactional(readOnly = true) // default값이 false
public class FruitService {
private final FruitRepository fruitRepository;
public FruitService(FruitRepository fruitRepository) {
this.fruitRepository = fruitRepository;
}
@Transactional
public void saveFruit(FruitRequest request) {
Fruit fruit = new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice());
fruitRepository.save(fruit);
}
@Transactional
public void sellFruit(FruitUpdateRequest updateRequest) {
Optional<Fruit> fruit = Optional.ofNullable(fruitRepository.findById(updateRequest.getId())
.orElseThrow(() -> new IllegalArgumentException("데이터베이스에 과일이 없습니다.")));
fruit.get().soldFruit();
}
public FruitSoldResponse getFruitIsSoldOrNot(String name) {
List<Fruit> fruit = fruitRepository.findByName(name);
if(fruit.size() == 0) {
throw new IllegalArgumentException("이름과 일치하는 과일이 없습니다.");
}
List<Object[]> fruits = fruitRepository.findIsSoldAndPriceByName(name);
Long isSold = 0L;
Long isNotSold = 0L;
for(Object[] res : fruits) {
if((Boolean) res[0]) {
isSold = ((BigDecimal) res[1]).longValue();
}
else {
isNotSold = ((BigDecimal) res[1]).longValue();
}
}
return new FruitSoldResponse(isSold, isNotSold);
}
}
// FruitRepository.java
package com.inflearn.Inflearn.Study.day07.repository;
import com.inflearn.Inflearn.Study.day07.dto.FruitResponse;
import com.inflearn.Inflearn.Study.day07.entity.Fruit;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface FruitRepository extends JpaRepository<Fruit, Long> {
List<Fruit> findByName(String name);
@Query(value = "select f.is_sold, sum(f.price) from fruit f where f.name = :name group by f.is_sold", nativeQuery = true)
List<Object[]> findIsSoldAndPriceByName(@Param("name") String name);
}
// FruitController.java
package com.inflearn.Inflearn.Study.day07.controller;
import com.inflearn.Inflearn.Study.day07.dto.*;
import com.inflearn.Inflearn.Study.day07.service.FruitService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class FruitController {
private final FruitService fruitService;
public FruitController(FruitService fruitService) {
this.fruitService = fruitService;
}
@PostMapping("/api/v3/fruit")
public void saveFruit(@RequestBody FruitRequest request) {
fruitService.saveFruit(request);
}
@PutMapping("/api/v3/fruit")
public void sellFruit(@RequestBody FruitUpdateRequest updateRequest) {
fruitService.sellFruit(updateRequest);
}
@GetMapping("/api/v3/fruit/stat")
public FruitSoldResponse getFruitIsSoldOrNot(@RequestParam String name) {
return fruitService.getFruitIsSoldOrNot(name);
}
}
(Dto는 동일하므로 코드 생략)
countByName
이라는 네이밍을 해줄 수 있다.@GetMapping("/api/v3/fruit/count")
public FruitCountResponse getFruitCountByName(@RequestParam String name) {
return fruitService.getFruitCountByName(name);
}
public FruitCountResponse getFruitCountByName(String name) {
return new FruitCountResponse(fruitRepository.countByName(name));
}
Long countByName(String name);
findAllByPriceGreaterThanEqualAndIsSoldFalse
라는 네이밍을 통해서 조건을 만족하는 쿼리를 날릴 수 있다.@GetMapping("/api/v3/fruit/list")
public List<FruitResponse> getFruitByPrice(@RequestParam String opt, @RequestParam Long price) {
if(opt.equals("GTE")) {
return fruitService.getFruitGreaterThanEqualByPrice(price);
}
return fruitService.getFruitLessThanEqualByPrice(price);
}