1. 项目概述与背景
作为一名经历过完整毕业设计开发流程的过来人,我深知在有限时间内完成一个功能完善、逻辑严谨的校园商铺管理系统有多么不易。这个基于SpringBoot+Vue+MySQL的太原学院商铺管理系统,是我在毕业设计期间耗时两个月完成的实战项目,期间踩过不少坑,也积累了许多宝贵的经验。
这个系统的核心价值在于为校园内的商铺管理提供了一个数字化解决方案。通过该系统,管理员可以高效审核商家资质和商品信息,学生用户能够方便地浏览和购买校园商铺的商品,商家则可以便捷地管理自己的商品和订单。相比传统的人工管理方式,这套系统将商铺管理的各个环节都进行了标准化和流程化,大大提升了管理效率。
在技术选型上,我选择了SpringBoot 2.7作为后端框架,Vue 2.x作为前端框架,MySQL 5.7作为数据库。这套技术组合虽然不算最新,但胜在稳定可靠、社区支持完善,特别适合毕业设计这类时间有限的项目。在实际开发过程中,这套技术栈也确实展现出了它的优势,让我能够把更多精力放在业务逻辑的实现上,而不是框架本身的兼容性问题。
2. 需求分析与功能设计
2.1 核心角色与功能划分
在需求分析阶段,我首先明确了系统的三大核心角色:管理员、商家和学生用户。每个角色都有其特定的功能需求:
管理员:
- 商品审核:审核商家提交的商品信息,确保内容合规
- 商家资质审核:验证商家提交的营业执照等资质文件
- 公告管理:发布校园商铺相关通知和活动信息
- 用户管理:管理学生用户账号状态
- 订单异常处理:处理交易纠纷和异常订单
商家:
- 商品管理:发布、编辑和上下架商品
- 订单处理:查看和处理用户订单,包括发货和退款
- 店铺信息维护:更新店铺联系方式和位置信息
- 销售数据查看:查看商品销售情况和统计
学生用户:
- 商品浏览:按类别、价格等条件筛选商品
- 购物车管理:添加、修改和删除购物车商品
- 订单操作:提交订单、选择支付方式和收货地址
- 评价与收藏:对购买过的商品进行评价和收藏
2.2 需求调研与验证
为了避免闭门造车,我特别注重实际需求的调研。我邀请了8位同学参与需求验证,模拟了完整的"商家提交商品-管理员审核-用户下单-商家发货"流程。通过这个验证过程,我发现了一些关键需求点:
- 学生用户非常关注商家资质的真实性,因此需要专门的"商家资质公示"模块
- 商品图片和详情信息的完整性对购买决策影响很大
- 订单状态的实时更新是用户最关心的功能之一
基于这些发现,我对系统功能进行了优化调整,确保每个功能都能解决实际的痛点问题。
2.3 业务规则与约束条件
为了给后续开发提供明确的依据,我提前定义了一系列业务规则:
- 文件上传:商品照片和营业执照仅支持JPG/PNG格式,大小不超过5MB
- 订单编号:自动生成,格式为DD+年份+序号(如DD2024001)
- 商品信息:价格必须≥0.1元,名称至少2个字符
- 公告内容:至少20个字符
- 收货地址:必须包含详细楼栋号
这些约束条件不仅确保了数据的规范性,也为前端表单验证和后端数据校验提供了明确的标准。
3. 技术架构与实现方案
3.1 后端技术选型与实现
SpringBoot 2.7作为后端框架,提供了诸多便利:
- 自动配置减少了大量样板代码
- 内置Tomcat服务器简化了部署流程
- 完善的事务管理机制确保了数据一致性
在SpringBoot应用中,我特别注意了以下几点:
- 数据库连接配置:在application.yml中明确指定了useSSL=false,避免MySQL连接问题
- 事务管理:对关键业务操作如订单创建加上了@Transactional注解,确保操作的原子性
- 异常处理:统一处理业务异常,返回友好的错误信息
java复制// 示例:订单创建服务方法
@Transactional
public Result createOrder(OrderDTO orderDTO) {
// 1. 校验商品库存
Product product = productMapper.selectById(orderDTO.getProductId());
if (product.getStock() < orderDTO.getQuantity()) {
throw new BusinessException("商品库存不足");
}
// 2. 扣减库存
product.setStock(product.getStock() - orderDTO.getQuantity());
productMapper.updateById(product);
// 3. 创建订单
Order order = new Order();
BeanUtils.copyProperties(orderDTO, order);
order.setOrderNo(generateOrderNo());
orderMapper.insert(order);
return Result.success(order);
}
3.2 前端技术选型与实现
Vue 2.x配合Element UI组件库,让我能够快速构建出美观实用的界面。前端架构的关键点包括:
- 路由设计:按功能模块划分路由,实现按需加载
- 状态管理:使用Vuex集中管理用户登录状态、购物车数据等全局状态
- API封装:统一封装axios请求,处理token过期等常见问题
javascript复制// 示例:商品列表组件
<template>
<div class="product-list">
<el-card v-for="product in products" :key="product.id">
<img :src="product.image" class="product-image">
<div class="product-info">
<h3>{{ product.name }}</h3>
<p class="price">¥{{ product.price }}</p>
<p class="stock">库存: {{ product.stock }}</p>
<el-button
type="primary"
@click="addToCart(product)"
:disabled="product.stock <= 0"
>
加入购物车
</el-button>
</div>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
products: []
}
},
async created() {
const res = await this.$api.getProducts();
this.products = res.data;
},
methods: {
addToCart(product) {
this.$store.dispatch('cart/addItem', product);
this.$message.success('已加入购物车');
}
}
}
</script>
3.3 数据库设计与优化
MySQL 5.7作为关系型数据库,提供了完善的事务支持和外键约束。数据库设计中的关键点:
- 字符集设置:使用utf8mb4字符集,支持完整的Unicode字符
- 表关系设计:通过外键建立表间关联,确保数据完整性
- 索引优化:为常用查询字段添加索引,提升查询性能
sql复制-- 示例:商品订单表创建语句
CREATE TABLE `shangpin_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`yonghu_id` int(11) NOT NULL COMMENT '用户ID',
`shangpin_id` int(11) NOT NULL COMMENT '商品ID',
`address_id` int(11) NOT NULL COMMENT '收货地址ID',
`shangpin_order_uuid_number` varchar(50) NOT NULL COMMENT '订单编号',
`buy_number` int(11) NOT NULL COMMENT '购买数量',
`shangpin_order_true_price` decimal(10,2) NOT NULL COMMENT '实付价格',
`shangpin_order_types` int(11) NOT NULL COMMENT '订单状态',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_order_user` (`yonghu_id`),
KEY `fk_order_product` (`shangpin_id`),
KEY `fk_order_address` (`address_id`),
CONSTRAINT `fk_order_address` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`),
CONSTRAINT `fk_order_product` FOREIGN KEY (`shangpin_id`) REFERENCES `shangpin` (`id`),
CONSTRAINT `fk_order_user` FOREIGN KEY (`yonghu_id`) REFERENCES `yonghu` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品订单表';
重要提示:绝对不要将图片文件直接存入数据库,这会导致数据库体积急剧膨胀。正确的做法是将图片保存在文件系统或对象存储中,数据库中只存储图片路径。
4. 核心功能实现细节
4.1 商品审核流程实现
商品审核是管理员的核心功能之一,其业务流程如下:
- 商家提交商品信息(包括名称、价格、库存、描述和图片)
- 系统将商品状态标记为"待审核"
- 管理员查看待审核商品列表
- 管理员审核商品内容,做出通过或驳回决定
- 系统根据审核结果更新商品状态
后端实现关键点:
java复制// 商品审核服务方法
public Result reviewProduct(ProductReviewDTO reviewDTO) {
Product product = productMapper.selectById(reviewDTO.getProductId());
if (product == null) {
return Result.error("商品不存在");
}
if (!ProductStatus.PENDING_REVIEW.equals(product.getStatus())) {
return Result.error("商品当前状态不可审核");
}
if (reviewDTO.isApproved()) {
product.setStatus(ProductStatus.APPROVED);
product.setOnlineTime(new Date());
} else {
if (StringUtils.isBlank(reviewDTO.getRejectReason())) {
return Result.error("驳回原因不能为空");
}
product.setStatus(ProductStatus.REJECTED);
product.setRejectReason(reviewDTO.getRejectReason());
}
product.setReviewerId(getCurrentUserId());
product.setReviewTime(new Date());
productMapper.updateById(product);
// 通知商家审核结果
notifyMerchant(product.getMerchantId(), product.getId(), product.getStatus());
return Result.success();
}
4.2 购物车与订单系统
购物车和订单系统是用户体验的核心环节,我特别注意了以下几个方面的实现:
- 购物车数据结构设计:使用Redis存储临时购物车数据,用户登录后同步到数据库
- 库存校验:在添加购物车和创建订单时双重校验库存
- 订单状态机:明确定义订单状态流转规则
订单创建的关键逻辑:
java复制@Transactional
public Result createOrder(OrderCreateDTO createDTO) {
// 1. 验证用户和收货地址
User user = getUser(createDTO.getUserId());
Address address = addressMapper.selectById(createDTO.getAddressId());
if (address == null || !address.getUserId().equals(user.getId())) {
throw new BusinessException("收货地址无效");
}
// 2. 验证购物车商品
List<CartItem> cartItems = cartService.getCartItems(createDTO.getUserId());
if (cartItems.isEmpty()) {
throw new BusinessException("购物车为空");
}
// 3. 检查库存并锁定
for (CartItem item : cartItems) {
int affected = productMapper.lockStock(
item.getProductId(),
item.getQuantity()
);
if (affected == 0) {
throw new BusinessException(item.getProductName() + "库存不足");
}
}
// 4. 创建订单
Order order = new Order();
order.setOrderNo(generateOrderNo());
order.setUserId(user.getId());
order.setAddressId(address.getId());
order.setTotalAmount(calculateTotal(cartItems));
order.setStatus(OrderStatus.WAITING_PAYMENT);
orderMapper.insert(order);
// 5. 创建订单项
for (CartItem item : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProductId(item.getProductId());
orderItem.setProductName(item.getProductName());
orderItem.setProductImage(item.getProductImage());
orderItem.setQuantity(item.getQuantity());
orderItem.setPrice(item.getPrice());
orderItemMapper.insert(orderItem);
}
// 6. 清空购物车
cartService.clearCart(user.getId());
return Result.success(order);
}
4.3 商家商品管理
商家端的商品管理功能需要特别注意以下几点:
- 商品状态管理:区分"草稿"、"待审核"、"已上架"、"已下架"等状态
- 批量操作:支持批量上下架商品
- 图片上传:实现多图上传和图片排序功能
商品上架的Vue组件示例:
javascript复制<template>
<div class="product-form">
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="商品名称" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="商品价格" prop="price">
<el-input-number
v-model="form.price"
:min="0.1"
:precision="2"
></el-input-number>
</el-form-item>
<el-form-item label="商品库存" prop="stock">
<el-input-number v-model="form.stock" :min="1"></el-input-number>
</el-form-item>
<el-form-item label="商品图片" prop="images">
<el-upload
action="/api/upload"
list-type="picture-card"
:file-list="form.images"
:on-success="handleUploadSuccess"
:before-upload="beforeUpload"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
<el-form-item label="商品描述" prop="description">
<el-input
type="textarea"
v-model="form.description"
:rows="5"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交审核</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
price: 0.1,
stock: 1,
images: [],
description: ''
},
rules: {
name: [
{ required: true, message: '请输入商品名称', trigger: 'blur' },
{ min: 2, message: '至少2个字符', trigger: 'blur' }
],
price: [
{ required: true, message: '请输入商品价格', trigger: 'blur' }
],
stock: [
{ required: true, message: '请输入商品库存', trigger: 'blur' }
],
description: [
{ required: true, message: '请输入商品描述', trigger: 'blur' }
]
}
}
},
methods: {
beforeUpload(file) {
const isImage = file.type.includes('image');
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isImage) {
this.$message.error('只能上传图片文件');
}
if (!isLt5M) {
this.$message.error('图片大小不能超过5MB');
}
return isImage && isLt5M;
},
handleUploadSuccess(response, file) {
this.form.images.push({
url: response.data.url,
name: file.name
});
},
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
if (this.form.images.length === 0) {
this.$message.error('请上传至少一张商品图片');
return;
}
this.$api.createProduct(this.form)
.then(() => {
this.$message.success('商品提交成功,等待管理员审核');
this.$router.push('/merchant/products');
});
}
});
}
}
}
</script>
5. 项目部署与测试
5.1 系统部署方案
项目采用前后端分离的部署方式:
后端部署:
- 打包SpringBoot应用为JAR文件
- 配置生产环境数据库连接
- 使用Nginx反向代理API请求
- 配置HTTPS证书确保通信安全
前端部署:
- 执行npm run build生成静态文件
- 配置Nginx托管静态资源
- 设置API请求代理
- 启用Gzip压缩提升加载速度
示例Nginx配置:
nginx复制server {
listen 80;
server_name shop.example.com;
# 前端静态资源
location / {
root /var/www/shop-frontend;
try_files $uri $uri/ /index.html;
expires 30d;
gzip on;
gzip_types text/plain application/xml text/css application/javascript;
}
# API代理
location /api {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 静态资源
location /static {
alias /var/www/shop-static;
expires 365d;
access_log off;
}
}
5.2 关键测试用例
为确保系统稳定性,我设计了以下关键测试场景:
并发下单测试:
- 测试目的:验证库存扣减的原子性
- 测试步骤:
- 准备一个库存为1的商品
- 使用两个用户同时发起购买该商品的请求
- 预期结果:只有一个用户的订单创建成功,另一个用户收到库存不足提示
订单状态流转测试:
- 测试目的:验证订单状态变更的正确性
- 测试步骤:
- 用户创建订单(待付款)
- 用户完成支付(待发货)
- 商家发货(待收货)
- 用户确认收货(已完成)
- 预期结果:每个状态变更都符合业务规则,相关通知及时发送
文件上传测试:
- 测试目的:验证文件上传限制的有效性
- 测试步骤:
- 尝试上传超过5MB的图片
- 尝试上传非图片文件
- 尝试上传符合要求的图片
- 预期结果:前两种情况被拒绝,第三种情况成功上传
5.3 性能优化措施
在项目后期,我实施了以下性能优化措施:
-
数据库查询优化:
- 为常用查询字段添加索引
- 优化复杂查询,避免全表扫描
- 使用JOIN替代多次单表查询
-
缓存策略:
- 使用Redis缓存热门商品数据
- 实现多级缓存(本地缓存+分布式缓存)
- 合理设置缓存过期时间
-
前端性能优化:
- 实现图片懒加载
- 使用Webpack进行代码分割
- 启用HTTP/2提升加载效率
-
异步处理:
- 将非关键路径操作(如发送通知)异步化
- 使用消息队列处理高延迟操作
6. 项目总结与经验分享
6.1 关键收获
通过这个毕业设计项目,我获得了以下几方面的宝贵经验:
- 需求分析能力:学会了如何从实际使用场景出发,识别核心需求,避免功能冗余
- 技术选型思维:理解了选择稳定、成熟技术栈的重要性,特别是在时间有限的情况下
- 数据库设计技巧:掌握了表关系设计和数据完整性的关键点
- 全栈开发能力:从后端到前端,从设计到部署,获得了完整的项目开发经验
6.2 遇到的挑战与解决方案
挑战一:订单表关联设计不合理
- 问题描述:初期订单表只设计了简单的编号字段,没有与商品表和用户表建立外键关联
- 解决方案:重构表结构,添加必要的外键约束,确保数据完整性
- 经验总结:数据库设计阶段就要充分考虑表间关系,避免后期重构
挑战二:库存并发问题
- 问题描述:高并发场景下可能出现超卖问题
- 解决方案:使用乐观锁和数据库事务确保库存扣减的原子性
- 经验总结:对于电商类系统,库存管理必须考虑并发场景
挑战三:图片存储方案选择
- 问题描述:初期将图片直接存入数据库,导致性能问题
- 解决方案:改为文件系统存储,数据库中只保存路径
- 经验总结:大数据量内容应该考虑专门的存储方案
6.3 给后来者的建议
基于我的项目经验,给后续开发类似系统的同学几点建议:
- 从简单开始:先实现核心功能,再考虑扩展功能,避免一开始就追求大而全
- 重视数据库设计:花足够时间设计合理的表结构,这能避免后期的很多麻烦
- 注重测试:特别是并发场景下的测试,很多问题在单用户测试时不会暴露
- 文档很重要:及时记录设计决策和实现细节,这对后期维护和答辩准备都很有帮助
- 合理规划时间:为每个开发阶段设定明确的时间节点,避免前松后紧
这个商铺管理系统虽然规模不大,但涵盖了从需求分析到部署上线的完整开发流程。通过这个项目,我不仅巩固了技术能力,更重要的是学会了如何将一个想法转化为实际可用的系统。希望我的这些经验能够帮助到正在或将要进行类似项目开发的同学。