728x90

과제 6번 코드 보기 👉 https://ddonydev.tistory.com/80

 

 

  • Controller
@RestController
public class FruitController {

    private final FruitServiceV2 fruitService;

    public FruitController(FruitServiceV2 fruitService) {
        this.fruitService = fruitService;
    }

    @GetMapping("/api/v1/fruit/stat")
    public FruitResponse selectFruits(@RequestParam String name) {
        return fruitService.selectFruits(name);
    }


    @PostMapping("/api/v1/fruit")
    public void insertFruits(@RequestBody FruitRequest fruitRequest) {
        fruitService.insertFruits(fruitRequest);
    }

    @PutMapping("/api/v1/fruit")
    public void updateFruits(@RequestBody FruitUpdateRequest request) {
        fruitService.updateFruits(request);
    }
}

 

  • Service
@Service
public class FruitServiceV2 {

    private final FruitRepository fruitRepository;

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

    public FruitResponse selectFruits(String name) {
        long salesAmount = fruitRepository.selectSalesAmount(name);
        long notSalesAmount = fruitRepository.selectNotSalesAmount(name);
        return new FruitResponse(salesAmount, notSalesAmount);
    }

    public void insertFruits(FruitRequest request){
        fruitRepository.save(new Fruits(request.getName(), 
        request.getWarehousingDate(), request.getPrice()));
    }

    public void updateFruits(FruitUpdateRequest request) {
        Fruits fruit = fruitRepository.findById(request.getId())
                .orElseThrow(() -> new IllegalArgumentException("해당하는 과일이 없습니다."));

        fruit.updateFruit();

        fruitRepository.save(fruit);
    }
}

 

  • Repository
public interface FruitRepository extends JpaRepository<Fruits, Long> {

    @Query(value = "SELECT SUM(price) as salesAmount FROM fruits 
    WHERE is_sold = true AND name = :name", nativeQuery = true)
    long selectSalesAmount(@Param("name") String name);

    @Query(value = "SELECT SUM(price) as notSalesAmount FROM fruits 
    WHERE is_sold = false AND name = :name", nativeQuery = true)
    long selectNotSalesAmount(@Param("name") String name);

}

 

 

Sql에서 SUM() 함수를 사용하여야 하는데 어떻게 해야할지 고민하다가 검색해보니 @Query어노테이션으로 사용자 정의 쿼리를 사용할 수 있는 것을 알게 되었다. @Query는 실행할 메서드 위에 정적 쿼리를 작성하는 방식으로 사용된다.

메서드에 @Param 어노테이션으로 조건에 사용할 변수를 지정해주어 사용할 수 있었다.

 

  • Fruit
@Entity
public class Fruits {
    @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 isSold = false;

    protected Fruits() {}

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

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public LocalDate getWarehousingDate() {
        return warehousingDate;
    }

    public long getPrice() {
        return price;
    }

    public boolean isSold() {
        return isSold;
    }

    public void updateFruit() {
        this.isSold = true;
    }


}

 

기존 코드를 JPA로 고치느라 엄청 애먹었다..😭

강사님 코드를 보며 하나하나씩 바꿔 보았지만 SQL의 SUM() 함수를 어떻게 사용해야할지 감이 오지 않았고, 어찌어찌 다 고치고 나니 Property가 없다는 에러가 났다.

No property 'updateFruits' found for type 'Fruit'

 

검색 해보니 클래스 명이 맞지 않거나 카멜케이스로 인한 오류 존재하지 않은 필드명을 사용한 쿼리 메서드를 만들었을 경우 오류가 난다는 것이었다.

그런데 아무리 봐도 내 코드엔 이상이 없었다. 그렇게 몇시간을 찾아보았는데..인터페이스에 내가 Service에 있는 메서드를 다 적어 놓은 것이었다..이걸 지우고 나니 아래와 같은 오류가 낫다.

Parameter 0 of constructor in com.group.libraryapp.controller.fruits.FruitService required a bean of type 'com.group.libraryapp.controller.fruits.FruitRepository' that could not be found.

 

FruitRepository를 찾을 수 없다는 것이었다. 찾아보니 이전에 만들었던 FruitService코드에 FruitRepository가 주입 된 상태였고 나는 FruitRepositoryV2를 사용하려고 했기 때문에 FruitRepository를 주석 처리하여 파일을 사용하지 않게 하니 당연히 못찾는 것이었다. 그래서 FruitServiceV2까지 주석 처리를 한 뒤 오류는 해결 되었고 프로그램이 정상적으로 실행 될 수 있었다.

 

 

 

  • Controller
@RestController
public class FruitController {

    private final FruitServiceV2 fruitService;

    public FruitController(FruitServiceV2 fruitService) {
        this.fruitService = fruitService;
    }

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

 

  • Service
@Service
public class FruitServiceV2 {

    private final FruitRepository fruitRepository;

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

    public FruitCountResponse countFruits(String name) {
        long count = fruitRepository.countByName(name);
        return new FruitCountResponse(count);
    }
}

 

  • Repository
public interface FruitRepository extends JpaRepository<Fruits, Long> {

    long countByName(String name);

}

 

  • FruitCountResponse
public class FruitCountResponse {
    private long count;

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

    public long getCount() {
        return count;
    }
}

 

[실행 결과]

 

  • 사과를 조회 했을 때 4개가 나오는 것을 볼 수 있다.

 

 

 

  • Controller
@RestController
public class FruitController {

    private final FruitServiceV2 fruitService;

    public FruitController(FruitServiceV2 fruitService) {
        this.fruitService = fruitService;
    }

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

 

  • Service
@Service
public class FruitServiceV2 {

    private final FruitRepository fruitRepository;

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

    public List<FruitListResponse> listFruits(String option, long price) {
        if (option.equals("GTE")) {
            return fruitRepository.findAllByPriceGreaterThanEqualAndIsSoldIsFalse(price)
                    .stream()
                    .map(fruit -> new FruitListResponse(fruit.getName(), 
                    fruit.getPrice(), fruit.getWarehousingDate()))
                    .collect(Collectors.toList());
        } else if (option.equals("LTE")) {
            return fruitRepository.findAllByPriceLessThanEqualAndIsSoldIsFalse(price)
                    .stream()
                    .map(fruit -> new FruitListResponse(fruit.getName(), 
                    fruit.getPrice(), fruit.getWarehousingDate()))
                    .collect(Collectors.toList());
        }
        return new ArrayList<>();
    }
}

 

여러 결과를 받아야 하기 때문에 List타입으로 나올 수 있도록 하였다.

여기서 findAllByPriceGreaterThanEqualAndIsSoldIsFalse를 사용하였는데 하나하나 살펴보자면

findAll: 모든 결과를 가져오고

price: price를 조건으로 가져오는데

GreaterThanEqual: 해당 조건 이상인 것

LessThanEqual: 해당 조건 이하인 것

AndIsSoldIsFalse: 그리고 IsSold 칼럼이 False인 것

이라고 해석할 수 있다.

 

즉, 입력한 가격이 이상이면서 IsSold가 false인 것을 조회하는 것이다.

SELECT * FROM FRUITS WHERE PRICE > 10000 AND IS_SOLD = FALSE;

 

  • Repository
public interface FruitRepository extends JpaRepository<Fruits, Long> {

    List<Fruits> findAllByPriceGreaterThanEqualAndIsSoldIsFalse(long price);

    List<Fruits> findAllByPriceLessThanEqualAndIsSoldIsFalse(long price);

}

 

  • FruitCountResponse
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;
    }
}

 

 

[실행결과]

 

 

[느낀점]

오늘 JPA는 처음 사용해보았다.

처음부터 JPA로 작성하는 것이 아닌 기존 코드를 JPA로 바꾸면서 해보는 것이라 JPA를 어떻게 사용하는 것인지 조금은 알게 되었다.

에러로 몇시간을 잡고 있었는진 모르겠지만 그래도 너무 재미있게 코딩한 것 같아 뿌듯하다..!

이제 JPA에 대해 조금 더 자세히 공부하고 프로젝트에도 적용해보아야겠다.

 

 

 

강의 링크 👉 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

728x90

+ Recent posts