springwebflux-构建响应式rest服务入门

1 依赖

要明确的是在spring5之后,spring开始支持响应式开发,并且内部支持两个响应式编程框架

  • rxJava
  • project-reactor(默认)

在spring-boot2.0以后,使用的spring版本就是spring5,这里就是用springboot构建:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

2 基于注释构建Rest服务

这种开发方式和springMvc很类似。

这里就以开发开发一个简单的商品的crud操作的rest服务

sevice:

@Component
public class GoodsService {

    /**
     * 使用Map模拟数据层
     */
    private final Map<String, Goods> goodsMap = new ConcurrentHashMap<>();

    @PostConstruct
    public void initGoodsMap(){
        Goods goods = new Goods();
        goods.setId("1");
        goods.setName("小米手机");
        goodsMap.put(goods.getId(), goods);
    }

    @ApiOperation("查询所有商品")
    public Flux<Goods> getGoods() {
        return Flux.fromIterable(goodsMap.values());
    }

    @ApiOperation("根据id批量查询")
    public Flux<Goods> getProductsByIds(final Flux<String> ids) {
       return ids.flatMap(id-> Mono.justOrEmpty(this.goodsMap.get(id)));
    }

    @ApiOperation("根据id查询")
    public Mono<Goods> getProductsById(final String id) {
       return Mono.justOrEmpty(goodsMap.get(id));
    }

    @ApiOperation("保存或者更新商品")
    public Mono<Void> creatOrUpdate(final Mono<Goods> goodsMono){
        return goodsMono
                .doOnNext(goods -> goodsMap.put(goods.getId(),goods))
                .thenEmpty(Mono.empty());

    }
    @ApiOperation("根据id删除商品")
    public Mono<Goods> deleteById(final String id){
        return Mono.justOrEmpty(this.goodsMap.remove(id));
    }
}
  1. controller
@RestController
@RequestMapping("goods")
public class GoodsController {

    private final GoodsService goodsService;

    public GoodsController(GoodsService goodsService) {
        this.goodsService = goodsService;
    }


    @GetMapping
    public Flux<Goods> getGoods(){
        return goodsService.getGoods();
    }

    @GetMapping("/{id}")
    public Mono<Goods> getGoodById(@PathVariable("id") final String id){
        return goodsService.getProductsById(id);
    }

    @PostMapping()
    public Mono<Void> creatOrUpdate(@RequestBody final Mono<Goods> goods){
        return goodsService.creatOrUpdate(goods);
    }


    @DeleteMapping("/{id}")
    public Mono<Goods> deleteGoodById(@PathVariable("id") final String id){
        return goodsService.deleteById(id);
    }
}
  1. 模型
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Goods implements Serializable {

    @ApiModelProperty("商品id")
    private String id;

    @ApiModelProperty("商品编码")
    private String code;

    @ApiModelProperty("商品名字")
    private String name;

    @ApiModelProperty("商品价格")
    private Float price;
}
  1. 主启动
@SpringBootApplication
public class GoodsServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsServiceApplication.class, args);
    }
}

都是flux或者mono作为返回值,这个就是WebFlux应用的特征

关于这两个对象的介绍可参考:

3 基于函数式编程构建Rest服务

spring-webflux中,函数式编程模型的核心概念是Router Functions,对应的就是@Controller和@RequestMapping等springMVc的注解。

Router Functions提供了一套函数式API,用于创建Router和Handler对象。可以简单的认识Router对应@RequestMapping,
Handler对应@Controller

传入的Http请求交由Handler Function处理,Handler Function本质是一个接收ServerRequest并返回一个Mono<ServerResponse>的函数

3.1 函数式构建入门程序

  1. 使用Handler Function定义处理逻辑,类似于Controller注解
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

/**
 * @author wyaoyao
 * @date 2021/5/6 9:45
 * 实现HandlerFunction接口
 */
public class HelloWorldHandlerFunction implements HandlerFunction<ServerResponse> {
    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest) {
        return ServerResponse.ok().bodyValue("hello web flux");
    }
}

HandlerFunction接口内部只有一个方法需要实现。

  1. 使用Router定义路由规则,比如这里当访问"/hello-world",交给上面HelloWorldHandlerFunction 处理,类似于之前的RequestMapping注解
@Component
public class HelloWorldHandlerRouter {

    @Bean
    public HandlerFunction helloHandlerFunction(){
        return new HelloWorldHandlerFunction();
    }

    @Bean
    public RouterFunction<ServerResponse> responseRouterFunction(@Autowired HelloWorldHandlerFunction helloWorldHandlerFunction){
        return RouterFunctions.route()
                .GET("/hello-world",helloWorldHandlerFunction)
                .build();
    }
}

主启动类就省略了,很简单
启动测试,
在这里插入图片描述

3.2 基于函数式构建Rest服务

实现上面商品的crud操作

  1. 提供一个GoodsHandlerFunction
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import study.wyy.spring.reactor.goods.model.Goods;
import study.wyy.spring.reactor.goods.service.GoodsService;

/**
 * @author wyaoyao
 * @date 2021/5/6 10:51
 */
@Component
public class GoodsHandlerFunction {

    private final GoodsService goodsService;

    public GoodsHandlerFunction(GoodsService goodsService) {
        this.goodsService = goodsService;
    }

    public Mono<ServerResponse> getGoods(ServerRequest serverRequest){
       return ServerResponse.ok().body(this.goodsService.getGoods(),Goods.class);
    }
    public Mono<ServerResponse> getGoodById(ServerRequest serverRequest){
        String id = serverRequest.pathVariable("id");
        return ServerResponse.ok().body(goodsService.getProductsById(id),Goods.class);
    }

    public Mono<ServerResponse> creatOrUpdate(ServerRequest serverRequest){
        return ServerResponse.ok()
                .body(goodsService.creatOrUpdate(serverRequest.bodyToMono(Goods.class)),Void.class);
    }

    public Mono<ServerResponse> deleteGoodById(ServerRequest serverRequest){
        String id = serverRequest.pathVariable("id");
        return ServerResponse.ok().body(goodsService.deleteById(id),Goods.class);
    }
}
  1. 使用router定义endpoint
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

/**
 * @author wyaoyao
 * @date 2021/5/6 16:43
 */
@Configuration
public class GoodsRouter {

    @Bean
    public RouterFunction<ServerResponse> goodsHandlerFunctionRouter(@Autowired GoodsHandlerFunction handlerFunction) {
        return   route(GET("/"), handlerFunction::getGoods)
                .andRoute(GET("/{id}"), handlerFunction::getGoodById)
                .andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)),handlerFunction::creatOrUpdate)
                .andRoute(DELETE("/{id}"),handlerFunction::deleteGoodById);
    }
}
  1. 启动类省略

  2. 测试
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值