前文中已出现request模型、domain模型、response模型,本文把增加do模型和repository仓储层,项目结构已见雏形。
阿里巴巴Java开发手册分层领域模型规约:
Query:数据查询对象,各层接收上层的查询请求。注意超过2个参数的查询封装,禁止使用Map类来传输。
DTO(Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。
BO(Business Object):业务对象,可以由Service层输出的封装业务逻辑的对象。
DO(Data Object):此对象与数据库表结构一一对应,通过DAO层向上传输数据源对象。
VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。(本文忽略)
复制代码
对应模型:
request => Query
response => DTO
domain => BO
do => DO
复制代码
下文通过几个案例来讲解每个模型在各个代码层如何穿梭和映射
案例一:获取订单详情(单个对象)
package controller
func (ctr *Order) Get(c *gin.Context) {
var request request.OrderGet
if err := c.ShouldB(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
order := ctr.repo.Get(c.Request.Context(), request.ID)
response := new(response.Order)
mapper.Map(&response, order)
c.JSON(http.StatusOK, gin.H{"data": response})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) Get(ctx context.Context, id int) *domain.Order {
order := &do.Order{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()}
domain := new(domain.Order)
mapper.Map(&domain, order)
return domain
}
复制代码
案例二:获取订单列表(对象数组)
package controller
func (ctr *Order) My(c *gin.Context) {
orders := ctr.repo.My(c.Request.Context())
response := []*response.Order{}
mapper.Map(&response, orders)
c.JSON(http.StatusOK, gin.H{"data": response})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) My(ctx context.Context) []*domain.Order {
orders := []*do.Order{
{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()},
{ID: 2, UserID: 1, SN: "987654", CreateTime: time.Now()},
}
domains := []*domain.Order{}
mapper.Map(&domains, orders)
return domains
}
复制代码
案例三:获取订单列表(查询参数+对象数组)
package controller
func (ctr *Order) List(c *gin.Context) {
request := new(request.OrderList)
if err := c.ShouldB(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
orders := ctr.repo.List(c.Request.Context(), request)
response := []*response.Order{}
mapper.Map(&response, orders)
c.JSON(http.StatusOK, gin.H{"data": response})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) List(ctx context.Context, request *request.OrderList) []*domain.Order {
fmt.Println(request)
orders := []*do.Order{
{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()},
{ID: 2, UserID: 1, SN: "987654", CreateTime: time.Now()},
}
domains := []*domain.Order{}
mapper.Map(&domains, orders)
return domains
}
复制代码
案例四:用户注册
package controller
func (ctr *User) Register(c *gin.Context) {
var request request.UserRegister
if err := c.ShouldB(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user := new(domain.User)
user.Register(request.Mobile, request.Password)
data := ctr.repo.Register(c.Request.Context(), user)
response := new(response.User)
mapper.Map(&response, data)
c.JSON(http.StatusOK, gin.H{"data": response})
}
--------------------------------------------------------------------------------
package domain
type NicknameS struct {}
func (dom *NicknameS) generate(str string) string {
return str[0:4] + "****" + str[8:11]
}
type PasswordS struct {}
func (dom *PasswordS) generate(str string) string {
str += dom.salt()
h := md5.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}
func (dom *PasswordS) salt() string {
return "~!@#abc123"
}
type User struct {
ID int
Mobile string
Nickname string
NicknameS *NicknameS
Password string
PasswordS *PasswordS
HeaderImage string
Money int
CreateTime time.Time
}
func (dom *User) Register(mobile string, password string) {
dom.Mobile = mobile
dom.Nickname = dom.NicknameS.generate(mobile)
dom.Password = dom.PasswordS.generate(password)
dom.CreateTime = time.Now()
dom.HeaderImage = dom.DefaultHeaderImage()
}
func (dom *User) DefaultHeaderImage() string {
return "header.jpg"
}
--------------------------------------------------------------------------------
package repository
func (repo *User) Register(ctx context.Context, user *domain.User) *domain.User {
do := new(do.User)
do.ID = 1
do.Mobile = user.Mobile
do.Password = user.Password
do.HeaderImage = user.HeaderImage
do.CreateTime = user.CreateTime
// do对象入库
domain := new(domain.User)
mapper.Map(&domain, do)
return domain
}
复制代码