Spring Boot 애플리케이션 기본 구조
- 토이 프로젝트를 진행하며 여러 오픈 소스를 접하게 되었다.
몇 년 전 개발했을 때와는 달리, 현재는 도메인 주도 설계(DDD)와 관련된 구조와 패턴이 일반적인 것 같다.
이를 이해하고 익숙해지기 위해 내용을 정리해보기로 한다.
1. 도메인(Domain)
- 애플리케이션이 해결하고자 하는 문제 영역 또는 비즈니스 로직의 집합이다.
- 도메인은 비즈니스 규칙, 정책, 엔티티, 값 객체 등을 포함한다.
- 역할: 도메인은 애플리케이션이 다루는 비즈니스 문제와 요구사항을 모델링한다.
2. 엔티티(Entity)
데이터베이스의 테이블과 매핑되는 객체이다.
고유 식별자를 가지며, 데이터의 상태와 비즈니스 로직을 포함할 수 있다.
직접 외부에서 수정되지 않고, 도메인 서비스나 도메인 모델을 통해 수정된다.
@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // 엔티티의 비즈니스 로직 예시 public void changeEmail(String newEmail) { this.email = newEmail; } // 엔티티의 정적 팩토리 메서드 public static User of(String name, String email) { User user = new User(); user.setName(name); user.setEmail(email); return user; } // getters and setters }
3. DTO(Data Transfer Object)
데이터 전송을 위한 객체로, 주로 클라이언트와 서버 간의 데이터 교환을 위해 사용한다.
특징: 데이터베이스와의 직접적인 연관이 없으며, 주로 컨트롤러에서 사용된다.
용도: 요청(Request) 데이터를 받거나 응답(Response) 데이터를 반환할 때 사용된다.
public class UserRequest { private String username; private String password; private String email; // getters and setters // of() 메서드: 입력 값을 받아 새로운 DTO 객체 생성 public static UserRequest of(String username, String password, String email) { UserRequest request = new UserRequest(); request.setUsername(username); request.setPassword(password); request.setEmail(email); return request; } } public class UserResponse { private String username; private String email; // getters and setters // fromEntity() 메서드: 엔티티 객체를 DTO 객체로 변환 public static UserResponse fromEntity(User user) { UserResponse response = new UserResponse(); response.setUsername(user.getUsername()); response.setEmail(user.getEmail()); return response; } }
4. DAO(Data Access Object)
- 데이터베이스에 접근하는 객체로, 주로 데이터베이스 CRUD(Create, Read, Update, Delete) 작업을 수행한다.
- 특징: 데이터베이스와의 상호작용을 추상화하여 데이터 액세스 로직을 분리합니다.
- 용도: JPA에서는 보통 Repository 인터페이스로 구현된다.
import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); }
5. Controller와 Service
Controller: 클라이언트 요청을 받아 서비스로 전달하고, 서비스에서 처리된 결과를 반환한다.
@RestController @RequestMapping("/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping public ResponseEntity<UserResponse> createUser(@RequestBody UserRequest request) { UserResponse response = userService.createUser(request); return new ResponseEntity<>(response, HttpStatus.CREATED); } @PutMapping("/{id}/email") public ResponseEntity<UserResponse> changeUserEmail(@PathVariable Long id, @RequestBody String newEmail) { UserResponse response = userService.changeUserEmail(id, newEmail); return new ResponseEntity<>(response, HttpStatus.OK); } @GetMapping("/{username}") public ResponseEntity<UserResponse> getUserByUsername(@PathVariable String username) { UserResponse response = userService.findUserByUsername(username); return new ResponseEntity<>(response, HttpStatus.OK); } }
Service: 비즈니스 로직을 처리하고, 데이터베이스와 상호작용하여 결과를 반환한다.
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public UserResponse createUser(UserRequest request) { User user = User.of(request.getUsername(), request.getPassword(), request.getEmail()); userRepository.save(user); return UserResponse.fromEntity(user); } public UserResponse changeUserEmail(Long userId, String newEmail) { User user = userRepository.findById(userId) .orElseThrow(() -> new IllegalArgumentException("User not found")); // 엔티티의 비즈니스 로직 호출 user.changeEmail(newEmail); userRepository.save(user); return UserResponse.fromEntity(user); } public UserResponse findUserByUsername(String username) { User user = userRepository.findByUsername(username); return UserResponse.fromEntity(user); } }
'Knowledge > Interview' 카테고리의 다른 글
HTTP 응답 코드 (0) | 2024.08.14 |
---|---|
디자인패턴(Design Pattern) (0) | 2024.08.14 |
정적 메서드(Static Method) (0) | 2024.08.14 |