๐Ÿ“ GitHub ๋ฐ”๋กœ๊ฐ€๊ธฐ

Project Intro


1 AllInOneController ์—ญํ• ๋ถ„๋ฆฌ

๐Ÿ“Œ ์„œ๋ฒ„์—์„œ์˜ ์ฒ˜๋ฆฌ๊ณผ์ • โ†’ ๋Œ€๋ถ€๋ถ„ ๋น„์Šทํ•จ
์ฒ˜๋ฆฌ๊ณผ์ •์„ ํฌ๊ฒŒ 3๊ฐœ๋กœ ๋ถ„๋ฆฌํ•จ (Controller, Service, Repository)

1๏ธโƒฃ Controller

  • โ‘  Client Request๋ฅผ ๋ฐ›์Œ

  • โ‘ก Request์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ Service์—๊ฒŒ ์ „๋‹ด์‹œํ‚ด

  • โ‘ข ์ฒ˜๋ฆฌ Response Client์—๊ฒŒ ๋ฐ˜ํ™˜

2๏ธโƒฃ Service

  • Client Request๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹ค์„ธ

  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง โ†’ ํ˜„์—…์—์„œ ์„œ๋น„์Šค์ฝ”๋“œ๊ฐ€ ๊ณ„์† ๋น„๋Œ€ํ•ด์ง

  • DB ์ •๋ณด โ†’ Repository์— Request ๋ณด๋ƒ„

3๏ธโƒฃ Repository

  • DB ๊ด€๋ฆฌ (์—ฐ๊ฒฐ, ํ•ด์ œ, ์ž์›๊ด€๋ฆฌ)

  • DB CRUD ์ž‘์—…์ฒ˜๋ฆฌ


2 AllInOneController ์ฝ”๋“œ๋ถ„๋ฆฌ

1๏ธโƒฃ ๊ด€์‹ฌ์‚ฌ๋ถ„๋ฆฌ

๐Ÿ“ Controller

๐Ÿ“ Service

๐Ÿ“ Repository

2๏ธโƒฃ ์ฝ”๋“œ๋ถ„๋ฆฌ

๐Ÿ“ Controller

// JSON ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฐ˜ํ™˜
@RestController
@RequestMapping("/api")
public class ProductController {

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    @PostMapping("/products")
    public ProductResponseDto createProduct(@RequestBody ProductRequestDto productRequestDto) throws SQLException {

        ProductService productService = new ProductService();

        return productService.createProduct(productRequestDto);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    @GetMapping("/products")
    public List<ProductResponseDto> getProducts() throws SQLException {

        ProductService productService = new ProductService();

        return productService.getProducts();

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    @PutMapping("/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto productMypriceRequestDto) throws SQLException {

        ProductService productService = new ProductService();

        return productService.updateProduct(id, productMypriceRequestDto);

    }

}

๐Ÿ“ Service

@Component // Bean ๋“ฑ๋ก
public class ProductService {

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    public ProductResponseDto createProduct(ProductRequestDto productRequestDto) throws SQLException {

        Product product = Product.of(productRequestDto);

        ProductRepository productRepository = new ProductRepository();

        return productRepository.createProduct(product);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    public List<ProductResponseDto> getProducts() throws SQLException {

        ProductRepository productRepository = new ProductRepository();

        return productRepository.getProducts();

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    public Long updateProduct(Long id, ProductMypriceRequestDto productMypriceRequestDto) throws SQLException {

        ProductRepository productRepository = new ProductRepository();

        Product product = productRepository.getProduct(id);

        if (product == null) {
            throw new NullPointerException("ํ•ด๋‹น ์ƒํ’ˆ์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค");
        }

        return productRepository.updateProduct(product.getId(), productMypriceRequestDto);

    }

}

๐Ÿ“ Repository

@Component // Bean ๋“ฑ๋ก
public class ProductRepository {

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    public ProductResponseDto createProduct(Product product) throws SQLException {

        // DB ์—ฐ๊ฒฐ
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:db;MODE=MYSQL", "mallang", "");

        // DB Query ์ž‘์„ฑ
        PreparedStatement preparedStatement = connection.prepareStatement("select max(id) as id from product");

        ResultSet resultSet = preparedStatement.executeQuery();

        if (resultSet.next()) {
            product.setId(resultSet.getLong("id") + 1);
        } else {
            throw new SQLException("Product ํ…Œ์ด๋ธ”์˜ ๋งˆ์ง€๋ง‰ id ๊ฐ’์„ ์ฐพ์•„์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค");
        }

        preparedStatement = connection.prepareStatement("insert into product(id, title, image, link, lprice, myprice)values(?, ?, ?, ?, ?, ?)");
        preparedStatement.setLong(1, product.getId());
        preparedStatement.setString(2, product.getTitle());
        preparedStatement.setString(3, product.getImage());
        preparedStatement.setString(4, product.getLink());
        preparedStatement.setInt(5, product.getLprice());
        preparedStatement.setInt(6, product.getMyprice());

        // DB Query ์‹คํ–‰
        preparedStatement.executeUpdate();

        // DB ์—ฐ๊ฒฐํ•ด์ œ
        preparedStatement.close();

        return ProductResponseDto.of(product);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    public List<ProductResponseDto> getProducts() throws SQLException {

        List<ProductResponseDto> productResponseDtoList = new ArrayList<>();

        // DB ์—ฐ๊ฒฐ
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:db;MODE=MYSQL", "mallang", "");

        // DB Query ์ž‘์„ฑ ๋ฐ ์‹คํ–‰
        Statement statement = connection.createStatement();

        ResultSet resultSet = statement.executeQuery("select * from product");

        // DB Query ๊ฒฐ๊ณผ -> ProductResponseDtoList๋กœ ๋ณ€ํ™˜
        // DB Query ๊ฒฐ๊ณผ -> productResponseDtoList ๋ณ€ํ™˜
        while (resultSet.next()) {
            Product product = new Product();

            product.setId(resultSet.getLong("id"));
            product.setTitle(resultSet.getString("title"));
            product.setImage(resultSet.getString("image"));
            product.setLink(resultSet.getString("link"));
            product.setLprice(resultSet.getInt("lprice"));
            product.setMyprice(resultSet.getInt("myprice"));

            productResponseDtoList.add(ProductResponseDto.of(product));
        }

        // DB ์—ฐ๊ฒฐํ•ด์ œ
        resultSet.close();

        connection.close();

        return productResponseDtoList;

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    public Long updateProduct(Long id, ProductMypriceRequestDto productMypriceRequestDto) throws SQLException {

        // DB ์—ฐ๊ฒฐ
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:db;MODE=MYSQL", "mallang", "");

        // DB Query ์ž‘์„ฑ
        PreparedStatement preparedStatement = connection.prepareStatement("update product set myprice = ? where id = ?");

        preparedStatement.setInt(1, productMypriceRequestDto.getMyprice());
        preparedStatement.setLong(2, id);

        // DB Query ์‹คํ–‰
        preparedStatement.executeUpdate();

        // DB ์—ฐ๊ฒฐํ•ด์ œ
        preparedStatement.close();

        connection.close();

        return null;

    }

    public Product getProduct(Long id) throws SQLException {

        Product product = new Product();

        // DB ์—ฐ๊ฒฐ
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:db;MODE=MYSQL", "mallang", "");

        // DB Query ์ž‘์„ฑ
        PreparedStatement preparedStatement = connection.prepareStatement("select * from product where id = ?");

        preparedStatement.setLong(1, id);

        // DB Query ์‹คํ–‰
        ResultSet resultSet = preparedStatement.executeQuery();

        if (resultSet.next()) {
            product.setId(resultSet.getLong("id"));
            product.setTitle(resultSet.getString("title"));
            product.setImage(resultSet.getString("image"));
            product.setLink(resultSet.getString("link"));
            product.setLprice(resultSet.getInt("lprice"));
            product.setMyprice(resultSet.getInt("myprice"));
        }

        // DB ์—ฐ๊ฒฐํ•ด์ œ
        resultSet.close();

        preparedStatement.close();

        connection.close();

        return product;

    }

}

3 ๊ฐ์ฒด์ค‘๋ณต์ƒ์„ฑ ํ•ด๊ฒฐ

๐Ÿ“Œ ๊ฐ์ฒด์ค‘๋ณต์ƒ์„ฑ ํ•ด๊ฒฐ : ํ•œ ํด๋ž˜์Šค ๋‚ด์—์„œ, ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ์ค‘๋ณตํ•ด์„œ ๊ณ„์† ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ โ†’ private final ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•ด์„œ ๊ณต์œ ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

๐Ÿ“ ProductController.java

ProductService productService = new ProductService(); โ†’ ์‚ญ์ œ

๐Ÿ“ ProductService.java

ProductRepository productRepository = new ProductRepository(); โ†’ ์‚ญ์ œ

4 DI(์˜์กด์„ฑ์ฃผ์ž…)

1๏ธโƒฃ ๊ฐ•ํ•œ๊ฒฐํ•ฉ

  • โ‘  Controller1 โ†’ Service1 ๊ฐ์ฒด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ
public class Controller1 {
	
    private final Service1 service1;
    
    public Controller1() {
    	this.service1 = new Service1();
    }

}
  • โ‘ก Service1 โ†’ Repository ๊ฐ์ฒด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ
public class Service1 {
	
    private final Repository1 repository1;
    
    public Service() {
    	this.repository1 = new Repository1;
    }
    
}
  • โ‘ข Repository1 ๊ฐ์ฒด์„ ์–ธ
public class Repository1 {โ€ขโ€ขโ€ข}

2๏ธโƒฃ ๊ฐ•ํ•œ๊ฒฐํ•ฉ ๋ฌธ์ œ์ 

  • Controller 5๊ฐœ โ†’ ๊ฐ๊ฐ Service1 ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉ์ค‘

  • Repository1 ์ƒ์„ฑ์ž ๋ณ€๊ฒฝ โ†’ ๋ชจ๋“  Controller, Service ์ฝ”๋“œ๋ณ€๊ฒฝ ํ•„์š” ๐Ÿšจ

3๏ธโƒฃ ๊ฐ•ํ•œ๊ฒฐํ•ฉ ํ•ด๊ฒฐ๋ฒ•

๐Ÿ“Œ ๊ฐ•ํ•œ๊ฒฐํ•ฉํ•ด๊ฒฐ๋ฒ• : ๊ฐ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๊ฐ์ฒด์ƒ์„ฑ 1๋ฒˆ๋งŒ โ†’ ์ƒ์„ฑ๋œ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๋ชจ๋“ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉ โญ๏ธ

  • โ‘  Repository1 ํด๋ž˜์Šค ์„ ์–ธ ๋ฐ ๊ฐ์ฒด์ƒ์„ฑ โ†’ repository1
public class Repository1{โ€ขโ€ขโ€ข}

// ๊ฐ์ฒด์ƒ์„ฑ
Repository1 repository1 = new Repository1();
  • โ‘ก Service1 ํด๋ž˜์Šค ์„ ์–ธ ๋ฐ ๊ฐ์ฒด์ƒ์„ฑ(repository1 ์žฌ์‚ฌ์šฉ) โ†’ service1
class Service1 {
	
    private final Repository1 repository1;
    
    // repository1 ๊ฐ์ฒด ์žฌ์‚ฌ์šฉ
    public Service1(Repository1 repository1) {
    	this.repository1 = repository1;
    }
    
}
  • โ‘ข Controller1 ์„ ์–ธ(service1 ์žฌ์‚ฌ์šฉ)
class Controller1 {
	
    private final Service1 service1;
    
    // service1 ๊ฐ์ฒด ์žฌ์‚ฌ์šฉ
    public Controller1(Service1 service1) {
    	this.service1 = service1;
    }
    
}

4๏ธโƒฃ ๊ฐ•ํ•œ๊ฒฐํ•ฉ ๊ฐœ์„ ๊ฒฐ๊ณผ

  • Repository1 ์ƒ์„ฑ์ž ๋ณ€๊ฒฝ โ†’ ๋‹ค๋ฅธ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ

  • Service1 ์ƒ์„ฑ์ž ๋ณ€๊ฒฝ โ†’ ๋‹ค๋ฅธ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ


5 Spring IoC ์ปจํ…Œ์ด๋„ˆ

๐Ÿ“Œ Spring Bean : Spring IoC ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฐ”๊ฐ์ฒด โ†’ Spring์— ์˜ํ•ด ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋˜๋Š” ์ž๋ฐ”๊ฐ์ฒด

๐Ÿ“ Java ํ”„๋กœ๊ทธ๋žจ
	- ๊ฐ ๊ฐ์ฒด โ†’ ํ”„๋กœ๊ทธ๋žจ์˜ ํ๋ฆ„์„ ๊ฒฐ์ •
    - ๊ฐ ๊ฐ์ฒด๋ฅผ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ƒ์„ฑ ๋ฐ ์กฐ์ž‘ (๊ฐ์ฒด์ƒ์„ฑ โ†’ ๋ฉ”์„œ๋“œํ˜ธ์ถœ)
    - "๋ชจ๋“ ์ž‘์—…์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๊ตฌ์กฐ"

๐Ÿ“ IoC ์ œ์–ด์˜ ์—ญ์ „
	- ๊ฐ์ฒด์ƒ์„ฑ โ†’ ๊ด€๋ฆฌ์œ„์ž„์ฃผ์ฒด์— ๋งก๊น€
    - ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ฐ์ฒด์ƒ์„ฑ โŒ
  • Spring์—์„œ๋Š” new ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•ด ์ƒ์„ฑํ•œ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ,
    Spring์— ์˜ํ•ด ๊ด€๋ฆฌ๋‹นํ•˜๋Š” ์ž๋ฐ”๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•จ

1๏ธโƒฃ Spring Bean ๋“ฑ๋ก๋ฐฉ๋ฒ•

๐Ÿ“ @Component

  • ํด๋ž˜์Šค ์œ„์— Annotation ์„ ์–ธ

  • ์Šคํ”„๋ง ์„œ๋ฒ„๊ฐ€ ๋œฐ ๋•Œ โ†’ ์Šคํ”„๋ง IoC์— Bean ์ €์žฅ

// 1. ProductService ๊ฐ์ฒด์ƒ์„ฑ
ProductService productService = new ProductService();

// 2. Spring IoC ์ปจํ…Œ์ด๋„ˆ์— Bean(productService) ์ €์žฅ
// productService -> Spring IoC ์ปจํ…Œ์ด๋„ˆ
  • @ComponentScan(basePackages = "") packages ์œ„์น˜ ๋ฐ ํ•˜์œ„ packages๋“ค์— ์ ์šฉ๋จ

2๏ธโƒฃ Spring Bean ์‚ฌ์šฉ๋ฐฉ๋ฒ•

๐Ÿ“ @Bean

  • โ‘  ์ง์ ‘ ๊ฐ์ฒด์ƒ์„ฑ โ†’ Bean ๋“ฑ๋ก์š”์ฒญ

  • โ‘ก ์Šคํ”„๋ง์„œ๋ฒ„ ๋œฐ ๋•Œ โ†’ ์Šคํ”„๋ง IoC์— Bean ์ €์žฅ

  • โ‘ข private final ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์„ ์–ธ ์œ„์— โ†’ @Autowired ์„ ์–ธ

  • โ‘ฃ Bean์„ ์‚ฌ์šฉํ•  ํ•จ์ˆ˜ ์œ„์— @Autowired ์„ ์–ธ

  • โ‘ค Lombok โ†’ @RequriedArgsConstructor ; @Autowired + ์ƒ์„ฑ์ž ์ƒ๋žต๊ฐ€๋Šฅ โญ๏ธ


6 ์ตœ์ข… Refactoring ์ฝ”๋“œ

1๏ธโƒฃ Product.java

<@Entity
@Getter @Setter
@NoArgsConstructor
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // Id ์ž๋™์ƒ์„ฑ ๋ฐ ์ฆ๊ฐ€
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String image;

    @Column(nullable = false)
    private String link;

    @Column(nullable = false)
    private int lprice;

    @Column(nullable = false)
    private int myprice;

    // ์ƒ์„ฑ์ž
    @Builder
    private Product(String title, String image, String link, int lprice) {
        this.title = title;
        this.image = image;
        this.link = link;
        this.lprice = lprice;
        this.myprice = 0;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static Product of(ProductRequestDto productRequestDto) {
        return Product.builder()
                .title(productRequestDto.getTitle())
                .image(productRequestDto.getImage())
                .link(productRequestDto.getLink())
                .lprice(productRequestDto.getLprice())
                .build();
    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก (update)
    public void update(ProductMypriceRequestDto productMypriceRequestDto) {
        this.myprice = productMypriceRequestDto.getMyprice();
    }

}

2๏ธโƒฃ ProductController.java

// JSON ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฐ˜ํ™˜
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class ProductController {

    // ๊ฐ์ฒด์ค‘๋ณต์ƒ์„ฑ ํ•ด๊ฒฐ -> ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์„ ์–ธ
    private final ProductService productService;

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    @PostMapping("/products")
    public ProductResponseDto createProduct(@RequestBody ProductRequestDto productRequestDto) {

        return productService.createProduct(productRequestDto);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    @GetMapping("/products")
    public List<ProductResponseDto> getProducts() {

        return productService.getProducts();

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    @PutMapping("/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto productMypriceRequestDto) {

        return productService.updateProduct(id, productMypriceRequestDto);

    }

}

3๏ธโƒฃ ProductService.java

@Service
@RequiredArgsConstructor
public class ProductService {

    // ๊ฐ์ฒด์ค‘๋ณต์ƒ์„ฑ ํ•ด๊ฒฐ -> ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์„ ์–ธ
    private final ProductRepository productRepository;

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    @Transactional
    public ProductResponseDto createProduct(ProductRequestDto productRequestDto) {

        Product product = productRepository.saveAndFlush(Product.of(productRequestDto));

        return ProductResponseDto.of(product);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    @Transactional(readOnly = true)
    public List<ProductResponseDto> getProducts() {

        List<ProductResponseDto> productResponseDtoList = new ArrayList<>();

        List<Product> productList = productRepository.findAll();

        for (Product product : productList) {
            productResponseDtoList.add(ProductResponseDto.of(product));
        }

        return productResponseDtoList;

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    @Transactional
    public Long updateProduct(Long id, ProductMypriceRequestDto productMypriceRequestDto) {

        Product product = productRepository.findById(id).orElseThrow(
                () -> new NullPointerException("ํ•ด๋‹น ์ƒํ’ˆ์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค;")
        );

        product.update(productMypriceRequestDto);

        return product.getId();

    }

}

4๏ธโƒฃ ProductRepository.java

public interface ProductRepository extends JpaRepository<Product, Long> {
}

7 ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€์—…๋ฐ์ดํŠธ ์Šค์ผ€์ค„๋Ÿฌ ์„ค๊ณ„

1๏ธโƒฃ Product.java

@Entity
@Getter @Setter
@NoArgsConstructor
public class Product extends Timestamped {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // Id ์ž๋™์ƒ์„ฑ ๋ฐ ์ฆ๊ฐ€
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String image;

    @Column(nullable = false)
    private String link;

    @Column(nullable = false)
    private int lprice;

    @Column(nullable = false)
    private int myprice;

    // ์ƒ์„ฑ์ž
    @Builder
    private Product(String title, String image, String link, int lprice) {
        this.title = title;
        this.image = image;
        this.link = link;
        this.lprice = lprice;
        this.myprice = 0;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static Product of(ProductRequestDto productRequestDto) {
        return Product.builder()
                .title(productRequestDto.getTitle())
                .image(productRequestDto.getImage())
                .link(productRequestDto.getLink())
                .lprice(productRequestDto.getLprice())
                .build();
    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก (update)
    public void update(ProductMypriceRequestDto productMypriceRequestDto) {
        this.myprice = productMypriceRequestDto.getMyprice();
    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ์—…๋ฐ์ดํŠธ
    public void updateLprice(ItemDto itemDto) {
        this.lprice = itemDto.getLprice();
    }

}

2๏ธโƒฃ Timestamped.java

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class Timestamped {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column
    private LocalDateTime modifiedAt;

}
  • Application.java โ†’ @EnableJpaAuditing ์ถ”๊ฐ€ํ•„์ˆ˜

3๏ธโƒฃ Scheduler.java

@Slf4j
@Component
@RequiredArgsConstructor
public class Scheduler {

    private final NaverApiService naverApiService;
    private final ProductService productService;
    private final ProductRepository productRepository;

    // ์ดˆ, ๋ถ„, ์‹œ, ์ผ, ์›”, ์ฃผ ์ˆœ์„œ
    @Scheduled(cron = "0 0 1 * * *")
    public void updateLprice() throws InterruptedException {

        log.info("์ตœ์ €๊ฐ€ ์—…๋ฐ์ดํŠธ ์‹คํ–‰");

        List<Product> productList = productRepository.findAll();

        for (Product product : productList) {
            // 1์ดˆ์— ํ•œ ์ƒํ’ˆ์”ฉ ์กฐํšŒ
            TimeUnit.SECONDS.sleep(1);

            String title = product.getTitle();

            List<ItemDto> itemDtoList = naverApiService.searchItems(title);

            ItemDto itemDto = itemDtoList.get(0);

            // 1๋ฒˆ์งธ ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€๋ฅผ ์—…๋ฐ์ดํŠธ
            Long id = product.getId();

            productService.updateBySearch(id, itemDto);
        }

    }

}
  • Application.java โ†’ @EnableScheduling ์ถ”๊ฐ€ํ•„์ˆ˜

4๏ธโƒฃ ProductService.java

@Service
@RequiredArgsConstructor
public class ProductService {

    // ๊ฐ์ฒด์ค‘๋ณต์ƒ์„ฑ ํ•ด๊ฒฐ -> ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์„ ์–ธ
    private final ProductRepository productRepository;

    // ๊ด€์‹ฌ์ƒํ’ˆ ๋“ฑ๋ก
    @Transactional
    public ProductResponseDto createProduct(ProductRequestDto productRequestDto) {

        Product product = productRepository.saveAndFlush(Product.of(productRequestDto));

        return ProductResponseDto.of(product);

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์กฐํšŒ
    @Transactional(readOnly = true)
    public List<ProductResponseDto> getProducts() {

        List<ProductResponseDto> productResponseDtoList = new ArrayList<>();

        List<Product> productList = productRepository.findAll();

        for (Product product : productList) {
            productResponseDtoList.add(ProductResponseDto.of(product));
        }

        return productResponseDtoList;

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ๋“ฑ๋ก
    @Transactional
    public Long updateProduct(Long id, ProductMypriceRequestDto productMypriceRequestDto) {

        Product product = productRepository.findById(id).orElseThrow(
                () -> new NullPointerException("ํ•ด๋‹น ์ƒํ’ˆ์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค")
        );

        product.update(productMypriceRequestDto);

        return product.getId();

    }

    // ๊ด€์‹ฌ์ƒํ’ˆ ์ตœ์ €๊ฐ€ ์—…๋ฐ์ดํŠธ
    public void updateBySearch(Long id, ItemDto itemDto) {

        Product product = productRepository.findById(id).orElseThrow(
                () -> new NullPointerException("ํ•ด๋‹น ์ƒํ’ˆ์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค")
        );

        // Product Entity method ์‹คํ–‰
        product.updateLprice(itemDto);

    }

}
profile
๐ŸฑSunyeon-Jeong, mallang developer๐Ÿฐ

0๊ฐœ์˜ ๋Œ“๊ธ€