使用 Spring webFlux,SpringData 和 MongoDB 创建一个响应的 RESTful Web 服务
了解如何在本教程中为 Spring WebFlux,Spring Data 和 MongoDB 一步步创建一个响应式的 RESTful web 服务.
这篇文章的基础是从 Spring 框架开始 第四版. 本文的源代码可以在 ch19-tor3-webservice 项目中找到.(http://bit.ly/2zTuD0Y) 要运行这个项目, 可以在 Tomcat 9 上部署 ch19-reptor3-webservice 项目, 并执行 ReactiveWebClient 的主要方法(位于 src/test/java 文件夹中).
要创建一个响应的 RESTful web 服务, 您需要确保 web 服务的每个层 (数据访问, 服务和 web ) 在本质上都是响应的.
使用 Spring Data 开发数据访问层.
对于 MongoDB 来说, 可以使用动态数据库驱动程序, 可以使用 Spring Data (Kay release )来重新与 MongoDB 数据库交互. BankAccountReactorRepository (一个 Spring 数据存储库), 它定义了返回响应类型的方法(由反应器定义):
- public interface BankAccountReactorRepository extends ReactiveMongoRepository<BankAccountDetails, String>, BankAccountReactorRepositoryCustom {
- Mono<Long> countByBalance(int balance);
- Flux<BankAccountDetails> findByBalance(int balance);
- .....
- }
注意 - 从存储库方法返回反应类型( Flux 和 Mono ), 也可以返回由 RxJava 2 定义的反应类型.
MongoDB 配置 Spring Data
- import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
- import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
- import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
- import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
- .....
- @Configuration
- @EnableReactiveMongoRepositories(basePackages = "sample.spring.chapter19.bankapp.repository")
- public class DatabaseConfig {
- @Bean
- public MongoClient mongoClient() throws UnknownHostException {
- return MongoClients.create("mongodb://localhost");
- }
- public ReactiveMongoDatabaseFactory mongoDbFactory() .. {
- return new SimpleReactiveMongoDatabaseFactory(mongoClient(),
- "test");
- }
- @Bean
- public ReactiveMongoTemplate reactiveMongoTemplate() .. {
- return new ReactiveMongoTemplate(mongoDbFactory());
- }
- }
@EnableReactiveMongoRepositories 注释允许使用响应式 MongoDB 存储库. basepackage 属性指定要扫描无反应 MongoDB 存储库的包.
@Bean 注解的 mongoDbFactory 方法创建并返回 SimpleReactiveMongoDatabaseFactory 的一个实例. SimpleReactiveMongoDatabaseFactory 的构造函数接受 MongoClient 的实例和数据库的名称(在我们的例子中是测试).
@Bean 注释的 reactiveMongoTemplate 方法配置了一个 Spring Data MongoDB 的 reactiveMongoTemplate 实例, 该模板被存储库用于在 MongoDB 上执行被动操作.
开发服务层
由于我们不希望服务层中的方法阻塞, 所以服务方法返回响应的类型. 下面的清单显示了定义服务方法的 BankAccountService 接口:
- public interface BankAccountService {
- Mono<BankAccountDetails> saveBankAccount(BankAccountDetails bankAccountDetails);
- Flux<BankAccountDetails> findByBalance(int balance);
- Mono<Void> addFixedDeposit(String bankAccountId, int amount);
- .....
- }
以下清单显示实现 BankAccountService 接口的 BankAccountServiceImpl 类:
- @Service
- public class BankAccountServiceImpl implements BankAccountService {
- @Autowired
- private BankAccountReactorRepository bankAccountRepository;
- .....
- @Override
- public Mono<Long> countByBalance(int balance) {
- return bankAccountRepository.countByBalance(balance);
- }
- @Override
- public Flux<BankAccountDetails> findByBalance(int balance) {
- return bankAccountRepository.findByBalance(balance);
- }
- .....
- }
countByBalance 和 findByBalance 方法调用 BankAccountReactorRepository 中定义的相应方法.
使用 Spring WebFlux 开发 Web 层
Spring WebFlux 模块 (在 Spring 5 中引入) 支持开发响应式 web 应用程序和基于 RESTful web 服务. 就像 Spring Web MVC 的情况一样, 您可以使用
@Controller,@GetMapping 等来编写响应式的 Web 控制器.
下面的清单显示了 BankAccountController 类(一个响应式的 web 控制器), 它调用 BankAccountService 的方法:
- import reactor.core.publisher.Flux;
- import reactor.core.publisher.Mono;
- .....
- @RestController
- @RequestMapping("/bankaccount")
- public class BankAccountController {
- @Autowired
- private BankAccountService bankAccountService;
- .....
- @GetMapping("/countByBalance/{balance}")
- public Mono<Long> countByBalance(@PathVariable("balance") int balance) {
- return bankAccountService.countByBalance(balance);
- }
- @GetMapping("/findByBalance/{balance}")
- public Flux<BankAccountDetails> findByBalance(@PathVariable("balance") int balance) {
- return bankAccountService.findByBalance(balance);
- }
- .....
- }
配置 Spring WebFlux
下面的清单展示了配置 WebFlux 的 WebConfig 类
- import org.springframework.web.reactive.config.EnableWebFlux;
- .....
- @EnableWebFlux
- @Configuration
- @ComponentScan(basePackages = "sample.spring.chapter19.bankapp.controller")
- public class WebConfig { }
在上面的清单中,@EnableWebFlux 注解为项目配置 WebFlux .@ComponentScan 指定包含特定于 web 层的类的包. 作为控制器在 sample.spring.chapter19.bankapp 中定义. 控制器包, 它被指定为 @ComponentScan 注解的 basePackages 属性的值.
ServletContext 配置
您可以通过使用 Spring 的 AbstractAnnotationConfigDispatcherHandlerInitializer 类以编程方式配置基于 webflux 的 web 应用程序 (或 RESTful web 服务) 的 ServletContext, 如下所示:
- import .....web.reactive.support.AbstractAnnotationConfigDispatcherHandlerInitializer;
- .....
- public class BankAppInitializer extends
- AbstractAnnotationConfigDispatcherHandlerInitializer {
- @Override
- protected Class<?>[] getConfigClasses() {
- return new Class[] { WebConfig.class,
- DatabaseConfig.class, BankAccountServiceImpl.class };
- }
- }
getConfigClasses 方法返回我们想要在应用程序上下文中注册的 @Configuration(或 @Component) WebConfig.class 在 web 层注册 bean , DatabaseConfig.class 在数据访问层中注册 bean.
测试响应的 RESTful Web 服务
Spring 的 WebClient 类 (不像 RestTemplate) 允许您重新与一个响应式的 RESTful web 服务交互. 下面的清单显示了访问 BankAccountController 定义的方法的 ReactiveWebClient 类:
- import org.springframework.web.reactive.function.BodyInserters;
- import org.springframework.web.reactive.function.client.WebClient;
- .....
- public class ReactiveWebClient {
- private static Logger logger =
- LogManager.getLogger(ReactiveWebClient.class);
- private static WebClient webClient =
- WebClient.create("http://localhost:8080/
- ch19-reactor3-webservice/bankaccount");
- public static void main(String args[]) throws InterruptedException {
- // --find BankAccountDetails entities with balance 1000
- webClient.get().uri("/findByBalance/{balance}",
- 1000).accept(MediaType.APPLICATION_JSON)
- .retrieve()
- .bodyToFlux(BankAccountDetails.class)
- .subscribe(account -> logger.info("account with balance 1000 ->" + account.getAccountId()));
- }
- }
WebClient 的 create 方法创建了一个带有基本 URL, 主机和端口信息的 WebClient 实例. 在端口 8080 上本地部署了 ch19- response -webservice, BankAccountController 被映射到 / bankaccount 请求路径, 下面的 URL 被传递给创建方法 http://localhost:8080/ch19-tor3 -webservice/bankaccount.
retrieve 方法发送 HTTP 请求并检索响应主体
bodyToFlux 方法将响应体提取到 Flux. 当 BankAccountController 的 findByBalance 方法返回 Flux 类型时, 调用 bodyToFlux (BankAccountDetails.class)方法将响应主体转换为 Flux .
来源: https://juejin.im/entry/5afe3a16f265da0b886da661