【问题标题】:SpringFox not finding jax-rs endpointsSpringFox 没有找到 jax-rs 端点
【发布时间】:2015-10-01 00:58:13
【问题描述】:

解决Using Springfox to document jax-rs services in a Spring app后,现在发现SpringFox的JSON回复没有显示任何API:

{
  "swagger": "2.0",
  "info": {
    "description": "Some description",
    "version": "1.0",
    "title": "My awesome API",
    "contact": {
      "name": "my-email@domain.org"
    },
    "license": {}
  },
  "host": "localhost:9090",
  "basePath": "/myapp"
}

这里是 springfox-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean class="com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON" />
    <bean class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider" />
    <bean class="com.wordnik.swagger.jaxrs.listing.ResourceListingProvider" />
</beans>

这是在一个属性文件中:

swagger.resourcePackage=org.myapp

Swagger 被配置为使用反射 jax-rs 扫描器查找实现类:

@Component
public class SwaggerConfiguration {

    @Value("${swagger.resourcePackage}")
    private String resourcePackage;

    @PostConstruct
    public void init() {
        ReflectiveJaxrsScanner scanner = new ReflectiveJaxrsScanner();
        scanner.setResourcePackage(resourcePackage);
        ScannerFactory.setScanner(scanner);

        ClassReaders.setReader(new DefaultJaxrsApiReader());

        SwaggerConfig config = ConfigFactory.config();
        config.setApiVersion(apiVersion);
        config.setBasePath(basePath);
    }

    public String getResourcePackage() {
        return resourcePackage;
    }

    public void setResourcePackage(String resourcePackage) {
        this.resourcePackage = resourcePackage;
    }
}

这是文档配置:

@Configuration
@EnableSwagger2
public class ApiDocumentationConfiguration {
    @Bean
    public Docket documentation() {
        System.out.println("=========================================== Initializing Swagger");
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build()
                .pathMapping("/")
                .apiInfo(metadata());
    }

    @Bean
    public UiConfiguration uiConfig() {
        return UiConfiguration.DEFAULT;
    }

    private ApiInfo metadata() {
        return new ApiInfoBuilder()
                .title("My awesome API")
                .description("Some description")
                .version("1.0")
                .contact("my-email@domain.org")
                .build();
    }
}

这是一个带有 api 注释的示例类:

@Api(value = "activity")
@Service
@Path("api/activity")
@Produces({ MediaType.APPLICATION_JSON })
public class ActivityService {

    @Autowired
    private CommandExecutor commandExecutor;
    @Autowired
    private FetchActivityCommand fetchActivityCommand;

    @ApiOperation(value = "Fetch logged-in user's activity", httpMethod = "GET", response = Response.class)
    @GET
    @Path("/mine")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    @Authorization(rejectionMessage = Properties.Authorization.NOT_LOGGED_IN_MESSAGE_PREFIX + "view your activities.")
    public List<Activity> listMyActivities(@Context HttpServletResponse response, @Context HttpServletRequest request) throws IOException {
        return buildActivityList(response, (UUID) request.getSession().getAttribute(Properties.Session.SESSION_KEY_USER_GUID));
    }
    ...
}

为什么不公开 API?使用 wordnik swagger 库会解决这个问题,还是改进解决方案?

【问题讨论】:

  • 不幸的是 springfox 不支持 jax-rs 注释。我认为使用 swagger-core 库会更好。
  • @dilip,swagger 是否直接支持 jax-rs 注解?
  • 是的,它确实支持它
  • @DilipKrishnan - 谢谢,这正是我需要的帮助。我关注了github.com/swagger-api/swagger-core/wiki/…,然后在上面添加了 swagger-ui。

标签: java jax-rs swagger wordnik springfox


【解决方案1】:

默认情况下,SpringFox 将记录您使用 Spring MVC 实现的 REST 服务 - 就像添加 @EnableSwagger2 注释一样简单

@SpringBootApplication
@EnableSwagger2
public class Application {

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

}

我设法让 SpringFox 与 JAX-RS 一起工作 起初,我在 SpringFox 中添加了一些 swagger 依赖项:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-jersey")
    compile("io.springfox:springfox-swagger-ui:2.4.0")
    compile("io.springfox:springfox-swagger2:2.4.0")
    compile("io.swagger:swagger-jersey2-jaxrs:1.5.8")
    testCompile("junit:junit")
}

然后我在我的 spring-boot 应用程序中启用了带有 Swagger 的 JAX-RS (Jersey):

@Component
@ApplicationPath("/api")
public static class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {

        BeanConfig swaggerConfig = new BeanConfig();
        swaggerConfig.setBasePath("/api");
        SwaggerConfigLocator.getInstance().putConfig(SwaggerContextService.CONFIG_ID_DEFAULT, swaggerConfig);

        packages(getClass().getPackage().getName(), ApiListingResource.class.getPackage().getName());
    }

}

请注意,所有 JAX-RS 端点都将在 /api 上下文中 - 否则会与 Spring-MVC 调度程序冲突

最后我们应该将为 Jersey 端点生成的 swagger json 添加到 Springfox:

@Component
@Primary
public static class CombinedSwaggerResourcesProvider implements SwaggerResourcesProvider {

    @Resource
    private InMemorySwaggerResourcesProvider inMemorySwaggerResourcesProvider;

    @Override
    public List<SwaggerResource> get() {

        SwaggerResource jerseySwaggerResource = new SwaggerResource();
        jerseySwaggerResource.setLocation("/api/swagger.json");
        jerseySwaggerResource.setSwaggerVersion("2.0");
        jerseySwaggerResource.setName("Jersey");

        return Stream.concat(Stream.of(jerseySwaggerResource), inMemorySwaggerResourcesProvider.get().stream()).collect(Collectors.toList());
    }

}

就是这样!现在 Swagger 将记录您的 JAX-RS 端点。 我使用了以下示例端点:

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Component;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Component
@Path("/hello")
@Api
public class Endpoint {

    @GET
    @ApiOperation("Get message")
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello";
    }

}

现在,当您启动服务器并转到 http://localhost:8080/swagger-ui.html 时,您将看到 JAX-RS 端点的文档。 使用页面顶部的组合框切换到 Spring MVC 端点的文档

【讨论】:

  • 感谢您的回答。我收到以下错误:*************************** 应用程序无法启动 ************* ************** 描述:一个组件需要一个无法找到的“springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider”类型的 bean。行动:考虑在你的配置中定义一个“springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider”类型的bean。你在哪里定义了 InMemorySwaggerResourcesProvider?
  • @yeremy 确保您的 Spring Boot 应用程序类上有 @EnableSwagger2 注释
  • @bedrin :我已经能够在 springfox swagger 2 上列出球衣端点。但是之前可见的授权按钮已经消失了..你能在这里帮忙吗?请看:当我从下拉列表中选择默认时,授权按钮出现
  • 我可以浏览:localhost:5000/swagger-ui.html#,它正在为我加载 UI,但我收到错误为“500:{“timestamp”:“2021-05-25T14:22:23.485+0000 ","status":500,"error":"Internal Server Error","message":"No message available","path":"/api/swagger.json"} localhost:5000/api/swagger.json" 而且,虽然我试图浏览 localhost:5000/api/swagger.json" ,我得到 java.lang.NullPointerException: null at org.glassfish.jersey.server.ResourceConfig.getProperties(ResourceConfig.java:751)
  • 您是否会使用 AspectJ?您的 NPE 与此类似:github.com/spring-projects/spring-boot/issues/6395
【解决方案2】:

关于授权的其他信息:

  • 如果您想为 Jersey 资源添加身份验证:
BeanConfig swaggerConfig = new BeanConfig();
Swagger swagger = new Swagger();

swagger.securityDefinition("apiKeyAuth", new ApiKeyAuthDefinition("Authorization", In.HEADER));
  
new SwaggerContextService().updateSwagger(swagger);
swaggerConfig.setBasePath("/api");
SwaggerConfigLocator.getInstance().putConfig(SwaggerContextService.CONFIG_ID_DEFAULT, swaggerConfig);

当然这是带有 JWT 令牌的 Auth。如果您需要基本身份验证,请使用:

swagger.securityDefinition("basicAuth", new BasicAuthDefinition());
  • 如果您需要为 Spring 资源添加身份验证:
@Configuration
public class SwaggerSpringConfig {
    
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.yourPackage"))
                .paths(PathSelectors.any())
                .build()
                .enable(true)
                .securitySchemes(Lists.newArrayList(apiKey()));
    }

    private ApiKey apiKey() {
        return new ApiKey("AUTHORIZATION", "Authorization", "header");
    }

    @Bean
    SecurityConfiguration security() {
        return new SecurityConfiguration(
                null,
                null,
                null,
                null,
                null,
                ApiKeyVehicle.HEADER,
                "Authorization",
                null
        );
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    相关资源
    最近更新 更多