Java编程网

分享 Java Web 开发相关知识

响应式Spring Boot Restful Web服务+ Google Books API

这篇文章的想法是该系列文章的第一篇,目的是演示如何编写Spring Boot Restful Web Service,该Web Service以被动方式访问远程API。我的意图是总是使用反应性范例来添加更多功能,例如缓存和数据库。在第一个例子中,我将描述如何从零开始到拥有功能正常的Web服务。

入门

我基于Spring教程“ 构建反应性RESTful Web服务”,并从头开始构建它,仅复制初始Gradle构建文件。项目结构如下图所示。

《响应式Spring Boot Restful Web服务+ Google Books API》

我创建了一个默认的Spring Boot Application类,唯一的区别是@ConponentScan批注指向应用程序的基本包。

package dev.alexladeira.springboot.reactive;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"dev.alexladeira.springboot.reactive"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

现在游戏开始了!

编写Router类

考虑到Router类,我放置了要公开的路由,这是一个简单的类,可在我公开的服务与我创建的处理请求的处理程序之间创建链接。

package dev.alexladeira.springboot.reactive.routes;

import dev.alexladeira.springboot.reactive.handlers.GoogleBooksHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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
@ComponentScan({"handlers"})
public class SearchRouter {
    @Bean
    public RouterFunction<ServerResponse> search(GoogleBooksHandler googleBooksHandler) {
        return RouterFunctions.route(RequestPredicates.GET("/search"), googleBooksHandler::search);
    }
}

到现在为止,我不需要使用Spring Reactor,这在我编写处理程序时已经改变。

编写Handler和The Service类

我创建了处理程序来处理请求,调用外部资源并创建响应。在这里,我从请求对象获得了搜索术语,并将其传递给服务,该服务负责返回有关一些书籍的信息,这些书籍具有我作为参数传递的单词,在本示例中,我使用的是Google Books API

package dev.alexladeira.springboot.reactive.handlers;

import dev.alexladeira.springboot.reactive.domain.google.GoogleBook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
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;
import dev.alexladeira.springboot.reactive.services.GoogleBooksService;

import java.util.ArrayList;
import java.util.List;

@Component
@ComponentScan({"services"})
public class GoogleBooksHandler {

    @Autowired
    private GoogleBooksService googleBooksService;

    public Mono<ServerResponse> search(ServerRequest request) {
        String searchTerm = request.queryParam("searchTerm").orElse(null);
        return searchTerm != null ? ServerResponse.ok().body(BodyInserters.fromPublisher(this.googleBooksService.getBooksBy(searchTerm).reduce(new ArrayList<GoogleBook>(), (list, googleBookServiceResponse) -> {
            list.addAll(googleBookServiceResponse.items);
            return list;
        }), List.class)) : ServerResponse.badRequest().build();
    }
}

搜索方法的工作就是从Google Books API中获取书籍,然后将其简化为GoogleBooks类型的列表(一个仅包含我希望服务返回的信息的java类),然后创建响应。如果服务收到并清空调用(没有任何参数),则将引发错误。

服务类如下,通过WebClient对象调用API

package dev.alexladeira.springboot.reactive.services;

import dev.alexladeira.springboot.reactive.domain.google.GoogleBookServiceResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

@Service
public class GoogleBooksService implements GenericService<GoogleBookServiceResponse> {
    private WebClient webClient = WebClient.builder().baseUrl("https://content.googleapis.com").build();

    @Override
    public Flux<GoogleBookServiceResponse> getBooksBy(String searchTerm) {
        return this.webClient.get().uri(uriBuilder -> uriBuilder
                .path("/books/v1/volumes")
                .queryParam("q", searchTerm)
                .queryParam("maxResults", MAX_RESULTS)
                .build()).retrieve().bodyToFlux(GoogleBookServiceResponse.class).timeout(TIMEOUT);
    }
}

该类扩展了GenericService,该类是为集中一些信息而创建的,这些信息将由我将来将创建的其他服务(常量MAX_RESULTS和TIMEOUT)使用。

结论…暂时

现在该启动服务器并查看结果了,将浏览器指向http:// localhost:8080,如果一切顺利,您将看到以下内容:

[{"volumeInfo":{"title":"Learning Spring Boot 2.0","authors":["Greg L. Turnquist"],"printType":"BOOK"}},{"volumeInfo":{"title":"Spring Boot 2.0 Projects","authors":["Mohamed Shazin Sadak
ath"],"printType":"BOOK"}},{"volumeInfo":{"title":"Spring: Microservices with Spring Boot","authors":["Ranga Rao Karanam"],"printType":"BOOK"}},{"volumeInfo":{"title":"Pro Spring Boot","
authors":["Felipe Gutierrez"],"printType":"BOOK"}},{"volumeInfo":{"title":"Mastering Spring Boot 2.0","authors":["Dinesh Rajput"],"printType":"BOOK"}}]

源代码位于github.com/alexladeira/gs-reactive-rest-service我将与其他人一起关注此帖子,始终尝试展示我在SpringBoot主题中正在学习的内容。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注