1. 项目背景与需求分析
大学食堂作为校园生活的重要场景,长期以来存在着就餐高峰期排队拥挤、人工点餐效率低下、支付方式单一等问题。传统窗口排队模式在中午11:30-12:30的用餐高峰时段,平均等待时间可达15-20分钟,严重影响了师生的用餐体验。
基于SpringBoot和Android开发的食堂点餐App能有效解决以下痛点:
- 分流窗口压力:提前在线点餐可减少现场决策时间
- 支付流程优化:集成校园卡/移动支付避免找零环节
- 后厨协同:订单数据实时同步提升备餐效率
- 个性化服务:收藏喜好菜品、营养分析等增值功能
典型用户场景示例:
- 上午10:00,学生在教室通过App预定午餐
- 食堂接单系统自动分配档口并打印小票
- 学生按预约时间到指定窗口扫码取餐
- 系统自动完成扣款并生成消费记录
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选型
采用分层架构设计,主要技术组件包括:
code复制前端层:Android客户端 (Java/Kotlin)
├─ UI框架:Jetpack Compose
├─ 网络通信:Retrofit + OkHttp
├─ 本地缓存:Room Database
后端层:SpringBoot 2.7.x (Java)
├─ Web框架:Spring MVC
├─ 数据持久化:MyBatis-Plus
├─ 消息队列:RabbitMQ
├─ 安全认证:Spring Security + JWT
基础设施:
├─ 数据库:MySQL 8.0集群
├─ 缓存:Redis 6.x
├─ 文件存储:MinIO
├─ 容器化:Docker + Kubernetes
2.2 核心模块划分
2.2.1 客户端功能模块
- 用户认证模块:校园统一身份认证对接
- 餐品展示模块:支持分类检索、模糊搜索
- 购物车模块:多店铺合并结算
- 订单模块:实时状态追踪
- 支付模块:校园卡/微信/支付宝三端聚合
- 评价系统:带图片的评分反馈
2.2.2 服务端微服务设计
java复制// 示例:订单服务领域模型
public class Order {
@TableId(type = IdType.ASSIGN_ID)
private Long orderId;
private String studentId;
private LocalDateTime createTime;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<OrderItem> items;
@EnumValue
private OrderStatus status;
}
// 使用Spring StateMachine实现订单状态流转
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig
extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEvent> {
// 状态机配置...
}
3. 关键实现细节
3.1 高并发订单处理
采用"预扣库存+异步确认"机制应对秒杀场景:
- Redis原子操作预减库存:
lua复制-- inventory.lua
local key = KEYS[1]
local num = tonumber(ARGV[1])
if (redis.call('exists', key) == 1) then
local stock = tonumber(redis.call('get', key))
if (stock >= num) then
return redis.call('decrby', key, num)
end
end
return -1
- 消息队列削峰填谷:
java复制@RabbitListener(queues = "order.queue")
public void processOrder(OrderMessage message) {
// 1. 数据库事务处理
// 2. 库存最终扣减
// 3. 推送通知
}
3.2 实时通信方案
使用WebSocket实现订单状态推送:
kotlin复制// Android端实现
class OrderWebSocket : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
val event = Gson().fromJson(text, OrderEvent::class.java)
when(event.type) {
"PAID" -> updateUI(R.drawable.ic_paid)
"PREPARING" -> showProgress(event.estimateTime)
// 其他状态处理...
}
}
}
4. 性能优化实践
4.1 客户端优化方案
- 图片加载优化:
kotlin复制Glide.with(context)
.load(foodImageUrl)
.apply(RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.food_placeholder)
.transform(RoundedCorners(16)))
.into(imageView)
- 数据缓存策略:
java复制@Dao
interface CanteenDao {
@Query("SELECT * FROM food WHERE stallId = :stallId")
fun getFoodsByStall(stallId: String): Flow<List<FoodEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(foods: List<FoodEntity>)
}
4.2 服务端优化要点
- API响应优化:
java复制@GetMapping("/menu")
@Cacheable(value = "dailyMenu", key = "#canteenId + '_' + #date")
public Result<MenuVO> getDailyMenu(
@RequestParam String canteenId,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
// 查询逻辑...
}
- 数据库分表策略:
sql复制-- 按月份分表的订单表
CREATE TABLE `order_202301` (
`id` bigint NOT NULL COMMENT '订单ID',
`student_id` varchar(20) NOT NULL COMMENT '学号',
`total_amount` decimal(10,2) NOT NULL COMMENT '总金额',
PRIMARY KEY (`id`),
INDEX `idx_student` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5. 安全防护措施
5.1 支付安全体系
- 交易签名方案:
java复制public class PaymentSignUtil {
public static String generateSign(Map<String,String> params, String key) {
String concat = params.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
return HmacSHA256(concat, key);
}
}
- 风控规则示例:
- 同一账号5分钟内下单频率限制
- 异常金额订单二次验证
- 新设备登录短信确认
5.2 数据隐私保护
- 敏感信息脱敏处理:
java复制@JsonComponent
public class SensitiveInfoSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen,
SerializerProvider provider) throws IOException {
if (value.length() > 2) {
gen.writeString(value.charAt(0) +
"*".repeat(value.length() - 2) +
value.charAt(value.length() - 1));
}
}
}
6. 运维监控体系
6.1 全链路监控
- Prometheus监控指标示例:
yaml复制- pattern: /api/order/create
metrics:
- name: order_create_latency_seconds
help: Order creation latency in seconds
labels:
status: $status
buckets: [0.1, 0.5, 1, 2, 5]
- 业务埋点日志:
java复制@Aspect
@Component
@RequiredArgsConstructor
public class BizLogAspect {
private final LogProducer logProducer;
@AfterReturning(pointcut = "@annotation(bizLog)", returning = "result")
public void afterReturning(JoinPoint jp, BizLog bizLog, Object result) {
LogEntry entry = new LogEntry();
entry.setBizType(bizLog.value());
entry.setParams(JsonUtils.toJson(jp.getArgs()));
logProducer.send(entry);
}
}
7. 实际部署经验
7.1 灰度发布方案
采用Nginx流量切分策略:
nginx复制upstream backend {
server 172.16.1.1:8080 weight=90; # 旧版本
server 172.16.1.2:8080 weight=10; # 新版本
}
map $http_x_debug_tag $group {
default $upstream_addr;
"canary" "172.16.1.2:8080";
}
7.2 容灾演练记录
- 数据库故障转移测试:
sql复制-- 主库模拟故障
STOP GROUP_REPLICATION;
-- 观察从库自动提升
SELECT MEMBER_STATE FROM performance_schema.replication_group_members;
- 客户端降级策略:
kotlin复制fun loadMenu() {
viewModelScope.launch {
try {
val remote = api.getMenu()
cache.save(remote)
_uiState.value = MenuUiState.Success(remote)
} catch (e: Exception) {
val cached = cache.load()
_uiState.value = if (cached != null) {
MenuUiState.Success(cached).also {
showToast("网络异常,显示缓存数据")
}
} else {
MenuUiState.Error(e)
}
}
}
}
在具体实施过程中,我们发现食堂档口的网络环境往往较差,为此专门优化了离线模式:当检测到网络信号弱时,客户端会自动切换为极简版界面,仅加载文字菜单并允许先下单后同步。这个改进使订单提交成功率从82%提升到了97%。
