π μλ²μμμ μ²λ¦¬κ³Όμ β λλΆλΆ λΉμ·ν¨
μ²λ¦¬κ³Όμ μ ν¬κ² 3κ°λ‘ λΆλ¦¬ν¨ (Controller, Service, Repository)
β Client Requestλ₯Ό λ°μ
β‘ Requestμ λν μ²λ¦¬λ₯Ό Serviceμκ² μ λ΄μν΄
β’ μ²λ¦¬ Response Clientμκ² λ°ν
Client Requestλ₯Ό μ²λ¦¬νλ μ€μΈ
λΉμ¦λμ€ λ‘μ§ β νμ μμ μλΉμ€μ½λκ° κ³μ λΉλν΄μ§
DB μ 보 β Repositoryμ Request 보λ
DB κ΄λ¦¬ (μ°κ²°, ν΄μ , μμκ΄λ¦¬)
DB CRUD μμ μ²λ¦¬
// 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);
}
}
@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);
}
}
@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;
}
}
π κ°μ²΄μ€λ³΅μμ± ν΄κ²°
: ν ν΄λμ€ λ΄μμ, λ©μλλ§λ€ κ°μ κ°μ²΄κ° μ€λ³΅ν΄μ κ³μ μμ±λλ κ² βprivate final
λ©€λ²λ³μλ‘ μ μΈν΄μ 곡μ νμ¬ μ¬μ©νλ λ°©λ²
ProductService productService = new ProductService(); β μμ
ProductRepository productRepository = new ProductRepository(); β μμ
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 {β’β’β’}
Controller
5κ° β κ°κ° Service1
μμ±ν΄μ μ¬μ©μ€
Repository1
μμ±μ λ³κ²½ β λͺ¨λ Controller
, Service
μ½λλ³κ²½ νμ π¨
π κ°νκ²°ν©ν΄κ²°λ²
: κ° κ°μ²΄μ λν κ°μ²΄μμ± 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;
}
}
Repository1
μμ±μ λ³κ²½ β λ€λ₯Έ μ½λμ μν₯μ μ£Όμ§ μμ
Service1
μμ±μ λ³κ²½ β λ€λ₯Έ μ½λμ μν₯μ μ£Όμ§ μμ
π Spring Bean
: Spring IoC 컨ν μ΄λκ° κ΄λ¦¬νλ μλ°κ°μ²΄ β Springμ μν΄ μμ±λκ³ κ΄λ¦¬λλ μλ°κ°μ²΄
π Java νλ‘κ·Έλ¨
- κ° κ°μ²΄ β νλ‘κ·Έλ¨μ νλ¦μ κ²°μ
- κ° κ°μ²΄λ₯Ό κ°λ°μκ° μ§μ μμ± λ° μ‘°μ (κ°μ²΄μμ± β λ©μλνΈμΆ)
- "λͺ¨λ μμ
μ κ°λ°μκ° μ μ΄νλ ꡬ쑰"
π IoC μ μ΄μ μμ
- κ°μ²΄μμ± β κ΄λ¦¬μμ주체μ 맑κΉ
- κ°λ°μκ° μ§μ κ°μ²΄μμ± β
new
μμ±μλ₯Ό μ΄μ©ν΄ μμ±ν κ°μ²΄κ° μλλΌ,ν΄λμ€ μμ Annotation μ μΈ
μ€νλ§ μλ²κ° λ° λ β μ€νλ§ IoCμ Bean μ μ₯
// 1. ProductService κ°μ²΄μμ±
ProductService productService = new ProductService();
// 2. Spring IoC 컨ν
μ΄λμ Bean(productService) μ μ₯
// productService -> Spring IoC 컨ν
μ΄λ
@ComponentScan(basePackages = "")
packages μμΉ λ° νμ packagesλ€μ μ μ©λ¨β μ§μ κ°μ²΄μμ± β Bean λ±λ‘μμ²
β‘ μ€νλ§μλ² λ° λ β μ€νλ§ IoCμ Bean μ μ₯
β’ private final
λ©€λ²λ³μ μ μΈ μμ β @Autowired
μ μΈ
β£ Beanμ μ¬μ©ν ν¨μ μμ @Autowired
μ μΈ
β€ Lombok β @RequriedArgsConstructor
; @Autowired
+ μμ±μ μλ΅κ°λ₯ βοΈ
<@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();
}
}
// 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);
}
}
@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 interface ProductRepository extends JpaRepository<Product, Long> {
}
@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();
}
}
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class Timestamped {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
private LocalDateTime modifiedAt;
}
Application.java
β @EnableJpaAuditing
μΆκ°νμ@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
μΆκ°νμ@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);
}
}