Swagger2详解

930 阅读8分钟

一,Swagger2介绍

Swagger2 是一种 API 文档生成工具,主要用于 描述、消费和可视化 RESTful Web 服务。它能根据你的后端代码(通常是 Spring Boot 项目中的 Controller)自动生成交互式文档页面,方便前端查看接口、参数、返回值,甚至直接在线测试接口。

核心作用:

  1. 自动生成 API 文档 不需要手动写 markdown 或 word 文档,Swagger 自动根据代码注解生成文档。
  2. 在线可视化文档页面(Swagger UI) 支持在浏览器中展示接口列表、请求参数、返回示例等,还能在线调试接口。
  3. 统一团队接口沟通 前后端对接口结构和字段定义一目了然,减少沟通成本。

Swagger2 的发展背景

年份阶段 / 事件说明
~2010Swagger 项目创建Wordnik 内部项目,解决接口文档不一致的问题。
2011Swagger 开源包含规范 + UI + 代码生成器。
2014Swagger 1.x 被广泛使用但文档能力有限,规范结构不清晰。
2015Swagger 2.0 发布重写规范,正式成为 OpenAPI 2.0。Swagger2 即基于此。
2015Swagger 捐献给 Linux Foundation形成 OpenAPI Initiative(OAI)。
2017OpenAPI 3.0 发布新规范支持更多高级特性,替代 Swagger2。
2021OpenAPI 3.1 发布完全兼容 JSON Schema,推动行业标准化。

Springfox

Springfox 是一个用于在 Spring(尤其是 Spring Boot)中集成 Swagger 的开源项目,核心目标是:

  • 自动将 Spring Controller 中的注解翻译成 Swagger2 文档(OpenAPI 2.0)
  • 简单说:Springfox 就是 Spring Boot + Swagger2 的桥梁。

二,Swagger2快速入门

  1. 添加 Maven 依赖

    <dependencies>
        <!-- 核心依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
    
        <!-- Swagger UI 页面 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
    </dependencies>
    
  2. 编写 Swagger 配置类

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
                .paths(PathSelectors.any())
                .build();
        }
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                .title("示例项目接口文档")
                .description("用于展示 Swagger2 基本用法")
                .version("1.0")
                .build();
        }
    }
    
  3. 给 Controller 添加注解

    @RestController
    @RequestMapping("/api")
    @Api(tags = "用户接口")  // 用于 UI 展示分组
    public class UserController {
    
        @GetMapping("/user")
        @ApiOperation("获取用户信息")
        public User getUser() {
            return new User("Alice", 20);
        }
    
        @PostMapping("/user")
        @ApiOperation("新增用户")
        public String addUser(@RequestBody User user) {
            return "添加成功: " + user.getName();
        }
    }
    
  4. 启动项目并访问

    启动 Spring Boot 项目后,访问:

    • 文档页面:http://localhost:8080/swagger-ui.html
    • 接口数据:http://localhost:8080/v2/api-docs
  5. 注意事项

    从 Spring Boot 2.6 开始默认使用 PathPatternParser 替代了 AntPathMatcher,而 Springfox 不兼容,需加上这个配置:

    # application.yml
    spring:
      mvc:
        pathmatch:
          matching-strategy: ant_path_matcher
    

三,Swagger2相关注解

3.1 接口类注解

接口注解:作用于 Controller类

@Api

  • 位置:标注在 Controller 类上。

  • 作用:用于描述整个类的用途。

  • 常用属性

    属性名说明
    value接口的大致说明(可选)
    tags分组标签(推荐用这个)
    description详细描述(可选)
    position控制 Controller 在 UI 中的显示顺序

示例

@Api(tags = "用户管理接口", description = "提供用户的增删改查 API")
@RestController
public class UserController { ... }

跨组显示接口

Swapper默认是按照每个Controller类来分组显示接口的,如果其中一个Controller执行需要另外其他组的Controller接口配合,这个时候就需要我们支持显示其他分组信息。

有两种写法:

  1. ApiOperation中tags参数

    @DeleteMapping("/delete/{id}")
    @ApiOperation(value="删除用户",tags={"用户管理","员工管理"})
    public int deleteUser(@PathVariable("id") int id){
        return userService.removeById(id)?1:0;
    }
    

    这样这个方法既可以在员工管理组显示也可以在用户管理组显示

  2. 多个不同接口同时指向一个不存在的组

    @DeleteMapping("/delete/{id}")
    @ApiOperation(value="删除用户",tags="不存在的组")
    public int deleteUser(@PathVariable("id") int id){
        return userService.removeById(id)?1:0;
    }
    

    Swapper会新建一个分组来展示这些接口的信息

3.2 方法注解

方法注解:作用于接口方法

@ApiOperation

  • 位置:标注在接口方法上。

  • 作用:说明接口的功能。

  • 常用属性

    属性名说明
    value接口方法的简要描述
    notes补充说明(可选)
    httpMethod请求方式(GET/POST 等,可选)

示例

@ApiOperation(value = "根据 ID 查询用户", notes = "输入用户 ID,返回用户详细信息")
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) { ... }

@ApiImplicitParams + @ApiImplicitParam

  • 位置:用于描述接口方法参数(尤其是非实体类参数)。

  • 作用:补充参数信息,Swagger 才能显示出来。

  • 常用属性

    属性名说明
    name参数名
    value参数说明
    required是否必填
    paramType参数类型(querypathbodyheaderform
    dataType参数数据类型(如 string, int

示例

@ApiImplicitParams({
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, paramType = "path", dataType = "Long"),
    @ApiImplicitParam(name = "token", value = "登录令牌", required = false, paramType = "header", dataType = "String")
})
@GetMapping("/{id}")
public User getUser(@PathVariable Long id, @RequestHeader String token) { ... }

3.3 模型注解

模型注解:作用于实体类

@ApiModel

  • 位置:标注在实体类(Java Bean)上。
  • 作用:描述一个数据模型类。
java复制编辑@ApiModel(description = "用户实体类")
public class User {
    ...
}

@ApiModelProperty

  • 位置:标注在实体类的字段上。
  • 作用:描述字段含义、是否必填、示例值等。

示例

@ApiModelProperty(value = "用户ID", example = "1001", required = true)
private Long id;

@ApiModelProperty(value = "用户名", example = "Tom", required = true)
private String name;
属性名说明
value字段说明
required是否必填
example示例值
hidden是否隐藏该字段

3.4 其他注解

@ApiResponse / @ApiResponses

  • 用于说明接口的响应信息(HTTP状态码、返回说明等)。
@ApiResponses({
    @ApiResponse(code = 200, message = "操作成功"),
    @ApiResponse(code = 400, message = "请求参数错误"),
    @ApiResponse(code = 500, message = "服务器内部错误")
})

四,Swagger2配置类

Swagger接口文档主要有四个部分构成:

  • 分组信息
  • 分组描述信息
  • 接口描述信息
  • 实体类信息

image

4.1 基础配置模板

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.example.controller")) // 扫描包路径
            .paths(PathSelectors.any()) // 路径过滤规则
            .build()
            .apiInfo(apiInfo()) // 文档基本信息
            .enable(true) // 是否启用 Swagger(默认 true)
            .groupName("默认分组") // 分组名称
            .securitySchemes(securitySchemes()) // 全局认证方案(如 Token)
            .securityContexts(securityContexts()); // 安全上下文
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("API 文档")
            .description("Spring Boot 集成 Swagger2 示例")
            .version("1.0")
            .contact(new Contact("作者", "https://example.com", "contact@example.com"))
            .license("Apache 2.0")
            .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0.html")
            .build();
    }
}

4.2 核心配置项详解

4.2.1 接口扫描规则

  • 指定扫描的包路径

    .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
    
  • 其他扫描规则

    • any():扫描所有接口。
    • none():不扫描任何接口。
    • withClassAnnotation(Controller.class):扫描带有 @Controller 注解的类。
    • withMethodAnnotation(GetMapping.class):扫描带有 @GetMapping 注解的方法。

4.2.2 路径过滤规则

  • 允许所有路径

    .paths(PathSelectors.any())
    
  • 其他规则

    • none():不匹配任何路径。
    • ant("/api/**"):匹配 /api/ 开头的路径。
    • regex("/.*"):通过正则表达式匹配路径。

4.2.3 文档信息(ApiInfo

配置项作用示例
title文档标题.title("用户管理 API")
description文档描述.description("用户增删改查接口")
versionAPI 版本号.version("1.0.0")
contact作者联系信息.contact(new Contact("John", "https://example.com", "john@example.com"))
license许可证名称.license("Apache 2.0")
licenseUrl许可证链接.licenseUrl("https://example.com/license")

4.2.4 分组配置

多分组配置

@Bean
public Docket userApi() {
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("用户接口")
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.example.user"))
        .build();
}

@Bean
public Docket orderApi() {
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("订单接口")
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.example.order"))
        .build();
}

4.2.5 全局参数(如 Token 认证)

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
            .paths(PathSelectors.any())
            .build()
            .apiInfo(apiInfo())
            // 配置全局认证方案
            .securitySchemes(securitySchemes())  // 定义认证类型
            .securityContexts(securityContexts()); // 定义认证范围
    }

    /**
     * 定义认证方案:使用 API Key(Token)
     */
    private List<ApiKey> securitySchemes() {
        return Arrays.asList(
            new ApiKey("Authorization", "Authorization", "header")
        );
    }

    /**
     * 定义认证范围:哪些接口需要认证
     */
    private List<SecurityContext> securityContexts() {
        return Arrays.asList(
            SecurityContext.builder()
                .securityReferences(defaultAuth()) // 关联认证方案
                .forPaths(PathSelectors.any())     // 对所有路径生效
                .build()
        );
    }

    /**
     * 关联认证方案和权限作用域
     */
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope[] scopes = new AuthorizationScope[]{
            new AuthorizationScope("global", "全局权限")
        };
        return Arrays.asList(
            new SecurityReference("Authorization", scopes)
        );
    }

    // 其他配置(如 apiInfo())省略...
}

securitySchemes():定义认证类型

  • ApiKey 参数说明

    new ApiKey(name, keyName, passAs)
    
    参数作用示例值
    name认证方案名称(自定义)"Authorization"
    keyName请求头/参数的键名"Authorization"
    passAs参数位置(header/query"header"

    示例:

    new ApiKey("Authorization", "Authorization", "header")
    

    效果:在请求头中添加 Authorization: xxx


securityContexts():定义认证范围

  • SecurityContext 配置项

    SecurityContext.builder()
        .securityReferences(defaultAuth()) // 关联认证方案
        .forPaths(PathSelectors.ant("/api/**")) // 仅对 /api/ 开头的路径生效
        .build()
    
    • securityReferences: 关联 securitySchemes 中定义的认证方案。
    • forPaths: 指定哪些路径需要认证(如 PathSelectors.any() 表示所有路径)。

defaultAuth():关联认证方案和作用域

  • SecurityReference:将认证方案与权限作用域绑定。

    new SecurityReference("Authorization", new AuthorizationScope[]{ ... })
    
    • 第一个参数:必须与 securitySchemes 中定义的 name 一致。
    • 第二个参数:定义权限作用域(一般保留默认即可)。

4.2.6 自定义响应模型

Docket docket = new Docket(DocumentationType.SWAGGER_2)
    .useDefaultResponseMessages(false) // 禁用默认响应码描述
    .globalResponseMessage(RequestMethod.GET, Arrays.asList(
        new ResponseMessageBuilder()
            .code(500)
            .message("服务器内部错误")
            .responseModel(new ModelRef("Error")) // 关联错误模型
            .build()
    ));

4.3 高级配置

4.3.1 自定义 Host 和 Path

Docket docket = new Docket(DocumentationType.SWAGGER_2)
    .host("api.example.com") // 指定 Host
    .pathMapping("/v1"); // 统一添加路径前缀

4.3.2 禁用默认响应码

Docket docket = new Docket(DocumentationType.SWAGGER_2)
    .useDefaultResponseMessages(false); // 关闭 200、401 等默认响应描述

4.4 生产环境优化

4.4.1 动态启用 Swagger

根据 Profile 控制是否启用 Swagger:

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
        .enable(!"prod".equals(env.getProperty("spring.profiles.active"))); // 生产环境关闭
}

4.4.2 结合 Spring Security 权限控制

限制访问 Swagger UI 路径:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/swagger-ui.html", "/v2/api-docs").hasRole("ADMIN"); // 仅管理员可访问
    }
}

五,整合bootstrap-ui框架

Swagger2最带的UI框架太丑了而且不是中文的,阅读不方便,这边将其替换成bootstrap-ui框架

步骤:

  1. 在依赖中将swagger-ui替换成bootstrap-ui

    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>swagger-bootstrap-ui</artifactId>
        <version>1.9.6</version>
    </dependency>
    
  2. 在Swagger配置类中放行资源

    @EnableWebMvc
    public class SpringMVCConfig implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/webjars/**")
                    .addResourceLocations("classpath:/META-INF/resources/webjars/");
            registry.addResourceHandler("/doc.html")
                    .addResourceLocations("classpath:/META-INF/resources/");
        }
    }
    
  3. 访问:http://localhost:8080/doc.html

需要注意的是,如果开启了其他拦截器,过滤器也必须方行这些静态资源和url