1. 概述

现代 Web 应用普遍采用前后端分离架构,后端通常以 REST API 形式对外提供服务。在这种模式下,API 的清晰、准确、可读性强的文档就显得尤为重要。

更关键的是:API 变了,文档必须同步更新。靠人工维护不仅效率低,还容易出错。因此,自动化文档生成工具成了刚需。

本文将带你使用 Springfox 实现的 Swagger 2 规范,为 Spring REST 服务生成 API 文档。

✅ 重要提示:
目前 Swagger 规范的最新版本是 OpenAPI 3.0,它由 Springdoc 项目支持得更好,推荐用于新项目(可参考 Spring REST OpenAPI 文档指南)。⚠️ Spring Boot 3 已不再支持 Springfox,本文内容适用于 Spring Boot 2.x 及以下版本。


2. 目标项目

本文不涉及 REST 服务的创建过程。如果你已有项目,可直接使用;如果没有,可参考以下资源快速搭建:


3. 添加 Maven 依赖

我们使用 Springfox 作为 Swagger 2 的实现。最新版本可在 Maven Central 查询。

pom.xml 中添加以下依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>

3.1 Spring Boot 项目依赖

如果你使用的是 Spring Boot,只需引入一个 starter 即可:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

同时确保你的项目继承了 Spring Boot 的 parent,以获得版本管理:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.5</version>
</dependency>

4. 集成 Swagger 2 到项目

4.1 Java 配置

Swagger 的核心配置围绕 Docket Bean 展开:

@Configuration
public class SpringFoxConfig {                                    
    @Bean
    public Docket api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}
  • Docket 是 Swagger 的配置入口。
  • select() 返回 ApiSelectorBuilder,用于控制哪些接口暴露给 Swagger。
  • RequestHandlerSelectors.any() 表示扫描所有 Controller。
  • PathSelectors.any() 表示匹配所有路径。

4.2 非 Spring Boot 项目的配置

在纯 Spring 项目中,需要显式启用 Swagger 2:

@Configuration
@EnableSwagger2
public class SpringFoxConfig {                                    
}

此外,还需手动配置资源处理器,因为 Spring Boot 的自动配置不可用:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");

    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
}

4.3 验证集成是否成功

启动应用后,访问:

http://localhost:8080/v2/api-docs

你会看到一个庞大的 JSON 响应。虽然机器可读,但对人类不友好。接下来,我们用 Swagger UI 来可视化它。


5. Swagger UI

Swagger UI 是一个内置的 UI 工具,让开发者可以直观地浏览和测试 API。

5.1 启用 Springfox 的 Swagger UI

添加以下依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>3.0.0</version>
</dependency>

访问:

http://localhost:8080/swagger-ui/

你应该能看到类似下面的界面:

Screenshot_1

5.2 探索 Swagger 文档

Swagger 会自动列出应用中所有的 Controller。点击任一 Controller,可查看其支持的 HTTP 方法(如 GET、POST 等)。

展开具体方法,可看到:

  • 响应状态码
  • 内容类型(Content-Type)
  • 参数列表
  • 在线试用功能(Try it out)

Swagger 的核心优势是与代码实时同步。例如,新增一个 Controller:

@RestController
public class CustomController {

    @RequestMapping(value = "/custom", method = RequestMethod.POST)
    public String custom() {
        return "custom";
    }
}

刷新 Swagger UI,你会发现 custom-controller 已出现在列表中,且只暴露了 POST 方法。


6. Spring Data REST 支持

Springfox 通过 springfox-data-rest 模块支持 Spring Data REST。

✅ 若使用 Spring Boot,只要引入 spring-boot-starter-data-rest,Spring Boot 会自动完成配置。

创建一个 User 实体:

@Entity
public class User {
    @Id
    private Long id;
    private String firstName;
    private int age;
    private String email;

    // getters and setters
}

创建 UserRepository 以启用 CRUD 操作:

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}

SpringFoxConfig 中导入 Spring Data REST 配置:

@EnableSwagger2
@Import(SpringDataRestConfiguration.class)
public class SpringFoxConfig {
    //...
}

⚠️ 注意:@EnableSwagger2WebMvc 在 Springfox 3.x 中已废弃,请使用 @EnableSwagger2

重启应用,Swagger UI 将自动生成 /users 的 CRUD 接口文档:

swagger_user_1


7. Bean Validation 支持

Springfox 可通过 springfox-bean-validators 模块解析 JSR-303 注解。

添加依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-bean-validators</artifactId>
    <version>2.9.2</version>
</dependency>

✅ Spring Boot 项目通常无需显式添加此依赖。

User 实体添加校验注解:

@Entity
public class User {
    //...
    
    @NotNull(message = "First Name cannot be null")
    private String firstName;
    
    @Min(value = 15, message = "Age should not be less than 15")
    @Max(value = 65, message = "Age should not be greater than 65")
    private int age;
}

SpringFoxConfig 中启用 Bean Validator 插件:

@EnableSwagger2
@Import(BeanValidatorPluginsConfiguration.class)
public class SpringFoxConfig {
    //...
}

Swagger UI 将显示校验规则:

swagger_user_2

  • firstName 标记为必填(* required)
  • age 显示最小值 15,最大值 65

8. 自定义插件

Springfox 提供 SPI 机制,允许通过插件扩展功能。常见插件接口包括:

  • ModelBuilderPlugin:模型构建
  • ModelPropertyBuilderPlugin:属性构建
  • ApiListingBuilderPlugin:接口列表构建

示例:为 @Email 注解添加 pattern 和 example

创建 EmailAnnotationPlugin

@Component
@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER)
public class EmailAnnotationPlugin implements ModelPropertyBuilderPlugin {
    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }

    @Override
    public void apply(ModelPropertyContext context) {
        Optional<Email> email = annotationFromBean(context, Email.class);
         if (email.isPresent()) {
            context.getSpecificationBuilder().facetBuilder(StringElementFacetBuilder.class)
              .pattern(email.get().regexp());
            context.getSpecificationBuilder().example("user@example.com");
        }
    }
}

Useremail 字段添加 @Email 注解:

@Entity
public class User {
    //...

    @Email(regexp=".*@.*\\..*", message = "Email should be valid")
    private String email;
}

SpringFoxConfig 中注册插件 Bean:

@Import({BeanValidatorPluginsConfiguration.class})
public class SpringFoxConfig {
    //...

    @Bean
    public EmailAnnotationPlugin emailPlugin() {
        return new EmailAnnotationPlugin();
    }
}

效果如下:

swagger_user_3

  • pattern 显示正则表达式
  • example 显示示例邮箱

9. 高级配置

9.1 过滤 API

并非所有接口都需要暴露文档。可通过 apis()paths() 精确控制:

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()                                       
      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
      .paths(PathSelectors.ant("/foos/*"))                     
      .build();
}
  • basePackage:仅扫描指定包下的 Controller
  • ant("/foos/*"):仅包含 /foos 开头的路径

9.2 自定义 API 信息

使用 apiInfo() 方法替换默认的文档元信息:

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()
      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
      .paths(PathSelectors.ant("/foos/*"))
      .build()
      .apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
    return new ApiInfo(
      "My REST API", 
      "Some custom description of API.", 
      "API TOS", 
      "Terms of service", 
      new Contact("John Doe", "www.example.com", "john.doe@example.com"), 
      "License of API", "https://example.com/license", Collections.emptyList());
}

9.3 全局覆盖响应消息

通过 globalResponses() 统一修改 HTTP 方法的默认响应描述:

.useDefaultResponseMessages(false)
.globalResponses(HttpMethod.GET, newArrayList(
    new ResponseBuilder().code("500")
        .description("服务器内部错误").build(),
    new ResponseBuilder().code("403")
        .description("禁止访问").build()
));

效果如下:

Screenshot_2


10. Swagger UI 接入 OAuth2 安全接口

当 API 受 OAuth2 保护时,Swagger UI 需要能获取 Token 才能调用。以下是基于 Authorization Code 模式的配置。

10.1 安全配置 Bean

@Bean
public SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder()
        .clientId("my-client-id")
        .clientSecret("my-client-secret")
        .scopeSeparator(" ")
        .useBasicAuthenticationWithAccessCodeGrant(true)
        .build();
}

10.2 SecurityScheme

定义 OAuth2 安全方案:

private SecurityScheme securityScheme() {
    GrantType grantType = new AuthorizationCodeGrantBuilder()
        .tokenEndpoint(new TokenEndpoint("http://auth-server/token", "oauthtoken"))
        .tokenRequestEndpoint(
          new TokenRequestEndpoint("http://auth-server/authorize", "my-client-id", "my-client-secret"))
        .build();

    SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
        .grantTypes(Arrays.asList(grantType))
        .scopes(Arrays.asList(scopes()))
        .build();
    return oauth;
}

private AuthorizationScope[] scopes() {
    AuthorizationScope[] scopes = { 
      new AuthorizationScope("read", "for read operations"), 
      new AuthorizationScope("write", "for write operations"), 
      new AuthorizationScope("foo", "Access foo API") };
    return scopes;
}

10.3 SecurityContext

定义安全上下文,指定哪些路径需要认证:

private SecurityContext securityContext() {
    return SecurityContext.builder()
      .securityReferences(
        Arrays.asList(new SecurityReference("spring_oauth", scopes())))
      .forPaths(PathSelectors.regex("/foos.*"))
      .build();
}

spring_oauth 必须与 SecurityScheme 中的 name 一致。

10.4 测试

访问 Swagger UI:

http://localhost:8080/swagger-ui/

你会看到 Authorize 按钮:

swagger_1

点击后可输入客户端信息并选择权限:

swagger_2

认证后,受保护的接口会显示锁图标:

swagger_3

⚠️ 重要提醒:生产环境务必谨慎暴露 Swagger UI,避免敏感信息泄露。


11. 总结

本文完整演示了如何在 Spring REST 项目中集成 Swagger 2,涵盖:

  • 基础配置与 UI 集成
  • Spring Data REST 和 Bean Validation 支持
  • 自定义插件开发
  • 高级过滤与信息定制
  • OAuth2 安全接口接入

虽然 Springfox 在新项目中已被 Springdoc 取代,但理解其原理对维护旧项目仍有价值。对于新项目,建议直接使用 Springdoc + OpenAPI 3


原始标题:Setting Up Swagger 2 with a Spring REST API | Baeldung

« 上一篇: Java XML指南