Swagger
一、描述
现代化的研发 组织 架构中,一个研发团队基本包括了 产品组、后端组、前端组、APP端研发、 测试组、 UI 组等,各个细分组织人员各司其职,共同完成产品的全周期工作。如何进行组织架构内的有效高效沟通就显得尤其重要。其中,如何构建一份合理高效的接口文档更显重要。 随着互联网技术的发展,现在的网站架构基本都由原来的后端变成前后端分离。前后端的唯一联系,是通过API接口;API文档变成了前后端开发人员联系的纽带,变得越来越重要。
二、API文档
解决方案:手写文档完成前后端开发。
开发文档手册:
https://wenku.baidu.com/view/f88529d185868762caaedd3383c4bb4cf6ecb707.html
手写文档存在的问题
-
文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时。
-
接口返回结果不明确
-
不能直接在线测试接口,通常需要使用工具,比如:
Postman
-
接口文档太多,不好进行维护管理
-
文档是接口提供方手动导入的,是静态文档,没有提供接口测试功能
三、 Swagger
1、简介
官网:https://swagger.io/ Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。 Swagger 也就是为了解决这个问题,当然也不能说 Swagger 就一定是完美的,当然也有缺点,最明显的就是代码植入性比较强。
作用:
1. 接口的文档在线自动生成。
2. 功能测试。
2、Swagger组件
Swagger是一组开源项目,其中主要要项目如下:
-
Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.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资源声明以各种语言生成客户端代码。
3、Swagger集成
增加 Swagger2 所需依赖
<!-- Swagger2 Begin --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.8.0</version> </dependency> <!-- Swagger2 End -->
创建Swagger2配置类
/** * @ClassName SwaggerConfig * author wangpengcheng */ 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; /** * Swagger2配置类 基于SpringBoot * 通过@Configuration注解,让Spring来加载该类配置。 * 再通过@EnableSwagger2注解来启用Swagger2。 */ @Configuration @EnableSwagger2 public class SwaggerConfig { /** * 创建API应用 * apiInfo() 增加API相关信息 * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现, * 本例采用指定扫描的包路径来定义指定要建立API的目录。 * * @return */ @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.wpc.springbootssm.controller")) .paths(PathSelectors.any()) .build(); } /** * 创建该API的基本信息(这些基本信息会展现在文档页面中) * 访问地址:http://项目实际地址/swagger-ui.html * * @return */ private ApiInfo apiInfo() { //联系人基本信息 Contact contact = new Contact("wangpengcheng", "url", "pengcheng965@163.com"); return new ApiInfoBuilder() .title("会议达人 --Swagger2构建API文档") .description("更多请关注https://blog.csdn.net/wenkezhuangyuan") .termsOfServiceUrl("http://localhost:8081/swagger-ui.html") .contact(contact) .version("1.0") .build(); } }
查看swagger2
完成上述代码添加,启动Spring Boot程序
访问:http://localhost:8081/springboot/swagger-ui.html
(有应用名需要加上相应的应用名)
四、swagger2注解说明
代码的植入性(侵入性)比较强。
注解:
Controller JavaBean
1 、类描述
@Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
@Controller @RequestMapping("user") @Api(tags = {"用户列表","用户列表控制类"})
2、 方法描述
@ApiOperation:用在请求的方法上,说明方法的用途、作用
value="说明方法的用途、作用" notes="方法的备注说明"
@ApiOperation(value = "查询用户",notes = "根据用户的请求ID查询用户信息")
3、方法参数描述
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面 name:参数名 value:参数的汉字说明、解释 required:参数是否必须传 paramType:参数放在哪个地方 · header --> 请求参数的获取:@RequestHeader · query --> 请求参数的获取:@RequestParam · path(用于restful接口)-->请求参数的获取:@PathVariable [实战中建议不加,用默认] · body(不常用) · form(不常用) dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
@ApiOperation(value = "添加用户",notes = "添加用户信息") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "姓名", required = true, paramType = "query", dataType = "String"), @ApiImplicitParam(name ="telphone",value ="手机号",required = true,paramType ="query",dataType = "String"), @ApiImplicitParam(name ="status",value ="状态",required = false,paramType ="query",defaultValue = "0",dataType = "String") }) @RequestMapping(value ="add",method = RequestMethod.PUT) public String add(User user,Model model){ }
4、方法响应参数
@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 code:数字,例如400 message:信息,例如"请求参数没填好" response:抛出异常的类
@ApiResponses({ @ApiResponse(code = 400,message = "客户端请求参数填写异常"), @ApiResponse(code = 404,message = "您所请求的资源无法找到") })
完整 代码如下:
@ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息") @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "用户ID", required = true,dataType = "String") }) @ApiResponses({ @ApiResponse(code = 400,message = "客户端请求参数填写异常"), @ApiResponse(code = 404,message = "您所请求的资源无法找到") }) @RequestMapping(value = "{id}", method = RequestMethod.GET) // user/id public ResponseEntity<ResultJson<User>> getUserById (@PathVariable(value = "id") Integer id) { User user = userService.selectByPrimaryKey(id); ResultJson<User> resultJson=null; if(user!=null){ resultJson=new ResultJson<>(200,"success",user); }else{ resultJson=new ResultJson<>(40013,"invalid id",user); } ResponseEntity re=new ResponseEntity(resultJson, HttpStatus.OK); return re; }
五、自定义返回码
1、简介:
模仿 微信开发者文档API调用 示例:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
2、自定义创建类
ResultJson
package com.wpc.util.resulst; import lombok.Data; @Data public class ResultJson<T> { /*响应码*/ private String code; /*消息提示内容文件*/ private String msg; /*返回指定对象*/ private T data; /** 成功的方法*/ public ResultJson(T t) { this.setCode(ResultCode.SUCCESS.getCode()); this.setMsg(ResultCode.SUCCESS.getMsg()); this.setData(t); } /**已有的ResultCode 进行返回*/ public ResultJson(T t,ResultCode code){ this.setCode(code.getCode()); this.setMsg(code.getMsg()); this.setData(t); } /** 完全自定义返回 */ public ResultJson(T t,String code,String message){ this.setCode(code); this.setMsg(message); this.setData(t); } }
常量工具类:
ResultCode
package com.wpc.util.resulst; public enum ResultCode { //##########TODO 请求成功 2** /** 成功 */ SUCCESS("2000", "成功"), /** 操作失败 */ FAIL("2001", "操作失败"), /** 数据已存在 */ SUCCESS_IS_HAVE("2002", "数据已存在"), /** 没有结果 */ NOT_DATA("2003", "没有结果"), //##########TODO 客户端错误 4** /** 没有登录 */ NOT_LOGIN("4000", "没有登录"), /** 发生异常 */ EXCEPTION("4001", "发生异常"), /** 系统错误 */ SYS_ERROR("4002", "系统错误"), /** 参数错误 */ PARAMS_ERROR("4003", "参数错误 "), /** 不支持或已经废弃 */ NOT_SUPPORTED("4004", "不支持或已经废弃"), /** AuthCode错误 */ INVALID_AUTHCODE("4005", "无效的AuthCode"), /** 太频繁的调用 */ TOO_FREQUENT("4006", "太频繁的调用"), /** 未知的错误 */ UNKNOWN_ERROR("4007", "未知错误"), /** 未设置方法 */ NOT_METHOD("4008", "未设置方法"); //##########TODO 服务器错误 5** private ResultCode(String code, String msg) { this.code = code; this.msg = msg; } /**对应状态码*/ private String code; /**返回内容*/ private String msg; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
3、代码调用示例
@RequestMapping(value = "r/{id}",method = RequestMethod.GET) // meetingpub/r/id public ResultJson selectMeetingpubById1(@PathVariable("id") final String id){ Meetingpub meetingpub=meetingpubService.selectByPrimaryKey(id); if (meetingpub==null){ return ResultJson.failed("用户ID不存在"); //失败后调用 } return ResultJson.ok(meetingpub); //成功后调用 }
使用spring ResponseEntity处理http响应
使用Spring-ResponseEntity可以响应json格式的数据,非常方便
ResponseEntity标识整个http相应:状态码、头部信息以及相应体内容。因此我们可以使用其对http响应实现完整配置。
4、代码API调用示例:
@RequestMapping(value = "{id}", method = RequestMethod.GET) // user/id public ResponseEntity<ResultJson<User>> getUserById (@PathVariable(value = "id") Integer id) { User user = userService.selectByPrimaryKey(id); ResultJson<User> resultJson=null; if(user!=null){ resultJson=new ResultJson<>(200,"success",user); }else{ resultJson=new ResultJson<>(40013,"invalid id",user); } ResponseEntity re=new ResponseEntity(resultJson, HttpStatus.OK); return re; }
5、调用显示返回JSON:
成功数据:
{"code":200,"message":"success","data":{"id":1,"name":"1","telphone":"123","status":1}}
失败数据:
{"code":40013,"message":"invalid id","data":null}
尽管ResponseEntity非常强大,但不应该过度使用。在一些简单情况下,还有其他方法能满足我们的需求,使代码更整洁。
替代方法 @ResponseBody 典型spring mvc应用,请求点通常返回html页面。有时我们仅需要实际数据,如使用ajax请求。这时我们能通过@ResponseBody注解标记请求处理方法,审批人能够处理方法结果值作为http响应体。
@ResponseStatus 当请求点成功返回,spring提供http 200(ok)相应。如果请求点抛出异常,spring查找异常处理器,由其返回相应的http状态码。对这些方法增加@ResponseStatus注解,spring会返回自定义http状态码。
6、其它方案:
使用 Spring REST Docs 创建 REST 服务文档
简介:
Spring REST Docs 是一个为 Spring 项目生成 API 文档的框架,它通过在单元测试中额外添加 API 信息描述,从而自动生成对应的文档片段。