Swagger
是一个规范且完整的,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务以及 集成Swagger自动生成API文档。
Swagger 的目标是对 REST [API]
定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 Swagger 进行正确定义,用户可以理解远程服务并使用最少实现逻辑与远程服务进行交互。与为底层编程所实现的接口类似,Swagger 消除了调用服务时可能会有的猜测。
支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档
,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。
提供 Web 页面在线测试 API:光有文档还不够,Swagger 生成的文档还支持在线测试
。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。
前后端集成联调,前端人员和后端人员无法做到 “及时协商,尽早解决”,通过swagger可以直观展现实时调整,减少沟通成本。
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.7</version>
</dependency>
<!--测试组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--添加Spring 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>
server:
port: 17006
/**
* Swagger配置类
* @author 共饮一杯无
*/
//指定为配置类
@Configuration
//开启Swagger2
@EnableSwagger2
public class SwaggerConfig {
/**
* 添加摘要信息(Docket)
*/
@Bean
public Docket controllerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("API文档标题")
.description("文档描述:用于实时查看、测试API")
.contact(new Contact("共饮一杯无", "https://zhanjq./", ""))
.version("版本号:1.0")
.build())
.select()
//API基础扫描路径
.apis(RequestHandlerSelectors.basePackage("com.zjq.swagger"))
.paths(PathSelectors.any())
.build();
}
}
/**
* SpringSwagger案例
* @author zjq
*/
@SpringBootApplication
//启用swagger
@EnableSwagger2
public class SpringSwaggerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSwaggerApplication.class, args);
}
}
带swagger注解的Controller类:
带swagger注解的实体类:
@Api(value = "用户管理", description = "系统中的用户操作")
@ApiOperation
: 这个注解用于方法级别,描述一个特定的API操作。例如:@ApiOperation(value = "获取所有用户", notes = "返回所有用户列表")
@ApiParam
: 这个注解用于描述方法参数的细节,如用途、是否必需、默认值等。例如:@ApiParam(value = "用户ID", required = true)
@ApiResponse
: 描述API的响应状态码及可能的响应体。例如:@ApiResponse(code = 200, message = "成功获取用户", response = User.class)
@ApiResponses
: 包含多个@ApiResponse
,可以描述多个可能的响应情况。例如:@ApiResponses(value = {
@ApiResponse(code = 200, message = "成功"),
@ApiResponse(code = 404, message = "未找到资源"),
@ApiResponse(code = 500, message = "服务器错误")
})
@ApiIgnore
: 如果你不希望某个方法出现在Swagger文档中,可以使用此注解。例如:@ApiIgnore
@GetMapping("/test")
public String test() {
return "This is a test endpoint";
}
@ApiModel
: 用于描述一个模型(即类)的结构。例如:@ApiModel(value = "用户模型", description = "用户数据模型")
public class User {
}
@ApiModelProperty
: 描述模型属性的细节。例如:@ApiModelProperty(value = "用户ID", example = "1")
private Integer id;
@ApiImplicitParam
这个注解通常用于方法级别,而不是参数级别,它描述的是隐式参数,即那些可能不直接从方法签名中明显看出的参数。
它可以用来描述查询参数 (query parameters
)、请求头 (headers
) 或者其他非显式的参数类型。
当你需要描述多个这样的参数时,可以使用 @ApiImplicitParams
,这是一个 @ApiImplicitParam
的数组。例如:
@GetMapping("/users")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "Page number of the result set", paramType = "query", dataType = "integer"),
@ApiImplicitParam(name = "limit", value = "Size of the page", paramType = "query", dataType = "integer")
})
public List<User> getUsers(@RequestParam Integer page, @RequestParam Integer limit) {
// ...
}
@ApiParam
更适用于描述与方法签名直接相关的参数,而 @ApiImplicitParam
更适合描述那些通过其他方式(如请求查询字符串或头部)传递的参数。
@ApiImplicitParam
提供了一种方法来集中描述多个参数,特别是在参数数量较多的情况下,这比在每个参数上使用 @ApiParam
要更整洁。
Caused by: java.lang.NullPointerException: null
at springfox.documentation.spi.service.contexts.Orderings$8.compare(Orderings.java:112) ~[springfox-spi-2.9.2.jar:null]
at springfox.documentation.spi.service.contexts.Orderings$8.compare(Orderings.java:109) ~[springfox-spi-2.9.2.jar:null]
解决办法:
版本对应(Maven官方仓库:)
SPB(SpringBoot) 2.7 以下 + Swagger-ui 和Swagger2 2.9.2
SPB(SpringBoot) 2.7 往上 + springfox-boot-starter(3.0.0包括Swagger-ui 和Swagger2 3.0.0)
SPB(SpringBoot) 3.0往上直接改用Springdoc OpenAPI
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.27.jar:5.3.27]
at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_171]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:937) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.11.jar:2.7.11]
at com.zjq.swagger.SpringSwaggerApplication.main(SpringSwaggerApplication.java:16) [classes/:na]
Caused by: java.lang.NullPointerException: null
at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0]
at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0]
at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[na:1.8.0_171]
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:1.8.0_171]
at java.util.TimSort.sort(TimSort.java:220) ~[na:1.8.0_171]
at java.util.Arrays.sort(Arrays.java:1512) ~[na:1.8.0_171]
at java.util.ArrayList.sort(ArrayList.java:1462) ~[na:1.8.0_171]
at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) ~[na:1.8.0_171]
at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_171]
at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_171]
at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_171]
at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_171]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[na:1.8.0_171]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_171]
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_171]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_171]
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_171]
解决办法:
在配置类注入如下bean:
@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
参考:
官方网站:
官方文档:
本文内容到此结束了,
如有收获欢迎点赞?收藏?关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问?欢迎各位指出。
主页:保持热爱,奔赴下一场山海。???