1. 项目背景与核心需求
2020年以来的特殊时期催生了大量社区服务类系统的开发需求。这个基于SpringBoot的小区疫情购物系统,正是为了解决封闭管理期间居民生活物资采购难题而设计的典型应用。我在实际开发中发现,这类系统需要同时满足三个核心诉求:
- 无接触配送:通过线上选购+定点自提/配送的方式减少人员接触
- 物资统筹:居委会需要实时掌握各户采购情况以便协调资源
- 紧急通道:为特殊群体(老人、孕妇等)开辟快速响应通道
关键设计原则:系统响应时间必须控制在2秒内(实测高峰期并发约300+),商品库存更新需要实现秒级同步,这是保证用户体验的基础线。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选型
mermaid复制graph TD
A[前端] -->|Vue.js| B(SpringBoot)
B -->|MyBatis-Plus| C[MySQL]
B -->|Redis| D[缓存层]
B -->|RabbitMQ| E[消息队列]
C --> F[阿里云OSS]
(注:根据规范要求,此处不应包含mermaid图表,改为文字说明)
系统采用前后端分离架构:
- 前端:Vue.js + ElementUI(适配移动端H5)
- 后端:SpringBoot 2.6.11 + Spring Security
- 数据层:MySQL 8.0(主从配置)+ Redis 7.0
- 中间件:RabbitMQ 3.11(订单异步处理)
- 文件存储:阿里云OSS(商品图片)
版本选择考量:
- SpringBoot 2.6.x长期支持版本,避免使用3.0+可能存在的兼容性问题
- MySQL 8.0优化了JSON字段处理,适合存储动态扩展的商品属性
2.2 核心模块划分
-
用户服务:
- 住户注册(需物业审核)
- 健康码状态校验(对接政府API)
- 购物权限管理
-
商品服务:
- 分类管理(食品/日用品/药品三级分类)
- 库存预警(Redis原子计数器)
- 限购策略(每人每日N件)
-
订单服务:
- 购物车合并下单
- 配送时段选择
- 支付对接(微信/支付宝沙箱)
-
物业后台:
- 团购数据统计
- 异常订单处理
- 志愿者调度
3. 关键实现细节
3.1 高并发库存控制
采用Redis+Lua脚本实现原子操作:
java复制String script = "if tonumber(redis.call('get', KEYS[1])) >= tonumber(ARGV[1]) then " +
"return redis.call('DECRBY', KEYS[1], ARGV[1]) " +
"else return -1 end";
redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList("stock:"+skuId),
String.valueOf(buyNum));
踩坑记录:初期直接用Redis的DECRBY导致超卖,必须配合WATCH+MULTI或直接使用Lua脚本保证原子性。
3.2 安全防护方案
-
XSS防御:
- 前端使用DOMPurify过滤
- 后端采用Spring HtmlUtils转义
- 商品描述富文本使用JSON Schema校验
-
CSRF防护:
java复制
http.csrf().csrfTokenRepository( CookieCsrfTokenRepository.withHttpOnlyFalse() ); -
SQL注入:
- 强制使用MyBatis-Plus的LambdaQueryWrapper
- 禁止${}拼接SQL
3.3 性能优化要点
-
缓存策略:
- 商品详情:Redis缓存+本地Caffeine二级缓存
- 采用@Cacheable注解实现自动缓存
java复制@Cacheable(value = "goods", key = "#id", unless = "#result == null") public GoodsDetailVO getDetail(Long id){...} -
数据库优化:
- 商品表垂直拆分(基础信息+扩展属性)
- 订单表按月分表(ShardingSphere-JDBC)
- 建立组合索引:
sql复制ALTER TABLE `order` ADD INDEX idx_community_status (`community_id`,`status`,`create_time`);
4. 典型问题解决方案
4.1 微信支付回调丢失
问题现象:支付成功但订单状态未更新
排查步骤:
- 检查Nginx日志确认请求到达
- 发现SpringBoot拦截了Content-Type=text/plain的请求
- 添加配置:
properties复制spring.mvc.contentnegotiation.media-types.plain=text/plain
4.2 定时任务重复执行
使用ShedLock解决方案:
- 添加依赖:
xml复制<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.42.0</version>
</dependency>
- 配置锁提供者:
java复制@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
- 注解使用:
java复制@Scheduled(cron = "0 0/5 * * * ?")
@SchedulerLock(name = "syncStockTask", lockAtLeastFor = "4m")
public void syncStock(){...}
5. 部署实践
5.1 多环境配置
使用Profile区分配置:
yaml复制# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/shopping_dev
username: devuser
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/shopping_prod?useSSL=true
username: ${DB_USER}
启动命令示例:
bash复制java -jar shopping.jar --spring.profiles.active=prod
5.2 Docker部署方案
Dockerfile关键配置:
dockerfile复制FROM openjdk:11-jre
WORKDIR /app
COPY target/shopping-0.0.1.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"]
常用命令:
bash复制# 构建镜像
docker build -t shopping:1.0 .
# 运行容器
docker run -d -p 8080:8080 \
-e "SPRING_PROFILES_ACTIVE=prod" \
-v /path/to/config:/config \
shopping:1.0
6. 毕设扩展建议
-
数据分析扩展:
- 使用ECharts实现物资需求热力图
- 基于用户购买记录做协同过滤推荐
-
物联网集成:
- 对接智能快递柜开箱接口
- 使用WebSocket实现配送员实时定位
-
应急模式:
java复制// 当社区出现特殊情况时触发 @PostMapping("/emergency") public Response emergencyMode( @RequestParam Integer communityId, @RequestParam EmergencyType type) { redisTemplate.opsForValue().set( "emergency:"+communityId, type.name(), 2, TimeUnit.HOURS); // 自动取消非必需品订单 orderService.cancelNonEssentialOrders(communityId); }
实际开发中发现,系统高峰期(早8-10点)需要特别注意:
- MySQL连接池建议配置:
yaml复制spring: datasource: hikari: maximum-pool-size: 50 connection-timeout: 3000 leak-detection-threshold: 5000 - 对商品查询接口添加限流:
java复制@RateLimiter(value = 100, key = "#root.methodName") @GetMapping("/goods") public List<GoodsVO> list(){...} - 静态资源建议启用CDN加速
