강좌/Spring WebFlux

WebFlux HandlerFunction

여름나라겨울이야기 2018. 11. 20. 23:30
728x90

WebFlux 003

1. Handler Function 001: 건드려 보기

새로운 ReactiveWeb 프로젝트를 생성하고 아래와 같은 클래스를 추가하도록 하자.

package com.heaven.webflux02;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

@Slf4j
@Component
public class RouteFunction01 {
    @Bean
    RouterFunction route001() {
        HandlerFunction helloHandlerFunction = req -> {
            Mono result = Mono.just("Hello handlerFunction");
            Mono res = ok().body(result, String.class);
            return res;
        };

        return RouterFunctions.route(GET("/hello"), helloHandlerFunction);
    }
}

Hello handlerFunction

RouterFunction.java 를 찾아 route 메서드의 시그니처를 살펴보면 아래와 같다.

public static  RouterFunction route(
        RequestPredicate predicate, HandlerFunction handlerFunction) {

    return new DefaultRouterFunction<>(predicate, handlerFunction);
}

작성한 소스와 비교해서 살펴보자.

GET("/hello")

RequestPredicate predicate

helloHandlerFunction

HandlerFunction<T> handlerFunction

HandlerFunction 의 경우는 무척이나 간결하니 확인해 보자.

package org.springframework.web.reactive.function.server;

import reactor.core.publisher.Mono;

@FunctionalInterface
public interface HandlerFunction {
	Mono handle(ServerRequest request);
}

여기서 주목할 점은 소스를 파고 또 파고 들어가도 Servlet 은 없다는 것이다.
따라서 Servlet Engine(Tomcat…​) 도 필요없다.
단순히 Servlet 제약이 없는 ServerRequest, ServerResponse 만 있을 뿐이다.
그래서 단순 Web Server 인 Netty 에서도 웹 요청과 응답을 프로그래밍하여 주고 받을 수 있는 것이다.

지난 시간 Board 에 대한 Rest RouteHandler 를 구현해 보았었는데 거기에 HandlerFunction 을 적용해 보자.
별도의 Repository 를 구현하지 않았음으로 List 로 대신 작성했다.

package com.heaven.webflux02;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import static org.springframework.web.reactive.function.BodyExtractors.toMono;
import static org.springframework.web.reactive.function.server.RequestPredicates.;
import static org.springframework.web.reactive.function.server.ServerResponse.;

@Slf4j
@Component
public class RouteFunction02 {
    @Bean
    RouterFunction route() {
        BoardHandler boardHandler = new BoardHandler();

        return RouterFunctions.route(GET("/boards"), boardHandler.list)
                .andRoute(POST("/boards"), boardHandler.create)
                .andRoute(GET("/boards/{num}"), boardHandler.read)
                .andRoute(PUT("/boards/{num}"), boardHandler.update)
                .andRoute(DELETE("/boards/{num}"), boardHandler.delete);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Board {
    private int num;
    private String title;
    private String content;
}

class BoardHandler {
    // List.of 는 JAVA 9 이상
    List boards;
    int num;

    {
        boards = new ArrayList<>();

        for(num = 1; num < 11; num++) {
            boards.add(new Board(num, "제목 " + num, "내용 " + num));
        }
    }

    HandlerFunction list = req -> {
        Flux result = Flux.fromIterable(boards);
        Mono res = ok().body(result, Board.class);
        return res;
    };

    HandlerFunction create = req -> {
        URI uri = null;

        try {
            uri = new URI("/boards");
        } catch (java.net.URISyntaxException ex) {

        }

        return req.body(toMono(Board.class))
                .doOnNext(board -> {
                    board.setNum(num++);
                    boards.add(board);
                })
                .then(created(uri).build());
    };

    HandlerFunction read = req -> {
        int num = Integer.valueOf(req.pathVariable("num"));

        Board foundBoard = null;

        for(Board board : boards) {
            if(board.getNum() == num) {
                foundBoard = board;
                break;
            }
        }

        Mono res;

        if(foundBoard == null) {
            res = notFound().build();
        } else {
            res = ok().body(Mono.just(foundBoard), Board.class);
        }

        return res;
    };

    HandlerFunction update = req -> {
        int num = Integer.valueOf(req.pathVariable("num"));

        return req.bodyToMono(Board.class)
                .doOnNext(updatedBoard -> {
                    for(Board board : boards) {
                        if(board.getNum() == num) {
                            if(updatedBoard.getTitle() != null) board.setTitle(updatedBoard.getTitle());
                            if(updatedBoard.getContent() != null) board.setContent(updatedBoard.getTitle());
                            break;
                        }
                    }
                }).then(noContent().build());
    };

    HandlerFunction delete = req -> {
        int num = Integer.valueOf(req.pathVariable("num"));

        for(Board board : boards) {
            if(board.getNum() == num) {
                boards.remove(board);
                break;
            }
        }

        Mono res = noContent().build();

        return res;
    };
}

POST MAN 등을 통해 확인해 보자.

반응형

'강좌 > Spring WebFlux' 카테고리의 다른 글

WebClient & WebTestClient  (0) 2018.11.20
WebFlux RouteFunction  (0) 2018.11.05
WebFlux 첫 만남  (1) 2018.10.24
Spring WebFlux 동영상 강좌 대방출  (0) 2018.10.18