Spring 웹 애플리케이션 계층 구조
📌 계층 구조는 애플리케이션을 여러 층으로 나누어 각 계층의 책임을 분리하여 관리하는 구조입니다. 이렇게 계층화하면 유지보수성, 확장성, 테스트 용이성 등이 향상됩니다.
- 대표적인 계층 구조는 Controller, Service, Repository, Domain(또는 Entity) 계층으로 나누어져 있습니다.
- 네트워크 계층 구조와는 다른 개념입니다만, 계층구조라는 점에선 같습니다.
1. Controller 계층 (Web Layer)
- 책임: 클라이언트의 HTTP 요청을 받아서 적절한 비즈니스 로직( 실제 문제를 해결하는 코드 = 문제 해결책 )을 처리할 서비스 계층에 전달하고, 처리 결과를 반환하는 계층입니다.
- 역할:
- 클라이언트(웹 브라우저, 모바일 앱 등)로부터 들어오는 HTTP 요청을 처리합니다.
- Service 계층을 호출하여 비즈니스 로직을 수행합니다.
- 결과를 View에 전달하여 응답을 반환합니다. JSON 데이터를 반환할 수도 있습니다 (REST API).
- 주로 @Controller나 @RestController로 정의됩니다.
- 주요 어노테이션: @Controller, @RestController, @GetMapping, @PostMapping
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public String getUsers(Model model) {
List<User> users = userService.getAllUsers();
model.addAttribute("users", users);
return "userList"; // view name을 반환 (thymeleaf 템플릿에서 사용)
}
}
어노테이션(Annotation)
🐳 사람보다는 프레임워크나 컴퓨터가 코드를 이해하고 처리하는 데 도움을 주는 메타데이터입니다. 즉, 어노테이션은 단순한 주석이 아니라 코드의 동작 방식을 지정하는 기능을 부여하는 역할을 합니다.
일반적인 주석은 코드의 설명을 사람에게 제공하는 반면, 어노테이션은 Spring과 같은 프레임워크가 코드의 동작을 자동으로 처리하도록 도와주는 특별한 주석입니다. 예를 들어, @Controller 어노테이션은 Spring에게 "이 클래스는 웹 요청을 처리하는 컨트롤러"라고 알려줍니다. 이를 통해 Spring은 해당 클래스를 자동으로 관리하고 필요한 처리를 해줍니다
// 이 메서드는 사용자 정보를 반환합니다.
public User getUser() {
return userService.getUser();
}
@GetMapping("/users")
public List<User> getUsers() {
return userService.getAllUsers();
}
- 위의 주석에서는 아무일도 일어나지 않지만
- 밑의 @GetMapping 어노테이션은 Spring에게 "이 메서드는 GET 요청을 처리하고, /users 경로로 요청이 오면 실행되어야 한다"는 의미를 전달한다. Spring은 이 어노테이션을 보고 자동으로 이 메서드와 URL 경로를 연결해 준다.
- 즉, 어노테이션은 프로그래머가 제작한 코드가 스프링에게 호출을 보낼 때 둘사이의 중간 연락망의 역활을 한다.
+ 프레임워크는 소프트웨어 개발을 위한 템플릿이다. 엄연히 하나의 프로그램임으로 내가 만든 코드와 소통을 해야한다.
2. 서비스 (Service)
- 책임: 비즈니스 로직을 처리하는 계층 (실제로 일하는 노동자 = 해결사)입니다. Controller에서 전달받은 데이터를 처리하고, 레포지토리를 사용하여 데이터를 가져옵니다. 비즈니스 규칙을 적용하고 필요한 데이터를 처리한 후 반환합니다.
- 역할:
- 애플리케이션의 핵심 비즈니스 로직을 처리합니다.
- 여러 도메인 객체와의 연산을 통해 데이터를 처리합니다.
- Controller에서 요청을 받은 후 레포지토리를 통해 데이터를 조회하거나 업데이트합니다.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
3. 도메인 (Domain)
- 책임: 애플리케이션에서 처리할 비즈니스 데이터를 모델링 (구현 대상[문제] 정의)하는 계층입니다. 도메인 객체(예: User, Product)는 애플리케이션에서 다루는 실제 데이터를 나타내며, 그 데이터를 위한 필드와 메서드를 정의합니다.
- 도메인은 기획의 요구사항을 구현하고, 문제를 풀기 위해 설계된 소프트웨어 프로그램의 기능성을 정의하는 영역이라고 설명합니다.
- 역할:
- 비즈니스 데이터(중요정보)를 표현하는 클래스입니다.
- 주로 **엔티티(Entity)**로 불리며, 데이터베이스 테이블과 매핑되는 객체입니다.
- 서비스 계층에서 처리되는 데이터를 담고 있으며, 필요한 경우 **DTO (Data Transfer Object)**로 변환되기도 합니다.
- 간단히 말해서, 앱의 기능(사진기, 앨범 등), 회사의 비즈니스 로직(회원, 주문 등)을 구현 대상을 정의하는 파트라고 생각하면 편하다.
- 쿠팡의 창을 보면 화장품 - 립스틱, 아이브러쉬, 파운데이션 등의 선택창이 있다. 이 중 뭐가 도메인일까?
- 정답은 화장품, 립스틱, 아이브러쉬 등 전부 다이다.
- 왜냐 전부 구현이 필요한 대상이니까
- 현업에서는 특정 비지니스에 대한 전문 지식을 말한다. 금융쪽 기업이 스프링을 통해 서버를 구축하면 당연히 금융 관련 지식과 거래 기능 서버 관리 등의 특정 전문성을 포함하는 프로그래밍을 진행해야한다. 여기서 특정 전문 분야를 도메인이라 한다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters and setters
}
4. 레포지토리 (Repository)
- 책임: 데이터베이스와의 상호작용을 담당하는 계층입니다. 레포지토리는 JPA 또는 MongoDB와 같은 ORM(Object-Relational Mapping) 기술을 사용하여 데이터베이스와의 CRUD(Create, Read, Update, Delete) 작업을 처리합니다.
- 역할:
- 데이터베이스에서 데이터를 조회하고, 저장하며, 수정하거나 삭제하는 작업을 처리합니다.
- Spring Data JPA를 사용하면 Repository 인터페이스만 작성하여 자동으로 CRUD 기능을 구현할 수 있습니다.
- 서비스에서 요청한 데이터를 처리하고 반환합니다.
- 자바 서버라는 회사의 직원 중 데이터베이스 회사랑 소통할 때 필요한 중개인(번역가) 정도로 보면 된다.
- 번역가라는 표현이 정확한데 자바는 말 그대로 Java 언어로 보내면 레포지토리는 데이터베이스가 이해할 수 있도록 SQL문으로 변역해서 전달한다.
- 그런데 단순 번역기의 역활이라면 JPA나 MongoDB와 같이 왜 레포지토리의 종류가 다양한가?
- JPA는 관계형 데이터베이스를 MongoDB를 비관계형 데이터베이스를 번역한다 = 즉, 번역하는 언어가 다르다.
- 전문적으로 데이터 소스가 다양하다보니 각 데이터 소스에 맞는 레포지토리 구현이 필요했다.
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByName(String name);
Optional<User> findById(Long id);
}
5. 데이터베이스 (Database)
- 책임: 실제 데이터를 영구적으로 저장하는 계층입니다. 데이터베이스는 관계형(RDBMS) 또는 비관계형(NoSQL) 데이터베이스를 사용할 수 있습니다. 데이터베이스는 레포지토리에서 처리한 데이터를 영속적으로 저장하고 조회하는 역할을 합니다.
- 역할:
- 레포지토리를 통해 데이터에 접근하며, 데이터를 저장하고, 수정하며, 삭제할 수 있습니다.
- SQL 또는 NoSQL 쿼리를 통해 데이터를 관리합니다.
< 전체 계층 구조 예시 >
+-----------------------+ +------------------------+ +-------------------------+
| Controller | | Service | | Repository |
| (입구, 요청 처리) | --> | (비즈니스 로직 처리) | --> | (데이터베이스 CRUD) |
+-----------------------+ +------------------------+ +-------------------------+
| | |
v v v
+----------------------------+ +-------------------------+ +----------------------------+
| View (HTML, JSP) | | Domain (Entity) | | Database (SQL/NoSQL) |
| (결과 응답, UI 표시) | | (데이터 객체, 모델) | | (데이터 저장, 조회, 수정) |
+----------------------------+ +-------------------------+ +----------------------------+
각 계층의 흐름
- Controller는 클라이언트의 요청을 처리하고 Service로 전달합니다.
- Service는 비즈니스 로직을 처리하고, 필요한 데이터를 Repository에서 조회하거나 저장합니다.
- Repository는 데이터베이스와 상호작용하여 실제 데이터를 저장하거나 조회합니다.
- 데이터를 처리한 후, Service는 결과를 Controller로 반환하고, Controller는 이를 View (HTML 등)로 전달하여 사용자에게 응답합니다.
< 결론 >
컨트롤러 | 클라이언트와 서버 사이의 소통 중개인 |
서비스 | 문제 해결 일꾼 |
도메인 | 문제 정의 |
레포지토리 | DB와 서버간의 번역가 |
DB | 정보 저장 창고 |
'Back-End (Web) > Spring' 카테고리의 다른 글
[Spring] Spring MVC 패턴 (1) | 2024.12.14 |
---|---|
[Spring] Spring Boot (0) | 2024.12.10 |
[Spring] Spring Framework (2) | 2024.12.09 |
[Spring] 웹 개발의 흐름 (1) | 2024.12.05 |
[Spring] 스프링 웹 개발 기초 (0) | 2024.11.13 |