728x90
📌 Controller, Service Repository 역할
- 전체적인 흐름
💻 AllInOneController ⇨ ProductController 로 변경
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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;
}
}
|
cs |
💻 ProductService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
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;
}
}
|
cs |
💻 ProductRepository.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
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;
}
}
|
cs |
🔑 1. 객체 중복 생성 문제 해결
new ProductRepository() 코드가 중복되므로 ProductService가 생성될 때 딱 한 번만 생성해서 계속 사용하면 됨
< 수정 후 코드 >
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class ProductService {
// 멤버 변수 선언
private final ProductRepository productRepository;
// 생성자: ProductService() 가 생성될 때 호출됨
public ProductService() {
// 멤버 변수 생성
this.productRepository = new ProductRepository();
}
public Product createProduct(ProductRequestDto requestDto) throws SQLException {
// 요청받은 DTO 로 DB에 저장할 객체 만들기
Product product = new Product(requestDto);
// 멤버 변수 사용
this.productRepository.createProduct(product);
return product;
}
|
cs |
🔑 2. DI (의존성 주입) : 강한 결합의 문제 해결
- Controller 5 개가 각각 Service1 을 생성하여 사용 중
- Repository1 생성자 변경에 의해.. ⇒ 모든 Contoller 와 모든 Service 의 코드 변경이 필요
💡 1. 각 객체에 대한 객체 생성은 딱 1번만
2. 생성된 객체의 모든 곳에서 재사용
< 수정 후 코드 >
- Service
1
2
3
4
5
6
7
8
9
10
11
12
|
Class Service1 {
private final Repository1 repitory1;
// repository1 객체 사용
public Service1(Repository1 repository1) {
this.repository1 = new Repository1();
this.repository1 = repository1;
}
}
// 객체 생성
Service1 service1 = new Service1(repository1);
|
cs |
- Controller
1
2
3
4
5
6
7
8
9
|
Class Controller1 {
private final Service1 service1;
// service1 객체 사용
public Controller1(Service1 service1) {
this.service1 = new Service1();
this.service1 = service1;
}
}
|
cs |
- Repository
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Repository1 {
public Repository1(String id, String pw) {
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", id, pw);
}
}
// 객체 생성
String id = "sa";
String pw = "";
Repository1 repository1 = new Repository1(id, pw);
|
cs |
[ 결과 ]
⇒ Repository1 생성자 변경은 이제 누구에게도 피해(?) 를 주지 않음
⇒ Service1 생성자가 변경되면? 모든 Contoller → Controller 변경 필요 X
결론적으로, 강한 결합 ⇒ 느슨한 결합
💡 DI(의존성 주입) 의 이해
: 프로그램의 제어 흐름이 뒤바뀜
- 일반적: 사용자가 자신이 필요한 객체를 생성해서 사용
- IoC (제어의 역전)
- 용도에 맞게 필요한 객체를 그냥 가져다 사용
- "DI (Dependency Injection)" 혹은 한국말로 "의존성 주입"이라고 부름
- 사용할 객체가 어떻게 만들어졌는지는 알 필요 없음
- 실생활 예제) 가위의 용도별 사용
- 음식을 자를 때 필요한 가위는? → 부엌가위 (생성되어 있는 객체 kitchenScissors)
- 무늬를 내며 자를 때 필요한 가위는? → 핑킹가위 (생성되어 있는 객체 pinkingShears)
- 정원의 나무를 다듬을 때 필요한 가위는? → 전지가위 (생성되어 있는 객체 pruningShears)
- 용도에 맞게 필요한 객체를 그냥 가져다 사용
🔑 3. IoC 컨테이너 사용
DI를 사용하기 위해서는 객체 생성이 우선되어야 했음. 과연 어디서 객체를 생성해야 할가?
바로, 스프링 프레임워크가 필요한 객체를 생성하여 관리하는 역할을 대신 해줌.
- 빈 (Bean): 스프링이 관리하는 객체
- 스프링 IoC 컨테이너: '빈'을 모아둔 통
📌 스프링 '빈'등록 방법
1. @Componen
1)클래스 선언 위에 설정
1
2
|
@Component
public class ProductService { ... }
|
cs |
2)스프링 서버가 뜰 때 스프링 IoC 에 '빈' 저장
- @Component 클래스에 대해서 스프링이 해 주는 일
12345// 1. ProductService 객체 생성ProductService productService = new ProductService();// 2. 스프링 IoC 컨테이너에 빈 (productService) 저장// productService -> 스프링 IoC 컨테이너
cs - 스프링 '빈' 이름: 클래스의 앞글자만 소문자로 변경 ⇨ public class ProductService → productService
3) 빈' 아이콘 확인 → 스프링 IoC 에서 관리할 '빈' 클래스라는 표시
4) @Component 적용 조건 ⭐
- @Component Scan 에 설정해 준 packages 위치와 하위 packages 들
123@Configuration@ComponentScan(basePackages = "com.sparta.springcore")class BeanConfig { ... }
cs
- @SpringBootApplication 에 의해 default 설정이 되어 있음
- 경로 : com.sparta.springcore/SpringcoreApplication.java
728x90
'🛠 BackEnd > Spring' 카테고리의 다른 글
[ Spring ] Table 'batch.batch_job_instance' doesn't exist / 에러 해결방법 (SpringBoot 2.5 이상) (0) | 2022.11.30 |
---|---|
[ Spring ] @Scheduled 스케줄러 사용법 (0) | 2022.11.02 |
[ Spring ] - Spring Security 인증 절차 인터페이스 UserDetails, UserDetailsService (0) | 2022.10.09 |
[ Spring ] Controller, Service Repository 코드 분리 (1/2) (1) | 2022.10.08 |
Springframework (0) | 2022.10.06 |
댓글