1. 项目概述
这个在线家具商城系统采用当前主流的前后端分离架构,前端基于Vue3框架实现响应式用户界面,后端使用SpringBoot+MyBatis技术栈构建RESTful API服务,数据库选用MySQL进行数据存储。系统实现了完整的电商业务流程,包括商品展示、购物车管理、订单处理、支付对接等核心功能模块。
技术选型上特别考虑了2023年主流技术趋势:Vue3的Composition API大幅提升前端开发效率,SpringBoot 3.x版本对JDK17的完整支持,以及MyBatis-Plus对单表操作的极致简化。
2. 系统架构设计
2.1 技术栈详解
后端技术栈:
- SpringBoot 3.1.5:提供自动配置、依赖管理等功能
- MyBatis-Plus 3.5.3:增强的ORM框架,内置通用Mapper
- Spring Security:负责认证授权流程
- Lombok:简化实体类编写
- Hutool:Java工具包集合
前端技术栈:
- Vue3 + TypeScript:组合式API开发模式
- Pinia:状态管理库替代Vuex
- Element Plus:UI组件库
- Axios:HTTP请求库
- Vue Router:路由管理
数据库:
- MySQL 8.0:采用InnoDB引擎
- Redis 7.0:缓存热点数据
2.2 系统分层架构
code复制表示层(Vue3) → 网关层(Nginx) → 应用层(SpringBoot) → 服务层 → 数据访问层(MyBatis) → 存储层(MySQL)
采用经典的四层架构设计:
- 表现层:处理用户交互和界面渲染
- 业务逻辑层:实现核心业务规则
- 数据访问层:封装数据库操作
- 基础设施层:提供技术支撑服务
3. 核心功能实现
3.1 商品模块
数据结构设计:
java复制// 商品SPU表
@Entity
public class Product {
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
private String description;
@OneToMany
private List<ProductImage> images;
@ManyToOne
private Category category;
}
// 商品SKU表
@Entity
public class Sku {
private Long id;
private String spec; // 规格JSON
private BigDecimal price;
private Integer stock;
@ManyToOne
private Product product;
}
关键技术点:
- 使用MySQL JSON类型存储商品规格参数
- 采用Elasticsearch实现商品搜索
- 商品图片使用OSS对象存储
3.2 订单模块
状态机设计:
code复制待支付 → 已支付 → 待发货 → 已发货 → 已完成
↘ 已取消
防超卖实现:
java复制@Transactional
public boolean createOrder(OrderDTO dto) {
// 1. 查询商品库存
Product product = productMapper.selectById(dto.getProductId());
// 2. 校验库存
if(product.getStock() < dto.getQuantity()) {
throw new BusinessException("库存不足");
}
// 3. 扣减库存(乐观锁)
int update = productMapper.deductStock(product.getId(), dto.getQuantity());
if(update == 0) {
throw new ConcurrentException("库存变更冲突");
}
// 4. 创建订单
Order order = convertToOrder(dto);
orderMapper.insert(order);
return true;
}
4. 前后端分离实践
4.1 接口规范
采用RESTful风格设计API:
- GET /api/products - 获取商品列表
- POST /api/orders - 创建订单
- PUT /api/orders/{id} - 更新订单
- DELETE /api/orders/{id} - 取消订单
响应格式统一:
json复制{
"code": 200,
"message": "success",
"data": {...},
"timestamp": 1689321600000
}
4.2 跨域解决方案
SpringBoot配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
}
Nginx配置:
nginx复制location /api {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
5. 安全防护措施
5.1 SQL注入防护
- 严格使用MyBatis参数绑定:
xml复制<!-- 错误方式 -->
<select id="findUser">
SELECT * FROM user WHERE name = '${name}'
</select>
<!-- 正确方式 -->
<select id="findUser">
SELECT * FROM user WHERE name = #{name}
</select>
- 使用MyBatis-Plus内置的Wrapper构建查询条件:
java复制QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", name).gt("age", 18);
userMapper.selectList(wrapper);
5.2 XSS防护
前端使用vue-dompurify-html:
javascript复制import dompurify from 'dompurify'
import VueDOMPurifyHTML from 'vue-dompurify-html'
app.use(VueDOMPurifyHTML, {
default: {
ALLOWED_TAGS: ['a', 'strong'],
ALLOWED_ATTR: ['href', 'class']
}
})
后端使用Jackson转义:
java复制@JsonSerialize(using = XssJacksonSerializer.class)
public class ProductDTO {
private String name;
private String description;
}
6. 性能优化实践
6.1 缓存策略
多级缓存架构:
- 浏览器缓存:静态资源设置Cache-Control
- CDN缓存:加速图片等静态资源
- 应用缓存:Redis缓存热点数据
- 数据库缓存:MySQL查询缓存
Redis缓存示例:
java复制@Cacheable(value = "product", key = "#id")
public Product getProductById(Long id) {
return productMapper.selectById(id);
}
@CacheEvict(value = "product", key = "#product.id")
public void updateProduct(Product product) {
productMapper.updateById(product);
}
6.2 数据库优化
索引设计:
sql复制-- 商品表索引
ALTER TABLE product ADD INDEX idx_category_status (category_id, status);
ALTER TABLE product ADD INDEX idx_price (price);
-- 订单表索引
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
ALTER TABLE orders ADD INDEX idx_create_time (create_time);
分表策略:
- 订单表按用户ID哈希分表
- 商品评价表按时间范围分表
7. 部署方案
7.1 容器化部署
Dockerfile示例:
dockerfile复制# 后端Dockerfile
FROM openjdk:17-jdk
COPY target/mall.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 前端Dockerfile
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
docker-compose.yml:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:7.0
backend:
build: ./backend
ports:
- "8080:8080"
frontend:
build: ./frontend
ports:
- "80:80"
7.2 CI/CD流程
- Git提交触发Webhook
- Jenkins拉取代码执行构建
- 运行单元测试和集成测试
- 构建Docker镜像并推送到仓库
- 滚动更新K8s集群中的服务
8. 常见问题解决方案
8.1 跨域问题
典型症状:
- 前端控制台出现CORS错误
- 预检请求(OPTIONS)失败
解决方案:
- 确保后端正确配置CORS
- 前端axios配置withCredentials: true
- Nginx添加跨域头配置
8.2 接口幂等性
订单重复提交问题:
- 前端提交后禁用按钮
- 后端生成唯一token机制:
java复制@PostMapping("/order/token")
public String createOrderToken() {
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("order:token:"+token, "1", 5, TimeUnit.MINUTES);
return token;
}
@PostMapping("/order")
public Result createOrder(@RequestHeader("X-Order-Token") String token) {
if(!redisTemplate.delete("order:token:"+token)) {
throw new BusinessException("请勿重复提交");
}
// 处理订单逻辑
}
9. 项目扩展方向
9.1 微服务改造
-
按业务拆分服务:
- 用户服务
- 商品服务
- 订单服务
- 支付服务
-
引入技术组件:
- Spring Cloud Gateway
- Nacos服务发现
- Sentinel流控
- Seata分布式事务
9.2 大数据分析
-
用户行为分析:
- 使用Flink实时处理点击流数据
- 生成用户画像
-
商品推荐:
- 基于协同过滤算法
- 实时推荐热门商品
10. 开发经验分享
-
接口文档管理:
- 使用Swagger UI生成在线文档
- 配合Knife4j增强UI体验
- 重要变更通过Git版本管理
-
前端工程化:
javascript复制// vite.config.js export default defineConfig({ plugins: [ vue(), AutoImport({ imports: ['vue', 'vue-router'] }), Components({ resolvers: [ElementPlusResolver()] }) ] }) -
调试技巧:
- 后端使用Arthas进行线上诊断
- 前端使用Vue Devtools分析组件状态
- 接口调试使用Postman自动化测试
-
团队协作规范:
- Git分支策略:Git Flow
- 代码提交规范:Angular Commit Message
- 代码审查:MR机制+SonarQube扫描
