How to confirgure swagger to handle custom Control

2019-08-09 18:09发布

In my Spring (4.3.2) project I'm using Swagger (2.7.0) to automatically generate docs and swagger-ui for my project. This worked great so far.

But now I determined that I need to be able to declare Path Variables at the Controller level (not method level). And I need to teach swagger to discover these path variables and add them to docs and swagger-ui.

I've created custom annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasCommonPathVariable {
    /**
     * The URI template variable to bind to.
     */
    String name();
    Class<?> type();
    String defaultValue() default "";
}

And I'm using it like this:

@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
}

I do not have controller methods that mentions parameters with Spring's PathVariable annotation, and the point is I'm not allowed to do so (it's due to the fact that I'm building micro-framework).

So question is: how to teach swagger to discover path variables described using custom annotation HasCommonPathVariable applied at the controller level?

1条回答
混吃等死
2楼-- · 2019-08-09 18:55

Ok, I've figured it out. Here is the solution. This bean needs to be registered in the context. Swagger will discover this bean and use it as one of the plugins to enrich operations

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();
    }
}
查看更多
登录 后发表回答