[워밍업 클럽 BE-0기] 6일차 과제 - 레이어 나누기와 @Primary 사용해보기
9개월 전
오늘 과제는 Controller 코드를 3 계층으로 나누는 것과 FruitMemoryReposiotry와 FruitMySqlRepository라는 두 개의 구현체 중에 하나만을 주입받아 사용하도록 하는 것이었습니다.
하지만 저는 이전의 과제에서부터 계층을 나누어서 코드를 작성했기 때문에 그 부분은 생략하고 Repository쪽의 코드를 확인해보겠습니다. 처음부터 JPA를 사용했으므로, 새로운 코드가 필요했습니다. 따라서 아래와 같이 작성했습니다.
FruitRepository
public interface FruitRepository {
void save(FruitCreateRequest request);
void updateStatus(Long id);
Map<String, Long> statForFruit(String name);
}
FruitMySqlRepository
@Repository
@Primary
public class FruitMysqlRepository implements FruitRepository {
private final JdbcTemplate jdbcTemplate;
public FruitMysqlRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void save(FruitCreateRequest request) {
String sql = "insert into fruit (name, warehousing_date, price) values(?, ?, ?)";
jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice());
}
@Override
public void updateStatus(Long id) {
String sql = "update fruit set is_sold = CASE WHEN is_sold = 0 THEN 1 ELSE 0 END WHERE id = ?";
jdbcTemplate.update(sql, id);
}
@Override
public Map<String, Long> statForFruit(String name) {
String sql = "SELECT \n"
+ " SUM(CASE WHEN is_sold = 1 THEN price ELSE 0 END) AS salesAmount,\n"
+ " SUM(CASE WHEN is_sold = 0 THEN price ELSE 0 END) AS notSalesAmount\n"
+ "FROM\n"
+ " fruit\n"
+ "WHERE \n"
+ " name = ?;";
Map<String, Object> result = jdbcTemplate.queryForMap(sql, name);
Map<String, Long> stats = new HashMap<>();
stats.put("salesAmount", ((Number)result.get("salesAmount")).longValue());
stats.put("notSalesAmount", ((Number)result.get("notSalesAmount")).longValue());
return stats;
}
}
FruitMemoryRepository
@Repository
public class FruitMemoryRepository implements FruitRepository {
private List<Fruit> fruits = new ArrayList<>();
private Long id = 1L;
@Override
public void save(FruitCreateRequest request) {
Fruit fruit = new Fruit(id++, request.getName(), request.getWarehousingDate(), request.getPrice());
fruits.add(fruit);
System.out.println(fruits.size());
}
@Override
public void updateStatus(Long id) {
Fruit fruit = fruits.stream().filter(f -> Objects.equals(f.getId(), id))
.findFirst().orElseThrow(IllegalArgumentException::new);
fruit.changeStatus();
}
@Override
public Map<String, Long> statForFruit(String name) {
List<Fruit> fruitsByName = fruits.stream()
.filter(f -> f.getName().equals(name)).collect(Collectors.toList());
Long salesAmount = fruitsByName.stream().filter(Fruit::getSold)
.mapToLong(Fruit::getPrice).sum();
Long notSalesAmount = fruitsByName.stream().filter(f -> !f.getSold())
.mapToLong(Fruit::getPrice).sum();
HashMap<String, Long> result = new HashMap<>();
result.put("salesAmount", salesAmount);
result.put("notSalesAmount", notSalesAmount);
return result;
}
}
저는 현재 FruitMySqlRepository에 @Primary
어노테이션을 달아주었습니다. 그러면 과연, 스프링 컨테이너가 띄워졌을 때, FruitMySqlRepository가 구현체로 등록되었는 지 확인해보겠습니다. 이를 위해 아래와 같은 코드를 사용했습니다.
@SpringBootApplication
public class LibraryAppApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(LibraryAppApplication.class, args);
FruitRepository bean = applicationContext.getBean(FruitRepository.class);
System.out.println("주입된 FruitRepository의 구현체: " + bean.getClass().getSimpleName());
}
}
스프링 부트 애플리케이션을 실행하고 난 뒤 FruitRepository에 주입되어있는 빈의 이름을 가져오게 했는데요. 실행 결과는 아래와 같습니다.
FruitMySqlRepository가 잘 주입된 것을 확인할 수 있습니다. 다시 FruitMemoryRepository에 @Primary
를 달아주면!
역시 잘 확인할 수 있었네요. 그런데... 저 뒤에 EnhancerBySpringCGLIB~~ 라는 놈은 무엇일까요?
더 깊게 알아보아야할 것을 얻은 것 같습니다. 6일차 과제 이상입니다.
댓글을 작성해보세요.