You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sql.NullString时c.IndentedJSON无法输出正确JSON数组的问题

解决sql.NullString序列化JSON为空对象的问题

问题原因

sql.NullString的内部字段String和Valid都是小写开头的非导出字段,Go标准库的encoding/json包只会序列化结构体中大写开头的导出字段。直接序列化包含sql.NullString的结构体时,这些字段会被序列化为空对象{},最终返回的数组看起来全是空对象。

而你用fmt打印结构体时能看到内容,是因为fmt包会输出结构体的所有字段(包括非导出的),和JSON序列化的规则完全不同。

解决方案

1. 使用第三方库的可序列化null类型

推荐使用gopkg.in/guregu/null.v4库,它提供的null.String类型原生支持JSON序列化:

  • 值有效时,序列化为对应字符串
  • 值无效(数据库NULL)时,序列化为null

只需把代码里的sql.NullString替换为null.String,直接用c.IndentedJSON输出就能得到正确结果。

2. 自定义可序列化的NullString类型

如果不想引入第三方库,可以自己封装sql.NullString并实现json.Marshaler接口:

import (
    "database/sql"
    "encoding/json"
)

// 自定义NullString,继承sql.NullString的结构
type NullString sql.NullString

// 实现JSON序列化方法
func (ns NullString) MarshalJSON() ([]byte, error) {
    if !ns.Valid {
        // 无效时返回JSON null
        return []byte("null"), nil
    }
    // 有效时返回字符串的JSON表示
    return json.Marshal(ns.String)
}

// 可选:实现反序列化方法
func (ns *NullString) UnmarshalJSON(data []byte) error {
    if string(data) == "null" {
        ns.String = ""
        ns.Valid = false
        return nil
    }
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    ns.String = s
    ns.Valid = true
    return nil
}

之后结构体里使用自定义的NullString代替sql.NullString,序列化时就能正确输出null或对应字符串。

3. 转换为普通指针类型后序列化

在返回响应前,把数据库模型转换成API专用结构体,用*string表示可能为null的字符串:

// 数据库查询用的模型
type Category struct {
    ID   int            `db:"id"`
    Name sql.NullString `db:"name"`
}

// API响应专用模型
type APICategory struct {
    ID   int     `json:"id"`
    Name *string `json:"name"`
}

func yourHandler(c *gin.Context) {
    var categories []Category
    // 从数据库查询数据...

    // 转换为API响应格式
    apiCategories := make([]APICategory, len(categories))
    for i, cat := range categories {
        var name *string
        if cat.Name.Valid {
            name = &cat.Name.String
        }
        apiCategories[i] = APICategory{
            ID:   cat.ID,
            Name: name,
        }
    }

    c.IndentedJSON(http.StatusOK, apiCategories)
}

这种方式完全基于标准库,适合不想引入依赖或需要精确控制响应格式的场景。

内容的提问来源于stack exchange,提问作者Josip Žaja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:10:32