우리는 스프링 컨테이너의 개념을 배우고, 기존에 작성했던 Controller 코드를 3단 분리해보았습니다. 앞으로 API를 개발할 때는 이 계층에 맞게 각 코드가 작성되어야 합니다! 🙂

과제 #4 에서 만들었던 API를 분리해보며, Controller - Service - Repository 계층에 익숙해져 봅시다! 👍

Untitled

문제 1

FruitController

package com.group.libraryapp.controller.fruit;

import com.group.libraryapp.dto.fruit.request.FruitCreateRequest;
import com.group.libraryapp.dto.fruit.request.FruitUpdateRequest;
import com.group.libraryapp.dto.fruit.response.FruitResponse;
import com.group.libraryapp.service.fruit.FruitService;
import org.springframework.web.bind.annotation.*;

@RestController
public class FruitController {

    private final FruitService fruitService;

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

    @PostMapping("/api/v1/fruit")
    public void saveFruit(@RequestBody FruitCreateRequest request){
        fruitService.saveFruit(request);
    }

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

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

}

FruitService

package com.group.libraryapp.service.fruit;

import com.group.libraryapp.dto.fruit.request.FruitCreateRequest;
import com.group.libraryapp.dto.fruit.request.FruitUpdateRequest;
import com.group.libraryapp.dto.fruit.response.FruitResponse;
import com.group.libraryapp.repository.fruit.FruitRepository;
import org.springframework.stereotype.Service;

@Service
public class FruitService {

    private final FruitRepository fruitRepository;

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

    public void saveFruit(FruitCreateRequest request){
        fruitRepository.saveFruit(request);
    }

    public void updateFruit(FruitUpdateRequest request){
        if(fruitRepository.isFruitNotExist(request.getId())){
            throw new IllegalArgumentException();
        }

        fruitRepository.updateFruit(request.getId());
    }

    public FruitResponse getFruitStatus(String name){
        if(fruitRepository.isFruitNotExist(name)){
            throw new IllegalArgumentException();
        }

        return fruitRepository.getFruitStatus(name);
    }
}

FruitRepository

package com.group.libraryapp.repository.fruit;

import com.group.libraryapp.dto.fruit.request.FruitCreateRequest;
import com.group.libraryapp.dto.fruit.response.FruitResponse;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class FruitRepository {

    private final JdbcTemplate jdbcTemplate;

    public FruitRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void saveFruit(FruitCreateRequest request){
        String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
        jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice());
    }

    public void updateFruit(long id){
        String sql = "UPDATE fruit SET status = 'SOLD' WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }

    public FruitResponse getFruitStatus(String name){
        String soldSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND status = 'SOLD'";
        String notSoldSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND status = 'NOT_SOLD'";

        long salesAmount = jdbcTemplate.queryForObject(soldSql, Long.class, name);
        long notSalesAmount = jdbcTemplate.queryForObject(notSoldSql, Long.class, name);

        return new FruitResponse(salesAmount, notSalesAmount);
    }

    public boolean isFruitNotExist(long id){
        String readSql = "SELECT * FROM fruit WHERE id = ?";
        return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
    }
    public boolean isFruitNotExist(String name){
        String readSql = "SELECT * FROM fruit WHERE name =?";
        return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, name).isEmpty();
    }
}

문제 2

FruitRepository (interface)

package com.group.libraryapp.repository.fruit;

import com.group.libraryapp.dto.fruit.response.FruitResponse;

import java.time.LocalDate;

public interface FruitRepository {
    public void saveFruit(String name, LocalDate warehousingDate, long price);
    public void updateFruit(long id);
    public FruitResponse getFruitStatus(String name);
    public boolean isFruitNotExist(long id);
    public boolean isFruitNotExist(String name);