1. 项目背景与核心价值
这个基于Java SSM框架的网上蛋糕店商城销售系统,是我在2022年为本地一家连锁烘焙品牌开发的线上销售平台。当时正值疫情后实体店转型线上销售的关键期,客户迫切需要一套能够快速上线、稳定运行且易于维护的电商系统。
选择SSM(Spring+SpringMVC+MyBatis)框架组合主要基于三个现实考量:
- 技术成熟度:相比Spring Boot,传统SSM架构在中小型电商项目中仍有明显优势 - 配置透明可控,适合需要精细调优的数据库密集场景
- 人才储备:客户的技术团队更熟悉传统SSM开发模式,后期维护成本低
- 性能平衡:MyBatis在复杂商品查询场景下比JPA更灵活,配合二级缓存可支撑2000+TPS
系统上线后日均订单量稳定在300-500单,峰值时期(节日促销)能承载1500+并发访问。特别在母亲节营销活动中,系统成功处理了单日2300笔订单的流量冲击,验证了架构的可靠性。
关键指标:MySQL配置了读写分离+Redis集群缓存,商品列表页响应时间<800ms,订单提交成功率99.2%
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计解析
2.1 技术栈选型决策
基础框架组合:
- Spring 4.3.18:控制反转和AOP支持,稳定版避免新版本兼容问题
- SpringMVC:RESTful接口设计,配合Jackson实现前后端分离
- MyBatis 3.4.6:定制化SQL优化,特别是复杂促销条件查询
- MySQL 5.7:事务型业务首选,配合主从复制
- Redis 4.0:缓存雪崩防护(随机过期时间+多级缓存)
辅助工具链:
- Maven 3.5:依赖管理和构建工具
- jQuery+Bootstrap:快速构建管理后台界面
- 阿里云OSS:商品图片存储(节省60%服务器带宽)
2.2 核心模块划分
mermaid复制graph TD
A[用户端] --> B(商品展示)
A --> C(购物车)
A --> D(订单支付)
A --> E(会员中心)
F[管理端] --> G(商品管理)
F --> H(订单处理)
F --> I(促销设置)
F --> J(数据分析)
实际开发中调整为四个微服务模块:
- shop-web:前端展示(Thymeleaf模板引擎)
- shop-service:业务逻辑层(Spring声明式事务)
- shop-dao:数据持久层(MyBatis动态SQL)
- shop-admin:管理后台(RBAC权限控制)
3. 数据库设计关键点
3.1 核心表结构
商品表设计示例:
sql复制CREATE TABLE `t_product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商品名称',
`category_id` int(11) NOT NULL COMMENT '分类ID',
`price` decimal(10,2) NOT NULL COMMENT '基准价',
`discount_price` decimal(10,2) DEFAULT NULL COMMENT '促销价',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
`weight` int(11) DEFAULT NULL COMMENT '蛋糕重量(g)',
`sugar_free` tinyint(1) DEFAULT '0' COMMENT '是否无糖',
`main_image` varchar(255) DEFAULT NULL COMMENT '主图URL',
`detail` text COMMENT '商品详情',
`status` tinyint(4) DEFAULT '1' COMMENT '上架状态',
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 业务难点解决方案
蛋糕规格参数化:
- 使用JSON字段存储可变属性(尺寸、口味、祝福语等)
- MyBatis自定义TypeHandler实现JSON与Java对象转换
库存扣减并发控制:
java复制@Transactional
public boolean reduceStock(Integer productId, Integer quantity) {
// 乐观锁实现
int affected = productMapper.updateStock(
productId,
quantity,
LocalDateTime.now() // 版本号替代方案
);
return affected > 0;
}
4. 典型功能实现细节
4.1 购物车设计
数据结构:
java复制public class CartItem {
private Integer productId;
private String productName;
private String specification; // JSON格式
private BigDecimal price;
private Integer quantity;
private String mainImage;
// 计算属性
public BigDecimal getTotalPrice() {
return price.multiply(new BigDecimal(quantity));
}
}
合并策略:
- 未登录用户:Cookie存储(7天有效期)
- 已登录用户:Redis Hash存储(用户ID为key)
- 合并时相同商品自动叠加数量
4.2 订单状态机
java复制public enum OrderStatus {
UNPAID(1, "待支付") {
@Override
public boolean canChangeTo(OrderStatus newStatus) {
return newStatus == PAID || newStatus == CANCELLED;
}
},
PAID(2, "已支付") {
@Override
public boolean canChangeTo(OrderStatus newStatus) {
return newStatus == SHIPPED || newStatus == REFUNDING;
}
},
// 其他状态...
public abstract boolean canChangeTo(OrderStatus newStatus);
}
5. 开发环境配置指南
5.1 IDEA项目导入步骤
-
安装必备插件:
- Lombok(自动生成getter/setter)
- MyBatisX(Mapper接口与XML跳转)
- Alibaba Java Coding Guidelines(代码规范检查)
-
数据库配置:
properties复制# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/cake_shop?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# MyBatis配置
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.cake.entity
5.2 常见问题排查
问题1:Lombok注解不生效
- 解决方案:IDEA中启用注解处理
- Settings → Build → Compiler → Annotation Processors
- 勾选"Enable annotation processing"
问题2:MyBatis XML文件热加载失效
- 修改pom.xml配置:
xml复制<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
6. 性能优化实践
6.1 缓存策略
三级缓存架构:
- 本地缓存(Caffeine):高频访问的基础数据
- Redis集群:热点商品和促销信息
- MySQL查询缓存:长尾数据
缓存击穿防护:
java复制public Product getProductById(Integer id) {
// 1. 尝试从缓存获取
Product product = redisTemplate.opsForValue().get("product:" + id);
if (product == null) {
// 2. 获取分布式锁
String lockKey = "lock:product:" + id;
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (locked) {
// 3. 查数据库
product = productMapper.selectById(id);
// 4. 回填缓存(设置随机过期时间防雪崩)
redisTemplate.opsForValue().set(
"product:" + id,
product,
30 + (int)(Math.random() * 20),
TimeUnit.MINUTES
);
} else {
// 等待重试
Thread.sleep(100);
return getProductById(id);
}
} finally {
redisTemplate.delete(lockKey);
}
}
return product;
}
6.2 SQL优化案例
慢查询优化前:
sql复制SELECT * FROM t_order
WHERE user_id = 123
AND status IN (2,3)
ORDER BY create_time DESC
优化方案:
- 添加复合索引:
ALTER TABLE t_order ADD INDEX idx_user_status (user_id, status) - 改写SQL:
sql复制SELECT o.* FROM t_order o
INNER JOIN (
SELECT id FROM t_order
WHERE user_id = 123 AND status IN (2,3)
ORDER BY create_time DESC
LIMIT 20
) AS tmp ON o.id = tmp.id
7. 安全防护措施
7.1 支付安全
-
金额校验:前端提交与后端校验双重验证
java复制@PostMapping("/pay") public Result pay(@Valid @RequestBody PayRequest request) { // 从数据库重新查询订单金额 Order order = orderService.getById(request.getOrderId()); if (!order.getAmount().equals(request.getAmount())) { throw new BusinessException("支付金额不一致"); } // 其他校验... } -
接口防重放:每次支付生成唯一nonce字符串
java复制String nonce = UUID.randomUUID().toString(); redisTemplate.opsForValue().set("pay:nonce:" + nonce, "1", 30, TimeUnit.MINUTES);
7.2 XSS防护
-
全局过滤器处理特殊字符
java复制public class XssFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { HttpServletRequest req = (HttpServletRequest) request; XssRequestWrapper wrappedRequest = new XssRequestWrapper(req); chain.doFilter(wrappedRequest, response); } } -
富文本内容使用Jsoup白名单过滤
java复制String safeHtml = Jsoup.clean(html, Whitelist.basicWithImages() .addAttributes("div", "class") );
8. 项目部署方案
8.1 生产环境配置
服务器架构:
- Nginx(前端静态资源+负载均衡)
- Tomcat集群(至少2节点)
- MySQL主从(1主2从)
- Redis哨兵模式(3节点)
JVM参数建议:
bash复制java -server -Xms2g -Xmx2g -XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=256m -Xmn1g -Xss256k \
-XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC \
-jar shop-web.war
8.2 监控方案
-
Spring Boot Actuator健康检查
properties复制management.endpoints.web.exposure.include=health,info,metrics management.endpoint.health.show-details=always -
Prometheus + Grafana监控看板
xml复制<!-- pom.xml --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
9. 二次开发建议
-
扩展营销功能:
- 拼团活动(参考美团拼好货模式)
- 预售模式(特别定制蛋糕场景)
- 会员积分体系
-
技术升级路径:
- 渐进式迁移到Spring Boot(保持兼容)
- 引入Elasticsearch实现商品搜索
- 试用GraalVM原生镜像编译
-
移动端适配:
- 开发微信小程序版本
- 对接APP推送系统(极光推送)
这个项目源码中最值得借鉴的是对传统SSM框架的深度优化实践。在开发过程中,我们特别注重MyBatis SQL的可维护性 - 所有复杂查询都写在XML中并附带详细注释,这使得后续新增促销规则时,团队成员能快速定位修改点。另一个经验是:电商系统一定要在开发初期就建立完整的日志埋点体系,我们采用的方案是SLF4J+Logback配合ELK日志分析,这在排查订单异常时发挥了关键作用。
