目录
swagger是什么?
swagger有什么用?
Swagger包含的工具集:
swagger的使用步骤:
swagger的相关注解:
Docket的源码
- 了解swagger的作用和概念
- 了解前后端分离
- 在SpringBoot中集成Swagger
swagger是什么?
- swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
- 直接运行,可以在线测试API接口,API是前后端的重要联系纽带
- 支持多种语言(java, php...)
- 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。
- 文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
swagger有什么用?
- 接口文档自动在线生成。
- 功能测试。
Swagger包含的工具集:
- Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger1.2文档转换成Swagger2.0文档等功能。
- Swagger-core:用于Java/Scala的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF…)、Servlets和Play框架进行集成。
- Swagger-js:用于JavaScript的Swagger实现。
- Swagger-node-express:Swagger模块,用于node.js的Express web应用框架。
- Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。
- Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码
swagger的使用步骤:
- 引入pomm的相关依赖
- 在代码中加入相应的配置,新建config包,写入swaggerConfig配置类
- 在basePackage指定的路径下使用swagger(使用api注解)
- 启动项目,浏览器打开http://ip:port/swagger-ui.html
swagger 的相关依赖:
</dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
swagger配置信息:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration//设置该类为spring配置类
@EnableSwagger2//开户swagger2
public class SwaggerConfig {
/**
* 创建API应用
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
* 本例采用指定扫描的包路径来定义指定要建立API的目录。
* .apis
* RequestHandlerSelectors 配置swagger扫描接口的方式
* basePackage() 指定要扫描哪些包
* any() 全部都扫描
* none() 全部不扫描
* withClassAnnotation() 扫描类上的注解 参数是一个注解的反射对象
* withMethodAnnotation() 扫描包上的注解
* .paths
* PathSelectors 路径扫描接口
* ant 配置以xxx 开头的路径
*
* @return
*/
@Bean //设置该方法的返回值为spring管理的bean
public Docket restApi() {//配置了swagger的docket的bean实例
return new Docket(DocumentationType.SWAGGER_2)
.groupName("标准接口")
.apiInfo(apiInfo("Spring Boot中使用Swagger2构建RESTful APIs", "1.0"))
.useDefaultResponseMessages(true)
.forCodeGeneration(false)
.select()
//RequestHandlerSelectors配置要扫描接口的方式
.apis(RequestHandlerSelectors.basePackage("com.example.learning.controller"))
.paths(PathSelectors.any())
.build();
}
/**
* 创建该API的基本信息(这些基本信息会展现在文档页面中)
* 访问地址:http://ip:port/swagger-ui.html
*
* @return
*/
private ApiInfo apiInfo(String title, String version) {//配置Swagger页面信息
return new ApiInfoBuilder()
.title(title)
.description("swagger")
.termsOfServiceUrl("https://swagger.io")
.contact("swagger")
.version("1.0")
.build();//构建者模式,快速构建一个对象
}
}
使用swagger
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;
@RestController
@RequestMapping("/api")
@Api(tags = "标准演示接口")
public class ApiController {
@Resource
private ObjectMapper mapper;
@PostMapping("/ps")
@ApiOperation(value = "接受json参数", notes = "演示json参数是否接受成功")
public String post(@ApiParam(name = "接收json参数", defaultValue = "{}")
@RequestBody String json) throws IOException {
Map map = mapper.readValue(json, Map.class);
System.out.println(map);
return json;
}
}
swagger的相关注解:
- @Configuration:表明这是一个配置类
- @EnableSwagger2:开启Swagger2
- @Api:放在类上,说明该类的作用。
- @ApiOperation:放在方法上,说明该方法的作用。
- @ApiImplicitParams:用在方法上包含一组参数说明。
- code:数字,例如400
- message:信息,例如“请求参数没填好”
- response:抛出异常的类
- @ApiImplicitParam:用来注解来给方法入参增加说明,一个请求能数。
- @ApiResponses:用于表示一组响应。
- @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
- @ApiModel:用对象来接收参数,描述一个Model的信息(一般用于在请求参数无法使用@ApiImplicitParam注解进行描述的时候)
- @ApiModelProperty:用对象接收参数时,描述对象的一个字段
- @ApiIgnore:使用该注解忽略这个API
- @ApiError :发生错误返回的信息
Docket的源码
/*
Docket的源码
Docket中拥有的属性,Swagger可更改这些属性
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package springfox.documentation.spring.web.plugins;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.PathProvider;
import springfox.documentation.annotations.Incubating;
import springfox.documentation.builders.BuilderDefaults;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.schema.AlternateTypeRules;
import springfox.documentation.schema.CodeGenGenericTypeNamingStrategy;
import springfox.documentation.schema.DefaultGenericTypeNamingStrategy;
import springfox.documentation.schema.WildcardType;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiListingReference;
import springfox.documentation.service.Operation;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.service.Tag;
import springfox.documentation.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.GenericTypeNamingStrategy;
import springfox.documentation.spi.service.DocumentationPlugin;
import springfox.documentation.spi.service.contexts.ApiSelector;
import springfox.documentation.spi.service.contexts.DocumentationContext;
import springfox.documentation.spi.service.contexts.DocumentationContextBuilder;
import springfox.documentation.spi.service.contexts.SecurityContext;
public class Docket implements DocumentationPlugin {
public static final String DEFAULT_GROUP_NAME = "default";
private final DocumentationType documentationType;
private final List<SecurityContext> securityContexts = Lists.newArrayList();
private final Map<RequestMethod, List<ResponseMessage>> responseMessages = Maps.newHashMap();
private final List<Parameter> globalOperationParameters = Lists.newArrayList();
private final List<Function<TypeResolver, AlternateTypeRule>> ruleBuilders = Lists.newArrayList();
private final Set<Class> ignorableParameterTypes = Sets.newHashSet();
private final Set<String> protocols = Sets.newHashSet();
private final Set<String> produces = Sets.newHashSet();
private final Set<String> consumes = Sets.newHashSet();
private final Set<ResolvedType> additionalModels = Sets.newHashSet();
private final Set<Tag> tags = Sets.newHashSet();
private PathProvider pathProvider;
private List<? extends SecurityScheme> securitySchemes;
private Ordering<ApiListingReference> apiListingReferenceOrdering;
private Ordering<ApiDescription> apiDescriptionOrdering;
private Ordering<Operation> operationOrdering;
private ApiInfo apiInfo;
private String groupName;
private boolean enabled;//是否启动swagger
private GenericTypeNamingStrategy genericsNamingStrategy;
private boolean applyDefaultResponseMessages;
private String host;
private Optional<String> pathMapping;
private ApiSelector apiSelector;
private boolean enableUrlTemplating;
private List<VendorExtension> vendorExtensions;
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
public Docket extensions(List<VendorExtension> vendorExtensions) {
this.vendorExtensions.addAll(vendorExtensions);
return this;
}
public Docket apiInfo(ApiInfo apiInfo) {
this.apiInfo = (ApiInfo)BuilderDefaults.defaultIfAbsent(apiInfo, apiInfo);
return this;
}
public Docket securitySchemes(List<? extends SecurityScheme> securitySchemes) {
this.securitySchemes = securitySchemes;
return this;
}
public Docket securityContexts(List<SecurityContext> securityContexts) {
this.securityContexts.addAll(securityContexts);
return this;
}
public Docket groupName(String groupName) {
this.groupName = (String)BuilderDefaults.defaultIfAbsent(groupName, this.groupName);
return this;
}
public Docket pathProvider(PathProvider pathProvider) {
this.pathProvider = pathProvider;
return this;
}
public Docket globalResponseMessage(RequestMethod requestMethod, List<ResponseMessage> responseMessages) {
this.responseMessages.put(requestMethod, responseMessages);
return this;
}
public Docket globalOperationParameters(List<Parameter> operationParameters) {
this.globalOperationParameters.addAll(BuilderDefaults.nullToEmptyList(operationParameters));
return this;
}
public Docket ignoredParameterTypes(Class... classes) {
this.ignorableParameterTypes.addAll(Arrays.asList(classes));
return this;
}
public Docket produces(Set<String> produces) {
this.produces.addAll(produces);
return this;
}
public Docket consumes(Set<String> consumes) {
this.consumes.addAll(consumes);
return this;
}
@Incubating("2.3")
public Docket host(String host) {
this.host = (String)BuilderDefaults.defaultIfAbsent(host, this.host);
return this;
}
public Docket protocols(Set<String> protocols) {
this.protocols.addAll(protocols);
return this;
}
public Docket alternateTypeRules(AlternateTypeRule... alternateTypeRules) {
this.ruleBuilders.addAll(FluentIterable.from(Lists.newArrayList(alternateTypeRules)).transform(this.identityRuleBuilder()).toList());
return this;
}
public Docket operationOrdering(Ordering<Operation> operationOrdering) {
this.operationOrdering = operationOrdering;
return this;
}
public Docket directModelSubstitute(Class clazz, Class with) {
this.ruleBuilders.add(this.newSubstitutionFunction(clazz, with));
return this;
}
public Docket genericModelSubstitutes(Class... genericClasses) {
Class[] arr$ = genericClasses;
int len$ = genericClasses.length;
for(int i$ = 0; i$ < len$; ++i$) {
Class clz = arr$[i$];
this.ruleBuilders.add(this.newGenericSubstitutionFunction(clz));
}
return this;
}
public Docket useDefaultResponseMessages(boolean apply) {
this.applyDefaultResponseMessages = apply;
return this;
}
public Docket apiListingReferenceOrdering(Ordering<ApiListingReference> apiListingReferenceOrdering) {
this.apiListingReferenceOrdering = apiListingReferenceOrdering;
return this;
}
public Docket apiDescriptionOrdering(Ordering<ApiDescription> apiDescriptionOrdering) {
this.apiDescriptionOrdering = apiDescriptionOrdering;
return this;
}
public Docket enable(boolean externallyConfiguredFlag) {
this.enabled = externallyConfiguredFlag;
return this;
}
public Docket forCodeGeneration(boolean forCodeGen) {
if (forCodeGen) {
this.genericsNamingStrategy = new CodeGenGenericTypeNamingStrategy();
}
return this;
}
public Docket pathMapping(String path) {
this.pathMapping = Optional.fromNullable(path);
return this;
}
@Incubating("2.1.0")
public Docket enableUrlTemplating(boolean enabled) {
this.enableUrlTemplating = enabled;
return this;
}
public Docket additionalModels(ResolvedType first, ResolvedType... remaining) {
this.additionalModels.add(first);
this.additionalModels.addAll(Sets.newHashSet(remaining));
return this;
}
public Docket tags(Tag first, Tag... remaining) {
this.tags.add(first);
this.tags.addAll(Sets.newHashSet(remaining));
return this;
}
public ApiSelectorBuilder select() {
return new ApiSelectorBuilder(this);
}
public DocumentationContext configure(DocumentationContextBuilder builder) {
return builder.apiInfo(this.apiInfo).selector(this.apiSelector).applyDefaultResponseMessages(this.applyDefaultResponseMessages).additionalResponseMessages(this.responseMessages).additionalOperationParameters(this.globalOperationParameters).additionalIgnorableTypes(this.ignorableParameterTypes).ruleBuilders(this.ruleBuilders).groupName(this.groupName).pathProvider(this.pathProvider).securityContexts(this.securityContexts).securitySchemes(this.securitySchemes).apiListingReferenceOrdering(this.apiListingReferenceOrdering).apiDescriptionOrdering(this.apiDescriptionOrdering).operationOrdering(this.operationOrdering).produces(this.produces).consumes(this.consumes).host(this.host).protocols(this.protocols).genericsNaming(this.genericsNamingStrategy).pathMapping(this.pathMapping).enableUrlTemplating(this.enableUrlTemplating).additionalModels(this.additionalModels).tags(this.tags).vendorExtentions(this.vendorExtensions).build();
}
public String getGroupName() {
return this.groupName;
}
public boolean isEnabled() {
return this.enabled;
}
public DocumentationType getDocumentationType() {
return this.documentationType;
}
public boolean supports(DocumentationType delimiter) {
return this.documentationType.equals(delimiter);
}
private Function<AlternateTypeRule, Function<TypeResolver, AlternateTypeRule>> identityRuleBuilder() {
return new Function<AlternateTypeRule, Function<TypeResolver, AlternateTypeRule>>() {
public Function<TypeResolver, AlternateTypeRule> apply(AlternateTypeRule rule) {
return Docket.this.identityFunction(rule);
}
};
}
private Function<TypeResolver, AlternateTypeRule> identityFunction(final AlternateTypeRule rule) {
return new Function<TypeResolver, AlternateTypeRule>() {
public AlternateTypeRule apply(TypeResolver typeResolver) {
return rule;
}
};
}
Docket selector(ApiSelector apiSelector) {
this.apiSelector = apiSelector;
return this;
}
private Function<TypeResolver, AlternateTypeRule> newSubstitutionFunction(final Class clazz, final Class with) {
return new Function<TypeResolver, AlternateTypeRule>() {
public AlternateTypeRule apply(TypeResolver typeResolver) {
return AlternateTypeRules.newRule(typeResolver.resolve(clazz, new Type[0]), typeResolver.resolve(with, new Type[0]), -2147480648);
}
};
}
private Function<TypeResolver, AlternateTypeRule> newGenericSubstitutionFunction(final Class clz) {
return new Function<TypeResolver, AlternateTypeRule>() {
public AlternateTypeRule apply(TypeResolver typeResolver) {
return AlternateTypeRules.newRule(typeResolver.resolve(clz, new Type[]{WildcardType.class}), typeResolver.resolve(WildcardType.class, new Type[0]), -2147481648);
}
};
}
}