Spring Boot + Vue3 DDD
Request에서 Command, Entity를 거쳐 Response로 이어지도록 계층별 객체를 갈라 스프링 부트 패키지 구조를 잡고, 같은 기준으로 Vue 3 쪽 구조와 견줘본 정리.
작성날짜: 25.07.14
Spring Boot 패키지 구조
Request → Command → Entity → Response
com.example.userapp
├── controller
│ └── UserController.java
├── service
│ └── UserService.java
├── domain
│ └── User.java
├── dto
│ ├── UserRequest.java // Request DTO (입력값)
│ ├── UserCommand.java // Command 객체 (서비스 계층)
│ └── UserResponse.java // Response DTO (출력값)
├── repository
│ └── UserRepository.java
└── exception
└── GlobalExceptionHandler.java
[요약 흐름]
[Client JSON 요청]
↓
UserRequest (Controller)
→ toCommand()
↓
UserCommand (Service)
→ User.from(command)
↓
User (Entity 저장)
→ UserResponse 로 변환
↓
[Client JSON 응답]
✅ 계층별 객체 분리 (Layered Architecture with Role-specific Objects)
Command 객체
→ 클라이언트로부터 전달된 명령(의도) 를 표현하는 객체. 주로 서비스 계층에서 사용되어 비즈니스 로직의 입력 값으로 전달됨
→ CreateUserCommand, UpdateOrderCommand 와 같은 이름으로 쓰임
DTO (Data Transfer Object)
→ 계층 간 데이터 전달용 객체. 순수 데이터만 담으며 로직 없음
→ UserDto, OrderResponseDto 등
Entity / Domain 객체
→ DB 테이블 매핑 객체 또는 도메인 로직을 포함하는 객체
예시 코드
1. RequestDTO (UserRequest.java)
public class UserRequest {
private String name;
private String email;
// 생성자, getter
public UserRequest(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() { return name; }
public String getEmail() { return email; }
public UserCommand toCommand() {
return new UserCommand(name, email);
}
}
2. Command 객체 (UserCommand.java)
public class UserCommand {
private final String name;
private final String email;
public UserCommand(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() { return name; }
public String getEmail() { return email; }
}
3. Entity (User.java)
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
private String email;
protected User() {} // JPA용
public User(String name, String email) {
this.name = name;
this.email = email;
}
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
public static User from(UserCommand command) {
return new User(command.getName(), command.getEmail());
}
}
4. Response DTO (UserResponse.java)
public class UserResponse {
private final Long id;
private final String name;
private final String email;
public UserResponse(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
실제 사용
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public UserResponse createUser(UserCommand command) {
User user = User.from(command);
User saved = userRepository.save(user);
return new UserResponse(saved.getId(), saved.getName(), saved.getEmail());
}
}
Vue 3 패키지 구조
src/
├── api/ # 백엔드 API 연동 모듈 (axios 인스턴스 포함)
│ └── userApi.js
├── components/ # 재사용 가능한 컴포넌트
│ └── UserForm.vue
├── pages/ # 페이지 단위 뷰 (라우터와 연결됨)
│ └── UserCreatePage.vue
├── stores/ # Pinia 상태 관리
│ └── userStore.js
├── types/ # 타입 정의 (TypeScript 또는 JS용 인터페이스)
│ └── user.js
├── router/ # Vue Router 설정
│ └── index.js
├── App.vue # 루트 컴포넌트
└── main.js # 앱 엔트리포인트
[흐름 요약]
[UserCreatePage.vue]
↓ 폼 입력
[UserForm.vue]
↓ emit("submit", data)
[Pinia userStore.js]
→ userApi.createUser(data)
→ 성공 시 상태 업데이트
비교
