由于公司项目采用前后端分离,维护接口文档基本上是必不可少的工作。一个理想的状态是设计好后,接口文档发给前端和后端,大伙按照既定的规则各自开发,开发好了对接上了就可以上线了。当然这是一种非常理想的状态,而手写文档虽然可以解决一些问题,但是也存在以下痛点。

手写Api文档的几个痛点:

  • 文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时。
  • 接口返回结果不明确
  • 不能直接在线测试接口,通常需要使用工具,比如postman
  • 接口文档太多,不好管理
  • 还好,有一些工具可以减轻我们的工作量,Swagger2 就是其中之一。

    本文以Demo示例展示一下在Spring Boot 中如何整合 Swagger2 。

    Swagger2常用注解说明

    swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。

    @Api:               修饰整个类,描述Controller的作用
    @ApiOperation:      描述一个类的一个方法,或者说一个接口
    @ApiParam:          单个参数描述
    @ApiModel:          用对象来接收参数
    @ApiModelProperty:  用对象接收参数时,描述对象的一个字段
    @ApiResponse:       HTTP响应其中1个描述
    @ApiResponses:      HTTP响应整体描述
    @ApiIgnore:         使用该注解忽略这个API
    @ApiError :         发生错误返回的信息
    @ApiImplicitParam:  一个请求参数
    @ApiImplicitParams: 多个请求参数

    具体说明如下:

    @Api:用在请求的类上,表示对类的说明
        tags="说明该类的作用,可以在UI界面上看到的注解"
        value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
    @ApiOperation:用在请求的方法上,说明方法的用途、作用
        value="说明方法的用途、作用"
        notes="方法的备注说明"
    @ApiImplicitParams:用在请求的方法上,表示一组参数说明
        @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
            name:参数名
            value:参数的汉字说明、解释
            required:参数是否必须传
            paramType:参数放在哪个地方
                · header --> 请求参数的获取:@RequestHeader
                · query --> 请求参数的获取:@RequestParam
                · path(用于restful接口)--> 请求参数的获取:@PathVariable
                · body(不常用)
                · form(不常用)    
            dataType:参数类型,默认String,其它值dataType="Integer"       
            defaultValue:参数的默认值
    @ApiResponses:用在请求的方法上,表示一组响应
        @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
            code:数字,例如400
            message:信息,例如"请求参数没填好"
            response:抛出异常的类
    @ApiModel:用于响应类上,表示一个返回响应数据的信息
                (这种一般用在post创建的时候,使用@RequestBody这样的场景,
                请求参数无法使用@ApiImplicitParam注解进行描述的时候)
        @ApiModelProperty:用在属性上,描述响应类的属性

    SpringBoot整合Swagger2进行CRUD操作

    数据准备:

    数据库名:springboottest,表名:ss_company

    建表语句:

    DROP TABLE IF EXISTS ss_company;
    CREATE TABLE ss_company (
      id varchar(40) NOT NULL COMMENT 'ID',
      name varchar(255) DEFAULT NULL COMMENT '公司名称',
      expiration_date datetime DEFAULT NULL COMMENT '到期时间',
      address varchar(255) DEFAULT NULL COMMENT '公司地址',
      license_id varchar(255) DEFAULT NULL COMMENT '营业执照-图片',
      representative varchar(255) DEFAULT NULL COMMENT '法人代表',
      phone varchar(255) DEFAULT NULL COMMENT '公司电话',
      company_size varchar(255) DEFAULT NULL COMMENT '公司规模',
      industry varchar(255) DEFAULT NULL COMMENT '所属行业',
      remarks varchar(255) DEFAULT NULL COMMENT '备注',
      state int(2) DEFAULT '1' COMMENT '状态',
      balance double DEFAULT NULL COMMENT '当前余额',
      city varchar(20) DEFAULT NULL,
      PRIMARY KEY (id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

    数据插入语句:

    INSERT INTO ss_company VALUES ('1', '字节跳动', null, '北京', 'xxx002', '张某', '123', '10000人以上', '互联网', '互联网公司', '1', '100', '北京');
    INSERT INTO ss_company VALUES ('2', '百度', null, '北京市海淀区', 'bzd001', '李某', '110', '5000-10000人', '计算机', '', '1', '100', '北京');
    INSERT INTO ss_company VALUES ('3', '阿里巴巴', null, '中国杭州市滨江区', 'bzd002', '马某', '110', '5000-10000人', '电子商务', '', '1', '100', '杭州');
    INSERT INTO ss_company VALUES ('4', '腾讯', null, '深圳市南山区', 'bzd003', '马某', '110', '5000-10000人', '游戏', '', '1', '100', '深圳');

    1>  创建SpringBoot工程,导入pom文件依赖

      application.yml配置:
    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springboottest?characterEncoding=utf-8
        username: root
        password: root
    server:
      port: 8090

    pom依赖:

    <dependencies>
            <!-- SpringBoot 启动器 web依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- swagger2文档配置依赖 -->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.9.2</version>
            </dependency>
            <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <!--springboot支持的是jpa,mybatisplus自己做了启动器-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.2.0</version>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!-- lombok插件依赖 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <!-- SpringBoot测试启动依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>

    2>  创建pojo实体类

    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import java.io.Serializable;
    import java.util.Date;
    @Data
    @TableName("ss_company")
    @ApiModel(value = "公司实体类")
    public class Company implements Serializable {
         * AUTO : AUTO(0, "数据库ID自增"),
         * INPUT : INPUT(1, “用户输入ID”),
         * ID_WORKER : ID_WORKER(2, "全局唯一ID"),默认值如果不设置会在用该策略
         * UUID : UUID(3, "全局唯一ID"),
         * NONE : NONE(4, "该类型为未设置主键类型"),
         * ID_WORKER_STR : ID_WORKER_STR(5, "字符串全局唯一ID");
        @TableId(type = IdType.UUID)
        @ApiModelProperty(value = "主键Id")
        private String id;
        @ApiModelProperty(value = "公司名称")
        private String name;
        @ApiModelProperty(value = "到期时间")
        private Date expirationDate;
        @ApiModelProperty(value = "公司地址")
        private String address;
        @ApiModelProperty(value = "营业执照")
        private String licenseId;
        @ApiModelProperty(value = "法人代表")
        private String representative;
        @ApiModelProperty(value = "公司电话")
        private String phone;
        @ApiModelProperty(value = "公司规模")
        private String companySize;
        @ApiModelProperty(value = "所属行业")
        private String industry;
        @ApiModelProperty(value = "备注")
        private String remarks;
        @ApiModelProperty(value = "公司状态")
        private Integer state;
        @ApiModelProperty(value = "当前余额")
        private Double balance;
        @ApiModelProperty(value = "公司所在地")
        private String city;
        private static final long serialVersionUID = 1L;
    

    3>  创建Result类(建议)

    备注:Result类主要是在测试的时候,给出提示信息

    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import java.io.Serializable;
    @ApiModel(value = "返回结果类")
    public class Result implements Serializable {
        @ApiModelProperty(value = "状态判断")
        private boolean success;
        @ApiModelProperty(value = "返回消息内容")
        private String message;
        public Result(boolean success,String message) {
            this.message = message;
            this.success = success;
        public boolean isSuccess() {
            return success;
        public void setSuccess(boolean success) {
            this.success = success;
        public String getMessage() {
            return message;
        public void setMessage(String message) {
            this.message = message;
    

    4>  创建Dao接口

    备注:由于com.baomidou.mybatisplus.core.mapper包已经封装了CRUD功能,所以这里的Dao接口只需继承对应的BaseMapper<Company>接口就可以了

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;

    public interface CompanyDao extends BaseMapper<Company> {

    5>  创建Service接口

    import java.util.List;
    public interface CompanyService {
        //查询所有
        List<Company> findAll();
        //单一查询
        Company findOne(String id);
        //更新
        void update(Company company);
        //添加
        void add(Company company);
        //删除
        void delete(String id);
    

    6>  创建ServiceImpl实现类

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import java.util.List;
    @Service
    public class CompanyServiceImpl implements CompanyService {
        @Autowired
        private CompanyDao companyDao;
        @Override
        public List<Company> findAll() {
            return companyDao.selectList(null);
        @Override
        public Company findOne(String id) {
            return companyDao.selectById(id);
        @Override
        public void update(Company company) {
            companyDao.updateById(company);
        @Override
        public void add(Company company) {
            companyDao.insert(company);
        @Override
        public void delete(String id) {
            companyDao.deleteById(id);
    

    7>   创建Controller类

    import io.swagger.annotations.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import java.util.List;
    @Api("Swagger示例CRUD操作")
    @RestController
    @RequestMapping("/company")
    public class CompanyController {
        @Autowired
        private CompanyService companyService;
        //查询所有
        @ApiOperation("获取公司列表")
        @GetMapping
        public List<Company> findAll(){
            return companyService.findAll();
        //查询单一
        @ApiOperation(value = "根据id获取公司信息",notes = "id必须是数字")
        @ApiImplicitParams({@ApiImplicitParam(name = "id",value = "id",required = true,paramType = "path")})
        @ApiResponses({@ApiResponse(code=400,message="id为空")})
        @GetMapping("/{id}")
        public Company findById(@PathVariable("id") String id){
            return companyService.findOne(id);
        //添加
        @ApiOperation("新增公司信息")
        @ApiImplicitParam(name = "company", value = "单个公司信息", dataType = "Company")
        @PostMapping
        public Result add(@RequestBody Company company){
            try {
                companyService.add(company);
                return new Result(true,"新增成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"新增失败");
        //修改
        @ApiOperation("修改公司信息")
        @ApiImplicitParam(name = "company", value = "单个公司信息", dataType = "Company")
        @PutMapping
        public Result update(@RequestBody Company company){
            try {
                companyService.update(company);
                return new Result(true,"修改成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"修改失败");
        //删除
        @ApiOperation("删除用户")
        @ApiImplicitParam(name = "id", value = "单个用户信息", dataType = "String")
        @DeleteMapping("/{id}")
        public Result delete(@PathVariable("id") String id){
            try {
                companyService.delete(id);
                return new Result(true,"删除成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"删除失败");
    

    8>  创建Controller类

    import io.swagger.annotations.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import java.util.List;
    @Api(tags = "Swagger示例CRUD操作")
    @RestController
    @RequestMapping("/company")
    public class CompanyController {
        @Autowired
        private CompanyService companyService;
        //查询所有
        @ApiOperation("获取公司列表")
        @GetMapping
        public List<Company> findAll(){
            return companyService.findAll();
        //查询单一
        @ApiOperation(value = "根据id获取公司信息",notes = "id必须是数字")
        @ApiImplicitParams({@ApiImplicitParam(name = "id",value = "id",required = true,paramType = "path")})
        @ApiResponses({@ApiResponse(code=400,message="id为空")})
        @GetMapping("/{id}")
        public Company findById(@PathVariable("id") String id){
            return companyService.findOne(id);
        //添加
        @ApiOperation("新增公司信息")
        @ApiImplicitParam(name = "company", value = "单个公司信息", dataType = "Company")
        @PostMapping
        public Result add(@RequestBody Company company){
            try {
                companyService.add(company);
                return new Result(true,"新增成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"新增失败");
        //修改
        @ApiOperation("修改公司信息")
        @ApiImplicitParam(name = "company", value = "单个公司信息", dataType = "Company")
        @PutMapping
        public Result update(@RequestBody Company company){
            try {
                companyService.update(company);
                return new Result(true,"修改成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"修改失败");
        //删除
        @ApiOperation("删除用户")
        @ApiImplicitParam(name = "id", value = "单个用户信息", dataType = "String")
        @DeleteMapping("/{id}")
        public Result delete(@PathVariable("id") String id){
            try {
                companyService.delete(id);
                return new Result(true,"删除成功");
            } catch (Exception e) {
                e.printStackTrace();
                return new Result(false,"删除失败");
    

    9>  创建Swagger2配置类

    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.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(restApiInfo())
                    .select()
                    // 指定包名
                    .apis(RequestHandlerSelectors.basePackage("com.darren.springbootswaggerdemo.controller"))
                    .paths(PathSelectors.any())
                    .build();
        private ApiInfo restApiInfo() {
            return new ApiInfoBuilder()
                    .title("springboot利用swagger2构建api文档")
                    .description("简单优雅的restful风格")
                    .termsOfServiceUrl("no terms of serviceUrl")
                    .version("1.0")
                    .build();
    

    备注说明:

    这里提供的配置类,首先通过 @EnableSwagger2 注解启用 Swagger2 ,然后配置一个 Docket Bean,这个 Bean 中,配置映射路径和要扫描的接口的位置,

    在 apiInfo 中,主要配置一下 Swagger2 文档网站的信息,例如网站的 title,网站的描述,联系人信息,使用的协议,版本信息,许可证信息等等。

    至此,SpringBoot整合Swagger2示例Demo已配置完成,下面启动SpringBoot启动类测试,然后打开浏览器,在地址栏中输入:

    http://localhost:8090/swagger-ui.html

    能够看到如下界面,说明配置已成功