使用 Springfox 構建 Spring REST API 的 Swagger 2 設置指南

REST,Security,Spring
Remote
1
03:52 PM · Dec 01 ,2025

1. 概述

如今,前端和後端組件經常分離一個 Web 應用程序。 通常,我們將 API 作為後端組件暴露給前端組件或第三方應用集成。

在這種情況下,對後端 API 必須有正確的規範。 同時,API 文檔應該具有信息量、可讀性和易於遵循性。

此外,參考文檔應同時描述 API 中的所有更改。 手動完成此操作是一項繁瑣的任務,因此自動化過程是不可避免的。

在本教程中,我們將探討 Spring REST Web 服務中的 Swagger 2,使用 Springfox 實現 Swagger 2 規範。 如果您不熟悉 Swagger,請訪問 其 Web 頁面 以瞭解更多信息,然後再繼續本教程。

需要注意的是,最新的 Swagger 規範,現在稱為 OpenAPI 3.0,由 Springdoc 項目更好地支持,並且應該用於記錄 Spring REST API。 此外,Spring Boot 3 不支持該庫。

2. 目標項目

我們使用的 REST 服務創建不屬於本文檔的範圍。如果您已經有合適的項目,請使用它。如果沒有,以下鏈接是一個不錯的起點:

3. 添加 Maven 依賴

如上所述,我們將使用 Springfox 的 Swagger 規範實現。最新版本可以在 Maven Central 上找到。

要將其添加到我們的 Maven 項目中,需要在 pom.xml 文件中添加一個依賴項:


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

3.1. Spring Boot 依賴

對於基於 Spring Boot 的項目,只需要添加一個 springfox-boot-starter 依賴項:


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

我們可以添加任何我們需要的 starter,版本由 Spring Boot 父項目管理:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.2</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 Bean 後,其 select() 方法返回一個 ApiSelectorBuilder 實例,該實例提供了一種控制 Swagger 暴露的端點的方法。

我們可以使用 RequestHandlerSelectorsPathSelectors 選擇 RequestHandler 實例,並使用 any() 對於兩者都使用 any() 將我們的 API 的整個文檔通過 Swagger 可用。

4.2. 不使用 Spring Boot 的配置

在純 Spring 項目中,我們需要顯式地啓用 Swagger 2。 要做到這一點,我們必須在配置類上使用 @EnableSwagger2 :

@Configuration
@EnableSwagger2
public class SpringFoxConfig {                                    
}

此外,如果沒有 Spring Boot,我們沒有自動配置資源處理器的奢侈品。

Swagger UI 添加了一組資源,我們需要將其配置為擴展 WebMvcConfigurerAdapter 且帶有 @EnableWebMvc 註解的類的一部分:

@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. 驗證

要驗證 Springfox 是否正在工作,我們可以通過以下 URL 在瀏覽器中訪問:

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

結果是一個包含大量鍵值對的 JSON 響應,不太容易閲讀。 幸運的是,Swagger 提供了 Swagger UI 用於此目的。

5. Swagger UI

Swagger UI 是一個內置解決方案,使與 Swagger 生成的 API 文檔的用户交互更加容易。

5.1. 啓用 Springfox 的 Swagger UI

要使用 Swagger UI,我們需要添加額外的 Maven 依賴項:

<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 的響應中包含一個 所有在我們的應用程序中定義的控制器列表

單擊其中任何一個將列出有效的 HTTP 方法(DELETEGETHEADOPTIONSPATCHPOSTPUT)。

展開每個方法將提供額外有用的數據,例如響應狀態、內容類型和參數列表。 還可以使用 UI 嘗試每個方法。

Swagger 與我們的代碼庫同步的能力至關重要。 為了演示這一點,我們可以向我們的應用程序添加一個新的控制器:

@RestController
public class CustomController {

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

現在,如果我們刷新 Swagger 文檔,我們將在控制器的列表中看到 custom-controller。 就像我們知道的,響應中只有一個方法(POST)顯示。

6. Spring Data REST

Springfox 提供對 Spring Data REST 的支持,通過其 springfox-data-rest 庫。

Spring Boot 將自動配置如果發現 spring-boot-starter-data-rest 在類路徑上

現在,我們創建一個名為 User 的實體:

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

    // getters and setters
}

然後,我們將創建 UserRepository 以向 User 實體添加 CRUD 操作:

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

最後,我們將導入 SpringDataRestConfiguration 類到 SpringFoxConfig 類中:

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

注意:我們將使用 @EnableSwagger2 註解來啓用 Swagger,因為 @EnableSwagger2WebMvc版本 3 的庫中已棄用

讓我們重啓應用程序以生成 Spring Data REST API 的規範:

swagger_user_1

我們可以看到 Springfox 已生成 User 實體與 HTTP 方法(如 GETPOSTPUTPATCHDELETE)的規範。

7. Bean Validations

Springfox 也支持通過其 springfox-bean-validators 庫來驗證 Bean 註解。

首先,我們將 Maven 依賴添加到我們的 pom.xml 中:


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

再次,如果使用 Spring Boot,我們不需要顯式提供上述依賴

接下來,我們為 User 實體添加幾個驗證註解,例如 @NotNull@Min


@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;
}

最後,我們將 BeanValidatorPluginsConfiguration 類導入到 SpringFoxConfig 類中:


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

讓我們看一下 API 規範的更改:

swagger_user_2

在這裏,我們可以觀察到 User 模型上 * 必需* 標記在 firstName 上。 此外,minimummaximum 值已定義在 age 上。

8. 插件

為了向 API 規範添加特定功能,我們可以創建一個 Springfox 插件。插件可以提供各種功能,從豐富模型和屬性到自定義 API 列表和默認值。

Springfox 支持通過其 spi 模塊創建插件。spi 模塊提供了一些接口,如 ModelBuilderPluginModelPropertyBuilderPluginApiListingBuilderPlugin,它們作為可擴展性鈎子來實現自定義插件。

為了演示其功能,讓我們創建一個插件來豐富 email 屬性的 User 模型。我們將使用 ModelPropertyBuilderPlugin 接口,並設置 patternexample 的值。

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

然後我們將覆蓋 apply 方法的 ModelPropertyBuilderPlugin 來設置構建器屬性的值:

@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("[email protected]");
    }
}

因此,API 規範將顯示屬性(email)的值,該屬性已使用 @Email 註解標記。

接下來,我們將向 User 實體添加 @Email 註解:

@Entity
public class User {
    //...

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

最後,我們將啓用 EmailAnnotationPluginSpringFoxConfig 類中,通過將其註冊為 Bean 來完成:

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

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

讓我們查看 EmailAnnotationPlugin 在行動中的情況:

swagger_user_3

我們可以看到 pattern 的值與 email 屬性的 User 實體中的 regexp (.*@.*\\..*) 值相同。

同樣,example 的值([email protected])也與 apply 方法中定義的 EmailAnnotationPlugin 中的值相同。

9. 進階配置

Docket 我們的應用程序的 Bean 可以配置為使我們能夠更好地控制 Swagger 文檔生成過程。

9.1. 過濾 Swagger 的響應

並非總是希望暴露整個 API 的文檔。我們可以通過將參數傳遞給 Docket 類中的 apis()paths() 方法來限制 Swagger 的響應。

如上所示,RequestHandlerSelectors 允許使用 anynone 謂詞,但也可以用於根據基礎包、類註解和方法註解來過濾 API。

PathSelectors 通過謂詞提供額外的過濾功能,掃描我們應用程序的請求路徑。我們可以使用 any(), none(), regex()ant()

在下面的示例中,我們將指導 Swagger 只包含來自特定包中的控制器,具有特定路徑,使用 ant() 謂詞:

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

9.2. 自定義信息

Swagger 還提供了一些默認響應值,我們可以自定義,例如“API 文檔”、“聯繫人電子郵件”、“Apache 2.0”。

要更改這些值,我們可以使用 apiInfo(ApiInfo apiInfo) 方法——ApiInfo 類,其中包含有關 API 的自定義信息:

@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", "[email protected]"), 
      "License of API", "API license URL", Collections.emptyList());
}

9.3. 自定義方法響應消息

Swagger 允許通過 DocketglobalResponses() 方法全局覆蓋 HTTP 方法的響應消息。

首先,我們需要指導 Swagger 不要使用默認響應消息。假設我們要覆蓋所有 GET 方法的 500403 響應消息。

要實現這一點,需要將一些代碼添加到 Docket 的初始化塊中(為了清晰起見,已排除原始代碼):

.useDefaultResponseMessages(false)
.globalResponses(HttpMethod.GET, newArrayList(
    new ResponseBuilder().code("500")
        .description("500 message").build(),
    new ResponseBuilder().code("403")
        .description("Forbidden!!!!!").build()
));
Screenshot_2

10. Swagger UI With an OAuth-Secured API

The Swagger UI provides a number of very useful features that we’ve covered well so far here. But we can’t really use most of these if our API is secured and not accessible.

Let’s see how we can allow Swagger to access an OAuth-secured API using the Authorization Code grant type in this example.

We’ll configure Swagger to access our secured API using the SecurityScheme and SecurityContext support:

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
        .apis(RequestHandlerSelectors.any())
        .paths(PathSelectors.any())
        .build()
        .securitySchemes(Arrays.asList(securityScheme()))
        .securityContexts(Arrays.asList(securityContext()));
}

10.1. The Security Configuration

We’ll define a SecurityConfiguration bean in our Swagger configuration and set some defaults:

@Bean
public SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder()
        .clientId(CLIENT_ID)
        .clientSecret(CLIENT_SECRET)
        .scopeSeparator(" ")
        .useBasicAuthenticationWithAccessCodeGrant(true)
        .build();
}

10.2. SecurityScheme

Next, we’ll define our SecurityScheme

In our case here, we’ll define an OAuth scheme used to secure our Resource Server:

private SecurityScheme securityScheme() {
    GrantType grantType = new AuthorizationCodeGrantBuilder()
        .tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/token", "oauthtoken"))
        .tokenRequestEndpoint(
          new TokenRequestEndpoint(AUTH_SERVER + "/authorize", CLIENT_ID, CLIENT_SECRET))
        .build();

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

Note that we used the Authorization Code grant type, for which we need to provide a token endpoint and the authorization URL of our OAuth2 Authorization Server.

And here are the scopes we need to have defined:

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;
}

These sync up with the scopes we actually have defined in our application, for the

10.3. SecurityContext

Finally, we need to define a SecurityContext

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

Note how the name we used here in the reference — spring_oauth

10.4. Test

Now that we have everything set up and ready to go, let’s take a look at our Swagger UI and try access the Foo API.

We can access the Swagger UI locally:

http://localhost:8082/spring-security-oauth-resource/swagger-ui.html

As we can see, a new Authorize button now exists due to our security configurations:

swagger_1

When we click the Authorize button, we can see the following pop-up to authorize our Swagger UI to access the secured API:

swagger_2

Note that:

  • We can already see the CLIENT_ID and CLIENT_SECRET, as we’ve pre-configured them earlier (but we can still change them).
  • We can now select the scopes we need.

Here’s how the secured API is marked:

swagger_3

And now, finally, we can hit our API!

Of course, it almost goes without saying that we need to be careful how we expose Swagger UI externally, now that this security configuration is active.

11. 結論

在本文中,我們設置了 Swagger 2 以生成 Spring REST API 的文檔。我們還探討了可視化和自定義 Swagger 輸出的方法。最後,我們研究了簡單的 OAuth 配置,用於 Swagger。

如果您是《REST With Spring》的學生,請參閲模塊 7 的第 1 課,以深入瞭解如何使用 Swagger 與 Spring 和 Spring Boot 配合使用。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.