<aside> 👉 우리는 스프링 컨테이너의 개념을 배우고, 기존에 작성했던 Controller 코드를 3단 분리해보았습니다. 앞으로 API를 개발할 때는 이 계층에 맞게 각 코드가 작성되어야 합니다! 🙂
과제 #4 에서 만들었던 API를 분리해보며, Controller - Service - Repository 계층에 익숙해져 봅시다! 👍
</aside>
Controller는 API의 진입 지점으로써 HTTP Body를 객체로 변환하는 역할만 하게 해주고 로직 처리를 Service로 넘기자.
// FruitService.java
package com.inflearn.Inflearn.Study.day06.service;
import com.inflearn.Inflearn.Study.day06.dto.FruitRequest;
import com.inflearn.Inflearn.Study.day06.dto.FruitSoldResponse;
import com.inflearn.Inflearn.Study.day06.dto.FruitUpdateRequest;
import com.inflearn.Inflearn.Study.day06.entity.Fruit;
import com.inflearn.Inflearn.Study.day06.repository.FruitRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service // 스프링 빈으로 만들어 줌
public class FruitService {
public void saveFruit(FruitRequest request, JdbcTemplate jdbcTemplate) {
String sql = "insert into fruit(name, warehousingDate, price) values (?, ?, ?)";
Fruit fruit = new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice());
jdbcTemplate.update(sql, fruit.getName(), fruit.getWarehousingDate(), fruit.getPrice());
}
public void sellFruit(FruitUpdateRequest updateRequest, JdbcTemplate jdbcTemplate) {
String readSql = "select * from fruit where id = ?";
boolean isExistFruit = jdbcTemplate.query(readSql, (rs, rowNum) -> 0, updateRequest.getId()).isEmpty();
if(isExistFruit) {
throw new IllegalArgumentException("데이터베이스에 팔 과일이 없습니다.");
}
String sql = "update fruit set is_sold = 1 where id = ?";
jdbcTemplate.update(sql, updateRequest.getId());
}
public FruitSoldResponse getFruitIsSoldOrNot(String name, JdbcTemplate jdbcTemplate) {
String sql = "select is_sold, sum(price) from fruit where name = ? group by is_sold";
boolean isExistFruit = jdbcTemplate.query(sql, (rs, rowNum) -> 0, name).isEmpty();
if(isExistFruit) {
throw new IllegalArgumentException("이름과 일치하는 과일이 없습니다.");
}
Map<Boolean, Long> soldStatusMap = jdbcTemplate.query(sql, new Object[]{name}, rs -> {
Map<Boolean, Long> map = new HashMap<>();
while(rs.next()) {
map.put(rs.getBoolean(1), rs.getLong(2));
}
return map;
});
Long soldPrice = soldStatusMap.getOrDefault(true, 0L);
Long notSoldPrice = soldStatusMap.getOrDefault(false, 0L);
return new FruitSoldResponse(soldPrice, notSoldPrice);
}
}
// FruitController.java
package com.inflearn.Inflearn.Study.day06.controller;
import com.inflearn.Inflearn.Study.day06.dto.FruitRequest;
import com.inflearn.Inflearn.Study.day06.dto.FruitSoldResponse;
import com.inflearn.Inflearn.Study.day06.dto.FruitUpdateRequest;
import com.inflearn.Inflearn.Study.day06.entity.Fruit;
import com.inflearn.Inflearn.Study.day06.service.FruitService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
public class FruitController {
private final FruitService fruitService;
private final JdbcTemplate jdbcTemplate;
public FruitController(FruitService fruitService, JdbcTemplate jdbcTemplate) {
this.fruitService = fruitService;
this.jdbcTemplate = jdbcTemplate;
}
@PostMapping("/api/v2/fruit")
public void saveFruit(@RequestBody FruitRequest request) {
fruitService.saveFruit(request, jdbcTemplate);
}
@PutMapping("/api/v2/fruit")
public void sellFruit(@RequestBody FruitUpdateRequest updateRequest) {
fruitService.sellFruit(updateRequest, jdbcTemplate);
}
@GetMapping("/api/v2/fruit/stat")
public FruitSoldResponse getFruitIsSoldOrNot(@RequestParam String name) {
return fruitService.getFruitIsSoldOrNot(name, jdbcTemplate);
}
}
DB와 연동되어 SQL문을 처리하는 로직은 Repository에게 넘겨주었다.
// FruitRepository.java
package com.inflearn.Inflearn.Study.day06.repository;
import com.inflearn.Inflearn.Study.day06.dto.FruitRequest;
import com.inflearn.Inflearn.Study.day06.dto.FruitSoldResponse;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
@Repository
public class FruitRepository {
private final JdbcTemplate jdbcTemplate;
public FruitRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save(String name, LocalDate warehousingDate, Long price) {
String sql = "insert into fruit(name, warehousingDate, price) values (?, ?, ?)";
jdbcTemplate.update(sql, name, warehousingDate, price);
}
public void update(Long id) {
String readSql = "select * from fruit where id = ?";
boolean isExistFruit = jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
if(isExistFruit) {
throw new IllegalArgumentException("데이터베이스에 팔 과일이 없습니다.");
}
String sql = "update fruit set is_sold = 1 where id = ?";
jdbcTemplate.update(sql, id);
}
public FruitSoldResponse getList(String name) {
String sql = "select is_sold, sum(price) from fruit where name = ? group by is_sold";
boolean isExistFruit = jdbcTemplate.query(sql, (rs, rowNum) -> 0, name).isEmpty();
if(isExistFruit) {
throw new IllegalArgumentException("이름과 일치하는 과일이 없습니다.");
}
Map<Boolean, Long> soldStatusMap = jdbcTemplate.query(sql, new Object[]{name}, rs -> {
Map<Boolean, Long> map = new HashMap<>();
while(rs.next()) {
map.put(rs.getBoolean(1), rs.getLong(2));
}
return map;
});
Long soldPrice = soldStatusMap.getOrDefault(true, 0L);
Long notSoldPrice = soldStatusMap.getOrDefault(false, 0L);
return new FruitSoldResponse(soldPrice, notSoldPrice);
}
}
// FruitService.java
package com.inflearn.Inflearn.Study.day06.service;
import com.inflearn.Inflearn.Study.day06.dto.FruitRequest;
import com.inflearn.Inflearn.Study.day06.dto.FruitSoldResponse;
import com.inflearn.Inflearn.Study.day06.dto.FruitUpdateRequest;
import com.inflearn.Inflearn.Study.day06.entity.Fruit;
import com.inflearn.Inflearn.Study.day06.repository.FruitRepository;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service // 스프링 빈으로 만들어 줌
public class FruitService {
private final FruitRepository fruitRepository;
public FruitService(FruitRepository fruitRepository) {
this.fruitRepository = fruitRepository;
}
public void saveFruit(FruitRequest request) {
Fruit fruit = new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice());
fruitRepository.save(fruit.getName(), fruit.getWarehousingDate(), fruit.getPrice());
}
public void sellFruit(FruitUpdateRequest updateRequest) {
fruitRepository.update(updateRequest.getId());
}
public FruitSoldResponse getFruitIsSoldOrNot(String name) {
return fruitRepository.getList(name);
}
}
// FruitController.java
package com.inflearn.Inflearn.Study.day06.controller;
import com.inflearn.Inflearn.Study.day06.dto.FruitRequest;
import com.inflearn.Inflearn.Study.day06.dto.FruitSoldResponse;
import com.inflearn.Inflearn.Study.day06.dto.FruitUpdateRequest;
import com.inflearn.Inflearn.Study.day06.service.FruitService;
import org.springframework.web.bind.annotation.*;
@RestController
public class FruitController {
private final FruitService fruitService;
public FruitController(FruitService fruitService) {
this.fruitService = fruitService;
}
@PostMapping("/api/v2/fruit")
public void saveFruit(@RequestBody FruitRequest request) {
fruitService.saveFruit(request);
}
@PutMapping("/api/v2/fruit")
public void sellFruit(@RequestBody FruitUpdateRequest updateRequest) {
fruitService.sellFruit(updateRequest);
}
@GetMapping("/api/v2/fruit/stat")
public FruitSoldResponse getFruitIsSoldOrNot(@RequestParam String name) {
return fruitService.getFruitIsSoldOrNot(name);
}
}
// FruitRepository.java
public boolean isFruitExistById(long id) {
String sql = "select * from fruit where id = ?";
return jdbcTemplate.query(sql, (rs, rowNum) -> 0, id).isEmpty();
}
public boolean isFruitExistByName(String name) {
String sql = "select * from fruit where name = ?";
return jdbcTemplate.query(sql, (rs, rowNum) -> 0, name).isEmpty();
}
// FruitService.java
public void sellFruit(FruitUpdateRequest updateRequest) {
boolean isExist = fruitRepository.isFruitExistById(updateRequest.getId());
if (isExist) {
throw new IllegalArgumentException("데이터베이스에 팔 과일이 없습니다.");
}
fruitRepository.update(updateRequest.getId());
}
public FruitSoldResponse getFruitIsSoldOrNot(String name) {
boolean isExist = fruitRepository.isFruitExistByName(name);
if (isExist) {
throw new IllegalArgumentException("이름과 일치하는 과일이 없습니다.");
}
return fruitRepository.getList(name);
}