“This is the 12th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
Hello everyone, I’m Ah Q!
We talked about springMVC and Swagger’s dependency on @RequestBody and found out what the problem is. In this article we will provide detailed answers on how to solve the problem!
To solve the problem
From the above analysis, it can be concluded that the fundamental problem here is the conflict between springMVC’s separate parameter parser functionality and Swagger functionality. One requirement cannot be annotated with @requestBody and the other must be annotated with @RequestBody, so there are two solutions
- from
springmvc
Start by looking for ways to increase the priority of a custom parameter parser, as long as the custom parameter parser priority ratioRequestResponseBodyMethodProcessor
High, can be added to the custom parameter@RequestBody
Annotations,swagger
The function will naturally return to normal. - from
swagger
Go ahead and figure out how to get rid of the top two parts Yeah@RequestBody
Is determined separately, not modifiedspringmvc
Related functions can also be madeswagger
Function is normal.
Considering that changing springMVC functionality might have a big impact on future upgrades, we decided to use sections to change the behavior of the original Swagger in both places of @RequestBody so that Swagger functions properly.
Logical adjustments to request type determination
First, define an annotation
@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(a) default false;
}
Copy the code
Add it to the input parameter
@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;
}
Copy the code
Then define the facets — omit parts consistent with the source code analyzed above, and give code only for the changes
@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("Start deciding whether to open the question.");
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; }}Copy the code
The most important thing is the modification here
We add a check on the custom annotation modifier so that the custom annotation modifier can be handled by Swagger as @requestBody.
Logical adjustment of the Definition property value population
Define a section again — omit sections consistent with the source code analyzed above, and give code only for the changes
@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()); }}Copy the code
There is only one change in the code here, so that input parameters that are modified by custom annotations can be added to the Definition property.
After the above two steps, we can fix the conflict between springMVC’s independent parameter parser function and Swagger function.
Post off
Ah Q will continue to update the Java practice of the article, interested in the public account can pay attention to: AH Q said the code, also can come to the technical group to discuss the problem!