前文中已出现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
entity => 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)
resp := new(response.OrderGet)
c.JSON(http.StatusOK, gin.H{"data": resp.Map(order)})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) Get(ctx context.Context, id int) *domain.Order {
order := &entity.Order{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()}
return order.ToDomain()
}
案例二:获取订单列表(对象数组)
package controller
func (ctr *Order) My(c *gin.Context) {
orders := ctr.repo.My(c.Request.Context())
resp := response.OrderMys{}
c.JSON(http.StatusOK, gin.H{"data": resp.Map(orders)})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) My(ctx context.Context) domain.Orders {
orders := entity.Orders{
{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()},
{ID: 2, UserID: 1, SN: "987654", CreateTime: time.Now()},
}
return orders.ToDomain()
}
案例三:获取订单列表(查询参数+对象数组)
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)
resp := response.OrderLists{}
c.JSON(http.StatusOK, gin.H{"data": resp.Map(orders)})
}
--------------------------------------------------------------------------------
package repository
func (repo *Order) List(ctx context.Context, request *request.OrderList) domain.Orders {
orders := entity.Orders{
{ID: 1, UserID: 1, SN: "123456", CreateTime: time.Now()},
{ID: 2, UserID: 1, SN: "987654", CreateTime: time.Now()},
}
return orders.ToDomain()
}
案例四:用户注册
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.UserRegister)
c.JSON(http.StatusOK, gin.H{"data": response.Map(data)})
}
--------------------------------------------------------------------------------
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, userDomain *domain.User) *domain.User {
userEntity := new(entity.User)
userEntity.ID = 1
userEntity.Mobile = userDomain.Mobile
userEntity.Password = userDomain.Password
userEntity.HeaderImage = userDomain.HeaderImage
userEntity.CreateTime = userDomain.CreateTime
// entity对象入库
return userEntity.ToDomain()
}