1. 项目概述
这个在线家具商城系统采用了当前主流的前后端分离架构,前端基于Vue.js框架实现响应式用户界面,后端使用SpringBoot快速构建RESTful API服务。系统核心功能模块包括商品展示、购物车管理、订单处理、支付集成和用户权限控制等,通过MyBatis实现数据持久化操作,MySQL作为关系型数据库存储业务数据。
提示:项目源码中pf管理系统指的是Platform Management System(平台管理系统),主要用于商家后台的商品管理、订单处理和数据分析等功能。
2. 技术栈选型分析
2.1 SpringBoot后端框架
SpringBoot 2.7.x版本作为基础框架,其自动配置特性大幅减少了XML配置工作量。我们特别使用了:
- Spring Security进行权限控制
- Spring Validation实现参数校验
- Spring Cache抽象做商品缓存
- Spring Transaction管理数据库事务
实测中,一个基础商品查询接口的QPS能达到1200+(4核8G服务器),这得益于SpringBoot内嵌Tomcat的优化配置。
2.2 Vue前端框架
采用Vue 3组合式API开发,主要技术点包括:
- Vue Router实现前端路由
- Pinia状态管理替代Vuex
- Element Plus组件库构建UI
- Axios封装HTTP请求
javascript复制// 典型API请求封装示例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 15000
})
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
})
2.3 数据持久层方案
MyBatis-Plus 3.5.x作为ORM框架,其亮点功能包括:
- Lambda表达式条件构造器
- 自动分页插件
- 逻辑删除注解
- 多租户SQL解析器
xml复制<!-- 动态SQL示例 -->
<select id="selectFurnitureByCondition" resultType="Furniture">
SELECT * FROM t_furniture
<where>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
<if test="minPrice != null">
AND price >= #{minPrice}
</if>
</where>
ORDER BY sales_volume DESC
</select>
3. 核心功能实现
3.1 商品模块设计
采用三级分类体系(家具类型→使用场景→风格),商品表关键字段包括:
- SPU标准信息(名称、描述、参数)
- SKU库存单元(颜色、尺寸、价格)
- 商品图片(主图+详情图分离存储)
java复制// 商品实体类片段
@Data
@TableName("t_furniture")
public class Furniture {
@TableId(type = IdType.AUTO)
private Long id;
private String spuCode;
private String title;
private BigDecimal price;
@TableField(exist = false)
private List<FurnitureSpec> specList;
}
3.2 购物车实现方案
采用混合存储策略:
- 登录用户:数据持久化到数据库
- 未登录用户:使用localStorage临时存储
关键操作时间复杂度:
- 添加商品:O(1)
- 批量删除:O(n)
- 全选/反选:O(1)
3.3 订单业务流程
状态机设计包含以下状态:
- 待支付(15分钟超时)
- 已支付待发货
- 已发货
- 已完成
- 已取消
使用Redis分布式锁解决超卖问题:
java复制public boolean decreaseStock(Long skuId, Integer num) {
String lockKey = "lock:stock:" + skuId;
try {
// 获取分布式锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 执行库存扣减
return stockMapper.decrease(skuId, num) > 0;
}
} finally {
redisTemplate.delete(lockKey);
}
return false;
}
4. 安全防护措施
4.1 SQL注入防护
- 严格使用MyBatis参数绑定(#{})
- 禁用${}拼接SQL
- 安装MyBatis插件拦截危险SQL
java复制@Intercepts(@Signature(type= StatementHandler.class,
method="prepare", args={Connection.class, Integer.class}))
public class SqlInjectionInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 检测SQL中包含危险关键词
if (hasDangerousKeywords(boundSql.getSql())) {
throw new RuntimeException("检测到危险SQL操作");
}
return invocation.proceed();
}
}
4.2 XSS防护方案
- 前端使用DOMPurify过滤富文本
- 后端Jackson配置HTML转义
- 响应头设置Content-Security-Policy
5. 性能优化实践
5.1 数据库优化
MySQL配置建议:
ini复制[mysqld]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
query_cache_type = 0
建立关键索引:
sql复制CREATE INDEX idx_category_status ON t_furniture(category_id, status);
CREATE INDEX idx_price_sales ON t_furniture(price, sales_volume);
5.2 缓存策略
采用多级缓存架构:
- 本地Caffeine缓存(热点商品)
- Redis集群缓存(分布式共享)
- MySQL持久层
缓存击穿解决方案:
java复制public Furniture getFurnitureById(Long id) {
// 1. 先查缓存
Furniture furniture = redisTemplate.opsForValue().get(CACHE_PREFIX + id);
if (furniture == null) {
// 2. 获取分布式锁
RLock lock = redissonClient.getLock("lock:product:" + id);
try {
if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
// 3. 二次检查缓存
furniture = redisTemplate.opsForValue().get(CACHE_PREFIX + id);
if (furniture == null) {
// 4. 查数据库
furniture = furnitureMapper.selectById(id);
// 5. 写入缓存(设置随机过期时间防雪崩)
redisTemplate.opsForValue().set(
CACHE_PREFIX + id,
furniture,
30 + new Random().nextInt(30),
TimeUnit.MINUTES
);
}
}
} finally {
lock.unlock();
}
}
return furniture;
}
6. 部署方案
6.1 容器化部署
Docker Compose编排示例:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
6.2 监控配置
Prometheus监控指标示例:
yaml复制- job_name: 'springboot'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['backend:8080']
7. 常见问题解决
7.1 跨域问题
后端解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
前端开发环境代理配置(vite):
javascript复制server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
7.2 文件上传限制
SpringBoot配置:
properties复制# 单个文件大小限制
spring.servlet.multipart.max-file-size=10MB
# 总请求大小限制
spring.servlet.multipart.max-request-size=50MB
前端分片上传示例:
javascript复制const uploadFile = async (file) => {
const chunkSize = 2 * 1024 * 1024 // 2MB
const chunks = Math.ceil(file.size / chunkSize)
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize
const end = Math.min(file.size, start + chunkSize)
const chunk = file.slice(start, end)
const formData = new FormData()
formData.append('file', chunk)
formData.append('chunkNumber', i + 1)
formData.append('totalChunks', chunks)
formData.append('identifier', file.uniqueIdentifier)
await axios.post('/api/upload', formData)
}
}
8. 扩展功能建议
-
智能推荐系统:
- 基于用户行为的协同过滤
- 基于内容的推荐算法
-
AR家具预览:
- 使用Three.js实现3D展示
- WebXR API支持AR模式
-
供应链管理:
- 供应商管理模块
- 库存预警系统
-
数据分析看板:
- 使用ECharts可视化
- 用户行为分析
这个项目在实际开发中,我们遇到最大的挑战是高并发下的库存准确性保障。最终采用的"Redis分布式锁+MySQL乐观锁+异步日志校对"方案,在压力测试中实现了99.99%的数据一致性。对于商品图片这类静态资源,建议使用CDN加速分发,我们实测将首屏加载时间从2.3秒降低到了800毫秒左右。
