AllInOneController 의 코드 분리

송영재·2022년 10월 10일

Spring

목록 보기
42/45
  • 38) Controller, Service, Repository 로 코드 분리

    👉 AllInOneController 클래스의 이름부터 변경해 볼까요?
    AllInOneController.java → ProductController.java

    • 클래스이름 변경 방법

      1. AllInOneController 클래스에서 마우스 오른쪽 버튼을 누른 후, Refactor → Rename 클릭

      2. 혹은 키보드 단축키로도 가능합니다. Shift + F6

      3. Rename 팝업창이 뜨면, "AllInOneController" 를 "ProductController" 로 변경해 준 후 "Refactor" 버튼을 클릭해 주세요.

        • 그러면 신기하게도 파일이름까지도 함께 변경이 됩니다!! Java 는 클래스명과 파일 이름이 동일해야 한다는 규칙이 있어 Intellij 가 똑똑하게 함께 변경을 해 주는 거예요~
    • [코드스니펫] ProductController.java

      import lombok.RequiredArgsConstructor;
      import org.springframework.web.bind.annotation.*;
      
      import java.sql.SQLException;
      import java.util.List;
      
      @RequiredArgsConstructor // final로 선언된 멤버 변수를 자동으로 생성합니다.
      @RestController // JSON으로 데이터를 주고받음을 선언합니다.
      public class ProductController {
      
          // 신규 상품 등록
          @PostMapping("/api/products")
          public Product createProduct(@RequestBody ProductRequestDto requestDto) throws SQLException {
              ProductService productService = new ProductService();
              Product product = productService.createProduct(requestDto);
      
              // 응답 보내기
              return product;
          }
      
          // 설정 가격 변경
          @PutMapping("/api/products/{id}")
          public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) throws SQLException {
              ProductService productService = new ProductService();
              Product product = productService.updateProduct(id, requestDto);
      
              // 응답 보내기 (업데이트된 상품 id)
              return product.getId();
          }
      
          // 등록된 전체 상품 목록 조회
          @GetMapping("/api/products")
          public List<Product> getProducts() throws SQLException {
              ProductService productService = new ProductService();
              List<Product> products = productService.getProducts();
      
              // 응답 보내기
              return products;
          }
      }
    • [코드스니펫] ProductService.java

      import java.sql.SQLException;
      import java.util.List;
      
      public class ProductService {
      
          public Product createProduct(ProductRequestDto requestDto) throws SQLException {
              // 요청받은 DTO 로 DB에 저장할 객체 만들기
              Product product = new Product(requestDto);
      
              ProductRepository productRepository = new ProductRepository();
              productRepository.createProduct(product);
      
              return product;
          }
      
          public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) throws SQLException {
              ProductRepository productRepository = new ProductRepository();
              Product product = productRepository.getProduct(id);
              if (product == null) {
                  throw new NullPointerException("해당 아이디가 존재하지 않습니다.");
              }
      
              int myprice = requestDto.getMyprice();
              productRepository.updateMyprice(id, myprice);
      
              return product;
          }
      
          public List<Product> getProducts() throws SQLException {
              ProductRepository productRepository = new ProductRepository();
              List<Product> products = productRepository.getProducts();
      
              return products;
          }
      }
    • [코드스니펫] ProductRepository.java

      import java.sql.*;
      import java.util.ArrayList;
      import java.util.List;
      
      public class ProductRepository {
      
          public void createProduct(Product product) throws SQLException {
              // DB 연결
              Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
      
              // DB Query 작성
              PreparedStatement ps = connection.prepareStatement("select max(id) as id from product");
              ResultSet rs = ps.executeQuery();
              if (rs.next()) {
                  // product id 설정 = product 테이블의 마지막 id + 1
                  product.setId(rs.getLong("id") + 1);
              } else {
                  throw new SQLException("product 테이블의 마지막 id 값을 찾아오지 못했습니다.");
              }
              ps = connection.prepareStatement("insert into product(id, title, image, link, lprice, myprice) values(?, ?, ?, ?, ?, ?)");
              ps.setLong(1, product.getId());
              ps.setString(2, product.getTitle());
              ps.setString(3, product.getImage());
              ps.setString(4, product.getLink());
              ps.setInt(5, product.getLprice());
              ps.setInt(6, product.getMyprice());
      
              // DB Query 실행
              ps.executeUpdate();
      
              // DB 연결 해제
              ps.close();
              connection.close();
          }
      
          public Product getProduct(Long id) throws SQLException {
              Product product = new Product();
      
              // DB 연결
              Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
      
              // DB Query 작성
              PreparedStatement ps = connection.prepareStatement("select * from product where id = ?");
              ps.setLong(1, id);
      
              // DB Query 실행
              ResultSet rs = ps.executeQuery();
              if (rs.next()) {
                  product.setId(rs.getLong("id"));
                  product.setImage(rs.getString("image"));
                  product.setLink(rs.getString("link"));
                  product.setLprice(rs.getInt("lprice"));
                  product.setMyprice(rs.getInt("myprice"));
                  product.setTitle(rs.getString("title"));
              }
      
              // DB 연결 해제
              rs.close();
              ps.close();
              connection.close();
      
              return product;
          }
      
          public void updateMyprice(Long id, int myprice) throws SQLException {
              // DB 연결
              Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
      
              // DB Query 작성
              PreparedStatement ps = connection.prepareStatement("update product set myprice = ? where id = ?");
              ps.setInt(1, myprice);
              ps.setLong(2, id);
      
              // DB Query 실행
              ps.executeUpdate();
      
              // DB 연결 해제
              ps.close();
              connection.close();
          }
      
          public List<Product> getProducts() throws SQLException {
              List<Product> products = new ArrayList<>();
      
              // DB 연결
              Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
      
              // DB Query 작성 및 실행
              Statement stmt = connection.createStatement();
              ResultSet rs = stmt.executeQuery("select * from product");
      
              // DB Query 결과를 상품 객체 리스트로 변환
              while (rs.next()) {
                  Product product = new Product();
                  product.setId(rs.getLong("id"));
                  product.setImage(rs.getString("image"));
                  product.setLink(rs.getString("link"));
                  product.setLprice(rs.getInt("lprice"));
                  product.setMyprice(rs.getInt("myprice"));
                  product.setTitle(rs.getString("title"));
                  products.add(product);
              }
      
              // DB 연결 해제
              rs.close();
              connection.close();
      
              return products;
          }
      }
  • 39) 리팩토링 후 UI 를 통해 기능 검증

    • 모든 기능이 정상적으로 수행된다면, 리팩토링이 잘 되었다고 판단할 수 있겠죠? ☺️
  • 40) 리팩토링 후 개선점 확인

    • AllInOneController 의 문제점 재확인!!
    1. 한 개의 클래스에 너무 많은 양의 코드가 존재

      1. 코드 이해가 어려움: 처음부터 끝까지 다 읽어야 코드 내용을 이해할 수 있음

      → 3개의 클래스에 역할 별로 코드가 정리됨

    2. 현업에서는 코드 추가 혹은 변경 요청이 계속 생김

      1. 신규 상품 등록 시 Client 에게 응답 (Response) 하는 값 변경

        1. 등록된 Product 전체 정보 → 등록된 Product 의 id

        → Controller 의 역할

      2. 최저가 (Myprice) 업데이트 조건 변경

        1. Client 가 최저가를 0원 이하로 입력 → 에러 발생

        → Service 의 역할

      3. DB 테이블 이름 변경

        1. Product 테이블의 lpricelowprice 변경

        → Repository 의 역할

0개의 댓글