spring boot:用swagger3生成接口文档,支持全局通用参数(swagger 3.0.0 / spring boot 2.3.2)
一,什么是 swagger?
1, Swagger 是一个规范和完整的文档框架,
用于生成、描述、调用和可视化 RESTful 风格的 Web 服务文档
官方网站:
https://swagger.io/
2,使用 swagger 要注意的地方:
在生产环境中必须关闭 swagger,
它本身只用于前后端工程师之间的沟通,
可以专门使用一台内部服务器来展示 ui 供访问,
即使在这上面要做好安全措施
3, 因为 swagger3.0.0 已发布,本文使用了最新版
如果有还在用 2.x 版本的请参考时注意区分
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/24/springboot-yong-swagger3-sheng-cheng-jie-kou-wen-dang-zhi-chi-quan-ju-tong-yong-can-shu/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者: 刘宏缔 邮箱: 371125307@qq.com
二,演示项目的相关信息
1, 项目地址
https://github.com/liuhongdi/swagger3
2, 项目功能说明
演示了使用 swagger3.0.0 生成接口站的文档,
包括:通用的全局参数,
响应时各种状态的返回
响应的封装后的 result 格式数据
3, 项目结构: 如图:
三,配置文件说明
1,pom.xml
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>
说明:用 springfox-boot-starter 来引入 swagger
2,application.properties
springfox.documentation.swagger-ui.enabled=true
说明:在生产环境中要设置 swagger-ui 的 enabled 值为 false,
用来关闭文档的显示
四,java 文件说明:
1,Swagger3Config.java
@EnableOpenApi @Configuration public class Swagger3Config implements WebMvcConfigurer {@Bean </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Docket createRestApi() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回文档摘要信息</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .select() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))</span> .apis(RequestHandlerSelectors.withMethodAnnotation(Operation.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) .paths(PathSelectors.any()) .build() .globalRequestParameters(getGlobalRequestParameters()) .globalResponses(HttpMethod.GET, getGlobalResonseMessage()) .globalResponses(HttpMethod.POST, getGlobalResonseMessage()); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成接口信息,包括标题、联系人等</span> <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ApiInfo apiInfo() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ApiInfoBuilder() .title(</span>"Swagger3接口文档"<span style="color: rgba(0, 0, 0, 1)">) .description(</span>"如有疑问,请联系开发工程师老刘。"<span style="color: rgba(0, 0, 0, 1)">) .contact(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Contact("刘宏缔", "https://www.cnblogs.com/architectforest/", "371125307@qq.com"<span style="color: rgba(0, 0, 0, 1)">)) .version(</span>"1.0"<span style="color: rgba(0, 0, 0, 1)">) .build(); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成全局通用参数</span> <span style="color: rgba(0, 0, 255, 1)">private</span> List<RequestParameter><span style="color: rgba(0, 0, 0, 1)"> getGlobalRequestParameters() { List</span><RequestParameter> parameters = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><span style="color: rgba(0, 0, 0, 1)">(); parameters.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RequestParameterBuilder() .name(</span>"appid"<span style="color: rgba(0, 0, 0, 1)">) .description(</span>"平台id"<span style="color: rgba(0, 0, 0, 1)">) .required(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) .in(ParameterType.QUERY) .query(q </span>-> q.model(m -><span style="color: rgba(0, 0, 0, 1)"> m.scalarModel(ScalarType.STRING))) .required(</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">) .build()); parameters.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RequestParameterBuilder() .name(</span>"udid"<span style="color: rgba(0, 0, 0, 1)">) .description(</span>"设备的唯一id"<span style="color: rgba(0, 0, 0, 1)">) .required(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) .in(ParameterType.QUERY) .query(q </span>-> q.model(m -><span style="color: rgba(0, 0, 0, 1)"> m.scalarModel(ScalarType.STRING))) .required(</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">) .build()); parameters.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RequestParameterBuilder() .name(</span>"version"<span style="color: rgba(0, 0, 0, 1)">) .description(</span>"客户端的版本号"<span style="color: rgba(0, 0, 0, 1)">) .required(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) .in(ParameterType.QUERY) .query(q </span>-> q.model(m -><span style="color: rgba(0, 0, 0, 1)"> m.scalarModel(ScalarType.STRING))) .required(</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">) .build()); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> parameters; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成通用响应信息</span> <span style="color: rgba(0, 0, 255, 1)">private</span> List<Response><span style="color: rgba(0, 0, 0, 1)"> getGlobalResonseMessage() { List</span><Response> responseList = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><span style="color: rgba(0, 0, 0, 1)">(); responseList.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> ResponseBuilder().code("404").description("找不到资源"<span style="color: rgba(0, 0, 0, 1)">).build()); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> responseList; }
}
说明:生成了全局的参数和通用的响应信息
2,RestResult.java
@ApiModel("api 通用返回数据") public class RestResult<T> {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">uuid,用作唯一标识符,供序列化和反序列化时检测是否一致</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> serialVersionUID = 7498483649536881777L<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">标识代码,0表示成功,非0表示出错</span> @ApiModelProperty("标识代码,0表示成功,非0表示出错"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer code; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">提示信息,通常供报错时使用</span> @ApiModelProperty("提示信息,供报错时使用"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String msg; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正常返回时返回的数据</span> @ApiModelProperty("返回的数据"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> T data; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">constructor</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RestResult() { } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">constructor</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RestResult(Integer status, String msg, T data) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.code =<span style="color: rgba(0, 0, 0, 1)"> status; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.msg =<span style="color: rgba(0, 0, 0, 1)"> msg; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.data =<span style="color: rgba(0, 0, 0, 1)"> data; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回成功数据</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RestResult success(T data) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RestResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMsg(), data); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> RestResult success(Integer code,String msg) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RestResult(code, msg, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回出错数据</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> RestResult error(ResponseCode code) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RestResult(code.getCode(), code.getMsg(), <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getCode() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> code; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCode(Integer code) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.code =<span style="color: rgba(0, 0, 0, 1)"> code; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getMsg() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setMsg(String msg) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.msg =<span style="color: rgba(0, 0, 0, 1)"> msg; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> T getData() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> data; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setData(T data) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.data =<span style="color: rgba(0, 0, 0, 1)"> data; }</span></pre>
说明:这里要注意使用泛型 T, 如果只用 Object, 则 swagger 不能识别我们所返回的数据的类型说明:
其中:ApiModel 用于类上面说明功能,
ApiModelProperty 用于字段上说明功能
尤其是 getData 方法的返回数据类型,要用 T,使用工具生成的 data 类容易出现这种错误,
3,Goods.java
@ApiModel("商品模型") public class Goods { //商品 id @ApiModelProperty("商品 id") Long goodsId; public Long getGoodsId() { return this.goodsId; } public void setGoodsId(Long goodsId) { this.goodsId = goodsId; }</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">商品名称</span> @ApiModelProperty("商品名称"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String goodsName; </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getGoodsName() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.goodsName; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setGoodsName(String goodsName) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.goodsName =<span style="color: rgba(0, 0, 0, 1)"> goodsName; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">商品标题</span> @ApiModelProperty("商品标题"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String subject; </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getSubject() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.subject; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setSubject(String subject) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.subject =<span style="color: rgba(0, 0, 0, 1)"> subject; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">商品价格</span> @ApiModelProperty("商品价格"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal price; </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal getPrice() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.price; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setPrice(BigDecimal price) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.price =<span style="color: rgba(0, 0, 0, 1)"> price; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">库存</span> @ApiModelProperty("商品库存"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> stock; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getStock() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.stock; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setStock(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> stock) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.stock =<span style="color: rgba(0, 0, 0, 1)"> stock; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString(){ </span><span style="color: rgba(0, 0, 255, 1)">return</span> " Goods:goodsId=" + goodsId +" goodsName=" + goodsName+" subject=" + subject+" price=" + price+" stock=" +<span style="color: rgba(0, 0, 0, 1)"> stock; }
}
4,GoodsController.java
@Api(tags = "商品信息管理接口") @RestController @RequestMapping("/goods") public class GoodsController {@Operation(summary </span>= "商品详情,针对得到单个商品的信息"<span style="color: rgba(0, 0, 0, 1)">) @GetMapping(</span>"/one"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> RestResult<Goods> one(@Parameter(description = "商品id,正整数") @RequestParam(value="goodsid",required = <span style="color: rgba(0, 0, 255, 1)">false</span>,defaultValue = "0"<span style="color: rgba(0, 0, 0, 1)">) Integer goodsid) { Goods goodsone </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Goods(); goodsone.setGoodsId(</span>3L<span style="color: rgba(0, 0, 0, 1)">); goodsone.setGoodsName(</span>"电子书"<span style="color: rgba(0, 0, 0, 1)">); goodsone.setSubject(</span>"学python,学ai"<span style="color: rgba(0, 0, 0, 1)">); goodsone.setPrice(</span><span style="color: rgba(0, 0, 255, 1)">new</span> BigDecimal(60<span style="color: rgba(0, 0, 0, 1)">)); goodsone.setStock(</span>10<span style="color: rgba(0, 0, 0, 1)">); RestResult res </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RestResult(); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> res.success(goodsone); } @Operation(summary </span>= "提交订单"<span style="color: rgba(0, 0, 0, 1)">) @PostMapping(</span>"/order"<span style="color: rgba(0, 0, 0, 1)">) @ApiImplicitParams({ @ApiImplicitParam(name</span>="userid",value="用户id",dataTypeClass = Long.<span style="color: rgba(0, 0, 255, 1)">class</span>, paramType = "query",example="12345"<span style="color: rgba(0, 0, 0, 1)">), @ApiImplicitParam(name</span>="goodsid",value="商品id",dataTypeClass = Integer.<span style="color: rgba(0, 0, 255, 1)">class</span>, paramType = "query",example="12345"<span style="color: rgba(0, 0, 0, 1)">), @ApiImplicitParam(name</span>="mobile",value="手机号",dataTypeClass = String.<span style="color: rgba(0, 0, 255, 1)">class</span>, paramType = "query",example="13866668888"<span style="color: rgba(0, 0, 0, 1)">), @ApiImplicitParam(name</span>="comment",value="发货备注",dataTypeClass = String.<span style="color: rgba(0, 0, 255, 1)">class</span>, paramType = "query",example="请在情人节当天送到"<span style="color: rgba(0, 0, 0, 1)">) }) </span><span style="color: rgba(0, 0, 255, 1)">public</span> RestResult<String> order(@ApiIgnore @RequestParam Map<String,String><span style="color: rgba(0, 0, 0, 1)"> params) { System.out.println(params); RestResult res </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RestResult(); </span><span style="color: rgba(0, 0, 255, 1)">return</span> res.success("success"<span style="color: rgba(0, 0, 0, 1)">); }
}
说明:Api 用来指定一个 controller 中的各个接口的通用说明
Operation: 用来说明一个方法
@ApiImplicitParams: 用来包含多个包含多个 @ApiImplicitParam,
@ApiImplicitParam: 用来说明一个请求参数
如果使用 @Parameter 来做说明,可以直接加到 @RequestParam 参数之前
@ApiIgnore: 用来忽略不必要显示的参数
五,效果测试
1, 访问文档:访问:
http://127.0.0.1:8080/swagger-ui/index.html
可以看到已有的接口:
2, 查看接口的详情:
参数: 可以看到我们添加的全局通用参数
响应:
六,查看 spring boot 的版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ (()\___ | '_ |'_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ))) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.2.RELEASE)