本文档描述项目整体架构、双应用部署、模块依赖、公共组件及开发规范要点。 帮助开发人员快速理解“为什么这样设计”以及各环节的特殊处理方式。
| 应用 | 模块 | 端口 | Context-Path | 用途 |
|---|---|---|---|---|
| AdminApplication | haha-admin | 7070 | /admin | 运营平台后端 |
| MiniappApplication | haha-miniapp | 7077 | /api | 小程序后端 |
两个应用共享 haha-common / haha-entity / haha-mapper / haha-service,通过 @ComponentScan(basePackages = {"com.haha"}) 和 @MapperScan("com.haha.mapper") 自动扫描。
运营平台(haha-admin)和小程序后端(haha-miniapp)的认证方式、API风格、安全要求完全不同:
分离部署的优势:
haha-admin --> haha-service --> haha-mapper --> haha-entity
haha-miniapp --> haha-service --> haha-mapper --> haha-entity
|
haha-common <---------------------------+(所有模块均可依赖)
haha-sdk(独立模块,不依赖其他内部模块)
禁止反向依赖:
| 技术 | 版本 | 说明 |
|---|---|---|
| Java | 21 | 禁止使用 Java 22+ 特性 |
| Spring Boot | 4.0.3 | 使用 Jakarta 命名空间 |
| MyBatis-Plus | 3.5.16 | mybatis-plus-spring-boot4-starter |
| Sa-Token | 1.45.0 | sa-token-spring-boot3-starter |
| Hutool | 5.8.40 | 禁止使用 hutool 6.x API |
| FastJson2 | 2.0.53 | 禁止使用 fastjson (v1) |
| Lombok | 1.18.36 | -- |
| Jakarta EE | Jakarta | 非 Javax |
com.haha.common.enums)| 枚举 | 说明 | code类型 |
|---|---|---|
| OrderStatus | 订单状态 | int |
| PayStatus | 支付状态 | String |
| PaymentChannel | 支付渠道 | String |
| DeviceDoorStatus | 门状态 | String |
| DeviceAlertType | 告警类型 | String |
| ActivityTypeEnum | 活动类型 | int |
| ActivityStatusEnum | 活动状态 | int |
| CouponTypeEnum | 优惠券类型 | int |
| CouponStatusEnum | 优惠券状态 | int |
| DiscountTypeEnum | 折扣类型 | int |
| ValidTypeEnum | 有效期类型 | int |
| DistributeTypeEnum | 发放类型 | int |
| ApplyScopeEnum | 适用范围 | int |
| OpenType | 开门类型 | String |
| InviteStatusEnum | 邀请状态 | int |
| InviteRewardStatusEnum | 邀请奖励状态 | int |
| PayScoreState | 支付分状态 | String |
枚举规范:
code + description/label 字段fromCode() / getByCode() 静态方法code 值,禁止存储 descriptioncom.haha.common.constant)| 常量类 | 说明 |
|---|---|
| OrderConstants | 订单状态/支付状态/订单类型常量 |
| DeviceConstants | 设备相关常量 |
| MarketingConstants | 营销相关常量 |
| RedisConstants | Redis Key 定义 |
| CallbackConstants | 回调类型常量 |
| CommonConstants | 通用常量 |
| ResponseEnum | 业务响应码枚举 |
| VO | 说明 |
|---|---|
| Result<T> | 统一返回封装(code/message/data) |
| PageResult<T> | 分页返回(通过 PageResult.of(IPage<T>) 转换) |
| StatusLabel | 状态标签(label + color) |
| OrderVO | 订单详情VO |
{
"code": 200,
"message": "操作成功",
"data": { ... }
}
| 场景 | code | message |
|---|---|---|
| 成功 | 200 | 操作成功 / 具体描述 |
| 参数错误 | 400 | 字段错误描述 |
| 未登录 | 401 | 未登录 / token已过期 |
| 无权限 | 403 | 无访问权限 |
| 资源不存在 | 404 | xxx不存在 |
| 业务异常 | 自定义 | BusinessException 消息 |
| 系统异常 | 500 | 系统繁忙,请稍后重试 |
独立模块,封装与哈哈平台(智能售卖机设备平台)的API交互,不依赖其他内部模块。
| 功能 | 说明 |
|---|---|
| 设备API | 开门、查询状态、设置温度/音量 |
| 商品API | 商品查询、同步 |
| 订单API | 创建订单、查询订单 |
| 回调验证 | 签名校验 |
通过 authToken 进行设备级认证,SDK内部处理签名和请求构建。
@RequirePermission("module:operation")read / create / update / delete / other@RequirePermission(通过 accessToken 鉴权)DataPermission)支持按门店维度的数据隔离,运营人员只能查看授权门店的数据。
@Log(module = "模块名", operation = OperationType.XXX, summary = "描述")@Logt_,如 t_order、t_devicet_{主实体}_{关联实体},如 t_activity_device、t_coupon_shop@TableId(type = IdType.ASSIGN_ID)map-underscore-to-camel-case: truehaha-mapper/src/main/resources/mapper/XxxMapper.xmlresultMap,禁止 resultType| 表名 | 说明 |
|---|---|
| t_order | 订单表 |
| t_order_goods | 订单商品明细 |
| t_order_item | 订单商品项 |
| t_device | 设备表 |
| t_shop | 门店表 |
| t_product | 商品表 |
| t_device_inventory | 设备库存表 |
| t_door_record | 开关门记录表 |
| t_user | 用户表 |
| t_account | 用户账户表 |
| 表名 | 说明 |
|---|---|
| t_marketing_activity | 营销活动表 |
| t_activity_shop | 活动-门店关联 |
| t_activity_device | 活动-设备关联 |
| t_activity_product | 活动-商品关联 |
| t_coupon_template | 优惠券模板表 |
| t_user_coupon | 用户优惠券表 |
| t_coupon_shop | 优惠券-门店关联 |
| t_coupon_product | 优惠券-商品关联 |
| t_coupon_distribute | 优惠券发放记录 |
| t_timed_discount_activity | 定时折扣活动表 |
| t_timed_discount_device | 定时折扣-设备关联 |
| t_timed_discount_shop | 定时折扣-门店关联 |
| t_timed_discount_product | 定时折扣-商品关联 |
| t_timed_discount_record | 定时折扣执行记录 |
| t_timed_discount_statistics | 定时折扣统计 |
| t_invite_activity | 邀请活动表 |
| t_invite_record | 邀请记录表 |
| t_invite_reward | 邀请奖励表 |
| t_marketing_statistics | 营销统计表 |
| 表名 | 说明 |
|---|---|
| t_stock_record | 补货记录表 |
| t_stock_record_item | 补货明细表 |
| t_inventory_log | 库存变更日志 |
| t_price_adjustment_log | 价格调整日志 |
| 表名 | 说明 |
|---|---|
| t_admin | 管理员表 |
| t_role | 角色表 |
| t_role_permission | 角色权限关联 |
| t_data_permission | 数据权限表 |
| t_operation_log | 操作日志表 |
| t_dict_type | 字典类型表 |
| t_dict_data | 字典数据表 |
| t_device_alert_record | 设备告警记录 |
| t_announcement | 公告表 |
| 表名 | 说明 |
|---|---|
| t_distributor | 合作商表 |
| t_distributor_commission | 佣金记录表 |
| t_distributor_config | 合作商配置表 |
| t_distributor_referral | 推荐记录表 |
| t_distributor_withdrawal | 提现记录表 |
| t_distributor_monthly_report | 月度报表 |
| 表名 | 说明 |
|---|---|
| t_stat_category_daily | 品类日统计 |
| t_stat_device_daily | 设备日统计 |
| t_stat_product_daily | 商品日统计 |
| t_stat_shop_daily | 门店日统计 |
| t_stat_user_repurchase | 用户复购统计 |
设备货架层配置模板,定义每一层的商品排列方式。
| 功能 | 说明 |
|---|---|
| 模板CRUD | 创建/编辑/删除层模板 |
| 层配置 | 每层的商品类型、数量、位置 |
| 设备应用 | 将模板应用到指定设备 |
@JsonSerialize(using = ToStringSerializer.class) 防精度丢失
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")BigDecimal,禁止 double / float
setScale(2, RoundingMode.HALF_UP) 保留2位小数final + @RequiredArgsConstructor),循环依赖时用 @Autowired @Lazy@Transactional(rollbackFor = Exception.class)
rollbackFor = Exception.class 不能省略,默认只回滚 RuntimeExceptionpage < 1 设为 1,pageSize > 100 设为 10BusinessException + ResponseEnum,禁止 Controller 中抛出未处理异常WHERE deleted = 0系统需要与哈哈平台(设备端)交互,设备端生成 activityId 关联开关门和订单。自增ID依赖数据库生成,在分布式场景和回调场景下不可用。雪花算法在应用层生成ID,不依赖数据库,且全局唯一。
迁移注意:项目早期使用自增ID,后改为雪花算法。已有数据需保留原ID,新数据使用雪花算法。alter_snowflake_id.sql 处理了迁移逻辑。
haha-sdk 封装与哈哈平台的HTTP交互,不依赖任何内部业务模块。这样设计是因为:
MyBatis-Plus 的 @TableLogic 注解在 MP 自动生成的 SQL 中会自动添加 WHERE deleted = 0,但手写SQL(XML或注解式)不会自动添加。开发手写SQL时必须手动处理逻辑删除条件,否则会查询到已删除的数据。