Creating a Reactive RESTful Web Service Using Spring WebFlux, Spring Data, and MongoDB

综合编程 DZone (源链)

Creating a Reactive RESTful Web Service Using Spring WebFlux, Spring Data, and MongoDB

DZone’s Guide to

Creating a Reactive RESTful Web Service Using Spring WebFlux, Spring Data, and MongoDB

Learn how to create a reactive RESTful web service step-by-step in this tutorial for Spring WebFlux, Spring Data, and MongoDB.

Ashish Sarin

Dec. 30, 17 ·
Integration Zone

Free Resource

Join the DZone community and get the full member experience.

The Integration Zone is brought to you in partnership with Cloud Elements . What’s below the surface of an API integration? Download The Definitive Guide to API Integrations to start building an API strategy.

This article is based on the book Getting Started With Spring Framework, 4th Edition . The source code for this article can be found in the ch19-reactor3-webservice project ( http://bit.ly/2zTuD0Y ). To run the project, deploy the ch19-reactor3-webservice project on Tomcat 9 and execute the ReactiveWebClient ‘s main method (located in the src/test/java folder).

To create a reactive RESTful web service, you need to ensure that each layer (data access, service and web) of the web service are reactive in nature.

Developing the Data Access Layer Using Spring Data

As reactive database driver is available for MongoDB, you can use Spring Data (Kay release) to reactively interact with MongoDB database. The following listing shows the BankAccountReactorRepository (a Spring Data repository) that defines methods that return reactive types (defined by Reactor):

public interface BankAccountReactorRepository extends ReactiveMongoRepository, BankAccountReactorRepositoryCustom {
    Mono countByBalance(int balance);
    Flux findByBalance(int balance);
    .....
}

NOTE– Instead of returning reactive types ( Flux and Mono ) from the repository methods, you can return reactive types defined by RxJava 2.

Configure Spring Data MongoDB

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());
    }
}

The @EnableReactiveMongoRepositories annotation enables the use of reactive MongoDB repositories. The basePackages attribute specifies the packages to scan for reactive MongoDB repositories.

The @Bean -annotated mongoDbFactory method creates and returns an instance of SimpleReactiveMongoDatabaseFactory . SimpleReactiveMongoDatabaseFactory ’s constructor accepts an instance of MongoClient and the name of the database (which is the test in our case).

The @Bean -annotated reactiveMongoTemplate method configures an instance of Spring Data MongoDB’s ReactiveMongoTemplate that is used by repositories for performing reactive operations on MongoDB.

Developing the Service Layer

As we don’t want the methods in the service layer to block, the service methods return reactive types. The following listing shows BankAccountService interface that defines service methods:

public interface BankAccountService {
    Mono saveBankAccount(BankAccountDetails bankAccountDetails);
    Flux findByBalance(int balance);
    Mono addFixedDeposit(String bankAccountId, int amount);
    .....
}

The following listing shows the BankAccountServiceImpl class that implements the BankAccountService interface:

@Service
public class BankAccountServiceImpl implements BankAccountService {
    @Autowired
    private BankAccountReactorRepository bankAccountRepository;
    .....
    @Override
    public Mono countByBalance(int balance) {
        return bankAccountRepository.countByBalance(balance);
    }

    @Override
    public Flux findByBalance(int balance) {
        return bankAccountRepository.findByBalance(balance);
    }
    .....
}

The countByBalance and findByBalance methods invoke the corresponding methods defined in the BankAccountReactorRepository .

Developing the Web Layer Using Spring WebFlux

Spring WebFlux module (introduced in Spring 5) supports developing reactive web applications and RESTful web services. As in the case of Spring Web MVC, you can use @Controller , @GetMapping , and so on, annotations to write reactive web controllers.

The following listing shows the BankAccountController class (a reactive web controller) that calls BankAccountService ’s methods:

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 countByBalance(@PathVariable("balance") int balance) {
        return bankAccountService.countByBalance(balance);
    }

    @GetMapping("/findByBalance/{balance}")
    public Flux findByBalance(@PathVariable("balance") int balance) {
        return bankAccountService.findByBalance(balance);
    }
    .....
}

Configure Spring WebFlux

The following listing shows the WebConfig class that configures WebFlux:

import org.springframework.web.reactive.config.EnableWebFlux;
.....
@EnableWebFlux
@Configuration
@ComponentScan(basePackages = "sample.spring.chapter19.bankapp.controller")
public class WebConfig { }

In the above listing, @EnableWebFlux annotation configures WebFlux for the project. @ComponentScan specifies the packages that contain the classes specific to the web layer. As controllers are defined in the sample.spring.chapter19.bankapp.controller package, it is specified as the value of basePackages attribute of @ComponentScan annotation.

Configuring the ServletContext

You can programmatically configure the ServletContext of a WebFlux-based web application (or RESTful web service) by using Spring’s AbstractAnnotationConfigDispatcherHandlerInitializer class, as shown in the following listing:

import .....web.reactive.support.AbstractAnnotationConfigDispatcherHandlerInitializer;
.....
public class BankAppInitializer extends
         AbstractAnnotationConfigDispatcherHandlerInitializer {
    @Override
    protected Class[] getConfigClasses() {
        return new Class[] { WebConfig.class,
             DatabaseConfig.class, BankAccountServiceImpl.class };
    }
}

getConfigClasses method returns @Configuration (or @Component ) classes that we want to register with the application context. WebConfig.class registers beans in the web layer and DatabaseConfig.class registers beans in the data access layer.

Testing the Reactive RESTful Web Service

Spring’s WebClient class (unlike RestTemplate ) allows you to reactively interact with a reactive RESTful web service. The following listing shows the ReactiveWebClient class that accesses methods defined by BankAccountController :

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 ’s create method creates an instance of WebClient with base URL, host, and port information. As ch19-reactor3-webservice is deployed locally on port 8080 and the BankAccountController is mapped to the /bankaccount request path, the following URL is passed to the create the method http://localhost:8080/ch19-reactor3-webservice/bankaccount .

The retrieve method sends the HTTP request and retrieves the response body.

The bodyToFlux method extracts the response body to a Flux . As BankAccountController ’s findByBalance method returns Flux type, the bodyToFlux ( BankAccountDetails.class ) method is called to convert the response body to Flux .

Your API is not enough. Learn why (and how) leading SaaS providers are turning their products into platforms with API integration in the ebook, Build Platforms, Not Products from Cloud Elements.

DZone责编内容来自:DZone (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » Creating a Reactive RESTful Web Service Using Spring WebFlux, Spring Data, and MongoDB

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录