Spring WebFlux 와 MySQL을 활용하여 가장 기본적인 CRUD를 만들어 볼 예정입니다.
Spring WebFlux란 Spring 진영의 비동기 프레임 워크 입니다.
Reactive Streams 의 Publiser 인터페이스의 구현체인 Mono 와 Flux를 사용하여 구현을 하게 됩니다.
여기서 Mono란 0 ~ 1의 데이터를 처리 할 수 있고, Flux는 0 ~ N 개의 데이터를 처리 할 수 있습니다.
의존성 추가
implementation "com.github.jasync-sql:jasync-r2dbc-mysql:2.2.4"
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
이 밖에도 롬복과 스프링 데브 툴을 추가 하여주었습니다.
application.yml
spring:
r2dbc:
url: r2dbc:mysql://127.0.0.1:3306/TestSchema
username: [db 유저]
password: [db 패스워드]
Controller.java
@RestController
@Slf4j
public class Controller {
private TestTableRepository testTablerepository;
Controller(TestTableRepository testTablerepository) {
this.testTablerepository = testTablerepository;
}
@GetMapping("/")
public Flux<TestTable> main() throws Exception {
return testTablerepository.findAll();
}
@GetMapping("/test1/{idx}")
public ResponseEntity<Mono<TestTable>> test1(@PathVariable("idx") int idx) throws Exception {
Mono<TestTable> test = testTablerepository.findById(idx);
return ResponseEntity.status(HttpStatus.OK).body(test);
}
@GetMapping("/test2")
public ResponseEntity<Flux<TestTable>> test2() throws Exception {
Flux<TestTable> test = testTablerepository.findAll().log();
Flux<TestTable> test2 = test.map(e -> {
log.info(Integer.toString(e.getIdx()));
e.setContents("변경된 내용");
return e;
}).log();
return ResponseEntity.status(HttpStatus.OK).body(test2);
}
@PostMapping("/insert")
public Mono<ResponseEntity<Boolean>> post(@RequestBody TestTable testTable) throws Exception {
return testTablerepository.save(testTable).map(data -> ResponseEntity.status(HttpStatus.CREATED).body(true))
.onErrorResume(error -> Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false)));
}
@PutMapping("/update/{idx}")
public Mono<ResponseEntity<Boolean>> put(@PathVariable("idx") int idx, @RequestBody TestTable testTable)
throws Exception {
Mono<TestTable> getData = testTablerepository.findById(idx);
Mono<ResponseEntity<Boolean>> update = getData.flatMap(data -> {
if (testTable.getContents() != null)
data.setContents(testTable.getContents());
return testTablerepository.save(data).map(innerData -> ResponseEntity.status(HttpStatus.OK).body(true))
.onErrorResume(
error -> Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false)));
}).switchIfEmpty(Mono.just(ResponseEntity.status(HttpStatus.NOT_FOUND).body(false)));
return update;
}
@DeleteMapping("/delete/{idx}")
public Mono<ResponseEntity<Boolean>> delete(@PathVariable("idx") int idx) throws Exception {
Mono<TestTable> getData = testTablerepository.findById(idx);
Mono<ResponseEntity<Boolean>> deleteData = getData.flatMap(data -> {
return testTablerepository.deleteById(idx).then(
Mono.just(ResponseEntity.status(HttpStatus.OK).body(true))
).onErrorReturn(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false));
}).defaultIfEmpty(ResponseEntity.status(HttpStatus.NOT_FOUND).body(false));
return deleteData;
}
}
subscribe(data-> System.out.println("성공"), error -> System.out.println("실패"))
위와 같은 방식으로도 에러를 잡을 수 있지만 이후 더 상세하게 다룰 수 없어 본문에 적혀있는 onErrorResume의 방식으로 진행 하였습니다.
또한 Mono와 Flux의 경우 return값이 void인 경우 map또는 flatMap이 호출이 되지 않기 때문에 switchIfEmpty 또는 defaultIfEmpty를 활용하여 예외 처리를 진행하여야 했습니다.
Error의 경우
- doOnError() : 예외가 발생했을 경우, 특정 행위를 실행시킬 경우 사용
- onErrorReturn : 예외가 발생했을 때 특정 값을 Return 함
- onErrorResume : 예외가 발생했을 때 다른 Flux형태로 Return 함
- onErrorContinue : 예외가 발생했을 때 멈추지 않고 해당 영역만 skip해서 동작함.
뒤에 log를 찍는 경우 상세하게 로그를 볼 수 있습니다.




각각의 api를 실행 시켜 보면 정상적으로 작동 하는 것을 알 수 있습니다.
map과 flapMap의 차이
flatMap의 경우는 새로운 비동기적인 함수를 리턴 할 때 사용 하고, map의 경우 단순한 요소를 변환하기 위해서 사용한다.
개인적으로 사용하면서 느낀점은 SpringWebFlux자체에서 사용하고 있는 메소드의 종류가 너무 많아서 사용하기 까다로웠던 것 같다. 비동기라서 어렵다기 보단 내가 원하는 로직을 구현 하기 위해서 필요한 메소드를 찾는 것이 가장 어려웠던 것 같다. 또한 에러를 상세하게
를 상세하게 컨트롤하기 좀 어려울 것 같다는 생각이 들었다.
'Java' 카테고리의 다른 글
LinkedList 와 List 선언 차이 (0) | 2024.09.11 |
---|---|
Spring Cloud GateWay API 인가 서버 구현 (0) | 2024.06.16 |
Spring Cloud Gateway 기본적인 사용 방법 (0) | 2024.06.12 |
자바 프로세스 메모리 증가 (0) | 2024.06.01 |
자바 멀티 스레드 프로그래밍 (0) | 2024.05.20 |