在Go语言中,控制实体字段生成JSON的方法非常灵活。以下是详细的各种方法:
json 标签控制字段package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"` // 序列化为 "id"
Username string `json:"username"` // 序列化为 "username"
Password string `json:"-"` // 忽略该字段,不参与序列化
Email string `json:"email,omitempty"` // 如果为空值则忽略
Age int `json:"age,omitempty"` // 如果为0则忽略
Secret string `json:"secret,omitempty"` // 如果为空字符串则忽略
Status string // 没有json标签,使用字段名 "Status"
}
func main() {
user := User{
ID: 1,
Username: "john_doe",
Password: "secret123",
Email: "", // 空值
Age: 0, // 零值
Secret: "confidential",
Status: "active",
}
data, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
}
输出:
{
"id": 1,
"username": "john_doe",
"Status": "active"
}
type Address struct {
Street string `json:"street,omitempty"`
City string `json:"city,omitempty"`
Country string `json:"country,omitempty"`
ZipCode string `json:"zip_code,omitempty"`
}
type Profile struct {
UserID int `json:"user_id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Phone string `json:"phone,omitempty"`
Address Address `json:"address,omitempty"`
Internal string `json:"-"` // 内部字段,不暴露
}
func main() {
profile := Profile{
UserID: 1,
FirstName: "John",
LastName: "Doe",
// Phone 为空,将被忽略
Address: Address{
Street: "123 Main St",
City: "New York",
// Country 和 ZipCode 为空,将被忽略
},
Internal: "sensitive data",
}
data, _ := json.MarshalIndent(profile, "", " ")
fmt.Println(string(data))
}
输出:
{
"user_id": 1,
"first_name": "John",
"last_name": "Doe",
"address": {
"street": "123 Main St",
"city": "New York"
}
}
type SensitiveUser struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"-"` // 直接忽略
SecretKey string // 需要自定义逻辑处理
CreatedAt time.Time
}
// 自定义JSON序列化方法
func (u SensitiveUser) MarshalJSON() ([]byte, error) {
// 创建匿名结构体,只包含需要暴露的字段
type Alias SensitiveUser
return json.Marshal(&struct {
Alias
SecretKey string `json:"-"` // 确保隐藏
FormattedDate string `json:"created_date"`
}{
Alias: Alias(u),
SecretKey: "", // 明确设置为空
FormattedDate: u.CreatedAt.Format("2006-01-02"),
})
}
func main() {
user := SensitiveUser{
ID: 1,
Username: "alice",
Email: "alice@example.com",
Password: "secret",
SecretKey: "very-secret-key",
CreatedAt: time.Now(),
}
data, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
}
输出:
{
"id": 1,
"username": "alice",
"email": "alice@example.com",
"created_date": "2024-01-15"
}
// 完整用户结构体(数据库模型)
type FullUser struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
PasswordHash string `json:"-"`
Phone string `json:"phone"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
IsActive bool `json:"-"`
}
// 公共视图(API响应)
type PublicUserView struct {
ID int `json:"id"`
Username string `json:"username"`
}
// 私有视图(用户自己的信息)
type PrivateUserView struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone,omitempty"`
}
// 转换方法
func (u *FullUser) ToPublicView() PublicUserView {
return PublicUserView{
ID: u.ID,
Username: u.Username,
}
}
func (u *FullUser) ToPrivateView() PrivateUserView {
return PrivateUserView{
ID: u.ID,
Username: u.Username,
Email: u.Email,
Phone: u.Phone,
}
}
func main() {
fullUser := &FullUser{
ID: 1,
Username: "bob",
Email: "bob@example.com",
PasswordHash: "hashed_password",
Phone: "123-456-7890",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
IsActive: true,
}
// 不同场景使用不同视图
publicView := fullUser.ToPublicView()
privateView := fullUser.ToPrivateView()
publicJSON, _ := json.MarshalIndent(publicView, "", " ")
privateJSON, _ := json.MarshalIndent(privateView, "", " ")
fmt.Println("公共视图:")
fmt.Println(string(publicJSON))
fmt.Println("\n私有视图:")
fmt.Println(string(privateJSON))
}
输出:
公共视图:
{
"id": 1,
"username": "bob"
}
私有视图:
{
"id": 1,
"username": "bob",
"email": "bob@example.com",
"phone": "123-456-7890"
}
type DynamicUser struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
// 控制显示级别的标记
showSensitive bool `json:"-"`
}
// 设置显示级别
func (u *DynamicUser) SetShowSensitive(show bool) {
u.showSensitive = show
}
// 自定义序列化
func (u DynamicUser) MarshalJSON() ([]byte, error) {
if u.showSensitive {
// 显示所有字段
type Alias DynamicUser
return json.Marshal(&struct {
Alias
}{
Alias: Alias(u),
})
} else {
// 只显示基本字段
return json.Marshal(&struct {
ID int `json:"id"`
Username string `json:"username"`
}{
ID: u.ID,
Username: u.Username,
})
}
}
func main() {
user := DynamicUser{
ID: 1,
Username: "charlie",
Email: "charlie@example.com",
Phone: "555-0123",
}
// 基本视图
basicJSON, _ := json.MarshalIndent(user, "", " ")
fmt.Println("基本视图:")
fmt.Println(string(basicJSON))
// 敏感信息视图
user.SetShowSensitive(true)
sensitiveJSON, _ := json.MarshalIndent(user, "", " ")
fmt.Println("\n敏感信息视图:")
fmt.Println(string(sensitiveJSON))
}
// JSONView 接口
type JSONView interface {
ToJSON() interface{}
}
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
Cost float64 `json:"-"` // 成本,不对外暴露
Stock int `json:"stock"`
IsActive bool `json:"-"`
}
// 客户视图
func (p *Product) CustomerView() interface{} {
return struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
}{
ID: p.ID,
Name: p.Name,
Description: p.Description,
Price: p.Price,
}
}
// 管理员视图
func (p *Product) AdminView() interface{} {
return struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
Cost float64 `json:"cost"`
Stock int `json:"stock"`
IsActive bool `json:"is_active"`
}{
ID: p.ID,
Name: p.Name,
Description: p.Description,
Price: p.Price,
Cost: p.Cost,
Stock: p.Stock,
IsActive: p.IsActive,
}
}
func main() {
product := &Product{
ID: 1,
Name: "Laptop",
Description: "High-performance laptop",
Price: 999.99,
Cost: 650.00,
Stock: 50,
IsActive: true,
}
// 客户看到的JSON
customerData, _ := json.MarshalIndent(product.CustomerView(), "", " ")
fmt.Println("客户视图:")
fmt.Println(string(customerData))
// 管理员看到的JSON
adminData, _ := json.MarshalIndent(product.AdminView(), "", " ")
fmt.Println("\n管理员视图:")
fmt.Println(string(adminData))
}
type BaseEntity struct {
ID int `json:"id"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
type Article struct {
BaseEntity
Title string `json:"title"`
Content string `json:"content"`
AuthorID int `json:"author_id"`
IsDraft bool `json:"-"`
}
// 文章列表视图(简洁)
func (a *Article) ListView() interface{} {
return struct {
ID int `json:"id"`
Title string `json:"title"`
CreatedAt string `json:"created_at"`
}{
ID: a.ID,
Title: a.Title,
CreatedAt: a.CreatedAt.Format("2006-01-02"),
}
}
// 文章详情视图(完整)
func (a *Article) DetailView() interface{} {
return struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
AuthorID int `json:"author_id"`
CreatedAt string `json:"created_at"`
}{
ID: a.ID,
Title: a.Title,
Content: a.Content,
AuthorID: a.AuthorID,
CreatedAt: a.CreatedAt.Format("2006-01-02 15:04:05"),
}
}
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
json:"-" 标签 |
简单字段忽略 | 简单直接 | 静态配置,无法动态调整 |
omitempty 标签 |
空值字段忽略 | 自动处理空值 | 只能处理零值情况 |
自定义 MarshalJSON |
复杂序列化逻辑 | 完全控制序列化过程 | 代码复杂度高 |
| 多视图结构体 | 不同API返回不同字段 | 清晰分离关注点 | 需要维护多个结构体 |
| 动态字段控制 | 根据条件显示字段 | 灵活性高 | 实现相对复杂 |
最佳实践建议:
json:"-"omitemptyMarshalJSON