像SpringBoot這樣的框架可以為你做很多事情,這真是太好了。
您只需要一個 JPA 實體類別加上一個簡單的儲存庫接口,SpringData 將為您提供典型 CRUD 資料庫操作所需的一切。
您編寫了一個簡單的 REST 控制器類,並且運行了一個 REST API,對吧?
嘿,但你忘了寫 DTO !但是,當您的應用程式無需它也可以運行時,為什麼您實際上需要它?
當然有一些一般原因:
但是其他奇怪的事情也可能發生。我將根據我的經驗向您展示一個奇怪的例子。
此 GitHub 儲存庫包含一個無需 DTO 即可運行的簡單應用程式。有一個User實體,每個User可以有多個Transaction。我們甚至在儲存庫和 RestController 之間有一個 Service bean,用於捕獲可能的資料庫存取異常。
由於我們想要製作一個可用於生產的應用程序,因此我們不希望 Hibernate 產生 DDL。相反,我們有一個 schema.sql 來建立表(稍後我們可能會切換到 Flyway 或 Liquibase)。對於我們的簡單範例,我們還有一個 data.sql,以便我們的表不為空。
當我們執行應用程式並呼叫 http://localhost:8080/users 處的 API 端點時,我們會得到包含使用者及其交易的預期 JSON。
現在我們專注於Transaction類別中的兩行程式碼,標記為//!!
@JsonIgnore //!!
第一個味道是,在 Transaction 類別中,我們必須將 @JsonIgnore 註解加入 User 參考中。如果沒有該註釋,JSON 序列化會因無限遞歸而崩潰。
現在讓我們想像一下,有人在向 Transaction 實體新增另一個欄位(描述)時犯了一個錯誤,但忘記調整 SQL 語句(或在尚未應用架構變更的環境中執行應用程式)。
私有字串描述;//!!
當然,現在API呼叫失敗了。但看看錯誤處理! UserService 內的 catch 子句未如預期運作。相反,我們可以在日誌中看到奇怪的堆疊追蹤:
GlobalExceptionHandler:意外錯誤org.springframework.http.converter.HttpMessageNotWritableException:無法寫入JSON:
我曾經見過這種情況(顯然,應用程式比這個範例大得多),我花了很長時間才理解為什麼 SQL 異常逃逸了服務以及為什麼我收到 HttpMessageNotWritableException。你能看見它嗎?
發生的情況是,UserService 類別(透過 UserRepository)僅查詢 USERS 資料庫表。由於預設的 Hibernate 延遲加載,事務實體不是結果的一部分。只有當 Jackson 反序列化器嘗試從 User 實例建立 JSON 時,它才會呼叫其 getTransactions 方法,使 Hibernate 取得 Transaction 實體。
這就是為什麼我們得到一個奇怪的堆疊跟踪,結合了 JSON 和 SQL 的內容。這個例外被 GlobalExceptionHandler 捕獲,但不知道如何處理它,這就是為什麼日誌訊息為「意外錯誤」的原因。
我希望這個小練習能讓您更深入地了解允許應用程式的不同層混合是多麼危險。在應用程式還很小的時候只看到應用程式的「晴天」場景可能會導致一些開發人員繼續做錯誤的事情,直到為時已晚。
您不必編寫在 DTO 和應用程式的其他層之間映射欄位的樣板程式碼。 MapStruct 可以為您做到。
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3