关于WebFlux
Spring在2017年下半年迎来了Webflux,Webflux的出现填补了Spring在响应式编程上的空白,在一些特殊的场景下Webflux体现出了不俗的性能。那到底Webflux和WebMVC有什么区别呢。具体webflux文档参考官网文档。集成教程参考Swagger2 WebFlux小试牛刀,这里就不在介绍如何集成,只解决一些使用中的问题。
Mono和Flux返回swagger不能正确识别的问题
写两个测试接口:
//同步写法
@GetMapping("/message")
public BaseResponse messageBaseResponse() {
return BaseResponse.ok(new ObjectMessage("hello world"));
}
//异步写法
@GetMapping("/reactive_message")
public Mono> reactiveMessageBaseResponse() {
return Mono.create(sink -> sink.success(BaseResponse.ok(new ObjectMessage("hello world"))));
}
同步写法在swagger显示
显示正常,返回解析也没问题。
异步写法在swagger显示
异步接口,response显示不正确。
查看model,类型正确,但是解析不正确。
问题分析
对比两个接口在swagger页面上的区别发现,同步异步在model的显示不同,那么替换掉异步model试试,只要将Mono<<>>去掉就和同步的model一样了。
源码分析
swagger源码中在ServiceModelToSwagger2MapperImpl的mapDocumentation方法将生产Swagger对象,Swagger包含了接口model值。
ServiceModelToSwagger2MapperImpl使用了@Component注解,由spring ioc管理了ServiceModelToSwagger2MapperImpl。既然由spring管理了这个bean那么事情简单了,使用Spring aop拦截mapDocumentation方法,将Swagger对象修改一下去掉Mono<<>>就可以了。
解决办法
写一个aop,环绕mapDocumentation方法,修改其返回值,将Mono<<>>去掉。
/**
* Classname ReactiveServiceModelToSwagger2MapperAop
* Description 修复Publisher的泛型变量mapping到swagger
* Date 2019/5/23 4:36 PM
* Created by Wang jun gang
*/
@Aspect
@Component
public class ReactiveServiceModelToSwagger2MapperAop {
@Pointcut("execution(* springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl.mapDocumentation(..))")
public void p() {
}
@Around("p()")
public Object around(ProceedingJoinPoint pdj) throws Throwable {
final Object proceed = pdj.proceed();
if (proceed instanceof Swagger) {
this.fixRef((Swagger) proceed);
}
return proceed;
}
@SuppressWarnings("deprecation")
private Swagger fixRef(Swagger swagger) {
swagger.getPaths().forEach((k, v) -> {
final Operation get = v.getGet();
if (Objects.nonNull(get)) {
get.getResponses().forEach((k2, v2) -> this.fixSchema(v2.getSchema()));
}
final Operation post = v.getPost();
if (Objects.nonNull(post)) {
post.getResponses().forEach((k2, v2) -> this.fixSchema(v2.getSchema()));
}
final Operation put = v.getPut();
if (Objects.nonNull(put))
put.getResponses().forEach((k2, v2) -> this.fixSchema(v2.getSchema()));
final Operation patch = v.getPatch();
if (Objects.nonNull(patch))
patch.getResponses().forEach((k2, v2) -> this.fixSchema(v2.getSchema()));
});
return swagger;
}
private void fixSchema(Property schema) {
if (schema instanceof RefProperty) {
final RefProperty refProperty = (RefProperty) schema;
if (refProperty.getSimpleRef().startsWith("Mono«")) {
final String replaced = refProperty.getSimpleRef()
.replaceFirst("Mono«", "")
.replaceAll("»$", "");
refProperty.set$ref("#/definitions/" + replaced);
} else if (refProperty.getSimpleRef().startsWith("Flux«")) {
final String replaced = refProperty.getSimpleRef()
.replaceFirst("Flux«", "")
.replaceAll("»$", "");
refProperty.set$ref("#/definitions/" + replaced);
} else {
refProperty.set$ref(refProperty.get$ref()
.replace("definitions/MonoOf", "definitions/")
.replace("definitions/FluxOf", "definitions/"));
}
}
}
}
结果和总结
结果
重启应用打开swagger页面查看接口,异步接口显示正常了。
总结
swagger大部分bean由spring 管理,所以可以使用spring的ioc和aop来修改swagger的默认实现。