[Day 21] Reactive Programming - Spring WebFlux(Hello World) Part 1

前言

经过了二十一天,进入到了实作的部分,接下来就会建置一系列实际连线至DB并透过Restful沟通的Reactive的服务。这篇主要是透过Restful沟通,後续会接着介绍连线至DB的部分。
大致上的流程是:

  1. 启动透过Run main 启动Netty Server
  2. 透过WebClient 发出Request
  3. Router 接受到Request ,转向到Handler
  4. Handler 处理後回传。

实作

1.Spring Initializr
产生Reactive Spring 专案,主要就是选择Spring Reactive Web,就会包含WebFluxNetty
https://ithelp.ithome.com.tw/upload/images/20211005/20141418D0lH5v3MbX.png

  1. VO & GreetingHandler
    Greeting.java单纯的值物件。
@Data 
@NoArgsConstructor 
@AllArgsConstructor 
public class Greeting { 
  private String message; 
}

GreetingHandler.java Handler 搭配下面介绍的Router类似於Controller,可以看到是一个functional的写法。

import com.robert.webfluxguide.vo.Greeting; 
import org.springframework.http.MediaType; 
import org.springframework.stereotype.Component; 
import org.springframework.web.reactive.function.BodyInserters; 
import org.springframework.web.reactive.function.server.ServerRequest; 
import org.springframework.web.reactive.function.server.ServerResponse; 
import reactor.core.publisher.Mono; 
@Component 
public class GreetingHandler { 
  public Mono<ServerResponse> hello(ServerRequest request) { 
    return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) 
        .body(BodyInserters.fromValue(new Greeting("Hello, Spring!"))); 
  } 
}

一样支援Spring Mvcannotation (不需要Router),效果会是一样的。

@RestController 
public class GreetingHandler { 
  @GetMapping("/hello") 
  public Mono<Greeting> hello() { 
    return Mono.just(new Greeting("Hello, Spring!")); 
  } 
//  public Mono<ServerResponse> hello(ServerRequest request) { 
//    return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) 
//        .body(BodyInserters.fromValue(new Greeting("Hello, Spring!"))); 
//  } 
}
  1. GreetingRouter.java 负责转导,在这边就是把路径/hello转给hanlder内的hello,跟以前写过前端的Router写法类似,感觉会把转导集中在Router内,相对於以前分散在各controller内可能会更好管理路径。
@Configuration(proxyBeanMethods = false) 
public class GreetingRouter { 
  @Bean 
  public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) { 
    return RouterFunctions 
        .route(GET("/hello").and(accept(MediaType.APPLICATION_JSON)), greetingHandler::hello); 
  } 
}
  1. GreetingClient.java 类似於之前的RestTemplate ,负责呼叫其他api,但WebClient同时支援阻断与非阻断式,在这边范例就是建立一个呼叫自己hello的api
import com.robert.webfluxguide.vo.Greeting; 
import org.springframework.http.MediaType; 
import org.springframework.stereotype.Component; 
import org.springframework.web.reactive.function.client.WebClient; 
import reactor.core.publisher.Mono; 
@Component 
public class GreetingClient { 
  private final WebClient client; 
  // Spring Boot auto-configures a `WebClient.Builder` instance with nice defaults and 
  // customizations. 
  // We can use it to create a dedicated `WebClient` for our component. 
  public GreetingClient(WebClient.Builder builder) { 
    this.client = builder.baseUrl("http://localhost:8080").build(); 
  } 
  public Mono<String> getMessage() { 
    return this.client 
        .get() 
        .uri("/hello") 
        .accept(MediaType.APPLICATION_JSON) 
        .retrieve() 
        .bodyToMono(Greeting.class) 
        .map(Greeting::getMessage); 
  } 
}
  1. WebFluxGuideApplication.java,启动服务器,并透过GreetingClient呼叫Api。补充一下避免有人跟我一开始看到这边,被前面太多陌生的内容影响,一看到GreetingClient 的取得是透过getBean而不是@Autowired,以为是WebFlux不支援@Autowired,其实是因为这边main方法是static,使用getBean会容易一些,透过constructor @Autowired一样是没问题的。
import com.robert.webfluxguide.client.GreetingClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class WebFluxGuideApplication {

 public static void main(String[] args) {
  ConfigurableApplicationContext context = SpringApplication.run(WebFluxGuideApplication.class, args);
  GreetingClient greetingClient = context.getBean(GreetingClient.class);
  // We need to block for the content here or the JVM might exit before the message is logged
  System.out.println(">> message = " + greetingClient.getMessage().block());
 }
}

成功画面
https://ithelp.ithome.com.tw/upload/images/20211005/20141418vUo0sIw2B9.png

结语

完成了一个单纯的服务,详细的介绍会在下一篇。

不知不觉也到了最後十篇了,reactive java可能对於台湾接受度还不高,可怜的点阅率,感谢三个追踪的人,让我觉得写的东西至少还是有人想看。

资料来源

<<:  食谱搜寻系统制作_中

>>:  [Day20] Vue 3 单元测试 (Unit Testing) - Form Elements Handling

Day06 X 图片最佳化

给你五秒钟思考一下,你在日常生活中还有在使用没有任何图片,包括小小 的 Icon 也没有的网站吗?...

沟通这回事:个人经验篇

前言 Hi,铁人赛第二天,跟大家聊聊沟通,预计会陆续写几篇相关的主题,今天来分享平时的观察。 在敏捷...

为你自己学 Laravel - Day 29 前端生态圈

嘿~~ 各位好,我是菜市场阿龙! Youtube 频道:https://www.youtube.co...

铁人赛 Day10-- PHP SQL基本语法(五) -- 帐密登入验证 & mysqli_query

前言 昨天知道了怎麽使用 SELECT 和 WHERE 之後,就要来实际做做看啦 (先附上整段程序码...

初学者跪着学JavaScript Day28 : 学迭代,学习不等待

一日客语:中文:报纸 客语:bo ziiˋ 最近很疑惑迭代物件和可迭代到底是什麽??於是查一下资料,...