文章一、二我们把外部提交的数据(比如表单数据)通过框架绑定的方式匹配到request层模型中,对外展示的数据通过copier函数转化成response层的模型中。
- request层:模型接受外部提交数据,过滤校验外部数据的正确性;
- response层:对外展示数据,隐藏敏感字段或不需要字段;
我们用两个真实案例来演示这两个分层的灵活性
案例一:金额单位换算
真实项目中,关于金额的单位大部分精确到分,在数据库中,金额数据类型为int,这样设计还可以有效的避免大多数浮点数计算问题,但是会出现金额单位不一致问题:
1、用户提现以元为单位,例如用户输入提现金额10.5,对应request层
2、显示用户余额也需要为元为单位,例如用户余额为101.78, 对应response层
先看request层如何换算,代码如下:
技术选型:精度计算库decimal
package request
type UserCash struct {
Money Money `form:"money"`
}
func (req *Money) UnmarshalJSON(b []byte) error {
float, err := strconv.ParseFloat(string(b),64)
if err != nil {
return err
}
if float <= 0 {
return errors.New("金额不能为负数")
}
req.Val = int(decimal.NewFromFloat(float).Mul(decimal.NewFromFloat(100)).IntPart())
return nil
}
func (req *Money) Value() int {
return req.Val
}
复制代码
代码分析:自定义Money结构体,实现UnmarshalJSON函数,实现浮点数转化为整型。
response层如何换算,代码如下:
package response
type User struct {
ID int `json:"id"`
Nickname string `json:"nickname"`
Money Money `json:"money"`
}
type Money int
func (resp Money) MarshalJSON() ([]byte, error) {
d, _ := decimal.NewFromFloat(float64(resp)).Mul(decimal.NewFromFloat(0.01)).Float64()
str := fmt.Sprintf("%.2f", d)
return []byte(str), nil
}
复制代码
代码分析:自定义Money结构体,实现MarshalJSON函数,实现整型转化为两位浮点数。
案例二:图片URL自动截取和补全
用户更新头像场景,用户上传头像,服务器需要返回用户上传头像生成的头像地址,页面需要展示,比如img.test.com/header.jpg ,用户查看没有问题提交服务器,数据库保存头像地址,通常为了节省数据库空间,只会存header.jpg图片名称,域名会省略,但是用户查看用户信息时,服务器返回头像地址又需要完整的图片地址:
1、用户提交完整头像地址,需要截取图片名称,对应request层
2、返回用户信息,头像需要补全为完整地址, 对应response层
request层如何截取,代码如下:
package request
type UserUpdate struct {
HeaderImage ImageURL `form:"headerImage"`
}
type ImageURL string
func (req *ImageURL) Name() string {
return strings.Replace(string(*req), "http://img.test.com/", "", -1)
}
复制代码
代码分析:新建string别名ImageURL结构体,实现结构体Name函数,截取图片名称,当然也可以如上文Money结构体,实现UnmarshalJSON函数截取图片名称,这样更灵活,还可以校验用户提交的头像地址是否符合格式,这里主要想展示解决问题的多种方式。
response层如何补全,代码如下:
package response
type ImageURL string
func (resp ImageURL) MarshalJSON() ([]byte, error) {
url := fmt.Sprintf(`"%s"`, "http://img.test.com/" + resp)
return []byte(url), nil
}
复制代码
代码分析:新建string别名ImageURL结构体,实现MarshalJSON函数,自动补全图片地址。 源码链接
案例三:网页图片多域名提高加载速度
因为浏览器对同域名请求有最大并发数限制,比如在Chrome浏览器,对于同一个域名,最多支持6个请求的并发,很多网站会使用多个图片域名提高图片的加载速度,例如下图京东首页的图片加载瀑布流,会有img20、img13、img30、img10等多个图片域名地址: 如何实现这一功能,可以在上文的ImageURL的MarshalJSON函数,随机给图片名称补全不同的图片域名
项目开发中,外部提交的参数和对外展示的数据都是经常易变的需求,希望读者好好体会,回想一下自己在开发中也没有遇到此类问题,熟练应用request层、response层。