赞
踩
https://juejin.cn/post/7249173717749940284
近期由于升级到springboot2.6X,所以服务端很多组件都需要重新导入以及解决依赖问题。
下面就是一个很经典的问题了,
springboot2.6与knife4j的整合。
springboot2.6与knife4j 3.0.3
由于Springfox使用的路径匹配是基于AntPathMatcher,而Spring Boot 2.6.X使用的是PathPatternMatcher,所以将MVC的路径匹配规则改成 AntPathMatcher。具体配置如下:
--- application.yml:
spring:
mvc:
pathmatch:
#Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher 解决knife4j匹配boot2.6.7 boot版本过高的问题
matching-strategy: ant_path_matcher
-- 或者:application.properties:
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
这时候你可以
新增一个配置类,注意配置类不能放到swagger的配置类下,测试无效。配置Bean可以放在启动类下或者重新新增一个配置Bean,代码如下:
package net.w2p.AppBase.fixBugs; import org.springframework.beans.BeansException; 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.spring.web.plugins.WebFluxRequestHandlerProvider; import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; import java.lang.reflect.Field; import java.util.List; import java.util.stream.Collectors; /** * Springboot整合Knife4j问题修正 */ @Configuration public class BeanPostProcessorConfig { @Bean public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() { return new BeanPostProcessor() { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) { customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); } return bean; } private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) { List<T> copy = mappings.stream() .filter(mapping -> mapping.getPatternParser() == null) .collect(Collectors.toList()); mappings.clear(); mappings.addAll(copy); } @SuppressWarnings("unchecked") private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) { try { Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); field.setAccessible(true); return (List<RequestMappingInfoHandlerMapping>) field.get(bean); } catch (IllegalArgumentException | IllegalAccessException e) { throw new IllegalStateException(e); } } }; } }
package net.w2p.AppBase; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import io.swagger.annotations.ApiOperation; import net.w2p.WebExt.config.AppENV; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import springfox.documentation.RequestHandler; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import javax.servlet.http.HttpSession; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.List; import static springfox.documentation.builders.PathSelectors.regex; /* * @Api: 修饰整个类,描述Controller的作用 * @ApiOperation: 描述一个类的一个方法,或者说一个接口 * @ApiParam: 单个参数描述 * @ApiModel: 用对象来接收参数 * @ApiProperty: 用对象接收参数时,描述对象的一个字段 * @ApiResponse: HTTP响应其中1个描述 * @ApiResponses: HTTP响应整体描述 * @ApiIgnore: 使用该注解忽略这个API * @ApiError :发生错误返回的信息 * @ApiImplicitParam: 一个请求参数 * @ApiImplicitParams: 多个请求参数 * doc.html */ @EnableSwagger2 @Configuration @EnableKnife4j public class Swagger2Configuration implements WebMvcConfigurer { private String accessToken="token"; private String title; private String description; private String version; private String termsOfServiceUrl; private String name; private String url; private String email; @Bean public Docket createRestApi() { boolean isEnableSwagger=true; if(!"test".equalsIgnoreCase(AppENV.getEnv())&&!"dev".equalsIgnoreCase(AppENV.getEnv())){ isEnableSwagger=false; } if("dev".equalsIgnoreCase(AppENV.getEnv())){ isEnableSwagger=true; }else{ isEnableSwagger=false; } String scanPaths = "net.w2p.AppBase.controller.api;" + "net.w2p.AppBase.controller.common;" ; return new Docket(DocumentationType.SWAGGER_2).enable(isEnableSwagger) .apiInfo(apiInfo()) // .enable(enableSwagger) .directModelSubstitute(Timestamp.class, Long.class)//将Timestamp类型全部转为Long类型 .directModelSubstitute(Date.class, Long.class)//将Date类型全部转为Long类型 .forCodeGeneration(true) .select() .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // .apis(RequestHandlerSelectors.any()) .apis(basePackage(scanPaths)) // .paths(PathSelectors.ant("/api/**")) // .paths(regex("^.*(?<!error)$")) .paths(PathSelectors.any()) .build() // 添加忽略类型 .ignoredParameterTypes(HttpSession.class) .securitySchemes(securitySchemes()) .securityContexts(securityContexts()); } private List<SecurityScheme> securitySchemes() { List<SecurityScheme> apiKeyList= new ArrayList(); apiKeyList.add(new ApiKey("token", "token", "header")); return apiKeyList; } private List<SecurityContext> securityContexts() { List<SecurityContext> securityContexts=new ArrayList<>(); securityContexts.add( SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(regex("^(?!auth).*$")) .build()); return securityContexts; } private List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; List<SecurityReference> securityReferences = new ArrayList<>(); securityReferences.add(new SecurityReference(accessToken, authorizationScopes)); return securityReferences; } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("api文档") .description("综合前台网站") .termsOfServiceUrl("http://www.baidu.com") .contact(new Contact("freeLife","baidu.com","1000@qq.com")) .version("2.9.2") .build(); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { System.out.println("================> add doc.html -url"); registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); // registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } // 定义分隔符 private static final String splitor = ";"; /** * 声明基础包 * * @param basePackage 基础包路径 * @return */ public static Predicate<RequestHandler> basePackage(final String basePackage) { return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true); } /** * 校验基础包 * * @param basePackage 基础包路径 * @return */ private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) { return input -> { for (String strPackage : basePackage.split(splitor)) { boolean isMatch = input.getPackage().getName().startsWith(strPackage); if (isMatch) { return true; } } return false; }; } /** * 检验基础包实例 * * @param requestHandler 请求处理类 * @return */ @SuppressWarnings("deprecation") private static Optional<? extends Class<?>> declaringClass(RequestHandler requestHandler) { return Optional.fromNullable(requestHandler.declaringClass()); } }
正常运行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。