構建基於 Spring 和 Java 配置的 REST API

REST,Spring
Remote
1
07:02 PM · Dec 01 ,2025

1. 概述

在本教程中,我們將學習如何在 Spring 中設置 RESTful API,包括控制器和 HTTP 響應代碼、負載映射配置以及內容協商。

2. 依賴項

為了使用 Spring Boot 創建 REST API,我們需要 Spring Boot Starter Web 依賴項,該依賴項包含用於構建 Web 應用程序、處理 HTTP 請求和 JSON 序列化的庫。只需在我們的 pom.xml 中包含以下依賴項:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot 自動配置 Jackson 作為 Java 對象和 JSON 之間的默認序列化器和反序列器。

3. 控制器

@RestController 是整個 RESTful API 的 Web 層中的核心 Artifact。 對於本文檔的目的,控制器正在建模一個簡單的 REST 資源,Foo

@RestController
@RequestMapping("/foos")
class FooController {

    @Autowired
    private IFooService service;

    @GetMapping
    public List<Foo> findAll() {
        return service.findAll();
    }

    @GetMapping(value = "/{id}")
    public Foo findById(@PathVariable("id") Long id) {
        return RestPreconditions.checkFound(service.findById(id));
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long create(@RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        return service.create(resource);
    }

    @PutMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        RestPreconditions.checkNotNull(service.getById(resource.getId()));
        service.update(resource);
    }

    @DeleteMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void delete(@PathVariable("id") Long id) {
        service.deleteById(id);
    }

}

正如我們所看到的,我們正在使用一種簡單直觀的 Guava 風格的 RestPreconditions 工具:

public class RestPreconditions {
    public static <T> T checkFound(T resource) {
        if (resource == null) {
            throw new MyResourceNotFoundException();
        }
        return resource;
    }
}

控制器的實現是非公共的,因為不需要公開訪問。

通常,控制器是依賴鏈中的最後一個,它接收來自 Spring 前端控制器(DispatcherServlet)的 HTTP 請求,並簡單地將它們委託轉發到服務層。如果控制器沒有必要被注入或通過直接引用進行操作,那麼我們可能更喜歡不將其聲明為公共的。

請求映射很簡單。與任何控制器一樣,映射的實際值以及 HTTP 方法確定請求的目標方法。 @RequestBody 將方法的參數綁定到 HTTP 請求的 body,而 ResponseBody 則將響應和返回類型綁定。

@RestController 是一個簡寫,用於在我們的類中包含 @ResponseBody 和 @Controller 註解。

它們還確保資源將使用正確的 HTTP 轉換器進行序列化和反序列化。內容協商將發生,以選擇將用於其中的一個活動轉換器,該轉換器主要基於 Accept 標頭,儘管其他 HTTP 標頭也可能用於確定表示形式。

4. 測試 Spring 上下文

當測試 Spring Boot 應用程序時,由於 Spring Boot 的自動配置和測試註解,流程會變得更加容易。

如果我們想在不啓動服務器的情況下測試完整的應用程序上下文,可以使用 @SpringBootTest 註解。

有了這個註解,我們還可以添加 @AutoConfigureMockMvc 來注入一個 MockMvc 實例併發送 HTTP 請求:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FooControllerAppIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void whenTestApp_thenEmptyResponse() throws Exception {
        this.mockMvc.perform(get("/foos")
          .andExpect(status().isOk())
          .andExpect(...);
    }

}

為了只測試 Web 層並避免加載應用程序中的不必要部分,可以使用 @WebMvcTest 註解:

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerWebLayerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private IFooService service;

    @Test()
    public void whenTestMvcController_thenRetrieveExpectedResult() throws Exception {
        // ...

        this.mockMvc.perform(get("/foos")
          .andExpect(...);
    }
}

通過使用 @WebMvcTest,我們僅關注測試 MVC 層,Spring Boot 會自動設置僅控制器層和依賴項(如 Mock 服務)的上下文。

5. HTTP 響應代碼映射

HTTP 響應狀態碼是 RESTful 服務中最重要的部分之一,並且這個主題可能很快變得非常複雜。正確設置這些狀態碼可以決定服務是否成功。

5.1. 未映射的請求

當 Spring MVC 收到沒有映射的請求時,它會認為該請求被拒絕,並返回 405 METHOD NOT ALLOWED 錯誤碼給客户端。

為了更好地實踐,在返回 405 錯誤碼時,應該包含 Allow HTTP 頭部,以指定允許的操作。 這種行為是 Spring MVC 的標準行為,不需要任何額外的配置。

5.2. 有效映射的請求

對於確實具有映射的請求,Spring MVC 會認為該請求有效,並返回 200 OK 響應,除非另有指定其他狀態碼。

因此,控制器聲明瞭不同的 @ResponseStatus 屬性,用於 createupdatedelete 操作,但沒有為 get 操作指定狀態碼,因為 get 操作應該返回默認的 200 OK。

5.3. 客户端錯誤

在客户端錯誤的情況下,自定義異常會被定義並映射到相應的錯誤碼。

從 Web 層中的任何位置拋出這些異常,將確保 Spring 映射到 HTTP 響應的相應狀態碼:

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
   //
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
   //
}

這些異常是 REST API 的一部分,因此我們應該只在與 REST 相關的適當層中使用它們;例如,如果存在 DAO/DAL 層,則不應直接使用這些異常。

此外,這些異常不是檢查異常,而是與 Spring 實踐和習慣相符的運行時異常。

5.4. 使用 @ExceptionHandler

另一種將自定義異常映射到特定狀態碼的方法是使用控制器中的 @ExceptionHandler 註解。 但是,這種方法的問題在於,該註解僅適用於其定義的控制器。 這意味着我們需要在每個控制器中單獨聲明它們。

當然,Spring 和 Spring Boot 提供了更多處理錯誤的方法,這些方法提供了更大的靈活性。

6. 結論

本文介紹瞭如何使用 Spring 和 Java 配置實現和配置 REST 服務。

在後續的文章中,我們將重點關注 API 的可發現性、高級內容協商以及與 資源的其他表示形式一起工作。

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

發佈 評論

Some HTML is okay.