13일 차 TIL
MSA를 완강하며, 전체적인 연동을 다시 해보고
간단한 상품-주문도메인으로 구성된 프로젝트를 구현해 봤다.
MSA의 사용법도 중요하지만..!
기본적인 CRUD와 디테일이 다시 한번 중요하다고 느껴졌다.
MSA의 설정법 자체는 한 번 익히고 나면 계속 보면서 따라 하면 되지만
강의에서는 CRUD의 성능을 높이고 각 데이터에 대한 검증, 권한, 보안등 여러 요소들을 신경 써서 한 것이 보였다.
MSA 마무리 프로젝트
- 구현해야 하는 상품-주문 프로젝트

프로젝트 설계)
boot 버전 : 3.5.11
springCloudVersion : 2025.0.1
사용한 라이브러리)
- Spring Web
- Lombok
- Mysql Driver
- Spring Data JPA
- Spring Security
- Eureka Server
- Eureka Discovery Client
- OpenFeign
- Config Server
- Config Client
- Reactive Gateway
- Spring Boot Actuator
- io.jsonwebtoken:jjwt:0.12.6
포트번호)
유레카 서버 : 19090
컨피그 서버 : 18080
게이트웨이 : 19091
주문 : 19092
상품 : 19093, 19094
유저 : 19095
eureka server에 client로 등록
1. gateway
2. config server
3. auth
4. product
5. order
config server에 client로 등록
1. gateway
2. auth
3. product]
4. order
config server는 auth, product, order의 db정보를 관리하고
gateway의 라우팅정보를 관리한다.
그리고 auth와 gateway에서는 jwt secretkey도 추가로 관리해 준다.
로그인 및 회원가입
먼저, Auth 서비스에서 간단하게 유저명과 비밀번호로 회원가입 및 로그인 기능을 구현했다.
회원가입 시 User 테이블에 저장,
role은 member를 기본적으로 설정
이후 manager로 변경하는 로직을 추가할 예정이다.
UserDetails에 User 객체를 담고, UserDetailsServiceImpl로 생성해서 로그인했고
로그인 성공 시 JWT를 발급해서 응답 body에 넣어 반환했다.
/auth/signUp, /auth/signIn은 Auth 앱과 Gateway에서 모두 필터를 거치지 않고 통과시켰다.
Gateway에서 Pre필터 방식으로 JWT를 검증해 로그인 유무를 판별한다.
상품 관리
Eureka와 config에 client로 등록한다.
- application.yaml
spring:
application:
name: product-service
config:
import: "configserver:"
cloud:
config:
discovery:
enabled: true
service-id: config-server
server:
port: 19093
eureka:
client:
service-url:
defaultZone: http://localhost:19090/eureka/
그리고 config server에서 받아오는 설정이다.
- product-service.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/msa_product?serverTimezone=Asia/Seoul&useSSL=false
username: root
password: mysql1234
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
database-platform: org.hibernate.dialect.MySQLDialect
이후 CRUD와 Search 구현은 모놀리틱 프로젝트와 동일하다.
- 상품 삭제 시, 실제로 삭제하지 않고 deletedAt에 현재 시간을 적어줬다.
private Product getProductById(Long id){
Product product = productRepository.findById(id)
.orElseThrow(()->new IllegalArgumentException("해당 ID의 상품이 없습니다."));
if(product.getDeletedAt() != null){
throw new IllegalArgumentException("삭제된 상품입니다.");
}
return product;
}
주문 관리
주문관리도 상품처럼 config과 eureka에 client로 동일하게 등록한다.
주문 엔티티는 상품명과 수량
pk필드와 삭제표시용 필드로 구성했다.
Order 파트에서는 주문을 진행할 때, 상품을 조회하는 로직이 필요하다.
이때 FeignClient가 사용된다.
- FeignClient를 사용한 인터페이스
package com.spring_cloud.eureka.client.order.client;
import com.spring_cloud.eureka.client.order.dto.ProductResponseDto;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/products")
List<ProductResponseDto> getProducts();
@GetMapping("/products/{id}")
ProductResponseDto getProduct(@PathVariable("id") Long id);
}
client 패키지 아래에 작성하였다.
ProductClient 인터페이스로 아래의 Product 컨트롤러의 메서드를 가져올 수 있다.
- ProductController의 상품목록을 가져오는 메서드
@GetMapping
public List<ProductResponseDto> getProducts(){
return productService.getProducts();
}
- Order 컨트롤러에서 주문을 생성하는 메서드
@PostMapping
public ResponseEntity<?> createOrder(@RequestBody OrderReqeustDto requestDto, @RequestParam("productId") Long productId) {
return ResponseEntity.ok(orderService.createOrder(requestDto,productId));
}
컨트롤러에서 주문생성 메서드를 호출하고,
Order의 서비스 레이어에서 사용된다.
- Order 서비스레이어에서 주문을 생성하는 메서드
public class OrderService {
private final OrderRepository orderRepository;
private final ProductClient productClient;
public OrderResponseDto createOrder(OrderReqeustDto requestDto, Long productId) {
ProductResponseDto product = productClient.getProduct(productId);
Order order = new Order(product.getProductName(),requestDto.getQuantity());
orderRepository.save(order);
return new OrderResponseDto(productId,product.getProductName(),requestDto.getQuantity());
}
// ...그 외 RUD + Search 기능들
}
ProductClient를 주입받아
Product를 읽어올 때 사용한다.
받아온 Product를 Dto로 변환해서 저장하고, Order를 생성할 때 상품명을 파라미터로 넘겨준다.
나머지 로직은 모놀리틱 프로젝트와 동일하게 진행했다.
강의에서 진행한 방식
패키지구조는 각 앱에서 2개의 패키지로 나눠 관리했다.
예를 들어, product service라면
core와 products패키지로 나누고
core패키지 안
도메인 패키지에 product 엔티티
client 패키지에 외부 호출 인터페이스와 반환받을 사용할 DTO
그 외 enum 같은 도메인 관련 패키지들이 들어간다.
products패키지에 나머지 컨트롤러 서비스 리포지 dto들을 구성한다.
검색 기능은 QueryDSL을 사용해서, 여러 개의 필터링을 한 번에 했다. ( JPA는 각각 따로 만들어야 함 )
gateway로부터 user정보를 exchange 안에 헤더로 넣고,
헤더에서 그 값을 받아와서 role을 통해 권한에 따라 실행했다.
order에서 주문을 생성할 때, 주문 안에 상품이 있는지 없는지 for문을 통해 체크했다.
'내배캠' 카테고리의 다른 글
| [내일배움캠프 본캠프] 14일 차 TIL Layered Architecture (0) | 2026.02.23 |
|---|---|
| [내일배움캠프 과제] MSA 강의 정리 (0) | 2026.02.23 |
| [내일배움캠프 본캠프] 12일 차 TIL MSA (0) | 2026.02.21 |
| [내일배움캠프 본캠프] 11일 차 TIL MSA, Git flow (0) | 2026.02.20 |
| [내일배움캠프 본캠프] 10일 차 TIL Spring AI (0) | 2026.02.19 |
