本文转载自微信公众号《程序新视界》,作者为二哥。转载本文请联系程序新视界公众号。前言随着项目架构的演进,前后端分离是不可阻挡的趋势。在这种协作模式的实践中经常遇到的问题之一是文档。在《一位CTO告诉我,项目中至少需要这3类文档》一文中,我们已经说明了文档的重要性,而接口文档就是其中之一,可以说是不可或缺的。但是编写接口文档对开发者来说是个大问题,而且接口还在不断变化,维护接口文档的更新是需要精力的。既然有痛点,就一定有解决这个痛点的产品。这是Swagger,已经更新到Swagger3版本。如果还卡在Swagger2,建议升级到Swagger3,整体UI风格和交互友好很多。本文将重点介绍Swagger3与SpringBoot的集成以及离线文档的生成。Swagger简介Swagger是一个标准化的完整框架,用于生成、描述、调用和可视化RESTful风格的Web服务。总体目标是让客户端和文件系统以与服务器相同的速率更新。记录方法、参数和模型紧密集成到服务器端代码中,使API始终保持同步。官网:https://swagger.ioSwagger解决的痛点传统提供文档的方式存在以下痛点:接口多,实现细节复杂,编写文档耗时长,需要持续维护;接口文件需要随时同步;接口返回的结果不明确,必须自己构造返回结构等;不能直接在线测试接口,通常需要额外的工具,比如PostMan。Swagger的引入解决了以上痛点,同时也带来了以下优势:及时性(接口变更后,前后端人员可以实时看到最新版本)标准化(具体接口的统一风格,如接口地址、请求方法、参数、Response格式和错误信息等)一致性(接口信息一致,不会因为接口文档版本问题而有差异)可测试性(可以直接根据接口文档进行测试)Swagger3改动Swagger3.0改动,官方文档总结如下要点:删除了对springfox-swagger2的依赖;删除了所有@EnableSwagger2...注解;添加了springfox-boot-starter依赖项;移除了guava等第三方依赖;将文档访问地址改为http://ip:port/project/swagger-ui/index.html。让我们在实践中使用它。SpringBoot集成Swagger3SpringBoot集成Swagger3,SpringBoot集成其他框架的方式相同,通常包括:引入依赖、指定配置文件、创建配置类并使用。引入依赖在SpringBoot项目的pom.xml中引入Swagger3依赖:io.springfoxspringfox-boot-starter3.0.0/dependency>指定配置文件。通常swagger只能在开发环境或者测试环境开启,在生产环境需要关闭。swagger的开启和关闭可以在application.properties中配置:#生产环境需要设置为falsespringfox.documentation.swagger-ui.enabled=true配置类通过@EnableOpenApi注解开启Swagger的使用,以及同时在配置类中配置了Swagger的通用参数。@Configuration@EnableOpenApipublicclassSwagger3Config{@BeanpublicDocketcreateRestApi(){//返回文档摘要信息returnnewDocket(DocumentationType.OAS_30).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.withMethodAnnotation(Operation.class)).paths(PathSelectors(PathSelectors.withMethodAnnotation(Operation.class)).paths(any()).build().globalRequestParameters(getGlobalRequestParameters()).globalResponses(HttpMethod.GET,getGlobalResponseMessage()).globalResponses(HttpMethod.POST,getGlobalResponseMessage());}/***生成接口信息,包括title,Contact等*/privateApiInfoapiInfo(){returnnewApiInfoBuilder().title("Swagger3接口文档").description("有问题可以联系二哥,微信:zhuan2quan").contact(newContact("二哥","https://www.choupangxia.com/","secbro2@gmail.com")).version("1.0").build();}/***封装全局通用参数*/privateListgetGlobalRequestParameters(){Listparameters=newArrayList<>();parameters.add(newRequestParameterBuilder().name("uuid").description(“设备uuid”).required(true).in(ParameterType.QUERY).query(q->q.model(m->m.scalarModel(ScalarType.STRING))).required(false).build());returnparameters;}/***封装通用响应信息*/privateListgetGlobalResponseMessage(){ListresponseList=newArrayList<>();responseList.add(newResponseBuilder().code("404").description("没有找到资源").build());returnresponseList;}}通过上面的配置,就完成了SpringBoot和Swagger的集成。让我们展示如何在业务逻辑中使用它。创建两个实体类Goods(商品类)和CommonResult(普通返回结果类)。商品类:@ApiModel("商品型号")publicclassGoods{/***商品id*/@ApiModelProperty("商品ID")LonggoodsId;/***商品名称*/@ApiModelProperty("商品名称")privateStringgoodsName;/***商品价格*/@ApiModelProperty("商品价格")privateBigDecimalprice;//省略getter/setter}CommonResult类:@ApiModel("API通用数据")publicclassCommonResult{/***标识码,0表示成功,非0表示错误*/@ApiModelProperty("标识码,0表示成功,非0表示错误")privateIntegercode;/***描述信息??,一般在出错时使用*/@ApiModelProperty("Errordescription")privateStringmsg;/***业务数据*/@ApiModelProperty("业务数据")privateTdata;publicCommonResult(Integerstatus,Stringmsg,Tdata){this.code=status;this.msg=msg;this.data=data;}/***成功*/publicstaticCommonResultsuccess(Tdata){returnnewCommonResult<>(0,"success",data);}publicstaticCommonResultsuccess(Integercode,Stringmsg){返回新的CommonResult<>(code,msg,null);}/***Error*/publicstaticCommonResulterror(intcode,Stringmsg){returnnewCommonResult<>(code,msg,null);}//省略getter/setter}下面对Controller层的接口使用Swagger对应的APIGoodsController类:@Api(tags="商品信息管理界面")@RestController@RequestMapping("/goods")publicclassGoodsController{@Operation(summary="单品详情")@GetMapping("/findGoodsById")publicCommonResultfindGoodsById(@Parameter(description="ProductID,positiveinteger")@RequestParam(value="goodsId",required=false,defaultValue="0")IntegergoodsId){System.out.println("基于productID="+goodsId+"查询商品详情");Goodsgoods=newGoods();goods.setGoodsId(1L);goods.setGoodsName("notebook");goods.setPrice(newBigDecimal(8888));returnCommonResult.success(goods);}}OrderController类:@Api(tags="订单管理界面")@RestController@RequestMapping("/order")publicclassOrderController{@Operation(summary="提交订单")@PostMapping("/order")@ApiImplicitParams({@ApiImplicitParam(name="userId",value="userid",dataTypeClass=Long.class,paramType="query",example="123"),@ApiImplicitParam(name="goodsId",value="productid",dataTypeClass=Integer.class,paramType="query",example="1")})publicCommonResulttoBuy(@ApiIgnore@RequestParamMapparams){System.out.println(params);returnCommonResult.success("success");}}显示效果集成完成,启动SpringBoot项目,访问地址:http://127.0.0.1:8080/swagger-ui/index.html整体可以看到如下效果:具体商品信息管理界面,可以看到请求参数,返回结果数据结构等信息,点击“试用”,即可输入参数请求参数,并实现接口调用:调用后返回相应的处理结果:在最下面的Schemas中,还可以看到相应的返回结果数据和Swagger注解的实体类信息Swagger3注解使用说明经过上面的例子,我们知道了大部分API是如何使用的,接下来总结一下相关API的功能:@Api:用在请求的类上,表示类标签的描述=“类的描述函数类的,在UI界面上可以看到的注解“value=”是没有意义的,在UI界面上也可以看到,所以不需要配置“@ApiOperation:usedintherequestedmethod,说明方法的目的,Functionvalue="Describethepurposeandfunctionofthemethod"notes="方法的备注"@ApiImplicitParams:用在请求的方法中,表示一组参数说明@ApiImplicitParam:用在@ApiImplicitParams注解指定每一个请求参数aspectname:参数名称value:汉字参数的描述和解释required:参数是否必须传递paramType:参数放在哪里ader-->请求参数获取:@RequestHeaderquery-->请求参数获取:@RequestParam·path(针对restful接口)-->获取请求参数:@PathVariable·body(不常用)·form(不常用))dataType:参数类型,默认String,其他值dataType="Integer"defaultValue:默认参数值@ApiResponses:用在请求方法中,表示一组响应@ApiResponse:用在@ApiResponses中,一般用来表达一个错误响应信息code:数字,如400message:信息,如“请求参数未填写”response:抛出异常的类@ApiModel:用在响应类上,表示返回响应数据的消息(this一般在创建post时使用,在这种场景下使用@RequestBody,请求参数不能使用@ApiImplicitParam注解来描述时)@ApiModelProperty:用在属性上,描述res的属性班级。集成knife4j导出离线文档。Swagger为我们提供了便捷的在线文档支持,但是在某些场景下我们需要提供接口文档给合作伙伴。我们需要将接口文档导出为离线文档,而不是直接给运营商一个地址。这里我们集成增强文档knife4j,实现离线文档的导出。添加knife4j依赖在pom.xml中添加knife4j依赖:com.github.xiaoyminknife4j-spring-boot-starter3.0.2启动knife4j在上面配置Swagger的Swagger3Config中添加@EnableKnife4j注解,可以开启knife4j的增强功能。@EnableKnife4j@Configuration@EnableOpenApipublicclassSwagger3Config{//...}此时,如果你仍然访问http://localhost:8080/swagger-ui/index.html,你会发现显示没有变化。这里我们需要访问http://localhost:8088/doc.html。整个项目源码地址:https://github.com/secbr/springboot-all/tree/master/springboot-swagger3。显示效果此时启动项目,访问doc.html后,你会发现文档样式现在变得很酷了。放几张效果图看看:其中,在“离线文档”栏目中,可以看到四种形式的离线文档下载:Markdown、HTML、Word、OpenAPI。其中,个人感觉HTML格式的文档功能更强大,也更易查看。这里放一张图看看效果。总结文档在项目中是必须的,但是随着开源框架的发展,技术人员的文档痛点正在逐渐被解决。如果你还在手写文档的阶段,真的可以试试这种更友好的文档呈现方式。