網站首頁 編程語言 正文
本文,我們將回到之前寫的showMovieHandler方法,并更新它以返回一個JSON響應,表示系統中的單個電影信息。類似于:
{ ? ? "id": 123, ? ? "title": "Casablanca",? ? ? "runtime": 102,? ? ? "genres": [ ? ? ? ? "drama",? ? ? ? ? "romance",? ? ? ? ? "war" ? ? ], ? ? "version": 1? }
我們不使用map序列化來創建這個JSON對象(就像我們在上一節中所做的那樣),這次我們將編碼一個自定義的Movie結構體。
首先,需要定義一個Movie結構體。我們將在一個新internal/data包中完成此操作,該包稍后將擴展用來封裝項目中所有自定義數據類型以及與數據庫交互的邏輯。
如果您按照文章步驟操作,請創建一個新的internal/data目錄,其中包含一個movies.go文件:
$ mkdir internal/data $ touch internal/data/movies.go
在這個新文件中,定義Movie結構,像這樣:
File: internal/data/movies.go
package main import ( ? ? "time" ) type Movie struct { ? ? ID ? ? ? ? ? ? int64 ? ? ?//唯一整數ID ? ? CreatedAt ? ? ?time.Time ?//創建電影到數據庫的時間 ? ? Title ? ? ? ? ?string ? ? //電影標題 ? ? Year ? ? ? ? ? int32 ? ? ?//電影發布年份 ? ? Runtime ? ? ? ?int32 ? ? ?//電影時長 ? ? Genres ? ? ? ? []string ? //電影類型(愛情片、喜劇片等) ? ? Version ? ? ? ?int32 ? ? ?//版本號從1開始,每更新一次遞增 }
這里需要指出的是,Movie結構體中的所有字段都是可導出的(即以大寫字母開頭),這對于Go的encoding/json包可見是必要的。在將結構體編碼為JSON時,不會包含任何未導出的字段。
現在結構體已經定義完成,讓我們更新showMovieHandler處理程序來初始化一個Movie結構體實例,然后使用writeJSON()幫助函數將其作為JSON響應發送給客戶端。
實現很簡單:
File: cmd/api/movies.go
package main import ( "fmt" "net/http" "time" "greenlight.alexedwards.net/internal/data" ) func (app *application) showMovieHandler(w http.ResponseWriter, r *http.Request) { id, err := app.readIDParam(r) if err != nil { http.NotFound(w, r) return } //創建一個Move結構體實例,包含從請求URL中解析的ID虛構的數據。注意這里故意沒有設置Year字段 movie := date.Movie{ ID: id, CreateAt: time.now(), Title: "Casablanca", Runtime: 102, Genres: []string{"drama", "romance", "war"}, Version: 1, } //將結構體序列化為JSON并以HTTP響應發送給客戶端 err = app.writeJSON(w, http.StatusOK, movie, nil) if err != nil { app.logger.Println(err) http.Error(w, "The server encountered a problem and could not process your request", http.StatusInternalServerError) } }
ok,下面試試!
重啟API,然后在瀏覽器中訪問localhost:4000/v1/movies/123。你應該會看到一個類似這樣的JSON響應:
在這個返回結果中,有幾件有趣的事情需要指出:
- Movie結構體被編碼成一個JSON對象,字段名和值作為鍵/值對。
- 默認情況下,JSON對象中的鍵等于結構體中的字段名(ID、CreatedAt、Title等等)。我們稍后將討論如何自定義JSON鍵。
- 如果結構體實例字段沒有顯式賦值,那么字段零值將序列化為json值。可以在上面的響應中看到——我們沒有在Go代碼中為Year字段設置值,但它仍然以0值出現在JSON輸出中。
更改JSON對象中的鍵
在Go中序列化結構體的一個好處是,您可以通過使用struct標簽注釋字段來定制JSON。
struct標簽最常見的用途可能是更改JSON對象中出現的鍵名稱。當你的結構體字段名不適合面向公眾展示,或者你想在JSON輸出中使用另一種大小寫樣式時,這是很有用的。
為了說明如何實現,對Movies結構體字段打標簽,使用蛇形格式:
File: internal/data/movies.go
//使用標記對Movie結構進行注釋,以控制json編碼的key顯示方式。 type Movie struct { ? ? ID ? ? ? int64 ? ? `json:"id"` ? ? CreateAt time.Time `json:"created_at"` ? ? Title ? ?string ? ?`json:"title"` ? ? Year ? ? int32 ? ? `json:"year"` ? ? Runtime ?int32 ? ? `json:"runtime"` ? ? Genres ? []string ?`json:"genres"` ? ? Version ?int32 ? ? `json:"version"` }
如果你重啟服務器并再次訪問localhost:4000/v1/movies/123,應該會看到一個類似于這樣的帶有蛇形鍵的響應:
在JSON對象中隱藏結構體字段
在定義結構體時候,通過使用omitempty可以控制對應字段在JSON中的可見性。當您不希望JSON輸出中出現特定的結構體字段時,可以使用-(連字符)指令。這對包含和用戶不相關的內部系統信息的字段或不想公開的敏感信息(如密碼哈希值)非常有用。
相反,當且僅當struct字段值為空時,omitempty指令會在JSON輸出中隱藏字段,其中empty被定義為:
- 等于false,0或“”
- 空數組,切片或map
- nil指針或接口值為nil
為了演示如何使用這些指令,我們對Movie結構進行更多的改造。CreatedAt字段與我們的最終用戶無關,所以我們使用-指令在輸出中將其隱藏。我們還將使用omitempty指令在輸出中隱藏Year、Runtime和types字段,當且僅當它們為空時生效。
繼續并像下面這樣更新struct標簽:
File:interface/data/movies.go
package data .... type Movie struct { ? ? ID ? ? ? int64 ? ? `json:"id"` ? ? CreateAt time.Time `json:"-"` ? ? ? //使用-指令 ? ? Title ? ?string ? ?`json:"title"` ? ? Year ? ? int32 ? ? `json:"year,omitempty"` ? ? ? ? ? ?//添加omitempty ? ? Runtime ?int32 ? ? `json:"runtime,omitempty"` ? ? ? ? //添加omitempty ? ? Genres ? []string ?`json:"genres,omitempty"` ? ? ? ? ?//添加omitempty ? ? Version ?int32 ? ? `json:"version"` }
如果你想使用omitempty而不改變鍵名,那么你可以在struct標簽中保留它為空-如:json:",omitempty"。注意,逗號是必要的。
現在,當你重新啟動應用程序并刷新你的web瀏覽器時,你應該會看到如下響應:
我們可以在這里看到,CreatedAt結構字段不再出現在JSON中,而且Year字段(值為0)也沒有出現,這要感謝omitempty指令。其他字段使用了omitempty不受影響(例如Runtime和Genres)。
注意:您還可以通過簡單地將結構體字段設置為不可導出來防止它出現在JSON序列化中。但使用json:“-“標記通常是一個更好的選擇:明確告知閱讀代碼的人,你不希望該字段包含在json。
舊版本的go vet如果你試圖在未導出的字段上使用struct標記會引發錯誤,但現在在go 1.16中已經修復了這個問題。
附加內容
結構體標簽string指令
最后一個不太常用的struct標記指令是string。可以使用這個標簽明確表示字段值序列化成JSON字符串類型。例如,如果我們希望Runtime字段的值表示為一個JSON字符串 (而不是數字)我們可以像這樣使用string指令:
type Movie struct { ? ? ID ? ? ? int64 ? ? `json:"id"` ? ? CreateAt time.Time `json:"-"` ? ? ? //使用-指令 ? ? Title ? ?string ? ?`json:"title"` ? ? Year ? ? int32 ? ? `json:"year,omitempty"` ?? ? ? Runtime ?Runtime ? `json:"runtime,omitempty,string"`? ? ? Genres ? []string ?`json:"genres,omitempty"` ? ? ?? ? ? Version ?int32 ? ? `json:"version"` }
JSON序列化結果如下所示:
{ "id": 123, "title": "Casablanca", "runtime": "102", ? //這是字符串 "genres": [ ? ? "drama",? ? ? "romance",? ? ? "war" ? ? ], "version": 1? }
注意string指令只對int, uint, float*或bool類型的字段有效。對于任何其他類型的結構體字段沒有作用。
原文鏈接:https://www.jianshu.com/p/49198840449c
相關推薦
- 2023-01-12 Kotlin注解實現Parcelable序列化流程詳解_Android
- 2023-04-04 Python筆記之Scipy.stats.norm函數使用解析_python
- 2021-07-18 vscode sftp no such file 解決辦法
- 2022-11-13 一文詳解Go語言單元測試的原理與使用_Golang
- 2022-08-04 python調用pymssql包操作SqlServer數據庫的實現_python
- 2022-08-04 Python?venv虛擬環境跨設備遷移的實現_python
- 2022-02-15 小程序搜索框歷史記錄,去除重復搜索內容,限制顯示條數
- 2022-11-03 C#如何給新建的winform程序添加資源文件夾Resources_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支