본문 바로가기

Knowledge/Interview

Spring Boot 애플리케이션 기본 구조

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