Springboot 2.6.x整合springfox-swagger 3.0 报 Failed to start bean documentationPluginsBootstrapper的问题

版本号

  • spring boot 2.6.11
  • springfox-swagger 3.0.0
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.11</version>               
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-boot-starter</artifactId>
                <version>3.0.0</version>
            </dependency>

问题现象

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.22.jar:5.3.22]
	at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_121]
	at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.22.jar:5.3.22]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.11.jar:2.6.11]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745) [spring-boot-2.6.11.jar:2.6.11]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420) [spring-boot-2.6.11.jar:2.6.11]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.6.11.jar:2.6.11]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317) [spring-boot-2.6.11.jar:2.6.11]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.6.11.jar:2.6.11]
	at com.winsyun.emr.portal.EmrApplication.main(EmrApplication.java:36) [classes/:na]
Caused by: java.lang.NullPointerException: null
	at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
	at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0]
	at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0]
	at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[na:1.8.0_121]
	at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:1.8.0_121]
	at java.util.TimSort.sort(TimSort.java:234) ~[na:1.8.0_121]
	at java.util.Arrays.sort(Arrays.java:1512) ~[na:1.8.0_121]
	at java.util.ArrayList.sort(ArrayList.java:1454) ~[na:1.8.0_121]
	at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) ~[na:1.8.0_121]
	at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_121]
	at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_121]
	at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_121]
	at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_121]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_121]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_121]
	at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_121]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_121]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_121]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_121]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_121]
	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) ~[springfox-spring-web-3.0.0.jar:3.0.0]
	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) ~[springfox-spring-web-3.0.0.jar:3.0.0]
	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) ~[springfox-spring-web-3.0.0.jar:3.0.0]
	at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) ~[springfox-spring-web-3.0.0.jar:3.0.0]
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.22.jar:5.3.22]
	... 14 common frames omitted

注意

  • 1 这里的异常一定是 NullPointerException
  • 2 一定要是方法 springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns 中抛出的

如果你的问题不符合以上两点那可能是其它问题导致的本文方法不一定能解决

网上可查的解决方法

一 修改配置文件(推荐使用)

这种方法认为Spring 2.6.x 默认路径匹配策略从AntPathMatcher 更改为PathPatternParser,而 springfox-swagger 还是使用 AntPathMather导致的错误

spring:
 mvc:
   pathmatch:
     matching-strategy: ant_path_matcher

二 添加继承自 WebMvcConfigurationSupport的配置类(有副作用谨慎使用)

并且要求将swagger前端资源webjars添加到resourceHandlers

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // swagger配置
        registry.
                addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                .resourceChain(false);
    }

三 添加BeanPostProcessor(不要使用)

@Bean
public static 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);
            }
        }
    };
   }

各方法的比较和不足

  • 1、先说一下第一种方案,不可否认确实是有效的并且是Spring boot官方提供的配置,我不知道为什么网上有些人说这个方案是治标的,但是这种方案还有一个问题当引入spring-boot-starter-actuator依赖时还会出现上术错误所以这个方案还有待改进
  • 2、第二种方案也是有效的但是网上并没有说原理,并且没有强调必须得继承自WebMvcConfigurationSupport,经测试加不加addResourceHandler 效果是一样的(swagger会处理的),并且配置类必须继承自WebMvcConfigurationSupport 而不能实现WebMvcConfigurer,不过这种方案是有副作用的,因为WebMvcConfigurationSupport 只有一个生效,会影响SpringBoot自带的配置,如果处理不好的话一些自定义配置也不生效(这种方案的本质也是通过使用自定义的WebMvcConfigurationSupport让Spring 自带的WebMvcConfigurationSupport 的pathMatche配置失效来达到目的,本质上和第一种方案一样)。
  • 3、第三种方案有人说这是最优雅的并且是治本的,首先需要说明的是程序确实不报错误,但是你会发现swagger页面根本就不生成API文档,这也就失去了引入swagger的价值了

综上所术第一种方案和第二种方案是有效的第三种方案虽然解决了程序报错问题但是把需要swagger生成文档的接口全部给过虑掉了失去了使用swagger的初衷,所以第三种方案是不可取的

问题解析

正如其它网上所说确实是spring boot 2.6之后默认的路径匹配策略从AntPathMatcher 更改为PathPatternParser而新规则生成的url保存在了一个新的字段上,老的字段为null而springfox-swagger在对url排序的时候使用了路径(还是取的老字段)这就是为什么会报 NullPointerException

根据错误信息报空指针的地方为springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns下面看一下它的代码

 @Override
  public Set<String> getPatterns() {
    //这里的condition为null
    return this.condition.getPatterns().stream()
        .map(p -> String.format("%s/%s", maybeChompTrailingSlash(contextPath),  maybeChompLeadingSlash(p)))
        .collect(Collectors.toSet());
  }

下一步就是要确定这里的condition是怎么来的,通过代码跟踪发现在类WebMvcRequestHandler 实例化了 WebMvcPatternsRequestConditionWrapper,并且将requestMapping.getPatternsCondition()做为参数传给了condition 如下:

   //这里实例化了WebMvcPatternsRequestConditionWrapper
  @Override
  public PatternsRequestCondition getPatternsCondition() {
    return new WebMvcPatternsRequestConditionWrapper(
        contextPath,
        requestMapping.getPatternsCondition());
  }

通过查看requestMapping的类型为RequestMappingInfo 是SpringMvc的一个类,并且是保存SpringMvc路径信息的,来看一下它的结构:

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
//...忽略一些不重要的信息
    //路径名
    @Nullable
	private final String name;

    //新的使用PathPatternParser 解析出来的路径保存在这里
	@Nullable
	private final PathPatternsRequestCondition pathPatternsCondition;
//原来的使用AntPathMatcher 解析出来的路径保存在这里
	@Nullable
	private final PatternsRequestCondition patternsCondition;

这里已经很明显 新版本Spring boot解析出来的路径信息使用了新的字段,而springfox-swagger使用的还是原字段patternsCondition

问题解决

问题弄清楚之后那么解决办法就很简单了

  • 方案一 修改springfox-swagger代码使用 getPathPatternsCondition 替换 getPatternsCondition
  • 方案二 想办法让patternsCondition 有值

由于springfox-swagger 不提供配置选项,所以第一种方案需要重新编译代码成本较高,所以选择第二种方案,Springboot是提供了对应的配置的也就是上文提到的spring.mvc.pathmatch.matching-strategy=ant_path_matcher

spring.mvc.pathmatch.matching-strategy 是怎么工作的呢

通过代码跟踪可以发现在自动配置类 WebMvcAutoConfiguration 中使用了这个配置代码如下:

        @Override
		public void configurePathMatch(PathMatchConfigurer configurer) {
		    //这里判断如果是PATH_PATTERN_PARSER 向配置类中加入了pathPatternParser
			if (this.mvcProperties.getPathmatch()
					.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
				configurer.setPatternParser(pathPatternParser);
			}
			configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
			configurer.setUseRegisteredSuffixPatternMatch(
					this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
			this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
				String servletUrlMapping = dispatcherPath.getServletUrlMapping();
				if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
					UrlPathHelper urlPathHelper = new UrlPathHelper();
					urlPathHelper.setAlwaysUseFullPath(true);
					configurer.setUrlPathHelper(urlPathHelper);
				}
			});
		}

在默认情况下Url匹配策略为PATH_PATTERN_PARSER 所以会通过configurer.setPatternParser(pathPatternParser);配置进去一个路径解析类,然后在通过RequestMappingInfo.DefaultBuilder创建 RequestMappingInfo时会根据这个配置向不同的字段上赋值代码如下:

        @Override
		@SuppressWarnings("deprecation")
		public RequestMappingInfo build() {

			PathPatternsRequestCondition pathPatterns = null;
			PatternsRequestCondition patterns = null;
            //当patternParser 非空时 将值赋给pathPatterns 
			if (this.options.patternParser != null) {
				pathPatterns = (ObjectUtils.isEmpty(this.paths) ?
						EMPTY_PATH_PATTERNS :
						new PathPatternsRequestCondition(this.options.patternParser, this.paths));
			}
			else { //当patternParser 为空时 将值赋给patterns
				patterns = (ObjectUtils.isEmpty(this.paths) ?
						EMPTY_PATTERNS :
						new PatternsRequestCondition(
								this.paths, null, this.options.getPathMatcher(),
								this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
								this.options.getFileExtensions()));
			}

			ContentNegotiationManager manager = this.options.getContentNegotiationManager();

			return new RequestMappingInfo(
					this.mappingName, pathPatterns, patterns,
					ObjectUtils.isEmpty(this.methods) ?
							EMPTY_REQUEST_METHODS : new RequestMethodsRequestCondition(this.methods),
					ObjectUtils.isEmpty(this.params) ?
							EMPTY_PARAMS : new ParamsRequestCondition(this.params),
					ObjectUtils.isEmpty(this.headers) ?
							EMPTY_HEADERS : new HeadersRequestCondition(this.headers),
					ObjectUtils.isEmpty(this.consumes) && !this.hasContentType ?
							EMPTY_CONSUMES : new ConsumesRequestCondition(this.consumes, this.headers),
					ObjectUtils.isEmpty(this.produces) && !this.hasAccept ?
							EMPTY_PRODUCES : new ProducesRequestCondition(this.produces, this.headers, manager),
					this.customCondition != null ?
							new RequestConditionHolder(this.customCondition) : EMPTY_CUSTOM,
					this.options);
		}

以上就是spring.mvc.pathmatch.matching-strategy配置工作的原理,也可以通过Java配置的方式修改这个配置WebMvcConfigurer.configurePathMatch(PathMatchConfigurer configurer)

解决引入spring-boot-starter-actuator后配置失效问题

熟悉actuator的都知道它向外暴露接口并不是通过RequestMapping注解实现的而是通过Endpoint注解来实现的所以咱们之前对RequestMappingHandlerMapping的配置并不会影响actuator的路径匹配规则,所以我们需要找到actuator对WebMvcEndpointHandlerMapping配置的部分进行配置修改,在配置类WebMvcEndpointManagementContextConfiguration中有以下配置:

    @Bean
	@ConditionalOnMissingBean //这里的条件注入使得我们可以定义自己的配置
	public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
			ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
			EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
			WebEndpointProperties webEndpointProperties, Environment environment) {
		List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
		Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
		allEndpoints.addAll(webEndpoints);
		allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
		allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
		String basePath = webEndpointProperties.getBasePath();
		EndpointMapping endpointMapping = new EndpointMapping(basePath);
		boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
		return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
				corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
				shouldRegisterLinksMapping, WebMvcAutoConfiguration.pathPatternParser); //这里配置了pathPatternParser
	}

所以这里的解决方案和之前的类似把这里的pathPatternParser置空就行了,在我们自己的项目中增加配置:

    @Bean
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
                                                                         ServletEndpointsSupplier servletEndpointsSupplier,
                                                                         ControllerEndpointsSupplier controllerEndpointsSupplier,
                                                                         EndpointMediaTypes endpointMediaTypes,
                                                                         CorsEndpointProperties corsProperties,
                                                                         WebEndpointProperties webEndpointProperties,
                                                                         Environment environment) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        String basePath = webEndpointProperties.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
                corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
                shouldRegisterLinksMapping, null);//这个地方置成了null
    }

这样问题就全部解决了。

其它知识扩展

  • 类 WebMvcRequestHandlerProvider 中处理了从Spring 中获取的路径信息,并将这些信息提供给Swagger
  @Override
  public List<RequestHandler> requestHandlers() {
    //这里的handlerMappings是从SpringMvc中获取的所有路径
    return nullToEmptyList(handlerMappings).stream()
        .filter(requestMappingInfoHandlerMapping ->
            !("org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping"
                  .equals(requestMappingInfoHandlerMapping.getClass()
                      .getName())))
        .map(toMappingEntries())
        .flatMap((entries -> StreamSupport.stream(entries.spliterator(), false)))
        //这里进行了RequestHandler 转换 最终生成WebMvcRequestHandler 
        .map(toRequestHandler())
        //这里调用WebMvcRequestHandler.getPatternsCondition 获取路径
        .sorted(byPatternsCondition())
        .collect(toList());
  }

这个 WebMvcRequestHandlerProvider 相当于一个适配器把SpringMvc中的路径获取到springfox-swagger中并转换成需要的数据,上面代码在排序的时候使用到了 WebMvcRequestHandler.getPatternsCondition

public static Comparator<RequestHandler> byPatternsCondition() {
    return Comparator
        .comparing(requestHandler -> sortedPaths(requestHandler.getPatternsCondition()));
  }
  • 这里的toRequestHandler方法将路径信息转换成了 WebMvcRequestHandler。
private Function<Map.Entry<RequestMappingInfo, HandlerMethod>, RequestHandler> toRequestHandler() {
    //这里的input 是 Map<RequestMappingInfo, HandlerMethod> 的一个元素,所以这里的key为对象RequestMappingInfo的实例
    return input -> new WebMvcRequestHandler(
        contextPath,
        methodResolver,
        input.getKey(),
        input.getValue());
  }
  • WebMvcRequestHandlerProvider 注入了所有的RequestMappingInfoHandlerMapping
@Autowired
  public WebMvcRequestHandlerProvider(
      Optional<ServletContext> servletContext,
      HandlerMethodResolver methodResolver,
      List<RequestMappingInfoHandlerMapping> handlerMappings) {
    this.handlerMappings = handlerMappings;//注入SpringMvc的路径处理器
    this.methodResolver = methodResolver;
    this.contextPath = servletContext
        .map(ServletContext::getContextPath)
        .orElse(ROOT);
  }
  • RequestMappingHandlerMapping 创建RequestMappingInfo
private RequestMappingInfo createRequestMappingInfo(WebOperationRequestPredicate predicate, String path) {
		return RequestMappingInfo.paths(this.endpointMapping.createSubPath(path)).options(this.builderConfig)
				.methods(RequestMethod.valueOf(predicate.getHttpMethod().name()))
				.consumes(predicate.getConsumes().toArray(new String[0]))
				.produces(predicate.getProduces().toArray(new String[0])).build();
	}
  • RequestMappingHandlerMapping 获取全部路径,注意这里返回的Map是不能修改了
public Map<T, HandlerMethod> getHandlerMethods() {
		this.mappingRegistry.acquireReadLock();
		try {
		    //这里返回的是不能被修改的Map
			return Collections.unmodifiableMap(
					this.mappingRegistry.getRegistrations().entrySet().stream()
							.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().handlerMethod)));
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 首先,需要在 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> ``` 接着,在 Spring Boot 的启动类上添加 `@EnableSwagger2WebFlux` 注解: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux; @SpringBootApplication @EnableSwagger2WebFlux public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 最后,在你的控制器类上添加 `@Api` 和 `@ApiOperation` 注解进行 API 文档的描述: ```java import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/hello") @Api(tags = "HelloController", description = "示例控制器") public class HelloController { @GetMapping("/") @ApiOperation(value = "hello", notes = "示例接口") public String hello() { return "Hello, Swagger!"; } } ``` 然后,启动应用程序并访问 `http://localhost:<port>/swagger-ui/index.html` 即可查看生成的 API 文档。 ### 回答2: Spring Boot整合Springfox Swagger 3.0 Springfox Swagger是一个用于为Spring Boot应用程序生成文档的框架。在Spring Boot中使用Springfox Swagger 3.0,可以方便地为API生成可视化的接口文档,并提供简化的API调试和测试功能。下面是整合Springfox Swagger 3.0的步骤: 首先,需要在Spring Boot项目的pom.xml文件中添加Springfox Swagger 3.0的依赖: ```xml <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> ``` 然后,在Spring Boot应用程序的启动类上添加`@EnableOpenApi`注解,以启用Springfox Swagger 3.0的功能: ```java @SpringBootApplication @EnableOpenApi public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 接下来,需要在项目中添加一个配置类,其中配置Swagger的相关信息: ```java @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .select() .apis(RequestHandlerSelectors.basePackage("com.example.controller")) .paths(PathSelectors.any()) .build(); } } ``` 上述配置中,通过`apis`方法指定需要生成文档的Controller所在的包,通过`paths`方法指定需要生成文档的接口路径。可以根据需要进行自定义配置。 最后,在浏览器中访问http://localhost:8080/swagger-ui/index.html,可以看到生成的接口文档页面。在该页面上,可以查看API的详细信息,进行测试和调试。 整合Springfox Swagger 3.0是一个方便快捷的方式来创建和管理API文档。它提供了友好的UI界面和强大的功能,可以大大简化API文档的维护工作,并提高团队合作效率。 ### 回答3: Spring Boot整合Springfox Swagger 3.0的步骤如下: 1. 添加相关依赖:在`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> ``` 2. 创建Swagger配置类:创建一个配置类,并使用`@Configuration`注解进行标记。在该类中,可以配置Swagger的相关信息,如标题、描述、版本等。 ```java @Configuration @EnableSwagger2 //启用Swagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("API文档标题") .description("API文档描述") .version("1.0.0") .build(); } } ``` 3. 配置Swagger的URL路径:在`application.properties`或`application.yml`文件中,添加以下配置项,指定Swagger的URL路径: ```yaml springfox.documentation.swagger-ui.path=/swagger-ui.html ``` 4. 启动项目:启动Spring Boot项目,访问http://localhost:8080/swagger-ui.html,即可查看生成的API文档。 以上是Spring Boot整合Springfox Swagger 3.0的基本步骤,通过配置Swagger相关信息,可以实现自动生成API文档,并提供可视化的界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值