스프링 부트의 webflux의 rest api 예제 입니다.
샘플 코드
https://github.com/withccm/spring-webflux-study/tree/feature/webflux-mysql-sample
북 테이블
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bookname` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
);
1. 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
runtimeOnly 'mysql:mysql-connector-java'
implementation 'dev.miku:r2dbc-mysql'
2. spring data r2dbc bean 등록
@Configuration
@EnableTransactionManagement
@EnableR2dbcRepositories
public class DataSourceR2DBCConfig extends AbstractR2dbcConfiguration {
@Bean
@Primary
public ConnectionFactory connectionFactory() {
ConnectionFactoryOptions options = ConnectionFactoryOptions.builder()
.option(ConnectionFactoryOptions.DRIVER, "pool")
.option(ConnectionFactoryOptions.PROTOCOL, "mysql")
.option(ConnectionFactoryOptions.HOST, "localhost")
.option(ConnectionFactoryOptions.PORT, 3306)
.option(ConnectionFactoryOptions.DATABASE, "mytest")
.option(ConnectionFactoryOptions.USER, "github")
.option(ConnectionFactoryOptions.PASSWORD, "test1234")
.option(ConnectionFactoryOptions.CONNECT_TIMEOUT, Duration.ofMillis(3000))
.option(Option.valueOf("socketTimeout"), 3000)
.option(Option.valueOf("allowMultiQueries"), true)
.option(Option.valueOf("useSSL"), false)
.build();
ConnectionFactory connectionFactory = ConnectionFactories.get(options);
ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration
.builder(connectionFactory)
.build();
return new ConnectionPool(configuration);
}
@Bean
ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) {
return new R2dbcTransactionManager(connectionFactory);
}
@Bean
public R2dbcEntityTemplate r2dbcEntityTemplate(ConnectionFactory connectionFactory) {
R2dbcEntityTemplate r2dbcEntityTemplate = new R2dbcEntityTemplate(connectionFactory);
return r2dbcEntityTemplate;
}
}
3. 북 객체 정의
@Table(value = "book") // @Table 을 사용해야 bean으로 등록이됨
public class Book {
@Id
private Integer id;
private String bookname;
}
4. 레파지토리 정의
public interface BookRepository extends ReactiveCrudRepository<Book, Integer> {
}
5. Handler 정의
@Component
@Slf4j
@RequiredArgsConstructor
public class BookHandler {
private final BookRepository bookRepository;
public Mono<ServerResponse> postBooks(ServerRequest serverRequest) {
Mono<BookRequest> bookRequestMono = serverRequest.bodyToMono(BookRequest.class);
Mono<Book> bookMono = bookRequestMono
.map(bookRequest -> Book.builder().bookname(bookRequest.getBookname()).build())
.flatMap(book -> bookRepository.save(book));
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON).body(bookMono, Book.class);
}
public Mono<ServerResponse> getBooks(ServerRequest serverRequest) {
Flux<Book> bookFlux = bookRepository.findAll();
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON).body(bookFlux, Book.class);
}
public Mono<ServerResponse> getBook(ServerRequest serverRequest) {
String id = serverRequest.pathVariable("id");
Mono<Book> bookMono = bookRepository.findById(Integer.valueOf(id));
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON).body(bookMono, Book.class);
}
public Mono<ServerResponse> putBooks(ServerRequest serverRequest) {
String id = serverRequest.pathVariable("id");
Mono<BookRequest> bookRequestMono = serverRequest.bodyToMono(BookRequest.class);
Mono<Book> bookMono = bookRequestMono
.map(bookRequest -> Book.builder()
.id(Integer.valueOf(id))
.bookname(bookRequest.getBookname()).build())
.flatMap(book -> bookRepository.save(book));
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON).body(bookMono, Book.class);
}
}
6. Router 정의
@Configuration
public class BookRouter {
@Bean
public RouterFunction<ServerResponse> route(BookHandler bookHandler) {
return RouterFunctions
.route(RequestPredicates.POST("/books")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), bookHandler::postBooks)
.andRoute(RequestPredicates.GET("/books")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), bookHandler::getBooks)
.andRoute(RequestPredicates.GET("/books/{id}")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), bookHandler::getBook)
.andRoute(RequestPredicates.PUT("/books/{id}")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), bookHandler::putBooks);
}
}
댓글
댓글 쓰기