博客 / 詳情

返回

Spring Boot 三層架構解密:從 Controller 到 Repository 的數據之旅

在構建 Spring Boot 應用時,初學者最容易犯的錯誤就是把所有的邏輯——參數接收、業務判斷、SQL 查詢——都塞進一個類裏。這種“麪條式代碼”不僅難以維護,而且充滿安全隱患。

為了解決這個問題,現代後端開發普遍採用 三層架構 (Three-Tier Architecture)。這種架構的核心思想是**“各司其職”**。

今天,我們就來拆解 Controller、Service、Repository 這三大核心組件,並深入探討 DTO 與 Entity 在這場數據之旅中扮演的關鍵角色。

一、 三大核心角色:各司其職

在一個規範的 Spring Boot 項目中,每個請求的處理就像是在餐廳點菜,三個角色配合默契:

1. 表現層:Controller (服務員)

  • 註解@RestController
  • 職責路由 API,只負責“接待”
  • 工作內容

    • 監聽 HTTP 請求(GET/POST)。
    • 將前端傳來的 JSON 解析為 Java 對象。
    • 做最基本的參數校驗(比如手機號格式對不對)。
    • 關鍵原則:Controller 絕不觸碰數據庫,也不寫複雜的業務邏輯。它只負責把任務派發給 Service。
  • 比喻:餐廳的服務員。他負責把菜單遞給客人,記下客人點的菜,然後把單子送到後廚。他不會自己去炒菜。

2. 業務層:Service (廚師)

  • 註解@Service
  • 職責核心業務邏輯
  • 工作內容

    • 它是整個系統的“大腦”。
    • 執行業務規則(如:檢查餘額是否充足、計算折扣、觸發報警)。
    • 數據轉換中心:負責將 DTO 轉換為 Entity,或將 Entity 轉換為 DTO。
    • 調用 Repository 獲取數據或保存數據。
  • 比喻:後廚的主廚。他拿到服務員的單子,負責切菜、烹飪、調味。如果缺食材了,他會叫庫管去拿。

3. 數據層:Repository (庫管)

  • 註解@Repository
  • 職責數據庫操作 (CRUD)
  • 工作內容

    • 它是系統的“底層”。
    • 只負責與數據庫對話(執行 Insert, Update, Delete, Select)。
    • 返回的是與數據庫表一一對應的 Entity 對象。
  • 比喻:倉庫管理員。他不管這道菜是給誰吃的,也不管好不好吃,他只負責把食材(數據)拿出來,或者把成品存進去。

二、 兩個數據載體:Entity 與 DTO 的雙人舞

在三層架構中,數據需要在不同的層級間傳遞。為什麼我們需要兩種對象來承載數據?

1. Entity (實體對象)

  • 定義數據庫表的鏡像
  • 特徵:類名通常與表名對應,字段與列對應。
  • 作用:它是持久化數據的載體。
  • 侷限它是隱私的。Entity 可能包含“密碼”、“鹽值”、“邏輯刪除標記”等不應該暴露給前端的字段。

2. DTO (數據傳輸對象)

  • 定義API 接口的契約
  • 特徵:普通的 POJO,沒有任何數據庫註解。
  • 作用

    • 安全過濾:把 Entity 中的敏感字段(如密碼)過濾掉。
    • 數據聚合:有時一個 API 需要返回兩張表的數據(如:用户信息 + 訂單概況),DTO 可以把多個 Entity 的數據聚合在一起。
    • 解耦:如果數據庫表結構變了,只要 DTO 不變,前端就感知不到,保證了接口的穩定性。

三、 數據的奇幻漂流:完整流程圖解

讓我們通過“創建數據”和“查詢數據”兩個場景,看看數據是如何在 JSON、DTO 和 Entity 之間流轉的。

場景一:創建數據 (Write Flow)

任務:用户註冊(前端發送 JSON)。

流程:JSON ➡️ Controller ➡️ Service ➡️ Repository ➡️ DB
  1. JSON -\> DTO (Controller 層)

    • 前端發送 JSON 數據。
    • Controller 接收請求,Spring Boot 自動將 JSON 反序列化為 UserCreateDTO
  2. DTO -\> Entity (Service 層)

    • Controller 將 UserCreateDTO 傳給 Service。
    • Service 進行轉換(例如使用 MapStruct),將 UserCreateDTO 轉化為 UserEntity
    • 注意:此時 Service 可能會處理密碼加密等邏輯。
  3. Entity -\> DB (Repository 層)

    • Service 將 UserEntity 傳給 Repository。
    • Repository 執行 save(entity),數據入庫。

場景二:查詢數據 (Read Flow)

任務:獲取用户詳情(返回 JSON)。

流程:DB ➡️ Repository ➡️ Service ➡️ Controller ➡️ JSON
  1. DB -\> Entity (Repository 層)

    • Repository 根據 ID 從數據庫查詢數據。
    • 返回完整的 UserEntity(包含密碼字段)。
  2. Entity -\> DTO (Service 層)

    • Repository 將 UserEntity 傳給 Service。
    • Service 進行轉換,將 UserEntity 轉化為 UserResponseDTO
    • 關鍵點:在轉換過程中,Service 剔除了密碼字段,只保留用户名和頭像。
  3. DTO -\> JSON (Controller 層)

    • Service 將安全的 UserResponseDTO 返回給 Controller。
    • Controller 將其序列化為 JSON,響應給前端。

四、 代碼實戰:這一層層是怎麼調用的?

為了加深理解,我們來看一段偽代碼:

// 1. Controller: 負責路由和參數接收
@RestController
public class UserController {
    @Autowired
    private UserService userService; // 引用 Service

    @PostMapping("/users")
    public UserResponseDTO createUser(@RequestBody UserCreateDTO dto) {
        // 接收 DTO,傳給 Service
        return userService.register(dto);
    }
}

// 2. Service: 負責業務邏輯和轉換
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository; // 引用 Repository

    public UserResponseDTO register(UserCreateDTO dto) {
        // 邏輯:DTO 轉 Entity
        UserEntity entity = new UserEntity();
        entity.setUsername(dto.getUsername());
        
        // 邏輯:調用 Repository 保存
        userRepository.save(entity);
        
        // 邏輯:Entity 轉 DTO (準備返回)
        UserResponseDTO response = new UserResponseDTO();
        response.setId(entity.getId());
        response.setUsername(entity.getUsername());
        return response;
    }
}

// 3. Repository: 負責數據庫操作
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
    // 繼承了基本的 save, findById 等方法
}

五、 總結

Spring Boot 的三層架構就像一個精密運轉的工廠:

  • Controller大門,負責把原材料(JSON)收進來,變成工單(DTO)。
  • Service車間,負責核心加工,它把工單(DTO)變成產品(Entity),或者把產品包裝成商品(DTO)。
  • Repository倉庫,只負責保管產品(Entity)。

通過這種設計,我們實現了**“外層契約(DTO)”“內層存儲(Entity)”**的完美隔離,讓代碼既安全又易於維護。

本文由mdnice多平台發佈

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

發佈 評論

Some HTML is okay.