swagger2和spring boot整合构建RESTful API文档

由于Spring Boot能够快速开发、便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。

这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发、Android开发或是Web开发等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题:

  • 由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。
  • 随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。

为了解决上面这样的问题,本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。

添加Swagger2依赖

pom.xml中加入Swagger2的依赖坐标

<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger2artifactId>
    <version>2.2.2version>
dependency>
<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger-uiartifactId>
    <version>2.2.2version>
dependency>

建立Swagger2配置类

注意这个配置类需要放到Application.java所在的同一目录或者子目录下

@SpringBootConfiguration
public class Swagger2Config {

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.itcrud.swagger"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(parameterBuilder());
    }

    //API的基本信息
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("IT-CRUD接口文档")
                .description("专注于学习笔记,想和我一起学习,请关注博客:http://blog.itcrud.com")
                .termsOfServiceUrl("http://blog.itcrud.com")
                .contact("IT-CRUD")
                .version("1.0.0")
                .build();
    }

    //请求参数构建
    private List<Parameter> parameterBuilder() {
        List<Parameter> parameters = Lists.newArrayList();
        parameters.add(new ParameterBuilder().name("token").description("登录验证")
                .modelRef(new ModelRef("string")).required(false)
                .parameterType("header").build());
        return parameters;
    }
}

通过createRestApi函数创建Docket的Bean之后,apiInfo()用来创建该Api的基本信息(这些基本信息会展现在文档页面中)。select()函数返回一个ApiSelectorBuilder实例用来控制哪些接口暴露给Swagger来展现,本例采用指定扫描的包路径来定义,Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被@ApiIgnore指定的请求)。另外一般项目可能都会用到请求头信息,这里通过ParameterBuilder构建头信息部分,添加到全局选项参数globalOperationParameters中。

添加文档内容

常用注解

在完成了上述配置后,其实已经可以生成文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。需要介绍几个常用的注解。

  • @Api:放在Controller类上面,对类做整体的介绍,主要使用descriptionvalue属性
  • @ApiOperation:放在接口方法上,用来描述方法的信息,常用属性是valuenotes
  • @ApiModel:放在接收请求参数类或者响应参数类上,用来描述类信息,常用属性是value
  • @ApiModelProperty:方法接收请求参数类或者响应参数类的属性字段上,用来描述字段信息,常用属性是value
  • @ApiImplicitParam:放在接口方法上,用来描述参数信息,常用属性有namevaluerequireddataTypeparamType(此注解不推荐用)
  • @ApiImplicitParams:放在接口方法上,用来描述参数信息,描述多个字段信息,其内部属性就一个,是@ApiImplicitParam数组,所以常用属性也是namevaluerequireddataTypeparamType(此注解不推荐用)
Controller代码

这是个Controller类,里面包含了上面的所有注解。

@Api(description = "UserController", value = "用户服务接口")
@Controller
@RequestMapping("/user")
public class UserController {

    @ApiOperation("添加用户信息")
    @PostMapping("/addUser")
    @ResponseBody
    public String addUser(@RequestBody UserReqDTO reqDTO) {
        return "";
    }

    @ApiOperation("删除用户信息")
    @DeleteMapping("/deleteUser")
    @ResponseBody
    public String deleteUser(@RequestParam(name = "userId") Long userId) {
        return "";
    }

    @ApiOperation("编辑用户信息")
    @PutMapping("/editUser")
    @ResponseBody
    public String editUser(@RequestBody UserReqDTO reqDTO) {
        return "";
    }

    @ApiOperation(value = "查询用户信息", notes = "查询用户信息")
    @GetMapping("/getUser")
    @ResponseBody
    public List<User> getUser(@ModelAttribute UserSearchReqDTO reqDTO) {
        return Lists.newArrayList();
    }

    @ApiOperation(value = "测试header信息", notes = "测试swagger配置中添加的header参数token在传入的时候是否在头信息里面")
    @GetMapping("/testHeader")
    @ResponseBody
    public String testHeader(HttpServletRequest request) {
        System.out.println("header-->" + request.getHeader("token"));
        return "";
    }

    @ApiOperation(value = "模糊查询用户", notes = "根据手机号、用户名模糊查询用户信息")
    @GetMapping("/getUserByKeywords")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userName", value = "用户名", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "userPhone", value = "手机号码", required = true, dataType = "String", paramType = "query")
    })
    @ResponseBody
    public List<User> getUsers(@RequestParam("userName") String userName, @RequestParam("userPhone") String userPhone) {
        return Lists.newArrayList();
    }
}
涉及的实体类

实体类包含请求的参数类和响应的参数类。

@Data
@ApiModel(value = "用户详细信息")
public class User {
    @ApiModelProperty(value = "用户ID")
    private Long id;
    @ApiModelProperty(value = "用户姓名")
    private String userName;
    @ApiModelProperty(value = "用户手机号码")
    private String userPhone;
    @ApiModelProperty(value = "用户性别")
    private Integer gender;
    @ApiModelProperty(value = "用户年龄")
    private Integer age;
    @ApiModelProperty(value = "注册时间")
    private Date registerTime;
}
//-----------------------
@Data
@ApiModel(value = "用户参数类")
public class UserReqDTO {
    @ApiModelProperty(value = "用户ID")
    private Long id;
    @ApiModelProperty(value = "用户姓名")
    private String userName;
    @ApiModelProperty(value = "用户手机号码")
    private String userPhone;
    @ApiModelProperty(value = "用户性别")
    private Integer gender;
    @ApiModelProperty(value = "用户年龄")
    private Integer age;
}
//-----------------------
@Data
@ApiModel(value = "用户查询类")
public class UserSearchReqDTO {
    @ApiModelProperty(value = "用户编号")
    private Long id;
    @ApiModelProperty(value = "查询关键字(用户名+手机号模糊查询)")
    private String keywords;
}

完成上面的代码就可以启动这个springboot项目了。然后直接访问:http://localhost:8080/swagger-ui.html。这个地址根据实际项目不同,但是都是swagger-ui.html结尾。

得到的结果如下:

swagger2和spring boot整合构建RESTful API文档_第1张图片

上面的图是整体页面的数据,再展示一下具体接口内部的细节图。

swagger2和spring boot整合构建RESTful API文档_第2张图片

上面细节图中的描述信息、字段名称、说明文字等对应到注解上的属性可以对照看一下,不多解释啦。另外要解释一下上面说@ApiImplicitParams@ApiImplicitParam不推荐用的原因。

不推荐使用@ApiImplicitParams@ApiImplicitParam原因
  • 当我们接收参数是对象的时候,使用@ApiImplicitParam和参数对象类上的@ApiModel系列的注解有兼容性问题,会打乱swagger上的显示,如下两张对比图:

swagger2和spring boot整合构建RESTful API文档_第3张图片

图一

swagger2和spring boot整合构建RESTful API文档_第4张图片

图二

对比图一和图二,图一是不使用@ApiImplicitParam的效果,图二是和@ApiModel混用的效果。很明显的看出来,不使用@ApiImplicitParam更优。这里的请求类UserReqDTO类的参数不多,如果多的话有没有自动填充的效果,会是一件很痛苦的事。

  • 当用@ApiImplicitParam注解来标识参数的时候,需要注明此参数的类型,也就是paramType必填,如果不填很可能导致请求参数不能传入,出现问题。看下面的两张对比图:

swagger2和spring boot整合构建RESTful API文档_第5张图片

图三

swagger2和spring boot整合构建RESTful API文档_第6张图片

图四

这两个图是请求同一个接口(GET请求),图三请求的时候,该接口的@ApiImplicitParam注解将paramType值设置为了query,图四是将这个属性去掉,默认的paramType就是body。很容易就会出错。那么应该怎么设置这个类型呢?有哪些类型?下面看一下:

  1. path:参数是链接上的占位符,如:http://blog.itcrud.com/api/getUserById/{id},id参数对应的类型就是path
  2. query:get请求,拼在地址后面的。如http://blog.itcrud.com/api/getUserById?id=123,id参数对应的类型就是query
  3. body:post请求对应的body体,这个就不多说啦(json体写着麻烦,自己意会)
  4. header:请求头数据,在请求的时候,常用@RequestHeader来接收的参数就是请求头内的数据
  5. form:form表单,不解释

从上面的两个例子,加上对@ApiImplicitParam的巨坑参数paramType的理解,就可以知道为什么这个注解不推荐使用啦。但是在请求参数比较多,而且零散的时候可以考虑使用一下,但是需要注意避坑即可。

Source Code

码云(gitee):https://gitee.com/itcrud/itcrud-note/tree/master/itcrud-note-1-1

你可能感兴趣的:(Spring,Boot系列,spring,boot,swagger)