如何配置招摇来处理自定义控制器级路径变量注释?
How to confirgure swagger to handle custom Controller-level PathVariable annotations?
在我的 Spring (4.3.2) 项目中,我使用 Swagger (2.7.0) 为我的项目自动生成文档和 swagger-ui。到目前为止效果很好。
但现在我确定我需要能够在控制器级别(而不是方法级别)声明路径变量。我需要教 swagger 发现这些路径变量并将它们添加到文档和 swagger-ui.
我创建了自定义注释
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasCommonPathVariable {
/**
* The URI template variable to bind to.
*/
String name();
Class<?> type();
String defaultValue() default "";
}
我是这样使用它的:
@RestController
@Secured(SecurityConstants.ROLE_USER)
@RequestMapping(path = "/rest/api/v1/env/{envId}/asset-type")
@HasCommonPathVariable(name = "envId", type = Long.class)
public class AssetTypeRestController extends CustomRestControllerBase<Long, AssetTypeRow, AssetTypeService> {
// ... contorller code
}
我没有使用 Spring 的 PathVariable 注释提及参数的控制器方法,关键是我不允许这样做(这是因为我是 building 微框架)。
所以问题是:如何教 swagger 发现使用在控制器级别应用的自定义注释 HasCommonPathVariable
描述的路径变量?
好的,我知道了。这是解决方案。这个 bean 需要在上下文中注册。 Swagger 将发现这个 bean 并将其用作插件之一来丰富操作
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.core.annotation.Order;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
public class CommonPathVariableOperationBuilderPlugin implements OperationBuilderPlugin {
protected Logger log = Logger.getLogger(getClass());
private TypeResolver typeResolver;
public CommonPathVariableOperationBuilderPlugin(TypeResolver typeResolver) {
this.typeResolver = typeResolver;
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
@Override
public void apply(OperationContext opCtx) {
List<Parameter> ret = new ArrayList<Parameter>();
Optional<HasCommonPathVariable> annSingle = opCtx.findControllerAnnotation(HasCommonPathVariable.class);
if (annSingle.isPresent()) {
ret.add(addParameter(annSingle.get()));
}
Optional<HasCommonPathVariables> annPlural = opCtx.findControllerAnnotation(HasCommonPathVariables.class);
if (annPlural.isPresent()) {
for (HasCommonPathVariable ann : annPlural.get().value()) {
ret.add(addParameter(ann));
}
}
opCtx.operationBuilder().parameters(ret);
}
private Parameter addParameter(HasCommonPathVariable ann) {
ParameterBuilder pb = new ParameterBuilder();
pb.parameterType("path").name(ann.name()).type(typeResolver.resolve(ann.type()));
pb.modelRef(new ModelRef("string"));
pb.required(true);
if (!"".equals(ann.defaultValue())) {
pb.defaultValue(ann.defaultValue());
}
return pb.build();
}
}
在我的 Spring (4.3.2) 项目中,我使用 Swagger (2.7.0) 为我的项目自动生成文档和 swagger-ui。到目前为止效果很好。
但现在我确定我需要能够在控制器级别(而不是方法级别)声明路径变量。我需要教 swagger 发现这些路径变量并将它们添加到文档和 swagger-ui.
我创建了自定义注释
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasCommonPathVariable {
/**
* The URI template variable to bind to.
*/
String name();
Class<?> type();
String defaultValue() default "";
}
我是这样使用它的:
@RestController
@Secured(SecurityConstants.ROLE_USER)
@RequestMapping(path = "/rest/api/v1/env/{envId}/asset-type")
@HasCommonPathVariable(name = "envId", type = Long.class)
public class AssetTypeRestController extends CustomRestControllerBase<Long, AssetTypeRow, AssetTypeService> {
// ... contorller code
}
我没有使用 Spring 的 PathVariable 注释提及参数的控制器方法,关键是我不允许这样做(这是因为我是 building 微框架)。
所以问题是:如何教 swagger 发现使用在控制器级别应用的自定义注释 HasCommonPathVariable
描述的路径变量?
好的,我知道了。这是解决方案。这个 bean 需要在上下文中注册。 Swagger 将发现这个 bean 并将其用作插件之一来丰富操作
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.core.annotation.Order;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
public class CommonPathVariableOperationBuilderPlugin implements OperationBuilderPlugin {
protected Logger log = Logger.getLogger(getClass());
private TypeResolver typeResolver;
public CommonPathVariableOperationBuilderPlugin(TypeResolver typeResolver) {
this.typeResolver = typeResolver;
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
@Override
public void apply(OperationContext opCtx) {
List<Parameter> ret = new ArrayList<Parameter>();
Optional<HasCommonPathVariable> annSingle = opCtx.findControllerAnnotation(HasCommonPathVariable.class);
if (annSingle.isPresent()) {
ret.add(addParameter(annSingle.get()));
}
Optional<HasCommonPathVariables> annPlural = opCtx.findControllerAnnotation(HasCommonPathVariables.class);
if (annPlural.isPresent()) {
for (HasCommonPathVariable ann : annPlural.get().value()) {
ret.add(addParameter(ann));
}
}
opCtx.operationBuilder().parameters(ret);
}
private Parameter addParameter(HasCommonPathVariable ann) {
ParameterBuilder pb = new ParameterBuilder();
pb.parameterType("path").name(ann.name()).type(typeResolver.resolve(ann.type()));
pb.modelRef(new ModelRef("string"));
pb.required(true);
if (!"".equals(ann.defaultValue())) {
pb.defaultValue(ann.defaultValue());
}
return pb.build();
}
}