Spring Boot 기반으로 WebFlux, CRUD API 를 개발하기 위한 기록을 남기도록 한다.
본격적인 프로젝트를 시작하면서 Spring Boot의 기본적인 WebFlux 아키텍쳐와 흐름에 대해 알아보고 API 를 구현 해보기로 한다.
1. 아키텍처 확인
기본적인 API 를 호출 했을때 요청에서 응답까지 구성할 Spring Boot 내부의 흐름을 따라가 보기로 한다.
2. 구성 및 설정
1) 디렉토리 구성
MVC 모델과 Reactor 모델은 개념상 큰 차이가 있지만 프로젝트에서 사용하던 MVC 기본 디렉토리 구조나 파일은 큰 차이가 없다. 설명이 부족한 개념은 MVC 모델 API를 작성하면서 정리한 이전글 을 참고 하도록 한다.
2) build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'io.netty:netty-resolver-dns-native-macos:4.1.95.Final:osx-aarch_64'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.mariadb:r2dbc-mariadb:1.1.3'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
tasks.named('test') {
useJUnitPlatform()
}
3) application.properties
spring.r2dbc.url=r2dbc:mariadb://localhost:3306/spring_test
spring.r2dbc.username=root
spring.r2dbc.password=root
spring.r2dbc.pool.enabled=true
spring.r2dbc.pool.initial-size=50
spring.r2dbc.pool.max-size=50
4) schema.sql
3. Member API 만들기
디렉토리 구조와 아키텍쳐에 맞는 기능들을 구성하며 사용자를 추가하는 API 를 만들어 보고자 한다.
1) 공통, Api Response 작성
API 응답시 일관된 결과값을 주기 위해서 common 에 ApiResponse 라는 이름으로 클래스를 하나 작성했다.
2) 공통, RestController Advice 작성
API 응답시 일관된 에러 메시지 처리를 위해서 common 에 ApiException 라는 이름으로 클래스를 하나 작성했다.
이 클래스에서는 SpringBoot 에서 전역적으로 예외를 처리하기 위해 @RestControllerAdvice 를 사용했다. 이 어노테이션을 사용하면 예외가 발생했을 때 적절한 메시지나 객체를 리턴할 수 있다.
3) Entity 작성
Entity 는 데이터베이스의 테이블을 나타내는 자바 클래스를 의미하며 다음과 같은 특징을 가지고 있음.
- @Entity 어노테이션
: JPA가 해당 클래스를 엔티티로 인식하게 하기 위해, 클래스 선언 위에 @Entity 어노테이션이 붙어야 한다. - 식별자 필드
: 각 엔티티 인스턴스를 유일하게 식별할 수 있는 식별자 필드가 필요한데 @Id 어노테이션으로 지정한다. - @Table 어노테이션
: 데이터베이스의 테이블 이름과 엔티티 이름이 다른 경우, @Table 어노테이션으로 테이블 이름을 지정할 수 있다. - @Column 어노테이션
: 테이블의 컬럼(column)과 엔티티의 속성(property)이 다른 경우, @Column 어노테이션으로 컬럼 이름을 지정할 수 있으며 컬럼의 길이, 널(null) 허용 여부, 유니크(unique) 여부 등도 지정할 수 있다.
4) DTO 작성
DTO(Data Transfer Object)란 계층간 데이터 교환을 위해 사용하는 객체이며 아래에서는 Member 에 대한 DTO 를 Inner Class 로 작성 해보았다.
5) Repository 작성
ReactiveCrudRepository 인터페이스는 스프링데이터에서 Reactive Stream 을 기반으로 하는 프로젝트 리액터의 타입들을 사용한다.
이 인터페이스를 상속 받아서 @Query 어노테이션으로 직접 쿼리를 정의하도록 새로운 함수를 추가했다.
6) Mapper 작성
특정 DTO 를 Entity 로 변경하거나 그 반대로 변경해야 할 상황이 있어서 따로 mapper 클래스를 작성했다.
7) Service 작성
Service 클래스는 @Service 어노테이션을 붙여서 스프링 컨테이너에 빈으로 등록하고 Controller 클래스와 Repository 클래스와 협력하여 웹 요청을 처리하고 데이터베이스와의 작업을 수행한다.
8) Controller 작성