zoukankan      html  css  js  c++  java
  • 【转】Building a Reactive RESTful Web Service

    【From】https://spring.io/guides/gs/reactive-rest-service/

    Building a Reactive RESTful Web Service —— 用 Spring WebFlux 构建reactive restful web服务

    本文转自以上Pivotal公司原文,简要概括翻译。

    使用spring framework 5 里面的webflux来构建一个最基本的restful web服务。本人实测使用环境是JDK1.8,springboot 2.2.1.RELEASE,gradle 5.2.1,IntelliJ IDEA 2019。

    一、创建项目

    在IDEA里创建一个新的gradle项目,例如取名“webflux_greeting”。在IDEA中建好项目会自己构建这个空项目,然后一直显示“configuring build...”,应该是一直连不了maven的官方仓库的问题,我直接关了。下面修改完build.gradle之后加上阿里云的maven仓库,再构建就好。

    二、配置build.gradle

    使用以下内容替换自动生成的build.gradle文件,buildscript里面的仓库信息是给gradle下载自己的依赖用的,buildscript后面的repositories才是项目构建时查找依赖的仓库地址,两个都加上阿里云仓库作为优先选择。

    buildscript {
        ext {
            springBootVersion = '2.2.1.RELEASE'
        }
        repositories {
    maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } mavenCentral() } dependencies { classpath(
    "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' bootJar { baseName = 'gs-reactive-rest-service' version = '0.1.0' } sourceCompatibility = 1.8 repositories {
    maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } mavenCentral() } dependencies { compile(
    'org.springframework.boot:spring-boot-starter-webflux') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('io.projectreactor:reactor-test') }

    Spring Boot gradle 插件提供了以下好处:

    a、会自动收集所有需要的jar,打包成一个uber-jar,即集成所有依赖包。

    b、自动识别所有 “public static void main()” 方法,并标记成可执行类。

    c、自动解决项目中和springboot的引用相关的版本依赖和冲突,你也可以手动指定依赖版本。

    三、编写WebFlux Handler

    在IDEA的项目名上右键,选择添加目录,然后会弹出快捷方式。选择创建“src/main/java”目录,再在目录下添加包“hello”,然后创建一个文件 GreetingHandler.java:

    package hello;
    
    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.TEXT_PLAIN)
          .body(BodyInserters.fromValue("Hello, Spring!"));
      }
    }

    四、编写router

    类似的方式,在hello包中添加新class GreetingRouter:

    package hello;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.server.RequestPredicates;
    import org.springframework.web.reactive.function.server.RouterFunction;
    import org.springframework.web.reactive.function.server.RouterFunctions;
    import org.springframework.web.reactive.function.server.ServerResponse;
    
    @Configuration
    public class GreetingRouter {
    
        @Bean
        public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) {
            return RouterFunctions
                    .route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), greetingHandler::hello);
        }
    }

    五、编写client (可选)

    类似的方式,在hello包中添加新class GreetingWebClient。这个客户端既可以访问reactive的restful endpoint,同样适用于访问non-reactive的阻塞restful服务。

    package hello;
    
    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.client.ClientResponse;
    import org.springframework.web.reactive.function.client.WebClient;
    
    import reactor.core.publisher.Mono;
    
    public class GreetingWebClient {
        private WebClient client = WebClient.create("http://localhost:8080");
    
        private Mono<ClientResponse> result = client.get()
                .uri("/hello")
                .accept(MediaType.TEXT_PLAIN)
                .exchange();
    
        public String getResult() {
            return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
        }
    }

    六、添加springboot主类

    类似的方式,在hello包中添加新class Application。此“@SpringBootApplication”的注解等效于 @Configuration + @EnableAutoConfiguration + @ComponentScan。

    package hello;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
    
            GreetingWebClient gwc = new GreetingWebClient();
            System.out.println(gwc.getResult());
        }
    }

    七、构建项目

    此时,执行gradle的build任务,项目会编译并运行,控制台会输出 >> result = Hello, Spring!,这是上面所写的客户端访问所得的结果。 如果从浏览器访问本地地址 http://localhost:8080/hello,同样可以得到 “Hello, Spring!” 的结果。

    在项目路径下会生成build/libs目录,里面有打包好的用bootJar里设置好的名字和版本所生成的uber-jar “gs-reactive-rest-service-0.1.0.jar”,可以用 java -jar gs-reactive-rest-service-0.1.0.jar 来直接启动。

    八、测试类

    创建测试类 GreetingRouterTest.java :

    package hello;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.reactive.server.WebTestClient;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    @RunWith(SpringRunner.class)
    //  We create a `@SpringBootTest`, starting an actual server on a `RANDOM_PORT`
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class GreetingRouterTest {
    
      // Spring Boot will create a `WebTestClient` for you,
      // already configure and ready to issue requests against "localhost:RANDOM_PORT"
      @Autowired
      private WebTestClient webTestClient;
    
      @Test
      public void testHello() {
        webTestClient
          // Create a GET request to test an endpoint
          .get().uri("/hello")
          .accept(MediaType.TEXT_PLAIN)
          .exchange()
          // and use the dedicated DSL to test assertions against the response
          .expectStatus().isOk()
          .expectBody(String.class).isEqualTo("Hello, Spring!");
      }
    }
  • 相关阅读:
    是否可以从一个静态(static)方法内部发出对非静态 (non-static)方法的调用?
    是否可以继承 String 类?
    如何实现字符串的反转及替换?
    String s = new String(“xyz”);创建了几个字符串对象?
    Serial 与 Parallel GC 之间的不同之处?
    SVG是什么?
    阐述静态变量和实例变量的区别?
    Java 中 ++ 操作符是线程安全的吗?
    什么是 REST / RESTful 以及它的用途是什么?
    WebSQL是HTML 5规范的一部分吗?
  • 原文地址:https://www.cnblogs.com/pekkle/p/12240100.html
Copyright © 2011-2022 走看看