Spring Boot - Swagger 文档不起作用

dav*_*009 5 java rest swagger-ui spring-boot swagger-2.0

我有一个使用 Spring Boot 构建的 REST API 项目,我想记录我的所有端点。我已经实现了 swagger 来做到这一点并且成功了,但是最近我的项目不再运行了,配置与创建项目时的配置相同并且 Swagger 可以工作。

尝试运行项目时出现此错误:

WARN 17868 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
....
ERROR 17868 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

这是我的项目配置:

主要的

package com.red.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@PropertySource(value = "classpath:application.properties")
@PropertySource(value = "classpath:propiedades.properties")
public class BackRedApplication {

    public static void main(String[] args) {
    SpringApplication.run(BackRedApplication.class, args);
}

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
       return new PropertySourcesPlaceholderConfigurer();
    }
}
Run Code Online (Sandbox Code Playgroud)

Pom.xml

...
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.0-SNAPSHOT</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.red.api</groupId>
<artifactId>RED</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>RED</name>
<description>RED</description>
<properties>
    <java.version>11</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-ldap</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>3.0.0</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20200518</version>
    </dependency>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports</artifactId>
        <version>6.8.0</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>io</artifactId>
        <version>7.1.9</version>
    </dependency>
    
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>kernel</artifactId>
        <version>7.1.9</version>
    </dependency>
    
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>layout</artifactId>
        <version>7.1.9</version>
    </dependency>
</dependencies>
...
Run Code Online (Sandbox Code Playgroud)

配置类

package com.red.api.configuracion;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.ObjectMapper;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;


@Configuration
@EnableSwagger2
public class Configuracion {

    @Bean
    public RestTemplate rest() {
        return new RestTemplate();
    }

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }

    @Bean
    public Docket redApi() {
        return new Docket(DocumentationType.SWAGGER_2).select()
                .apis(RequestHandlerSelectors.basePackage("com.co.dejsoftware.red.ws"))
                .paths(PathSelectors.any()).build();
    }

}
Run Code Online (Sandbox Code Playgroud)

控制器

package com.red.api.ws;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.red.api.interfaces.InterfaceSeguridad;

@RestController
@CrossOrigin
@RequestMapping("/seguridad")
public class WsSeguridad {

    private Logger logger = LogManager.getLogger(WsSeguridad.class);

    @Autowired
    private InterfaceSeguridad servicioSeguridad;

    @PostMapping(path="/getToken", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Object> getToken(@RequestHeader(name = "user") String usuario, 
            @RequestHeader(name = "pwd") String contrasena) {
    
        try {
        
            return ResponseEntity.ok(servicioSeguridad.getToken(usuario, contrasena));
        
        } catch (Exception e) {
            logger.error(e);
        
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

界面

package com.red.api.interfaces;

import org.springframework.http.ResponseEntity;

public interface InterfaceSeguridad {

    public ResponseEntity<Object> getToken(String usuario, String contrasena);
}
Run Code Online (Sandbox Code Playgroud)

执行

package com.red.api.implementacion;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.red.api.interfaces.InterfaceSeguridad;

@Service
public class ServicioSeguridad implements InterfaceSeguridad {

    private Logger logger = LogManager.getLogger(ServicioSeguridad.class);

    public ResponseEntity<Object> getToken(String usuario, String contrasena) {
        try {
            System.out.println("usuario... " + usuario);
            System.out.println("contrasena... " + contrasena);
        
            JSONObject item = new JSONObject();
            item.put("description", "Success...");
            item.put("usuario", usuario);
            item.put("contrasena", contrasena);
            String jsonResponse = new JSONObject().put("exito", item).toString();
        
            return ResponseEntity.ok(jsonResponse);
        }catch (Exception e) {
            logger.error(e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Joã*_*ias 8

我知道这不能直接解决您的问题,但请考虑转向springdoc。Springfox 目前存在如此多的 bug,使用起来很痛苦。由于 Spring WebFlux 支持,我已经转向springdoc2 年前,对此我感到非常高兴。此外,它还支持 Kotlin 协程,我不确定 Springfox 是否支持。

如果您决定迁移,springdoc甚至还有迁移指南

  • 按照 OpenAPI 规范记录您的 API?当然,这就是它的作用。除非你对“Springfox”有一些非常奇怪的用例,而“springdoc”不支持(我对此表示怀疑),否则我会说你很好。但请尝试并检查一下。 (2认同)