1. 项目背景与技术选型
蛋糕销售商城是一个典型的B2C电商平台,采用前后端分离架构。这种架构模式在当今互联网项目中已成为主流选择,主要优势在于前后端开发可以并行进行,且前端展示层与后端业务逻辑完全解耦。
技术栈选择上,我们采用:
- 后端:Spring Boot 2.7.x(当前稳定版本)
- 前端:Vue 3 + Element Plus
- 视图层:传统HTML作为fallback方案
为什么选择这套技术组合?Spring Boot的自动配置特性可以快速搭建RESTful API服务,Vue的响应式特性非常适合电商类频繁交互的场景,而保留HTML模板则是为了SEO优化和兼容性考虑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体架构图
code复制[客户端层]
├── 移动端H5(Vue)
├── PC网页版(Vue/HTML)
└── 管理后台(Vue)
[接入层]
├── Nginx反向代理
└── CDN静态资源加速
[应用层]
├── Spring Boot应用集群
└── Redis缓存集群
[数据层]
├── MySQL主从集群
└── Elasticsearch商品搜索
2.2 核心模块划分
-
用户中心模块
- 注册/登录(JWT鉴权)
- 个人信息管理
- 地址簿管理
-
商品模块
- 分类管理(三级分类)
- 商品SPU/SKU设计
- 商品搜索(Elasticsearch集成)
-
订单模块
- 购物车设计(Redis存储)
- 订单状态机设计
- 支付对接(微信/支付宝)
-
营销模块
- 优惠券系统
- 限时折扣
- 拼团功能
3. 开发环境搭建
3.1 后端环境准备
bash复制# 使用IDEA创建Spring Boot项目
File -> New -> Project -> Spring Initializr
选择依赖:
- Spring Web
- MyBatis Plus
- Lombok
- Redis
- MySQL Driver
关键配置示例(application.yml):
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/cake_shop?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
3.2 前端环境搭建
bash复制# 使用Vue CLI创建项目
npm install -g @vue/cli
vue create cake-shop-frontend
选择配置:
- Vue 3
- Router
- Vuex
- CSS Pre-processors (Sass)
推荐安装的额外依赖:
bash复制npm install element-plus axios vue-axios --save
4. 核心功能实现
4.1 商品详情页实现
前端关键代码(Vue组件):
vue复制<template>
<div class="product-detail">
<el-carousel :interval="4000" type="card">
<el-carousel-item v-for="img in product.images" :key="img">
<img :src="img" class="product-image">
</el-carousel-item>
</el-carousel>
<el-form :model="skuForm" label-width="80px">
<el-form-item label="规格">
<el-radio-group v-model="skuForm.skuId">
<el-radio
v-for="sku in product.skus"
:key="sku.id"
:label="sku.id"
:disabled="sku.stock <= 0">
{{sku.spec}} ¥{{sku.price}}
<span v-if="sku.stock <=0">(售罄)</span>
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
</template>
后端接口设计(Spring Boot Controller):
java复制@RestController
@RequestMapping("/api/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/detail/{id}")
public Result<ProductDetailVO> getDetail(@PathVariable Long id) {
return Result.success(productService.getDetail(id));
}
}
4.2 购物车功能实现
Redis数据结构设计:
code复制用户购物车key: cart:{userId}
存储结构: Hash
field: skuId
value: JSON字符串 {
"count": 2,
"selected": true,
"price": 68.00,
"spec": "6寸/巧克力"
}
并发控制方案:
java复制public void addToCart(Long userId, CartItemDTO item) {
String key = "cart:" + userId;
String field = item.getSkuId().toString();
// 使用Redis事务保证原子性
redisTemplate.execute(new SessionCallback<>() {
@Override
public Object execute(RedisOperations operations) {
operations.watch(key);
// 检查库存
Integer stock = (Integer) operations.opsForValue()
.get("stock:" + item.getSkuId());
if (stock == null || stock < item.getCount()) {
throw new BusinessException("库存不足");
}
operations.multi();
operations.opsForHash().put(key, field, JSON.toJSONString(item));
return operations.exec();
}
});
}
5. 典型问题解决方案
5.1 跨域问题处理
Spring Boot解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
Vue开发环境代理配置(vue.config.js):
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
5.2 文件上传实现
Spring Boot后端实现:
java复制@PostMapping("/upload")
public Result<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.error("请选择文件");
}
String filename = UUID.randomUUID() +
file.getOriginalFilename().substring(
file.getOriginalFilename().lastIndexOf(".")
);
try {
Files.copy(
file.getInputStream(),
Paths.get("/upload", filename),
StandardCopyOption.REPLACE_EXISTING
);
return Result.success("/static/" + filename);
} catch (IOException e) {
log.error("文件上传失败", e);
return Result.error("上传失败");
}
}
Vue前端实现:
vue复制<template>
<el-upload
action="/api/upload"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button type="primary">点击上传</el-button>
</el-upload>
</template>
<script>
export default {
methods: {
beforeUpload(file) {
const isImage = file.type.includes('image/');
if (!isImage) {
this.$message.error('只能上传图片');
return false;
}
return true;
},
handleSuccess(res) {
if (res.code === 200) {
this.imageUrl = res.data;
}
}
}
}
</script>
6. 项目部署方案
6.1 后端部署
推荐使用Docker Compose部署:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: cake_shop
volumes:
- ./mysql/data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:6
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
6.2 前端部署
Nginx配置示例:
nginx复制server {
listen 80;
server_name cakeshop.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
7. 常见问题排查
7.1 Vue路由刷新404问题
解决方案:
- 开发环境:在vue.config.js中配置historyApiFallback
- 生产环境:Nginx配置try_files
7.2 Spring Boot跨域配置失效
可能原因及解决:
- 配置顺序问题:确保CorsConfig在SecurityConfig之前加载
- 重复配置:检查是否同时在Controller和方法上使用@CrossOrigin
- 过滤器优先级:自定义过滤器可能覆盖CORS配置
7.3 MyBatis Plus分页失效
正确配置方式:
java复制@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
8. 项目优化建议
8.1 性能优化
-
前端优化:
- 路由懒加载
- 图片懒加载
- 组件按需引入
-
后端优化:
- 二级缓存设计(Redis + Caffeine)
- SQL优化(索引检查、慢查询监控)
- 异步化处理(支付回调、日志记录)
8.2 安全加固
-
XSS防护:
- 前端:DOMPurify过滤富文本
- 后端:Jackson配置HTML转义
-
CSRF防护:
- 前后端分离项目建议使用JWT + 自定义请求头
-
SQL注入防护:
- 坚持使用MyBatis参数绑定
- 避免直接拼接SQL
我在实际开发中发现,蛋糕类电商项目需要特别注意商品规格的灵活性设计。比如一个6寸的草莓蛋糕,可能需要选择糖度(少糖/正常)、奶油类型(动物/植物)、附加配件(蜡烛/贺卡)等,这些都需要在SKU设计中充分考虑扩展性。建议采用"规格组+规格项"的动态组合模式,而不是写死在前端代码中。
