
과제 #4 에서 만들었던 API를 분리해보며, Controller - Service - Repository 계층에 익숙해져 봅시다!
FruitController.java
@RestController
public class FruitController {
private final JdbcTemplate jdbcTemplate;
public FruitController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostMapping("/api/v1/fruit")
public void saveFruit(@RequestBody FruitAddRequest request){
String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice());
}
@PutMapping("/api/v1/fruit")
public void updateFruitStatus(@RequestBody FruitUpdateRequest request) throws IllegalAccessException {
String readSql = "SELECT * FROM fruit WHERE id = ?";
boolean isFruitNotExist = jdbcTemplate.query(readSql , (rs, rowNum) -> 0, request.getId()).isEmpty();
if(isFruitNotExist){
throw new IllegalAccessException();
}
String sql = "UPDATE fruit SET sold = 'Y' WHERE id = ?";
jdbcTemplate.update(sql, request.getId());
}
@GetMapping("/api/v1/fruit/stat")
public FruitResponse saleState (@RequestParam String name) throws IllegalAccessException {
String readSql = "SELECT * FROM fruit WHERE name = ?";
boolean isFruitNotExist = jdbcTemplate.query(readSql , (rs, rowNum) -> 0, name).isEmpty();
if(isFruitNotExist){
throw new IllegalAccessException();
}
String salesSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? and sold = 'Y'";
String notSalesSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? and sold = 'N'";
long salesAmount = jdbcTemplate.queryForObject(salesSql,Integer.class, name);
long notSalesAmount = jdbcTemplate.queryForObject(notSalesSql,Integer.class, name);
return new FruitResponse(salesAmount, notSalesAmount);
}
}
Controller 하나에 모든 기능이 구현되어 있다.
Controller - Service - Repository 분리
FruitController.java
@RestController
public class FruitController {
private final FruitService fruitService;
public FruitController(FruitService fruitService) {
this.fruitService = fruitService;
}
@PostMapping("/api/v1/fruit")
public void saveFruit(@RequestBody FruitAddRequest request){
fruitService.saveFruit(request);
}
@PutMapping("/api/v1/fruit")
public void updateFruit(@RequestBody FruitUpdateRequest request) {
fruitService.updateFruit(request);
}
@GetMapping("/api/v1/fruit/stat")
public FruitResponse salesStat(@RequestParam("name") String name){
return fruitService.saleState(name);
}
}
FruitService.java
@Service
public class FruitService {
private final FruitRepository fruitRepository;
public FruitService(FruitRepository fruitRepository) {
this.fruitRepository = fruitRepository;
}
public void saveFruit(FruitAddRequest request){
fruitRepository.saveFruit(request.getName(), request.getWarehousingDate(), request.getPrice());
}
public void updateFruit(FruitUpdateRequest request){
boolean isFruitNotExist = fruitRepository.findById(request.getId());
if (isFruitNotExist) {
throw new IllegalArgumentException("과일이 존재하지 않습니다.");
}
fruitRepository.updateFruit(request.getId());
}
public FruitResponse saleState(String name){
boolean isFruitNotExist = fruitRepository.findByName(name);
if (isFruitNotExist) {
throw new IllegalArgumentException("과일이 존재하지 않습니다.");
}
long salesAmount = fruitRepository.salesAmount(name);
long notSalesAmount = fruitRepository.notSalesAmount(name);
return new FruitResponse(salesAmount, notSalesAmount);
}
}
FruitRepository.java
@Repository
public class FruitRepository {
private final JdbcTemplate jdbcTemplate;
public FruitRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void saveFruit(String name, LocalDate warehousingDate, long price){
String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, name, warehousingDate, price);
}
public boolean findById(long id){
String readSql = "SELECT * FROM fruit WHERE id = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
}
public void updateFruit(long id) {
String sql = "UPDATE fruit SET sold = 'Y' WHERE id = ?";
jdbcTemplate.update(sql, id);
}
public boolean findByName(String name){
String readSql = "SELECT * FROM fruit WHERE name = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, name).isEmpty();
}
public long salesAmount(String name) {
String salesAmountSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND sold = 'Y'";
return jdbcTemplate.queryForObject(salesAmountSql, Integer.class, name);
}
public long notSalesAmount(String name) {
String notSalesAmountSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND sold = 'N'";
return jdbcTemplate.queryForObject(notSalesAmountSql, Integer.class, name);
}
}
기존에 작성했던 FruitRepository를 FruitMemoryRepository와 FruitMySqlRepository로 나누고 @Primary 어노테이션을 활용해 두 Repository를 바꿔가며 동작시킬 수 있도록 코드를 변경해보기
FruitRepository.java
@Repository
public interface FruitRepository {
public void saveFruit(String name, LocalDate warehousingDate, long price);
public boolean findById(long id);
public void updateFruit(long id);
public boolean findByName(String name);
public long salesAmount(String name);
public long notSalesAmount(String name);
}
FruitMemoryRepository.java
@Repository
public class FruitMemoryRepository implements FruitRepository{
public void saveFruit(String name, LocalDate warehousingDate, long price){
}
public boolean findById(long id){
return false;
}
public void updateFruit(long id) {
}
public boolean findByName(String name){
return false;
}
public long salesAmount(String name) {
return 0;
}
public long notSalesAmount(String name) {
return 0;
}
}

@Primary 어노테이션 사용
FruitMySqlRepository.java
@Primary
@Repository
public class FruitMySqlRepository implements FruitRepository {
private final JdbcTemplate jdbcTemplate;
public FruitMySqlRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void saveFruit(String name, LocalDate warehousingDate, long price){
String sql = "INSERT INTO fruit (name, warehousingDate, price) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, name, warehousingDate, price);
}
public boolean findById(long id){
String readSql = "SELECT * FROM fruit WHERE id = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
}
public void updateFruit(long id) {
String sql = "UPDATE fruit SET sold = 'Y' WHERE id = ?";
jdbcTemplate.update(sql, id);
}
public boolean findByName(String name){
String readSql = "SELECT * FROM fruit WHERE name = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, name).isEmpty();
}
public long salesAmount(String name) {
String salesAmountSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND sold = 'Y'";
return jdbcTemplate.queryForObject(salesAmountSql, Integer.class, name);
}
public long notSalesAmount(String name) {
String notSalesAmountSql = "SELECT COALESCE(SUM(price), 0) FROM fruit WHERE name = ? AND sold = 'N'";
return jdbcTemplate.queryForObject(notSalesAmountSql, Integer.class, name);
}
}