SpringFox 找不到 jax-rs 端点
SpringFox not finding jax-rs endpoints
解决后,我现在发现SpringFox的JSON回复没有显示任何APIs:
{
"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 扫描器查找实现 classes:
@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 注释的示例 class:
@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 将记录使用 Spring MVC 实现的 REST 服务 - 它就像添加 @EnableSwagger2
注释一样简单
@SpringBootApplication
@EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我设法让 SpringFox 使用 JAX-RS
起初我添加了一些 swagger 依赖项以及 SpringFox:
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(泽西岛):
@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());
}
}
就是这样!现在,您的 JAX-RS 端点将由 Swagger 记录。
我使用了以下示例端点:
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 端点
的文档
有关授权的其他信息:
- 如果要为 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 资源添加 authetnctioan:
@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
);
}
}
解决
{
"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 扫描器查找实现 classes:
@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 注释的示例 class:
@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 将记录使用 Spring MVC 实现的 REST 服务 - 它就像添加 @EnableSwagger2
注释一样简单
@SpringBootApplication
@EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我设法让 SpringFox 使用 JAX-RS 起初我添加了一些 swagger 依赖项以及 SpringFox:
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(泽西岛):
@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());
}
}
就是这样!现在,您的 JAX-RS 端点将由 Swagger 记录。 我使用了以下示例端点:
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 端点
的文档有关授权的其他信息:
- 如果要为 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 资源添加 authetnctioan:
@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
);
}
}