我不打算解釋什麼是響應式編程
,也不解釋爲何要使用它。我但願你已經在其餘地方瞭解過,若是沒有,你能夠使用Google
去搜索它。在本文中,我將告訴您如何使用專門針對Spring Boot
和RxJava
的響應式編程。讓咱們開始吧。html
在你繼續閱讀以前,我但願你能理解如何使用Spring Boot
和RxJava
建立簡單的REST API
。若是不能,你能夠在Baeldung
上了解更多關於Spring Boot
的知識,也能夠在AndroidHive
上了解更多關於RxJava
的知識。它們很好地解釋了這兩種技術。java
構建一個只包含做者和書籍的簡單CRUD
響應式REST API
。這些是端點:react
[POST] /api/authors → 添加做者git
[POST] /api/books → 添加書籍github
[PUT] /api/books/{bookId} → 根據書籍id更新書籍信息web
[GET] /api/books?limit={limit}&page={page} → 分頁獲取書籍列表spring
[GET] /api/book/{bookId} → 根據書籍id獲取書籍詳細信息編程
[DELETE] /api/book/{bookId} → 刪除書籍api
打開pom.xml並添加以下依賴項。app
<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對象的依賴項。可是我將在另外一篇文章中討論單元測試。
對於服務層,返回值不單單是常規數據類型,而是我將它們封裝在RxJava
的Single
(單一)數據類型中。例如,下面的代碼處理新書的添加。
@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
中的字符串。
@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層中,它只是將請求轉發給相應的服務,如上所示,用於處理新書的添加。
整個代碼(+單元測試)能夠在GitHub上找到。
原文:https://dzone.com/articles/reactive-rest-api-using-spring-boot-and-rxjava-1
譯者:李東
------
9月福利,關注公衆號後臺回覆:004,領取8月翻譯集錦!往期福利回覆:001,002, 003便可領取!