我不打算解释什么是响应式编程,也不解释为什么要使用它。我希望你已经在其他地方了解过,如果没有,你可以使用Google去搜索它。在本文中,我将告诉您如何使用专门针对Spring BootRxJava的响应式编程。让我们开始吧。

1.预备知识

在你继续阅读之前,我希望你能理解如何使用Spring BootRxJava创建简单的REST API。如果不能,你可以在Baeldung上了解更多关于Spring Boot的知识,也可以在AndroidHive上了解更多关于RxJava的知识。它们很好地解释了这两种技术。

2.响应式REST API

构建一个只包含作者和书籍的简单CRUD响应式REST API。这些是端点:

[POST] /api/authors → 添加作者

[POST] /api/books → 添加书籍

[PUT] /api/books/{bookId} → 根据书籍id更新书籍信息

[GET] /api/books?limit={limit}&page={page} → 分页获取书籍列表

[GET] /api/book/{bookId} → 根据书籍id获取书籍详细信息

[DELETE] /api/book/{bookId} → 删除书籍

3.依赖

打开pom.xml并添加如下依赖项。

<dependencies>	
        <dependency>	
            <groupId>org.springframework.boot</groupId>	
            <artifactId>spring-boot-starter-web</artifactId>	
            <version>2.1.5.RELEASE</version>	
        </dependency>	
        <dependency>	
            <groupId>org.springframework.boot</groupId>	
            <artifactId>spring-boot-starter-data-jpa</artifactId>	
            <version>2.1.5.RELEASE</version>	
        </dependency>	
        <dependency>	
            <groupId>io.reactivex</groupId>	
            <artifactId>rxjava</artifactId>	
            <version>1.3.8</version>	
        </dependency>	
    <!--IMPORTANT!!! ADD THIS DEPENDENCY TO SOLVE HttpMediaNotAcceptableException-->	
        <dependency>	
            <groupId>io.reactivex</groupId>	
            <artifactId>rxjava-reactive-streams</artifactId>	
            <version>1.2.1</version>	
        </dependency>	
        <dependency>	
            <groupId>com.h2database</groupId>	
            <artifactId>h2</artifactId>	
            <version>1.4.199</version>	
        </dependency>	
        <dependency>	
            <groupId>org.projectlombok</groupId>	
            <artifactId>lombok</artifactId>	
            <optional>true</optional>	
            <version>1.18.8</version>	
        </dependency>	
        <dependency>	
            <groupId>org.springframework.boot</groupId>	
            <artifactId>spring-boot-starter-test</artifactId>	
            <version>2.1.5.RELEASE</version>	
            <scope>test</scope>	
        </dependency>	
        <dependency>	
            <groupId>org.mockito</groupId>	
            <artifactId>mockito-core</artifactId>	
            <version>2.25.0</version>	
            <scope>test</scope>	
        </dependency>	
    </dependencies>

备注:请记住,您必须添加第19-23行依赖项。如果您不添加该依赖项,那么每次您点击响应式API时都会得到HttpMediaNotAcceptableException。如您所见,我还添加了mockito作为单元测试中mock对象的依赖项。但是我将在另一篇文章中讨论单元测试。

4.服务层

对于服务层,返回值不仅仅是常规数据类型,而是我将它们封装在RxJavaSingle(单一)数据类型中。例如,下面的代码处理新书的添加。

@Override	
    public Single<String> addBook(AddBookRequest addBookRequest) {	
        return saveBookToRepository(addBookRequest);	
    }	
    private Single<String> saveBookToRepository(AddBookRequest addBookRequest) {	
        return Single.create(singleSubscriber -> {	
            Optional<Author> optionalAuthor = authorRepository.findById(addBookRequest.getAuthorId());	
            if (!optionalAuthor.isPresent())	
                singleSubscriber.onError(new EntityNotFoundException());	
            else {	
                String addedBookId = bookRepository.save(toBook(addBookRequest)).getId();	
                singleSubscriber.onSuccess(addedBookId);	
            }	
        });	
    }	
    private Book toBook(AddBookRequest addBookRequest) {	
        Book book = new Book();	
        BeanUtils.copyProperties(addBookRequest, book);	
        book.setId(UUID.randomUUID().toString());	
        book.setAuthor(Author.builder()	
                .id(addBookRequest.getAuthorId())	
                .build());	
        return book;	
    }

正如您所看到的,addBook方法的返回值是一个封装在RxJava中的字符串。

5.web层

@PostMapping(	
            consumes = MediaType.APPLICATION_JSON_VALUE,	
            produces = MediaType.APPLICATION_JSON_VALUE	
    )	
    public Single<ResponseEntity<BaseWebResponse>> addBook(@RequestBody AddBookWebRequest addBookWebRequest) {	
        return bookService.addBook(toAddBookRequest(addBookWebRequest))	
                .subscribeOn(Schedulers.io())	
                .map(s -> ResponseEntity.created(URI.create("/api/books/" + s)).body(BaseWebResponse.successNoData()));	
    }	
    private AddBookRequest toAddBookRequest(AddBookWebRequest addBookWebRequest) {	
        AddBookRequest addBookRequest = new AddBookRequest();	
        BeanUtils.copyProperties(addBookWebRequest, addBookRequest);	
        return addBookRequest;	
    }

在web层中,它只是将请求转发给相应的服务,如上所示,用于处理新书的添加。

6.结束

整个代码(+单元测试)可以在GitHub上找到。

 

推荐关注:锅外的大佬

由SpringForAll社区核心成员维护,专注于收集国外优质、前沿好文,带大家了解锅外大佬们都在搞啥,有什么独到观点!

使用Spring Boot和RxJava的构建响应式REST API_Spring Boot

 

留言交流不过瘾?添加微信:zyc_enjoy

根据指引加入各种主题讨论群

 

 

使用Spring Boot和RxJava的构建响应式REST API_Spring Boot_02

 

使用Spring Boot和RxJava的构建响应式REST API_Spring Boot_03