记录下 Springboot2.6.3不兼容swagger3.0.0问题
1.springboot版本
org.springframework.boot
spring-boot-starter-parent
2.6.0
2.springfox版本
io.springfox
springfox-boot-starter
3.0.0
spring5支持PathMatchConfigurer导致
Failed to start bean ‘documentationPluginsBootstrapper
启动报错解决方案1:
appliaction.yml 添加配置
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
重写
springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper
springfox.documentation.spring.web.WebMvcRequestHandler
两个类;
将PatternsRequestCondition改为PathPatternsRequestCondition;
package springfox.documentation.spring.web;
import static springfox.documentation.spring.web.paths.Paths.maybeChompLeadingSlash;
import static springfox.documentation.spring.web.paths.Paths.maybeChompTrailingSlash;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
/**
* swagger3.0兼容springBoot2.6.3处理
*/
public class WebMvcPatternsRequestConditionWrapper
implements
springfox.documentation.spring.wrapper.PatternsRequestCondition {
private final String contextPath;
private final PathPatternsRequestCondition condition;
public WebMvcPatternsRequestConditionWrapper(
String contextPath,
PathPatternsRequestCondition condition) {
this.contextPath = contextPath;
this.condition = condition;
}
@Override
public springfox.documentation.spring.wrapper.PatternsRequestCondition combine(
springfox.documentation.spring.wrapper.PatternsRequestCondition other) {
if (other instanceof WebMvcPatternsRequestConditionWrapper && !this.equals(other)) {
return new WebMvcPatternsRequestConditionWrapper(
contextPath,
condition.combine(((WebMvcPatternsRequestConditionWrapper) other).condition));
}
return this;
}
@Override
public Set getPatterns() {
return this.condition.getPatternValues().stream()
.map(p -> String.format("%s/%s", maybeChompTrailingSlash(contextPath),
maybeChompLeadingSlash(p)))
.collect(Collectors.toSet());
}
@Override
public boolean equals(Object o) {
if (o instanceof WebMvcPatternsRequestConditionWrapper) {
return this.condition.equals(((WebMvcPatternsRequestConditionWrapper) o).condition);
}
return false;
}
@Override
public int hashCode() {
return this.condition.hashCode();
}
@Override
public String toString() {
return this.condition.toString();
}
}
package springfox.documentation.spring.web;
import static java.util.Optional.ofNullable;
import com.fasterxml.classmate.ResolvedType;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import springfox.documentation.RequestHandler;
import springfox.documentation.RequestHandlerKey;
import springfox.documentation.service.ResolvedMethodParameter;
import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver;
import springfox.documentation.spring.wrapper.NameValueExpression;
import springfox.documentation.spring.wrapper.PatternsRequestCondition;
/**
* swagger3.0兼容springBoot2.6.3处理
*/
public class WebMvcRequestHandler implements RequestHandler {
private final String contextPath;
private final HandlerMethodResolver methodResolver;
private final RequestMappingInfo requestMapping;
private final HandlerMethod handlerMethod;
public WebMvcRequestHandler(
String contextPath,
HandlerMethodResolver methodResolver,
RequestMappingInfo requestMapping,
HandlerMethod handlerMethod) {
this.contextPath = contextPath;
this.methodResolver = methodResolver;
this.requestMapping = requestMapping;
this.handlerMethod = handlerMethod;
}
@Override
public HandlerMethod getHandlerMethod() {
return handlerMethod;
}
@Override
public RequestHandler combine(RequestHandler other) {
return this;
}
@Override
public Class> declaringClass() {
return handlerMethod.getBeanType();
}
@Override
public boolean isAnnotatedWith(Class extends Annotation> annotation) {
return null != AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation);
}
@Override
public PatternsRequestCondition getPatternsCondition() {
return new WebMvcPatternsRequestConditionWrapper(
contextPath,
requestMapping.getPathPatternsCondition());
}
@Override
public String groupName() {
return ControllerNamingUtils.controllerNameAsGroup(handlerMethod);
}
@Override
public String getName() {
return handlerMethod.getMethod().getName();
}
@Override
public Set supportedMethods() {
return requestMapping.getMethodsCondition().getMethods();
}
@Override
public Set produces() {
return requestMapping.getProducesCondition().getProducibleMediaTypes();
}
@Override
public Set consumes() {
return requestMapping.getConsumesCondition().getConsumableMediaTypes();
}
@Override
public Set> headers() {
return WebMvcNameValueExpressionWrapper
.from(requestMapping.getHeadersCondition().getExpressions());
}
@Override
public Set> params() {
return WebMvcNameValueExpressionWrapper
.from(requestMapping.getParamsCondition().getExpressions());
}
@Override
public Optional findAnnotation(Class annotation) {
return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation));
}
@Override
public RequestHandlerKey key() {
return new RequestHandlerKey(
requestMapping.getPathPatternsCondition().getPatternValues(),
requestMapping.getMethodsCondition().getMethods(),
requestMapping.getConsumesCondition().getConsumableMediaTypes(),
requestMapping.getProducesCondition().getProducibleMediaTypes());
}
@Override
public springfox.documentation.spring.wrapper.RequestMappingInfo> getRequestMapping() {
return new WebMvcRequestMappingInfoWrapper(requestMapping);
}
@Override
public List getParameters() {
return methodResolver.methodParameters(handlerMethod);
}
@Override
public ResolvedType getReturnType() {
return methodResolver.methodReturnType(handlerMethod);
}
@Override
public Optional findControllerAnnotation(Class annotation) {
return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), annotation));
}
@Override
public String toString() {
return new StringJoiner(", ", WebMvcRequestHandler.class.getSimpleName() + "{", "}")
.add("requestMapping=" + requestMapping)
.add("handlerMethod=" + handlerMethod)
.add("key=" + key())
.toString();
}
}
swagger 配置类添加 bean
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${swagger.show}")
private boolean swaggerShow;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(swaggerShow)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("xxxxxx")
.description("xxxxxx")
.termsOfServiceUrl("")
.version("1.0")
.build();
}
@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private void customizeSpringfoxHandlerMappings(
List mappings) {
List copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List) field.get(bean);
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
}
访问地址
http://ip:port/swagger/