1. 项目概述与技术选型
"衣依"服装销售平台是一个典型的B2C电商系统,采用当前主流的前后端分离架构。这套源码的价值在于它完整实现了电商核心功能链路,同时使用了2023年最前沿的技术组合:后端基于SpringBoot 3.x(支持JDK17+),前端采用Vue3组合式API,数据层使用MyBatis-Plus增强,数据库为MySQL 8.0。
为什么选择这套技术栈?从实际开发角度看:
- SpringBoot:简化了传统SSM繁琐的XML配置,内置Tomcat容器,通过starter机制实现依赖自动装配。最新3.x版本对GraalVM原生镜像的支持,为未来可能的云原生部署留出扩展空间。
- Vue3:相比Vue2的Options API,组合式API更适合复杂业务逻辑的组织。特别是在商品SKU选择、购物车联动等电商典型场景中,
<script setup>语法糖能让代码更紧凑。 - MyBatis-Plus:省去了90%的单表CRUD代码,其Lambda表达式写法(如
QueryWrapper<User>().lambda().eq(User::getName, "张三"))完美规避SQL注入风险,同时保留了MyBatis对复杂SQL的掌控力。
提示:这套技术栈对开发者机器配置有一定要求。实测开发环境下,IDEA+MySQL+Vue脚手架同时运行需要至少16GB内存,否则可能出现Java堆内存不足(建议JVM参数:
-Xmx2048m -Xms1024m)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统核心模块拆解
2.1 权限控制设计
系统采用RBAC(基于角色的访问控制)模型,具体实现包含以下技术要点:
-
Spring Security改造:重写
UserDetailsService加载用户权限,使用@PreAuthorize("hasRole('ADMIN')")进行方法级鉴权。特别注意处理了前后端分离场景下的几个关键问题:- 跨域配置:
CorsConfiguration中需显式允许credentials(携带cookie) - JWT过期处理:通过
AuthenticationEntryPoint返回401状态码而非跳转登录页 - 密码加密:采用
BCryptPasswordEncoder而非MD5,避免彩虹表攻击
- 跨域配置:
-
Vue3前端路由守卫:通过
router.beforeEach实现动态路由添加,关键代码片段:
javascript复制// 从JWT解析用户角色
const roles = decodedToken.roles
// 过滤异步路由表
const accessRoutes = filterAsyncRoutes(asyncRoutes, roles)
// 动态添加路由
accessRoutes.forEach(route => {
router.addRoute(route)
})
2.2 商品SPU/SKU管理
服装类目的商品管理复杂度远高于普通商品,主要体现在:
- 数据库设计:
sql复制CREATE TABLE `product_spu` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(120) NOT NULL COMMENT '商品名称',
`category_id` INT NOT NULL COMMENT '类目ID',
`detail_html` TEXT COMMENT '商品详情HTML'
);
CREATE TABLE `product_sku` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`spu_id` BIGINT NOT NULL COMMENT '关联SPU',
`attributes_json` JSON NOT NULL COMMENT '规格属性,如{"color":"red","size":"XL"}',
`price` DECIMAL(10,2) NOT NULL COMMENT '售价',
`stock` INT NOT NULL DEFAULT 0 COMMENT '库存',
INDEX `idx_spu` (`spu_id`)
);
- 前后端交互设计:
- 规格属性动态渲染:前端根据后台返回的
specTemplate数组生成选择器 - 价格实时计算:使用Vue3的
computed基于选中规格计算最终价格 - 库存校验:加入购物车前通过
/api/stock/check接口预校验
2.3 订单状态机设计
电商订单的复杂状态流转通过状态模式实现:
java复制public enum OrderStatus {
UNPAID(1, "待支付") {
@Override
public boolean canChangeTo(OrderStatus nextStatus) {
return nextStatus == PAID || nextStatus == CANCELLED;
}
},
PAID(2, "已支付") {
@Override
public boolean canChangeTo(OrderStatus nextStatus) {
return nextStatus == SHIPPED || nextStatus == REFUNDING;
}
};
// 其他状态省略...
public abstract boolean canChangeTo(OrderStatus nextStatus);
}
配合MyBatis的类型处理器:
xml复制<resultMap id="orderResultMap" type="Order">
<result property="status" column="status"
typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
</resultMap>
3. 开发环境搭建指南
3.1 后端工程初始化
- 依赖管理关键点:
xml复制<!-- 必须注意的版本冲突 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
<!-- 排除内置的mybatis版本 -->
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
- 多环境配置技巧:
- 使用
spring.profiles.active=dev激活开发配置 - 敏感信息放在
jasypt-encrypted.properties中加密存储 - 推荐IDEA插件:
.env files support管理环境变量
3.2 前端工程配置
- Vue3项目优化项:
javascript复制// vite.config.js 关键配置
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
},
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
})
- Element Plus按需引入:
javascript复制// 正确方式:使用unplugin-vue-components自动导入
Components({
resolvers: [
ElementPlusResolver({
importStyle: 'sass'
})
]
})
4. 典型业务场景实现
4.1 购物车高并发处理
服装促销期间可能面临的并发问题解决方案:
- Redis缓存方案:
java复制public Cart addToCart(Long userId, Long skuId, Integer num) {
String key = "cart:" + userId;
// 使用Lua脚本保证原子性
String luaScript = "if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +
" return redis.call('hincrby', KEYS[1], ARGV[1], ARGV[2]) " +
"else " +
" return redis.call('hset', KEYS[1], ARGV[1], ARGV[2]) " +
"end";
redisTemplate.execute(
new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(key),
skuId.toString(),
num.toString()
);
// 异步持久化到数据库
cartAsyncService.syncCart(userId);
return getCart(userId);
}
- 库存扣减方案对比:
- 乐观锁:
UPDATE product_sku SET stock=stock-1 WHERE id=? AND stock>=1 - Redis原子操作:
DECR+ Lua脚本 - 分布式锁:Redisson的
RLock(适用于秒杀场景)
4.2 支付结果异步通知
处理微信/支付宝回调的注意事项:
- 幂等性设计:
java复制@Transactional
public String handlePayNotify(PayNotifyDTO dto) {
// 1. 签名验证(略)
// 2. 幂等判断
Payment payment = paymentMapper.selectByOrderNo(dto.getOrderNo());
if (payment.getStatus() == PaymentStatus.PAID) {
return "SUCCESS"; // 重要:必须返回成功标识
}
// 3. 更新订单状态(使用状态机校验)
orderService.updateStatus(dto.getOrderNo(), OrderStatus.PAID);
return "SUCCESS";
}
- 网络异常处理:
- 配置重试机制:使用Spring Retry的
@Retryable - 添加补偿任务:通过
@Scheduled定时检查未支付订单
5. 性能优化实践
5.1 MySQL索引优化
针对服装查询场景的特殊优化:
- 多条件查询索引:
sql复制ALTER TABLE product_spu ADD INDEX idx_search (category_id, price, sales_count);
- JSON字段查询优化:
sql复制-- 错误做法:无法使用索引
SELECT * FROM product_sku WHERE JSON_EXTRACT(attributes_json, '$.color') = 'red';
-- 正确做法:生成列+索引
ALTER TABLE product_sku
ADD color VARCHAR(20) GENERATED ALWAYS AS (attributes_json->>"$.color") STORED,
ADD INDEX idx_color (color);
5.2 Vue3组件性能
- 列表渲染优化:
vue复制<template>
<!-- 使用v-memo缓存虚拟DOM -->
<div v-for="item in items" :key="item.id" v-memo="[item.id]">
<ProductCard :data="item" />
</div>
</template>
<script setup>
// 使用shallowRef减少响应式开销
const items = shallowRef([]);
</script>
- API请求防抖:
javascript复制import { debounce } from 'lodash-es';
const search = debounce(async (query) => {
const { data } = await axios.get('/api/search', { params: { q: query } });
results.value = data;
}, 300);
6. 部署上线方案
6.1 容器化部署
- Docker多阶段构建:
dockerfile复制# 前端构建阶段
FROM node:18 as frontend-builder
WORKDIR /app
COPY frontend .
RUN npm install && npm run build
# Java构建阶段
FROM maven:3.8.6 as backend-builder
WORKDIR /app
COPY backend .
RUN mvn clean package -DskipTests
# 最终镜像
FROM openjdk:17-jdk-slim
COPY --from=backend-builder /app/target/*.jar /app.jar
COPY --from=frontend-builder /app/dist /static
ENTRYPOINT ["java","-jar","/app.jar"]
- MySQL配置建议:
ini复制[mysqld]
innodb_buffer_pool_size = 2G # 建议分配物理内存的50-70%
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2 # 非金融级应用可适当放宽
6.2 监控与日志
- SpringBoot Actuator配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
- 前端错误监控:
javascript复制// 使用Sentry捕获前端错误
import * as Sentry from "@sentry/vue";
Sentry.init({
app,
dsn: "your_dsn",
integrations: [
new Sentry.BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router)
})
],
tracesSampleRate: 0.2
});
7. 二次开发建议
对于想要基于此系统进行扩展的开发者,建议重点关注以下几个方向:
- 移动端适配:
- 使用
postcss-px-to-viewport插件实现vw单位转换 - 添加
@vueuse/gesture处理手势操作 - 配置PWA离线缓存策略
- 数据分析增强:
- 集成Apache Kafka收集用户行为事件
- 使用Flink实时计算商品点击热力图
- 基于Elasticsearch实现商品搜索词建议
- 微服务改造:
- 将订单服务拆分为独立模块
- 采用Spring Cloud Alibaba实现服务发现
- 使用Seata处理分布式事务
这套源码的价值不仅在于开箱即用的电商功能,更在于它展示了一套经过实战检验的现代化Java技术栈最佳实践。特别是在处理服装行业特有的SKU组合、促销活动叠加等复杂业务场景时,其设计思路值得深入研究和借鉴。
