- 更新应用程序处理程序中的 URL 赋值逻辑,确保静态文件使用原始路径 - 修改缓存数据库的 JSON 解析方法,使用 JsonToObj 函数替代 json.Unmarshal,提升代码可读性和性能 - 在 Map 和 Slice 类型中新增获取四舍五入浮点数的方法,增强数据处理能力 - 在 Obj 类型中添加四舍五入功能,支持精度控制 - 改进数据库查询结果的处理逻辑,确保数据类型的准确性和一致性 - 优化日志格式设置,增强日志信息的可读性
9.4 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Row方法方案审查与修正 | 修改 4 个文件:common/objtoobj.go(新增 JsonToObj + 增强 ObjToMap/ObjToSlice)、common/map.go(增强 JsonToMap)、db/query.go(Row 重写)、cache/cache_db.go(用 JsonToObj 替换 json.Unmarshal)。 |
|
false |
Row() + JSON 反序列化类型保留修正方案
修改文件一览
| 文件 | 改动 |
|---|---|
| common/objtoobj.go | 新增 JsonToObj + fixJsonNumbers;增强 ObjToMap、ObjToSlice 的 4 处 json.Unmarshal |
| common/map.go | 增强 Map.JsonToMap |
| db/query.go | 重写 Row() + 新增辅助函数 + 更新 import |
| cache/cache_db.go | 3 处 json.Unmarshal 改用 JsonToObj |
文件 1:common/objtoobj.go
新增 JsonToObj 和 fixJsonNumbers
在文件 StrToMap 之前(约第 378 行前)新增,需要在 import 中添加 "bytes":
// JsonToObj 将 JSON 字符串反序列化为 interface{},保留数字原始类型。
// 标准 json.Unmarshal 会把所有 JSON 数字变成 float64,本函数保留整数为 int64、小数为 float64。
// JsonToObj(`{"id":2,"price":1.20}`) → Map{"id": int64(2), "price": float64(1.2)}
// JsonToObj(`[1, 2.5, "a"]`) → Slice{int64(1), float64(2.5), "a"}
func JsonToObj(jsonStr string) (interface{}, error) {
dec := json.NewDecoder(bytes.NewReader([]byte(jsonStr)))
dec.UseNumber()
var result interface{}
if err := dec.Decode(&result); err != nil {
return nil, err
}
return fixJsonNumbers(result), nil
}
// fixJsonNumbers 递归将 json.Number 转为 int64 或 float64
func fixJsonNumbers(v interface{}) interface{} {
switch val := v.(type) {
case json.Number:
if n, err := val.Int64(); err == nil {
return n
}
if f, err := val.Float64(); err == nil {
return f
}
return string(val)
case map[string]interface{}:
for k, item := range val {
val[k] = fixJsonNumbers(item)
}
return val
case []interface{}:
for i, item := range val {
val[i] = fixJsonNumbers(item)
}
return val
default:
return val
}
}
增强 ObjToMap(2 处 json.Unmarshal)
位置 1 -- string case(约第 27-31 行):
// 修改前:
case string:
v = Map{}
e := json.Unmarshal([]byte(obj.(string)), &v)
if e != nil {
err = errors.New("没有合适的转换对象!" + e.Error())
v = nil
}
// 修改后:
case string:
result, e := JsonToObj(val)
if e != nil {
err = errors.New("没有合适的转换对象!" + e.Error())
v = nil
} else if m, ok := result.(map[string]interface{}); ok {
v = m
} else {
err = errors.New("没有合适的转换对象!")
v = nil
}
位置 2 -- default case(约第 34-44 行):
// 修改前:
default:
data, err := json.Marshal(obj)
if err != nil { ... }
v = Map{}
e := json.Unmarshal(data, &v)
if e != nil { ... }
// 修改后:
default:
data, e2 := json.Marshal(obj)
if e2 != nil {
err = errors.New("没有合适的转换对象!" + e2.Error())
v = nil
} else {
result, e3 := JsonToObj(string(data))
if e3 != nil {
err = errors.New("没有合适的转换对象!" + e3.Error())
v = nil
} else if m, ok := result.(map[string]interface{}); ok {
v = m
} else {
err = errors.New("没有合适的转换对象!")
v = nil
}
}
增强 ObjToSlice(2 处 json.Unmarshal)
位置 1 -- string case(约第 82-83 行):
// 修改前:
case string:
v = Slice{}
err = json.Unmarshal([]byte(obj.(string)), &v)
// 修改后:
case string:
result, e := JsonToObj(val)
if e != nil {
err = e
} else if s, ok := result.([]interface{}); ok {
v = s
} else {
err = errors.New("没有合适的转换对象!")
}
位置 2 -- default case(约第 86-91 行):
// 修改前:
default:
v = Slice{}
var data []byte
data, err = json.Marshal(obj)
err = json.Unmarshal(data, &v)
// 修改后:
default:
data, e2 := json.Marshal(obj)
if e2 != nil {
err = e2
} else {
result, e3 := JsonToObj(string(data))
if e3 != nil {
err = e3
} else if s, ok := result.([]interface{}); ok {
v = s
} else {
err = errors.New("没有合适的转换对象!")
}
}
文件 2:common/map.go
增强 JsonToMap(第 183-189 行)
需要在 import 中添加 "bytes":
// 修改前:
func (that Map) JsonToMap(jsonStr string, err ...*Error) {
e := json.Unmarshal([]byte(jsonStr), &that)
if e != nil && len(err) != 0 {
err[0].SetError(e)
}
}
// 修改后:
func (that Map) JsonToMap(jsonStr string, err ...*Error) {
dec := json.NewDecoder(bytes.NewReader([]byte(jsonStr)))
dec.UseNumber()
e := dec.Decode(&that)
if e != nil {
if len(err) != 0 {
err[0].SetError(e)
}
return
}
for k, v := range that {
that[k] = fixJsonNumbers(v)
}
}
这里 fixJsonNumbers 定义在 objtoobj.go 中,同属 common 包,可以直接调用。
影响链路:
StrToMap(s)→ 调用JsonToMap(s)→ 自动修复Map.JsonToMap(s)→ 直接修复
文件 3:db/query.go -- Row() 重写
(内容与上一版相同,此处只列关键点)
import 变更
移除 "reflect",新增 "math"、"strconv"。
新增辅助函数
dbTypeUnknown/dbTypeInteger/dbTypeFloat/dbTypeDecimal 常量 + classifyDBType + getDecimalScale + getFloatScale + fixFloatValue + roundFloat + convertBytes。
覆盖 MySQL/SQLite/PostgreSQL 三种数据库的类型名。
Row() 方法替换(第 362-391 行)
defer resl.Close()+resl.Err()检查ColumnTypes()预分类列类型- type switch 替代 reflect:
[]byte→convertBytes,float64→fixFloatValue,float32→fixFloatValue,其余不变
文件 4:cache/cache_db.go -- DB 缓存
3 处 json.Unmarshal 改用 JsonToObj(来自 common 包,已通过 . "code.hoteas.com/golang/hotime/common" 导入):
位置 1 -- getLegacy() 约第 359-363 行:
// 修改前:
var data interface{}
err := json.Unmarshal([]byte(valueStr), &data)
// 修改后:
data, err := JsonToObj(valueStr)
位置 2 -- get() 约第 411-416 行:
// 修改前:
var data interface{}
err := json.Unmarshal([]byte(valueStr), &data)
// 修改后:
data, err := JsonToObj(valueStr)
位置 3 -- CachesGet() 约第 594-598 行:
// 修改前:
var data interface{}
err := json.Unmarshal([]byte(valueStr), &data)
// 修改后:
data, err := JsonToObj(valueStr)
不需要新增 import(JsonToObj 在 common 包,cache_db.go 已 import)。
修正效果总结
| 数据路径 | 修正前 | 修正后 |
|---|---|---|
| DB → Row() → Map | float32/float64 原样存入,[]byte 全转 string | 按列类型精确转换:INT→int64, DECIMAL→roundFloat, FLOAT→fixFloat |
| DB 缓存 → json.Unmarshal | 所有数字→float64 | JsonToObj:整数→int64, 小数→float64 |
| ObjToMap(string) | json.Unmarshal 数字全→float64 | JsonToObj:保留 int64/float64 |
| ObjToSlice(string) | json.Unmarshal 数字全→float64 | JsonToObj:保留 int64/float64 |
| StrToMap(string) | JsonToMap → json.Unmarshal | JsonToMap → UseNumber + fixJsonNumbers |
| Map.JsonToMap(string) | json.Unmarshal | UseNumber + fixJsonNumbers |
| Redis 缓存 | ObjToStr → string → ObjToMap | ObjToMap 已增强,自动修复 |
Redis 缓存路径:set 用 ObjToStr → get 返回 string → 调用方用 ObjToMap 转回 Map。由于 ObjToMap 的 string 分支现在使用 JsonToObj,Redis 缓存也自动获得类型保留,无需单独改 cache_redis.go。