为什么 springdoc-openapi 在按照开箱即用的描述组装时不会返回 api 文档?

问题描述 投票:0回答:1

当我尝试在一个有很多移动部件的应用程序中从 springdoc 检索 api-docs 时,我遇到了错误 404。为了调试问题,我构建了一个简单的 springboot 应用程序,其中只有用于测试 springdoc 的基本代码。
我按照 https://springdoc.org/index.html#getting-started 中的说明进行操作,在尝试检索 api-docs 端点时收到错误 404。 我想我一路上错过了一些东西,但看不到它是什么。

pom.xml 是:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  
  <groupId>org.ihc.hdd.s3</groupId>
  <artifactId>springboot-example</artifactId>
  <version>1.1.0-SNAPSHOT</version>
  <name>springboot-example</name>
  <description>Example Spring Boot S3 Project</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.4.0</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>21</java.version>
    </properties>
  
    <dependencies>
        <!-- project dependencies -->

        <!-- Spring boot starters -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
        
        <!-- Test Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>${project.artifactId}</finalName>
    </build>

  
</project>

控制器是:

/**
 * 
 */
package org.ihc.hdd.s3.controller;

import org.ihc.hdd.s3.models.HelloWorldApi;
import org.ihc.hdd.s3.service.HelloWorldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;

/**
 * @author dtsteven
 *
 *         The controller should just contain logic to read from and write to
 *         the REST interface. All other work should be done by the service.
 */
@RestController
@RequestMapping("/hello")
public class HelloWorldController {

    @Autowired
    private HelloWorldService helloWorldService;

    @PostMapping("/world")
    @Operation(summary = "Post hello world ")
    public ResponseEntity<?> newHelloWorld(@RequestBody HelloWorldApi hello) {

        if (hello.getPosition() != null) {
            return ResponseEntity.badRequest().body("Position is not valid on POST record");
        }

        HelloWorldApi result = this.helloWorldService.saveHelloWorldRecord(hello);

        return ResponseEntity.status(HttpStatus.CREATED).body(result);

    }

    @GetMapping("/world/{id}")
    @Operation(summary = "Get hello world record that was created.  ", description = "{id} Must be less than records created with post")
    public ResponseEntity<?> getHelloWorldSingle(@PathVariable Integer id) {

        HelloWorldApi result = this.helloWorldService.getHelloWorldRecord(id);

        if (result == null) {
            return ResponseEntity.notFound().build();
        }

        return ResponseEntity.ok(result);
    }

    @GetMapping("/world")
    @Operation(summary = "Get hello world ")
    public ResponseEntity<String> getHelloWorld() {

        return ResponseEntity.ok("Hello World");
    }
}

application.yml:

server:
  context-path: /springboot-example
  
spring:
  profiles:
    active: local

# Spring Actuator
endpoints:
  enabled: false # Disable all endpoints
  info:
    enabled: true # Enable only the info endpoint
  health:
    enabled: true

# This information will be displayed at /monitor/info using spring actuator
info:
  app:
    name: '@project.name@' # @{value}@ are pulled from the pom.xml
    description: '@project.description@'
    version: '@project.version@'
    artifactId: '@project.artifactId@'

application-local.yml:

server:
  port: 8888

logging:
  level:
    org.springframework.web: TRACE

当我启动应用程序时,我包含 TRACE 消息并获得以下结果。 请注意,它会查找控制器中定义的端点、api-docs 和 swagger-ui 的端点。 我可以看到所有端点都已定义。

2024-12-12T14:43:30.447-07:00  INFO 39932 --- [           main] o.i.hdd.s3.SpringbootExampleServicesApp  : Starting SpringbootExampleServicesApp using Java 21.0.3 with PID 39932 (C:\Users\dtsteven\dev\git\samples\springboot-example\target\classes started by dtsteven in C:\Users\dtsteven\dev\git\samples\springboot-example)
2024-12-12T14:43:30.452-07:00  INFO 39932 --- [           main] o.i.hdd.s3.SpringbootExampleServicesApp  : The following 1 profile is active: "local"
2024-12-12T14:43:32.628-07:00  INFO 39932 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8888 (http)
2024-12-12T14:43:32.649-07:00  INFO 39932 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-12-12T14:43:32.649-07:00  INFO 39932 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.33]
2024-12-12T14:43:32.804-07:00  INFO 39932 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-12-12T14:43:32.805-07:00  INFO 39932 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2270 ms
2024-12-12T14:43:33.010-07:00 DEBUG 39932 --- [           main] o.s.w.f.ServerHttpObservationFilter      : Filter 'webMvcObservationFilter' configured for use
2024-12-12T14:43:33.277-07:00 TRACE 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
    o.i.h.s.c.HelloWorldController:
    {GET [/hello/world/{id}]}: getHelloWorldSingle(Integer)
    {POST [/hello/world]}: newHelloWorld(HelloWorldApi)
    {GET [/hello/world]}: getHelloWorld()
2024-12-12T14:43:33.293-07:00 TRACE 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
    o.s.b.a.w.s.e.BasicErrorController:
    { [/error]}: error(HttpServletRequest)
    { [/error], produces [text/html]}: errorHtml(HttpServletRequest,HttpServletResponse)
2024-12-12T14:43:33.313-07:00 TRACE 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
    o.s.w.a.OpenApiWebMvcResource:
    {GET [/v3/api-docs], produces [application/json]}: openapiJson(HttpServletRequest,String,Locale)
    {GET [/v3/api-docs.yaml], produces [application/vnd.oai.openapi]}: openapiYaml(HttpServletRequest,String,Locale)
2024-12-12T14:43:33.318-07:00 TRACE 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
    o.s.w.u.SwaggerWelcomeWebMvc:
    {GET [/swagger-ui.html]}: redirectToUi(HttpServletRequest)
2024-12-12T14:43:33.320-07:00 TRACE 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
    o.s.w.u.SwaggerConfigResource:
    {GET [/v3/api-docs/swagger-config], produces [application/json]}: openapiJson(HttpServletRequest)
2024-12-12T14:43:33.324-07:00 DEBUG 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 9 mappings in 'requestMappingHandlerMapping'
2024-12-12T14:43:33.330-07:00 DEBUG 39932 --- [           main] o.s.w.s.h.BeanNameUrlHandlerMapping      : Detected 0 mappings in 'beanNameHandlerMapping'
2024-12-12T14:43:33.400-07:00 TRACE 39932 --- [           main] o.s.w.s.f.support.RouterFunctionMapping  : 0 RouterFunction(s) in 'routerFunctionMapping'
2024-12-12T14:43:33.427-07:00 TRACE 39932 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped [/webjars/**] onto ResourceHttpRequestHandler [classpath [META-INF/resources/webjars/]]
2024-12-12T14:43:33.427-07:00 TRACE 39932 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped [/**] onto ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]
2024-12-12T14:43:33.428-07:00 TRACE 39932 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped [/swagger-ui*/*swagger-initializer.js] onto ResourceHttpRequestHandler [classpath [META-INF/resources/webjars/]]
2024-12-12T14:43:33.429-07:00 TRACE 39932 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped [/swagger-ui*/**] onto ResourceHttpRequestHandler [classpath [META-INF/resources/webjars/]]
2024-12-12T14:43:33.429-07:00 DEBUG 39932 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/webjars/**, /**, /swagger-ui*/*swagger-initializer.js, /swagger-ui*/**] in 'resourceHandlerMapping'
2024-12-12T14:43:33.465-07:00 DEBUG 39932 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2024-12-12T14:43:33.542-07:00 DEBUG 39932 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 1 @ExceptionHandler, 1 ResponseBodyAdvice
2024-12-12T14:43:33.976-07:00  INFO 39932 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint beneath base path '/actuator'
2024-12-12T14:43:34.078-07:00  INFO 39932 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8888 (http) with context path '/'
2024-12-12T14:43:34.102-07:00  INFO 39932 --- [           main] o.i.hdd.s3.SpringbootExampleServicesApp  : Started SpringbootExampleServicesApp in 4.444 seconds (process running for 6.373)
2024-12-12T14:43:34.626-07:00  INFO 39932 --- [on(4)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-12-12T14:43:34.626-07:00  INFO 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-12-12T14:43:34.627-07:00 TRACE 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@4a8dbea6
2024-12-12T14:43:34.627-07:00 TRACE 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@26276164
2024-12-12T14:43:34.627-07:00 TRACE 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.theme.FixedThemeResolver@26278361
2024-12-12T14:43:34.628-07:00 TRACE 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected DefaultRequestToViewNameTranslator
2024-12-12T14:43:34.629-07:00 TRACE 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Detected SessionFlashMapManager
2024-12-12T14:43:34.631-07:00 DEBUG 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2024-12-12T14:43:34.631-07:00  INFO 39932 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

当我在浏览器中输入此 URL 时,收到 404 错误。

http://localhost:8888/springboot-example/v3/api-docs

这是生成的日志:

2024-12-12T14:44:07.459-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/springboot-example/v3/api-docs", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2024-12-12T14:44:07.467-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to HandlerExecutionChain with [ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]] and 3 interceptors
2024-12-12T14:44:07.481-07:00 DEBUG 39932 --- [nio-8888-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2024-12-12T14:44:07.486-07:00 DEBUG 39932 --- [nio-8888-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.servlet.resource.NoResourceFoundException: No static resource springboot-example/v3/api-docs.]
2024-12-12T14:44:07.486-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : No view rendering, null ModelAndView returned.
2024-12-12T14:44:07.486-07:00 DEBUG 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND, headers={masked}
2024-12-12T14:44:07.493-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2024-12-12T14:44:07.495-07:00 TRACE 39932 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : 2 matching mappings: [{ [/error], produces [text/html]}, { [/error]}]
2024-12-12T14:44:07.496-07:00 TRACE 39932 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
2024-12-12T14:44:07.507-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.web.method.HandlerMethod             : Arguments: [org.apache.catalina.core.ApplicationHttpRequest@42d5a1e6, org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleHttpServletResponse@360f1ef1]
2024-12-12T14:44:07.524-07:00 TRACE 39932 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerAdapter : Applying default cacheSeconds=-1
2024-12-12T14:44:07.528-07:00 DEBUG 39932 --- [nio-8888-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, text/html;q=0.8]
2024-12-12T14:44:07.528-07:00 TRACE 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : Rendering view [org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$StaticView@4050f757] 
2024-12-12T14:44:07.534-07:00 DEBUG 39932 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 404, headers={masked}

没有定义配置。 文档表明这应该开箱即用。
我很感激任何帮助。 谢谢。

swagger springdoc spring-boot-3
1个回答
0
投票

我解决了这个问题。 感谢 roar-s 建议查看已经运行的示例代码。 我无法找到一些正确运行代码的示例。 最终我添加了上下文路径,但没有使用正确的属性路径。 它应该是 server.servlet.context-path

© www.soinside.com 2019 - 2024. All rights reserved.