beego仅提供web api框架,停车场收费需自研计费逻辑、定义含status的状态结构体、用int存“分”防浮点误差、独立service包实现可测试计费规则,并通过数据库唯一索引与服务端时间戳保障幂等性。

Beego 本身不提供停车场业务逻辑,直接用它“实现收费系统”会陷入框架功能错配——你真正需要的是:用 Beego 搭建 Web API 层 + 自己写计费规则 + 连接数据库存车记录。别指望 bee new 跑出来就能收停车费。
为什么不能直接套用 Beego 的 CRUD 模板
停车场核心逻辑不在增删改查,而在状态机和时间计算:车辆入场、离场、跨时段计费、免费时长、夜间封顶、VIP 折扣……这些没法靠 beego.Controller 自动生成。
-
Insert()和Update()只管存数据,不管“入场时间是否早于离场时间” - Beego 的
orm.RegisterModel()不校验“同一车牌在库中是否已有未结账记录” - 它的
session默认基于 cookie,不适合做终端设备(如道闸)的长连接会话管理
必须自己写的三个关键结构体
别急着写路由,先定义清楚数据契约。Beego 的 orm 支持 struct tag 映射,但字段语义得你定。
示例:
type ParkingRecord struct {
Id int `orm:"auto"`
Plate string `orm:"size(10);index"` // 车牌号
InTime time.Time `orm:"type(datetime)"`
OutTime *time.Time `orm:"null;type(datetime)"` // 允许为空,表示未出场
Fee float64 `orm:"digits(10);decimals(2);null"`
Status int `orm:"default(0)"` // 0=在场, 1=已离场, 2=异常(如冲卡)
}
-
Status字段必须有,否则无法区分“正在停车”和“已结账”,OutTime为nil不代表没出场,可能只是系统没收到信号 - 不要用
float64存金额做运算,实际计费应先转成“分”用int算,避免浮点误差;Fee字段仅用于展示 - 加
orm:"index"到Plate和InTime,查“某车牌最新入场记录”才不会慢
计费逻辑必须独立成包,别塞进 Controller
把 CalculateFee(in, out time.Time, carType string) 写在 service/fee.go,而不是 controllers/parking.go。Controller 只负责取参数、调 service、返回 JSON。
- 计费规则常变(比如商场晚上 8 点后首小时免费),硬编码在 handler 里,每次改都要重启服务
- 测试时你能直接
go test -run TestCalculateFee,不用起 Beego server 模拟 HTTP 请求 - 如果未来要对接微信支付回调,同一套
CalculateFee可复用,不必重写
简单示例逻辑:
func CalculateFee(in, out time.Time, isVip bool) int {
duration := out.Sub(in).Minutes()
if duration 60 {
fee += int((duration - 60) / 30) * 200 // 超过1小时,每30分钟2元
}
if isVip {
fee = fee * 9 / 10 // 9折,整数运算防浮点
}
return fee
}
道闸硬件对接最容易忽略的幂等性
真实场景中,地感线圈可能重复触发、网络可能超时重发,导致同一辆车被多次 POST /api/in。Beego 的 Post 方法本身不解决这个问题。
- 入场接口必须校验:
SELECT COUNT(*) FROM parking_record WHERE plate=? AND out_time IS NULL,存在未出场记录就直接返回 409 Conflict - 用数据库唯一索引防双写:
CREATE UNIQUE INDEX idx_plate_unfinish ON parking_record (plate) WHERE out_time IS NULL(PostgreSQL)或 MySQL 8.0+ 的函数索引 - 别依赖前端传来的
in_time,服务端用time.Now()记录,防止终端时钟不准
这套逻辑跑通前,所有“收费准确”都是假象。硬件信号不可靠是常态,不是异常。











