Search

6일차) 3단 분리

주제

스프링 컨테이너의 개념을 배우고, 기존에 작성했던 Controller 코드를 3단 분리해보았다. 앞으로 API를 개발할 때는 이 계층에 맞게 각 코드가 작성되어야 한다 
#4 에서 만들었던 API를 분리해보며, Controller - Service - Repository 계층에 익숙해져 보자! 

 주요 내용

키워드

3단 분리

3단 분리

요구사항 1

FruitController
package com.group.libraryapp.controller.fruit; @RequestMapping("/api/v1/fruit") @RestController public class FruitController { private final FruitService fruitService; public FruitController(FruitService fruitService) { this.fruitService = fruitService; } @PostMapping public void saveFruit(@RequestBody FruitRequest request) { fruitService.saveFruit(request); } @PutMapping public void updateFruit(@RequestBody FruitRequest request) { fruitService.updateFruit(request); } @GetMapping("/status") public FruitResponse getFruitStatus(@RequestParam String name) { return fruitService.getFruitStatus(name); } }
Java
복사
FruitService
package com.group.libraryapp.service.fruit; @Service public class FruitService { private final FruitRepository fruitRepository; public FruitService(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void saveFruit(FruitRequest request) { fruitRepository.saveFruit(request.getName(), request.getWarehousingDate(), request.getPrice()); } public void updateFruit(FruitRequest request) { fruitRepository.updateFruit(request.getId()); } public FruitResponse getFruitStatus(String name) { return fruitRepository.getFruitStatus(name); } }
Java
복사
FruitRepository
package com.group.libraryapp.repository.fruit; @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 void updateFruit(long id) { //먼저 과일이 있는지 체크 String readSql = "SELECT * FROM fruit WHERE id = ?"; boolean isFruitNotExit = jdbcTemplate.query(readSql, (rs, rowNum) -> 0,id).isEmpty(); //존재 하지않는다면 예외처리 if (isFruitNotExit) { throw new IllegalStateException(); } //있으면 업데이트 String sql = "UPDATE fruit SET status = 'SOLD' WHERE id = ?"; jdbcTemplate.update(sql, id); } public FruitResponse getFruitStatus(String name) { // 과일 이름을 기준으로 데이터베이스에서 과일 정보를 조회 String readFruitInfo = "SELECT * FROM fruit WHERE name = ?"; // 해당 과일이 존재하지 않는 경우 예외 처리 boolean isFruitNotExist = jdbcTemplate.query(readFruitInfo, (rs, rowNum) -> 0, name).isEmpty(); if (isFruitNotExist) { throw new IllegalStateException(); } // 과일이 판매된 총액을 조회 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); } }
Java
복사

요구사항 2

정리 하면서 서비스랑 레파지토리 더 쪼개서 나눠봄.
getFruitStatus쪽도 더 나눌 수 있을거 같다.
FruitService
package com.group.libraryapp.service.fruit; @Service public class FruitService { private final FruitRepository fruitRepository; public FruitService(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public void saveFruit(FruitRequest request) { fruitRepository.saveFruit(request.getName(), request.getWarehousingDate(), request.getPrice()); } public void updateFruit(FruitRequest 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); } }
Java
복사
FruitRepository
package com.group.libraryapp.repository.fruit; public interface FruitRepository { void saveFruit(String name, LocalDate warehousingDate, long price); boolean isFruitNotExist(long id); boolean isFruitNotExist(String name); void updateFruit(long id); FruitResponse getFruitStatus(String name); }
Java
복사
FruitMySqlRepository
package com.group.libraryapp.repository.fruit; @Repository @Primary 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); } @Override public boolean isFruitNotExist(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 status = 'SOLD' WHERE id = ?"; jdbcTemplate.update(sql, id); } public boolean isFruitNotExist(String name){ String readFruitInfo = "SELECT * FROM fruit WHERE name = ?"; return jdbcTemplate.query(readFruitInfo, (rs, rowNum) -> 0, name).isEmpty(); } 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); } }
Java
복사
FruitMemoryRepository
package com.group.libraryapp.repository.fruit; @Repository public class FruitMemoryRepository implements FruitRepository { public void saveFruit(String name, LocalDate warehousingDate, long price) {} @Override public boolean isFruitNotExist(long id) { return false; } @Override public boolean isFruitNotExist(String name) { return false; } public void updateFruit(long id) {} public FruitResponse getFruitStatus(String name) { return null; } }
Java
복사

참고

챗GPT