Spring WebFlux 简单业务代码及其Swagger文档
上一篇文章《Spring 5 中函数式webmvc开发中的swagger文档》中讲了如何给传统MVC开发模式中的RouterFunction增加swagger文档。这一篇讲一下如何给函数式WebFlux开发增加Swagger文档。
类似于MVC的webflux开发(基于
Controller实现)的swagger和web mvc方法一样,这里不讲了
依赖变更
既然要从webmvc改造成webflux,就需要换一下依赖。
首先需要增加webflux依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
接下来引入对应的doc依赖:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.5.12</version>
</dependency>
业务代码改造
我们首先把传统web中的代码改造成webFlux的。之前的Handler中的方法返回的都是org.springframework.web.reactive.function.server.ServerResponse:
public ServerResponse getStations(ServerRequest req) {
Long entId = Long.valueOf(path(req, "entId"));
List<StationBO> stationBoList = modelBuildingService.getStations(entId);
List<StationVO> stationVoList = TransformUtils.transformList(stationBoList, StationVO.class);
return body(PagedResult.success(stationVoList));
}
public ServerResponse getDeviceTypes(ServerRequest req) {
String stationId = path(req, "stationId");
List<DeviceTypeBO> deviceTypeBoList = modelBuildingService.getDeviceTypes(stationId);
List<DeviceTypeVO> deviceTypeVoList = TransformUtils.transformList(deviceTypeBoList, DeviceTypeVO.class);
return body(PagedResult.success(deviceTypeVoList));
}
// 其他方法
其中path()和body()定义在基类中:
public abstract class BaseHandler {
protected ServerResponse body(Object body) {
return ServerResponse.ok().body(body);
}
protected String path(ServerRequest req, String path) {
return req.pathVariable(path);
}
protected <T> T req(ServerRequest req, Class<T> clazz) {
try {
return req.body(clazz);
} catch (ServletException | IOException e) {
throw new RuntimeException(e);
}
}
}
Reactor中有两个实体,一个是Mono,表示单个对象,可以为空;一个是Flux,表示对象的集合(以序列的形式)。我们这里的接口都是返回的集合,所以应该改造成Flux。但是一来为了方便,二来我们的数据是一次性拿到,过程并不是响应式的,所以也无需用Flux,所以我们改造成Mono:
public Mono<ServerResponse> getStations(ServerRequest req) {
Long entId = Long.valueOf(path(req, "entId"));
List<StationBO> stationBoList = modelBuildingService.getStations(entId);
List<StationVO> stationVoList = TransformUtils.transformList(stationBoList, StationVO.class);
return body(PagedResult.success(stationVoList));
}
public Mono<ServerResponse> getDeviceTypes(ServerRequest req) {
String stationId = path(req, "stationId");
List<DeviceTypeBO> deviceTypeBoList = modelBuildingService.getDeviceTypes(stationId);
List<DeviceTypeVO> deviceTypeVoList = TransformUtils.transformList(deviceTypeBoList, DeviceTypeVO.class);
return body(PagedResult.success(deviceTypeVoList));
}
public Mono<ServerResponse> getRealTimeData(ServerRequest req) {
return req(req, RealTimeDataQueryVO.class)
.doOnNext(body -> {
log.info("请求参数{}", body);
})
.flatMap(body -> {
RealTimeDataResultBO resultBo = modelBuildingService.getRealTimeData(transferRealTimeDataQueryParam(body));
return body(Result.success(transferRealTimeDataResult(resultBo)));
});
}
可以看到,我们获取数据的方式不是响应式的,这样实际上并不能发挥出webFlux的能力。另外看到,Mono对象的生成都是通过基类来的,所以基类改造成了:
public abstract class BaseHandler {
protected Mono<ServerResponse> body(Object body) {
return ServerResponse.ok().bodyValue(body);
}
protected String path(ServerRequest req, String path) {
return req.pathVariable(path);
}
protected <T> Mono<T> req(ServerRequest req, Class<T> clazz) {
return req.bodyToMono(clazz);
}
}
这里用到了一些WebFlux的API,感兴趣的可以独自去了解,这里就先不介绍了。
RouterFunction的代码几乎不用改变,只要把引入的包从org.springframework.web.servlet.function改到org.springframework.web.reactive.function.server即可,之前的swagger就依然生效:
import com.enn.view.studio.web.handler.ModelBuildingHandler;
import com.enn.view.studio.web.vo.request.RealTimeDataQueryVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.springdoc.core.annotations.RouterOperation;
import org.springdoc.core.annotations.RouterOperations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
@Configuration
public class RoutingConfig {
@Bean
@RouterOperations({
@RouterOperation(
path = "/model/building/{entId}/stations",
beanClass = ModelBuildingHandler.class,
beanMethod = "getStations",
method = RequestMethod.GET,
operation = @Operation(
operationId = "getStations",
parameters = @Parameter(
name = "entId",
in = ParameterIn.PATH,
required = true,
description = "企业ID"
)
)
),
@RouterOperation(
path = "/model/building/devices/points/real-time-data",
beanClass = ModelBuildingHandler.class,
beanMethod = "getRealTimeData",
operation = @Operation(
operationId = "getRealTimeData",
requestBody = @RequestBody(
required = true,
description = "请求体",
content = @Content(
schema = @Schema(implementation = RealTimeDataQueryVO.class)
)
)
)
)
})
public RouterFunction<ServerResponse> getModelBuildingRouters(ModelBuildingHandler modelBuildingHandler) {
return RouterFunctions.nest(
path("/model/building"),
RouterFunctions.route(GET("/{entId}/stations"), modelBuildingHandler::getStations)
.andRoute(GET("/{stationId}/device-types"), modelBuildingHandler::getDeviceTypes)
.andRoute(POST("/devices/points/real-time-data"), modelBuildingHandler::getRealTimeData)
);
}
}
问题排查
如果增加了上面这个依赖,但是swagger页面打不开,或者swagger页面看不到
RouterFunction的文档(只能看到Controller的文档),通常都是因为依赖冲突。我本地的老项目引入上述依赖后调整了好几天依赖才成功显示出文档来。
- 不要依赖springdoc-openapi-ui
依赖了springdoc-openapi-webflux-ui就把springdoc-openapi-ui移除掉
<!--<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.12</version>
</dependency>-->
- 不要依赖springdoc-openapi-webmvc-core
即使同时使用了mvc和webflux,也不要再依赖springdoc-openapi-webmvc-core
<!--<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>1.5.12</version>
</dependency>-->
- 不要依赖spring-boot-starter-web
这个可能因项目而异。我这边需要删掉这个依赖才能启动
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
Spring WebFlux 简单业务代码及其Swagger文档的更多相关文章
- Spring Boot:整合Swagger文档
综合概述 spring-boot作为当前最为流行的Java web开发脚手架,越来越多的开发者选择用其来构建企业级的RESTFul API接口.这些接口不但会服务于传统的web端(b/s),也会服务于 ...
- 如何Spring Cloud Zuul作为网关的分布式系统中整合Swagger文档在同一个页面上
本文不涉及技术,只是单纯的一个小技巧. 阅读本文前,你需要对spring-cloud-zuul.spring-cloud-eureka.以及swagger的配置和使用有所了解. 如果你的系统也是用zu ...
- Spring Boot中使用Swagger2构建API文档
程序员都很希望别人能写技术文档,自己却很不愿意写文档.因为接口数量繁多,并且充满业务细节,写文档需要花大量的时间去处理格式排版,代码修改后还需要同步修改文档,经常因为项目时间紧等原因导致文档滞后于代码 ...
- Swagger文档转Word 文档
GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 原创作品,转载请注明出处:http://www.cnblogs.co ...
- Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档
0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...
- Swagger文档转Word
Swagger文档转Word 文档 GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 原创作品,转载请注明出处:h ...
- springboot成神之——swagger文档自动生成工具
本文讲解如何在spring-boot中使用swagger文档自动生成工具 目录结构 说明 依赖 SwaggerConfig 开启api界面 JSR 303注释信息 Swagger核心注释 User T ...
- Core + Vue 后台管理基础框架8——Swagger文档
1.前言 作为前后端分离的项目,或者说但凡涉及到对外服务的后端,一个自描述,跟代码实时同步的文档是极其重要的.说到这儿,想起了几年前在XX速运,每天写完代码,还要给APP团队更新文档的惨痛经历.给人家 ...
- 懒得写文档,swagger文档导出来不香吗
导航 前言 离线文档 1 保存为html 2 导出成pdf文档 3 导出成Word文档 参考 前言 早前笔者曾经写过一篇文章<研发团队,请管好你的API文档>.团队协作中,开发文档的重 ...
- 手动编写Swagger文档与部署指南
Swagger介绍 在Web开发中,后端开发者在完成接口开发后,需要给前端相应的接口使用说明,所以一般会写一份API文档.一般来说,有两种方式提供API接口文档,一种是利用插件在代码中自动生成,另一种 ...
随机推荐
- NSThread的start方法内部做了什么?
下面是NSThread start方法的汇编码: 1 1 1 ;Foundation`-[NSThread start]: 2 2 2 -> 0x7fff2594f47f <+0>: ...
- 鸿蒙stage模型
app.json5全局的配置文件 icon和label是应用列表的 module.json5模块配置文件 中有一个abilities其中的icon和label才是桌面的图标和名称 日志的话就是hail ...
- python小功能
django实现将linux目录和文件名列出来 def index(request): obj=models.USER.objects.all() fileroot = 'd:\machangwei' ...
- 图片GPS度分秒转换经纬度
图片位置信息转化经纬度 1 public static String strToLatOrLng(String str) { 2 int i = str.lastIndexOf("°&quo ...
- Asp-Net-Core开发笔记:使用原生的接口限流功能
前言 之前介绍过使用 AspNetCoreRateLimit 组件来实现接口限流 从 .Net7 开始,AspNetCore 开始内置限流组件,当时我们的项目还在 .Net6 所以只能用第三方的 现在 ...
- powershell 设置代理
$env:HTTP_PROXY="http://127.0.0.1:10809" $env:HTTPS_PROXY="http://127.0.0.1:10809&quo ...
- git 安装 和 git 客户端的使用
git clone 命令 # 查前当前登录用户的一些基本信息: # 查看当前登录的账号:git config user.name # 修改当前登录的账号为xcj:git config --global ...
- winform cefsharp chart.js 再winform上使用chart.js 绘制动态曲线
CefSharp 是一款开源的使用.net平台基于谷歌的 封装浏览器组件,可用于winform wpf . chart.js 也是一款开源的图表展示组件. 我所作的就是使用这两个组件再winform上 ...
- js 求任意两数之间的和
知识点:函数的传参,函数的返回值 函数的传参 函数的参数包括以下两种类型: 1.形参:在定义函数时,声明的参数变量仅在函数内部可见: 2.实参:在调用函数时,实际传入的值. 示例 我们在定义函数的时候 ...
- Qt内存回收机制
参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=16 Qt中内存的回收是自己完成的,实验中,我们自定义一个按钮,通过重写析构函数来观察现象. 新建 ...