1. 项目概述:临期零食小程序的商业逻辑与技术选型
临期食品市场近年来呈现爆发式增长态势,根据行业数据显示,2022年我国临期食品市场规模已突破300亿元。这个基于SpringBoot+微信小程序的毕业设计项目,瞄准了校园场景下的临期零食交易需求,通过技术手段解决食品浪费和学生消费降级的双重痛点。
技术栈选择上,后端采用SpringBoot 2.7.3 + MyBatis-Plus组合,前端使用微信小程序原生开发。这种架构组合具有三个显著优势:首先,SpringBoot的自动配置特性大幅减少了XML配置工作量,让毕业生能聚焦业务逻辑开发;其次,MyBatis-Plus的代码生成器可快速产出DAO层代码;最后,微信小程序无需安装、即用即走的特性完美匹配校园场景的高频使用需求。
提示:实际开发中建议使用SpringBoot 2.7.x而非最新3.x版本,避免因JDK版本要求(SpringBoot 3.x需JDK17+)导致校园机房环境兼容性问题。
2. 核心功能模块设计与实现
2.1 商品智能预警系统
临期食品管理的核心在于保质期监控。我们在数据库设计中采用双时间戳方案:
@Entity public class Product { @TableField("production_date") private Date productionDate; // 生产日期 @TableField("shelf_life") private Integer shelfLife; // 保质期(天) // 计算临期状态(非数据库字段) @TableField(exist = false) private Integer status; // 0-正常 1-临期 2-过期 }通过定时任务每天凌晨2点扫描商品表,动态计算商品状态:
@Scheduled(cron = "0 0 2 * * ?") public void checkExpiration() { List<Product> products = productMapper.selectList(null); LocalDate now = LocalDate.now(); products.forEach(p -> { long days = ChronoUnit.DAYS.between( p.getProductionDate().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(), now); int newStatus = 0; if (days >= p.getShelfLife()) newStatus = 2; else if (days >= p.getShelfLife()*0.8) newStatus = 1; if (newStatus != p.getStatus()) { p.setStatus(newStatus); productMapper.updateById(p); } }); }2.2 混合推荐算法实现
为提高临期商品转化率,系统采用规则+协同过滤的混合推荐策略:
- 距离优先规则:优先展示3公里内的商家商品
- 价格降序规则:同距离下折扣力度大的优先
- 用户行为加权:根据历史浏览/购买记录计算品类偏好
public List<Product> recommend(Long userId, Double lat, Double lng) { // 获取用户历史行为数据 UserBehavior behavior = behaviorService.getByUser(userId); // 基础查询:临期未过期商品 LambdaQueryWrapper<Product> query = new LambdaQueryWrapper<>(); query.eq(Product::getStatus, 1) .gt(Product::getStock, 0); List<Product> products = productMapper.selectList(query); // 计算综合得分 return products.stream() .map(p -> { // 距离分(0-50分) double distance = GeoUtils.getDistance( lat, lng, p.getShop().getLat(), p.getShop().getLng()); double distanceScore = 50 * (1 - Math.min(distance/5000, 1)); // 折扣分(0-30分) double discountScore = 30 * (1 - p.getPrice()/p.getOriginalPrice()); // 偏好分(0-20分) double preferScore = behavior.getCategoryPrefers() .getOrDefault(p.getCategory(), 0.0) * 20; p.setScore(distanceScore + discountScore + preferScore); return p; }) .sorted(Comparator.comparing(Product::getScore).reversed()) .limit(20) .collect(Collectors.toList()); }3. 微信小程序端关键技术实现
3.1 高性能列表渲染优化
临期商品列表采用分页加载+虚拟滚动方案,关键配置如下:
// page.json { "usingComponents": { "virtual-list": "/components/virtual-list/index" } } // 页面wxml <virtual-list height="800rpx" item-data="{{productList}}" item-size="200" bind:scrolltolower="loadMore"> <view slot="item" wx:for="{{productList}}" wx:key="id"> <!-- 商品项模板 --> </view> </virtual-list>针对图片加载性能问题,我们采用CDN+懒加载+WebP格式转换方案:
// 在onPageScroll事件中处理图片懒加载 onPageScroll(e) { this.createSelectorQuery() .selectAll('.product-img') .boundingClientRect(rects => { rects.forEach((rect, idx) => { if (rect.top <= wx.getSystemInfoSync().windowHeight + 300) { this.setData({ [`productList[${idx}].showImg`]: true }) } }) }).exec() }3.2 地理位置服务深度集成
校园场景下,我们采用三级地理位置精度策略:
- 首次进入:城市级定位(快速响应)
- 商品浏览:校区级定位(500米精度)
- 下单时:建筑级定位(50米精度)
// 封装定位服务 const LOCATION_LEVEL = { CITY: 0, CAMPUS: 1, BUILDING: 2 }; function getLocation(level) { return new Promise((resolve, reject) => { let accuracy = '80m'; if (level === LOCATION_LEVEL.CITY) accuracy = '1km'; else if (level === LOCATION_LEVEL.CAMPUS) accuracy = '500m'; wx.getLocation({ type: 'gcj02', accuracy, success: resolve, fail: () => { // 降级处理 if (level < LOCATION_LEVEL.BUILDING) { getLocation(level + 1).then(resolve).catch(reject); } else { reject(); } } }); }); }4. 后台管理系统关键实现
4.1 基于RBAC的权限控制系统
采用修改后的RBAC模型,增加部门维度:
@Data public class User { private Long id; private String username; private String password; private Long departmentId; // 新增部门维度 // ... } @Data public class Role { private Long id; private String name; private Integer dataScope; // 1-全部 2-本部门 3-自定义 private List<Long> deptIds; // 自定义部门范围 // ... }权限拦截器实现数据过滤:
public void filterDataScope(User user) { String sqlFilter = ""; if (!user.isAdmin()) { Role role = user.getRole(); switch (role.getDataScope()) { case 2: // 本部门 sqlFilter = "dept_id = " + user.getDepartmentId(); break; case 3: // 自定义 sqlFilter = "dept_id IN (" + StringUtils.join(role.getDeptIds(), ",") + ")"; break; default: throw new RuntimeException("无数据权限"); } } if (StringUtils.isNotBlank(sqlFilter)) { // MyBatis-Plus数据权限过滤 DataPermissionHelper.setDataPermission(new DataPermission(sqlFilter)); } }4.2 销售数据分析看板
使用ECharts实现动态数据可视化,关键配置:
// 使用dataset管理数据 option = { dataset: { source: [ ['product', 'normal', 'nearExpire', 'expired'], ['薯片', 43, 12, 5], ['巧克力', 32, 8, 3], // ... ] }, tooltip: {}, legend: {}, xAxis: { type: 'category' }, yAxis: {}, series: [ { type: 'bar', stack: 'total' }, { type: 'bar', stack: 'total' }, { type: 'bar', stack: 'total' } ] }; // 动态更新策略 function updateChart() { const currentTab = this.data.currentTab; let url = ''; if (currentTab === 'day') url = '/api/stats/day'; else if (currentTab === 'week') url = '/api/stats/week'; wx.request({ url, success: (res) => { this.chart.setOption({ dataset: { source: res.data } }); } }); }5. 项目部署与运维实践
5.1 多环境配置方案
采用SpringBoot Profile + Maven Profile组合方案:
<!-- pom.xml --> <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <profile.active>dev</profile.active> </properties> </profile> <profile> <id>prod</id> <properties> <profile.active>prod</profile.active> </properties> </profile> </profiles>对应application-dev.yml配置示例:
wx: appid: 测试小程序ID secret: 测试密钥 datasource: url: jdbc:mysql://localhost:3306/snacks_dev?useSSL=false username: dev password: dev123 redis: host: localhost port: 63795.2 微信支付沙箱联调
支付模块开发阶段建议使用沙箱环境:
public class WxPayService { private boolean sandboxMode = true; public String getPaySign(Map<String, String> params) { if (sandboxMode) { params.put("sign_type", "MD5"); params.put("sandbox_signkey", getSandboxSignKey()); // 沙箱环境特殊处理... } else { // 生产环境处理... } // 生成签名... } private String getSandboxSignKey() { // 调用微信沙箱API获取签名密钥 String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; // ...实现请求逻辑 } }重要提示:正式上线前必须关闭沙箱模式,并完成以下检查:
- 微信支付商户平台配置完成
- 小程序后台已关联商户号
- 域名备案已完成
- HTTPS证书有效
6. 毕业设计答辩要点
6.1 技术亮点阐述建议
临期计算算法:解释定时任务+状态缓存的设计考量
- 为什么选择凌晨2点执行?
- 状态字段缓存带来的查询性能提升
混合推荐策略:展示不同权重的业务考量
- 校园场景下距离权重的特殊设置
- 如何平衡商家利益与用户体验
数据权限设计:RBAC扩展的实际价值
- 不同角色(管理员/校区经理/店员)的权限差异
- 数据隔离在连锁场景中的必要性
6.2 典型答辩问题准备
食品安全问题:
- 如何确保临期食品质量?
- 过期商品自动下架机制
技术选型问题:
- 为什么不用Vue而用原生小程序?
- SpringBoot相比传统SSM的优势
商业模式问题:
- 如何激励商家入驻?
- 学生用户获取策略
7. 项目扩展方向建议
7.1 功能扩展
智能预警推送:
// 基于Spring Event的事件驱动模型 public class ProductNearExpireEvent extends ApplicationEvent { public ProductNearExpireEvent(Product source) { super(source); } } @EventListener public void handleNearExpire(ProductNearExpireEvent event) { Product p = (Product) event.getSource(); // 1. 给商家发模板消息 // 2. 给附近用户发优惠推送 }直播清仓功能:
- 集成微信小程序直播组件
- 开发直播间专属优惠券系统
7.2 技术升级
微服务化改造:
- 按功能拆分为商品服务、订单服务、用户服务
- 采用SpringCloud Alibaba技术栈
大数据分析:
- 使用Flink实时计算商品周转率
- 基于用户画像的精准营销
在实际开发中遇到的最意外的问题是微信iOS端对WebSocket的支持差异,建议在真机测试阶段重点关注网络相关功能的兼容性。对于时间紧张的毕业设计,可以优先保证核心业务流程完整,扩展功能作为加分项实现。