1. 项目概述与架构设计
这个基于SpringBoot+Vue3+MyBatis的网购平台系统采用了典型的前后端分离架构,是目前电商类项目的主流技术选型方案。后端使用SpringBoot 2.7.x构建RESTful API,前端采用Vue3组合式API开发,数据持久层使用MyBatis 3.5.x与MySQL 8.0交互。这种架构组合既保证了开发效率,又能满足电商系统的高并发需求。
我在实际电商项目开发中发现,这套技术栈有三大核心优势:首先,SpringBoot的自动配置特性大幅减少了XML配置,内置Tomcat容器简化了部署;其次,Vue3的Composition API比Options API更灵活,特别适合处理电商复杂的页面状态;最后,MyBatis的动态SQL能力完美适配电商业务中多变的数据查询场景。
提示:新手开发者常犯的错误是直接拷贝博客系统的架构到电商项目。实际上电商系统需要更复杂的分布式事务处理和缓存机制,这点在后续章节会重点说明。
2. 核心模块设计与实现
2.1 用户中心模块
用户模块采用JWT+Spring Security实现认证授权,这是经过多个线上项目验证的可靠方案。数据库表设计需要注意密码字段必须使用BCrypt加密存储,绝对不能明文保存。我推荐使用如下DDL创建用户表:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` varchar(100) NOT NULL COMMENT 'BCrypt加密密码',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`status` tinyint DEFAULT '1' COMMENT '状态(0-禁用 1-正常)',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
在SpringBoot中实现注册接口时,务必注意这三个要点:
- 密码加密必须放在Service层而非Controller层
- 手机号/邮箱验证要采用异步方式避免阻塞主流程
- 用户创建后需要清除缓存中的验证码信息
2.2 商品管理模块
商品模块采用了SPU+SKU的数据模型,这是大型电商平台的通用设计方案。核心表关系如下:
| 表名 | 作用 | 关键字段 |
|---|---|---|
| product_spu | 标准产品单元 | spu_id, name, category_id |
| product_sku | 库存量单位 | sku_id, spu_id, price, stock |
| product_image | 商品图片 | img_id, sku_id, url, sort |
| product_category | 分类树 | category_id, parent_id, name |
在MyBatis映射文件中,商品查询需要特别注意N+1问题。我推荐使用<collection>标签实现一对多关联查询:
xml复制<resultMap id="spuWithSkus" type="com.example.model.ProductSpu">
<id property="spuId" column="spu_id"/>
<collection property="skuList" ofType="com.example.model.ProductSku"
select="selectSkusBySpuId" column="spu_id"/>
</resultMap>
2.3 订单交易模块
订单模块是电商系统最复杂的部分,需要处理高并发下的数据一致性问题。我们采用的状态机设计如下:
code复制待支付 --支付成功--> 待发货
待发货 --发货--> 待收货
待收货 --确认收货--> 已完成
任何状态 --取消--> 已取消
在SpringBoot中实现订单创建时,必须使用@Transactional注解保证原子性,同时要注意:
- 库存检查使用乐观锁防止超卖
- 订单号生成使用分布式ID算法
- 敏感操作需要记录完整日志
3. 前后端协同开发
3.1 接口规范设计
我们采用RESTful风格设计API,但针对电商场景做了适当调整。例如商品搜索接口:
code复制GET /api/products?keyword=手机&category=3&priceFrom=1000&priceTo=3000&sort=price_asc&page=1&size=20
在SpringBoot中可以使用@Validated实现参数校验:
java复制@GetMapping("/products")
public PageResult<ProductVO> searchProducts(
@RequestParam(required = false) String keyword,
@Min(0) @RequestParam(defaultValue = "0") Integer page,
@Range(min = 1, max = 100) @RequestParam(defaultValue = "20") Integer size) {
// 业务逻辑
}
3.2 Vue3前端工程化
前端项目使用Vite4构建,推荐采用如下目录结构:
code复制src/
├── api/ # Axios接口封装
├── assets/ # 静态资源
├── components/ # 通用组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
对于商品列表页,使用Composition API可以这样组织代码:
javascript复制import { ref, computed } from 'vue'
import { useProductStore } from '@/stores/product'
export default {
setup() {
const productStore = useProductStore()
const searchParams = ref({
keyword: '',
categoryId: null,
page: 1
})
const products = computed(() => productStore.filteredProducts)
const loadProducts = async () => {
await productStore.fetchProducts(searchParams.value)
}
return { searchParams, products, loadProducts }
}
}
4. 性能优化实战
4.1 缓存策略设计
电商系统必须采用多级缓存:
- 前端使用localStorage缓存静态资源
- Nginx配置静态文件缓存
- Redis缓存热点数据
- MySQL查询缓存
SpringBoot中整合Redis的典型配置:
yaml复制spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 20
max-wait: -1ms
max-idle: 8
min-idle: 0
4.2 数据库优化
针对MySQL的优化建议:
- 商品表需要建立组合索引 (category_id, status, sales)
- 订单表按用户ID分片
- 大文本字段单独拆分表存储
在MyBatis中处理分页查询时,推荐使用PageHelper插件:
java复制PageHelper.startPage(pageNum, pageSize);
List<Product> products = productMapper.selectByExample(example);
PageInfo<Product> pageInfo = new PageInfo<>(products);
5. 部署与监控
5.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "3000:3000"
5.2 监控方案
推荐使用Prometheus+Grafana监控系统关键指标:
- JVM内存使用情况
- API接口响应时间
- MySQL查询性能
- Redis命中率
SpringBoot集成Prometheus的配置:
groovy复制implementation 'io.micrometer:micrometer-registry-prometheus'
yaml复制management:
endpoints:
web:
exposure:
include: health,info,prometheus
metrics:
tags:
application: ${spring.application.name}
6. 常见问题排查
6.1 跨域问题
前后端分离项目必遇跨域,解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
}
6.2 接口幂等性
支付接口必须保证幂等,典型实现:
java复制@PostMapping("/pay")
public Result payOrder(@RequestBody PayRequest request) {
String idempotentKey = request.getOrderNo() + "_" + request.getPayType();
if (redisTemplate.opsForValue().setIfAbsent(idempotentKey, "1", 24, TimeUnit.HOURS)) {
// 处理支付逻辑
} else {
throw new BusinessException("请勿重复支付");
}
}
6.3 性能瓶颈定位
使用Arthas诊断慢查询:
bash复制# 监控方法调用耗时
watch com.example.service.ProductService getProductDetail '{params,returnObj}' -x 3 -n 5 -b -s 'cost > 200'
在开发过程中,我发现最容易出问题的环节是分布式事务处理。比如订单创建时需要同时操作订单表、库存表和支付记录,推荐使用Seata框架解决:
java复制@GlobalTransactional
public void createOrder(OrderCreateDTO dto) {
// 1. 扣减库存
productService.reduceStock(dto.getSkuId(), dto.getQuantity());
// 2. 创建订单
Order order = buildOrder(dto);
orderMapper.insert(order);
// 3. 创建支付记录
paymentService.createPayment(order.getOrderNo(), dto.getAmount());
}
