点餐系统(一阶)
简言
一阶为入门,画出大概"轮廓",后面几阶在进行逐步填充,添加细节和上色🎨,这篇文章算是我上一篇<基于gorilla websocket搭建聊天室>的接龙,这里的代码也是那篇文章代码的继续
本阶将会实现
- 客户点菜
- 厨师实时收到客户点餐
- 客户状态(是否结账,当前用餐金额)
客户吃饭流程
整个点餐系统的运作流程
数据库表构造
基本依赖
var customerpool = make(map[*Connection]*userinfo)
var dishespool = make(map[*singledish]bool) //菜单池,false表示点单未出单,true表示出单
var ordhub = &OrderHub{SendToChef: make(chan *singledish)}
var chefpool = make(map[*Connection]struct{})
// order system
type order struct {
Header string `json:"header"`
Dish int `json:"dish"`
}
// 记录点菜的客户讯息
type userinfo struct {
Id int `json:"id"` //用于识别客户的id
OrderId int `json:"orderid"` //客户点菜的菜单id,一个客户可以持有多份菜单,一个菜单可持有一份以上的菜,结算以每份菜单具体金额为准
Sum float32 `json:"sum"` //客户一共需要结算的金额
Status bool `json:"status"` //客户是否买单
Action string `json:"action"` //记录客户的所有点菜操作
}
type singledish struct {
Name string
time string
}
type aboutdish struct {
Name string
Price float32
Id int
}
type OrderHub struct {
SendToChef chan *singledish
}
点菜服务
func OrderSomething(w http.ResponseWriter, r *http.Request) {
upgrade.CheckOrigin = func(r *http.Request) bool { return true }
ws, err := upgrade.Upgrade(w, r, nil)
if err != nil {
errorlog.Println(err)
}
con := &Connection{con: ws, send: make(chan []byte, 256)}
hub.register <- con
defer func() {
hub.unregister <- con
ws.Close()
}()
Waiter(con)
}
func Waiter(con *Connection) {
var orderinfo order
for {
err := con.con.ReadJSON(&orderinfo)
if err != nil {
errorlog.Println("read from connection failed,", err)
} else {
//debug zone
if _, ok := customerpool[con]; !ok {
fmt.Println("connection dont exsit")
id := rand.Intn(89999) + 10000
orderid := rand.Intn(899999) + 100000
customerpool[con] = &userinfo{Id: id, OrderId: orderid, Sum: 0, Action: ""}
}
//end
userorderinfo := customerpool[con]
fmt.Println(userorderinfo) //debug line
price, actionid := getdishinfo(orderinfo.Dish)
fmt.Println(price) //debug line
userorderinfo.Sum += price
userorderinfo.Action += actionid + "\n"
//这里还应有一个推送功能,用于将新点菜品发送给后厨端
dish := new(singledish)
dish.ScanAction(actionid)
dish.PushToPool()
ordhub.SendToChef <- dish
}
con.send <- []byte("im live")
}
}
func getdishinfo(id int) (float32, string) {
//从数据库中获取菜品讯息
dbcon, err := sql.Open("mysql", "test:123456@tcp(127.0.0.1)/lab?charset=utf8")
if err != nil {
errorlog.Println(err)
return -1, ""
}
defer dbcon.Close()
var dishinfo aboutdish
dishinfo.Id = id
err = dbcon.QueryRow("select price,name from ordersystem where id =?", id).Scan(&dishinfo.Price, &dishinfo.Name)
if err != nil {
errorlog.Println(err)
}
//操作id=下单时间+菜品名称+菜品id
actionid := time.Now().Format(time.Kitchen) + "&" + dishinfo.Name + "&" + strconv.Itoa(dishinfo.Id)
return dishinfo.Price, actionid
}
这里的操作ID是很重要的,他包含了客户点某个菜品的时间,点的什么菜,菜品id(菜品唯一的识别标志,可能同一个菜有多个版本,他们菜名和价格相同,菜品id就可以区分它们之间的版本来告诉后厨客人对于这道菜到底要哪种做法),操作id将会保存起来以供日后使用或分析。
厨师端
一阶厨师端很简单,不用实现任何功能,挂起接收前台订单就行了,后面几阶会对厨师端进行或多或少的强化
func ChefPlatform(w http.ResponseWriter, r *http.Request) {
upgrade.CheckOrigin = func(r *http.Request) bool { return true }
ws, err := upgrade.Upgrade(w, r, nil)
if err != nil {
errorlog.Println("establish connection with chef failed", err)
}
con := &Connection{con: ws, send: make(chan []byte, 256)}
chefregister <- con
defer func() {
chefunregister <- con
ws.Close()
}()
for {
con.send <- []byte("im live")
}
}
websocket必备注册机
这里的注册机是上篇聊天室注册机增强版(在保留了聊天室原有的注册机制上,新增客户注册和厨师注册)
type Hub struct {
register chan *Connection
unregister chan *Connection
customer chan *Connection
clearcustomer chan *Connection
Broadcast chan []byte
}
var chefregister = make(chan *Connection)
var chefunregister = make(chan *Connection)
func (s *Hub) Run() {
fmt.Println("start register machine")
for {
rand.Seed(time.Now().UnixNano())
select {
case c := <-s.register:
conpool[c] = struct{}{}
fmt.Println("register connection")
case c := <-s.unregister:
if _, ok := conpool[c]; ok {
delete(conpool, c)
fmt.Println("unregister connection")
}
//order system zone start
case c := <-s.customer:
conpool[c] = struct{}{}
case c := <-s.clearcustomer:
if _, ok := conpool[c]; ok {
delete(conpool, c)
}
if _, ok := customerpool[c]; ok {
delete(customerpool, c)
}
//order system zone end
//chef zone start
case c := <-chefregister:
conpool[c] = struct{}{}
chefpool[c] = struct{}{}
processlog.Println("register a chef")
case c := <-chefunregister:
if _, ok := chefpool[c]; ok {
delete(chefpool, c)
processlog.Println("unregister a chef")
}
if _, ok := conpool[c]; ok {
delete(conpool, c)
}
case c := <-ordhub.SendToChef:
for con, _ := range chefpool {
err := con.con.WriteJSON(c)
errorlog.Println(err)
}
//chef zone end
case m := <-s.Broadcast:
for clients := range conpool {
select {
case clients.send <- m:
default:
delete(conpool, clients)
fmt.Println("delete connection")
}
}
}
}
}
测试
func ServerStart() {
go hub.Run()
http.HandleFunc("/chat", ChatRoom)
http.HandleFunc("/orderdish", OrderSomething)
http.HandleFunc("/chef", ChefPlatform)
http.ListenAndServe(":8001", nil)
}
postman