「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。
哈喽大家好,我是阿Q!
上文中我们谈到了springmvc
和swagger
对@Requestbody
的依赖问题,找到了问题所在,本文我们将围绕如何解决问题来详细给出答案!
解决问题
从以上分析可以得到结论,这里的根本问题是springmvc
中独立的参数解析器功能和swagger
功能上的冲突,一个要求不能加上@RequestBody
注解,一个要求必须加上@RequestBody
注解,所以解决方法上可以使用两种方式
- 从
springmvc
入手,想办法提高自定义参数解析器的优先级,只要自定义的参数解析器优先级比RequestResponseBodyMethodProcessor
高,则就可以在自定义的参数上加上@RequestBody
注解,swagger
功能自然而然就能正常了。 - 从
swagger
入手,想办法解决掉上面两部分对@RequestBody
的单独判定,不修改springmvc
相关功能也可以让swagger
功能正常。
考虑到修改springmvc
功能可能会对以后的版本升级造成较大影响,这里决定利用切面修改原有的swagger
对@RequestBody
的两个地方的行为,从而让swagger
功能正常。
请求类型判定的逻辑调整
首先,定义一个注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface NoSwaggerExpand {
/**
* default swagger expand disable
* @see OperationParameterReader#shouldExpand(springfox.documentation.service.ResolvedMethodParameter, com.fasterxml.classmate.ResolvedType)
*/
boolean expand() default false;
}
复制代码
将其加到入参上
@ApiOperation(value = "demo", notes = "demo")
@PostMapping(value = "/test")
public Result<boolean> test(@HdxDecrypt @NoSwaggerExpand @ApiParam(required = true) ReqDTO reqDTO) {
try {
log.info(ObjectMapperFactory.getObjectMapper().writeValueAsString(reqDTO));
} catch (JsonProcessingException e) {
log.error("", e);
}
return null;
}
复制代码
然后定义切面 —— 省略部分与上文分析的源代码保持一致,只对变化的内容给出代码
@Slf4j
@Aspect
@Component
public class SwaggerExpandAspect {
......
@Around("execution(* springfox.documentation.spring.web.readers.operation.OperationParameterReader.apply(..))")
public Object pointCut(ProceedingJoinPoint point) throws Throwable {
Object[] args = point.getArgs();
OperationContext context = (OperationContext) args[0];
context.operationBuilder().parameters(context.getGlobalOperationParameters());
context.operationBuilder().parameters(readParameters(context));
return null;
}
......
private boolean shouldExpand(final ResolvedMethodParameter parameter, ResolvedType resolvedParamType) {
return !parameter.hasParameterAnnotation(RequestBody.class)
&& !parameter.hasParameterAnnotation(RequestPart.class)
&& !parameter.hasParameterAnnotation(RequestParam.class)
&& !parameter.hasParameterAnnotation(PathVariable.class)
&& !isBaseType(typeNameFor(resolvedParamType.getErasedType()))
&& !enumTypeDeterminer.isEnum(resolvedParamType.getErasedType())
&& !isContainerType(resolvedParamType)
&& !isMapType(resolvedParamType)
&& !noExpandAnnotaion(parameter);
}
private boolean noExpandAnnotaion(ResolvedMethodParameter parameter) {
log.info("开始决定是否展开问题");
if (!parameter.hasParameterAnnotation(NoSwaggerExpand.class)) {
return false;
}
NoSwaggerExpand noSwaggerExpand = (NoSwaggerExpand) parameter.getAnnotations().stream().filter(item -> item instanceof NoSwaggerExpand).findAny().orElse(null);
if (noSwaggerExpand.expand()) {
return false;
}
return true;
}
}
复制代码
最重要的是这里的修改
这里加上对自定义注解修饰的入参进行了判定,使得被自定义注解修饰的入参可以被Swagger
当做@RequestBody
一样处理。
Definition属性值填充的逻辑调整
再定义一个切面 —— 省略部分与上文分析的源代码保持一致,只对变化的内容给出代码
@Slf4j
@Aspect
@Component
public class SwaggerDefinitionAspect {
......
@Around("execution(* springfox.documentation.spring.web.readers.operation.OperationModelsProvider.apply(..))")
public Object pointCut(ProceedingJoinPoint point) throws Throwable {
Object[] args = point.getArgs();
RequestMappingContext context = (RequestMappingContext) args[0];
collectFromReturnType(context);
collectParameters(context);
collectGlobalModels(context);
return null;
}
......
private void collectParameters(RequestMappingContext context) {
LOG.debug("Reading parameters models for handlerMethod |{}|", context.getName());
List<resolvedmethodparameter> parameterTypes = context.getParameters();
for (ResolvedMethodParameter parameterType : parameterTypes) {
if (parameterType.hasParameterAnnotation(RequestBody.class)
|| parameterType.hasParameterAnnotation(RequestPart.class)
|| parameterType.hasParameterAnnotation(NoSwaggerExpand.class)
) {
ResolvedType modelType = context.alternateFor(parameterType.getParameterType());
LOG.debug("Adding input parameter of type {}", resolvedTypeSignature(modelType).or("<null>"));
context.operationModelsBuilder().addInputParam(modelType);
}
}
LOG.debug("Finished reading parameters models for handlerMethod |{}|", context.getName());
}
}
复制代码
在这里只改动了一处代码,使得被自定义注解修饰的入参能够被添加到Definition
属性中去。
做完以上两步,即可修复springmvc
独立的参数解析器功能和swagger
功能冲突的问题。
题外篇
阿Q将持续更新
java
实战方面的文章,感兴趣的可以关注下公众号:阿Q说代码
,也可以来技术群讨论问题呦,点赞之交值得深交!