毕业设计实战:基于Spring Boot的中国陕西民俗网设计与实现,从需求到测试全流程拆解,新手也能轻松通关!
谁懂啊!当初做中国陕西民俗网毕设时,光用户表和商品订单表的关联就卡了3天——一开始没设外键,查某用户的历史订单时数据全乱套,导师看了直接让我“重画数据库E-R图”😫 后来踩遍无数坑才摸出一套高效落地流程,今天把需求分析、技术选型、功能实现到测试的细节全说透,宝子们不用再熬夜改代码,轻松搞定毕设!
一、先搞懂“中国陕西民俗网要啥”!需求分析别瞎蒙
刚开始我跳过需求分析就写代码,花两周加了个“民俗论坛互动功能”,结果导师一句“核心是民俗展示与商品管理,不是社交讨论”直接打回重改!后来才明白,需求分析得先抓准“谁用系统、要干啥”,这步做对,后面少走90%弯路。
1. 核心用户&功能拆解(踩坑后总结版)
中国陕西民俗网就两类核心用户:管理员和普通用户(别加“民俗专家审核角色”!我当初加了后,民俗信息发布流程多了3层审批,普通用户根本没法快速查看内容,最后砍掉才顺畅):
- 管理员端(必做功能):
- 用户管理:查看用户列表、新增用户、重置密码、模糊查询(支持按姓名/手机号搜,我当初没加,查用户要翻几十页)
- 商品管理:增删改查商品信息(含传图/设库存/改价格)、上下架商品(用不同颜色标“上架/下架”,直观清晰)
- 民俗信息管理:发布民俗介绍(传民俗图片/写详情)、修改民俗类型、删除过期内容(加“民俗类型”字段,比如“传统技艺/民俗节日”,方便筛选)
- 公告管理:发布系统通知、修改公告类型、删除过期公告(别让管理员手动输公告类型,用下拉框选“系统通知/活动提醒”,效率翻倍)
- 普通用户端(核心功能):
- 民俗浏览:按类型筛选民俗、看详情(含图片/文字介绍)、收藏感兴趣的民俗(按“创建时间”排序,我当初没加,用户找最新民俗要翻半天)
- 商品操作:浏览商品、加购物车、提交订单(支持查看订单状态,避免下单后查不到进度)
- 个人中心:修改个人信息(头像/联系方式)、查看订单记录、管理收货地址(显示默认地址,方便快速下单)
2. 需求分析避坑指南(血泪教训!)
- 别光靠“空想”!找2个同学模拟管理员和普通用户提意见:比如有同学说“想快速找收藏的民俗”,我才加了“民俗收藏夹”,比瞎加“民俗论坛”实用多了
- 一定要画用例图!用DrawIO画简单版,标清“管理员-发布民俗”“用户-提交订单”,跟导师汇报时,比光说“我要做XX功能”直观10倍(当初没画,导师听20分钟还没get到逻辑)
- 写“需求规格说明书”!不用复杂,把“功能描述、约束条件”写清楚(比如“商品库存不能为负”“民俗标题不能重复”),编码时对着做,不会跑偏
3. 可行性分析别敷衍!3点写清楚就能过
导师超爱问“你这系统可行吗”,别只说“我觉得可行”,从3个角度写,显得专业:
- 技术可行性:Spring Boot、Java、MySQL都是课堂学过的,图书馆有《Spring Boot实战》《MySQL从入门到精通》,遇到问题能查资料(别选Vue3!我当初想试,环境配置卡了一周,换回Vue2才顺利)
- 经济可行性:所有工具全免费!Eclipse(社区版)、MySQL、Tomcat官网直接下,不用花钱买版权,答辩时说“开发成本为0”,导师会觉得你懂成本控制
- 操作可行性:界面用简洁布局,按钮位置参考同类展示型网站,我找系里同学测试,3分钟就学会浏览民俗和下单,导师直接认可
二、技术选型别跟风!这套组合稳到爆
刚开始我跟风用Spring Boot+Vue3+Redis,结果“民俗图片缓存”卡了5天——Redis的key-value逻辑不熟,图片总加载失败😫 后来换成Spring Boot+Vue2+MySQL+Tomcat9,新手友好度拉满,调试效率翻两倍!
1. 技术栈详细对比(附避坑提醒)
宝子们别盲目选“最新技术”,稳定比炫酷重要!我整理了4个核心工具的选择理由和坑点,直接抄:
| 技术工具 | 为啥选它 | 避坑提醒!(重点!) |
|---|---|---|
| Spring Boot | 比SSM配置简单,自带依赖管理 | 别用3.x版本!2.7.x就行,3.x和Vue2兼容性差,会报“接口请求错误” |
| MySQL 8.0 | 占内存小,存民俗、商品数据足够用 | 安装时设“utf8mb4”编码!我当初用默认编码,用户姓名含特殊符号乱码,查2小时才解决 |
| Tomcat 9.0 | 稳定!和Spring Boot、Vue适配最好 | 别用Tomcat 10!会出现“Servlet API包名变更”,答辩时崩了就完了 |
| Vue 2 | 文档丰富,新手易上手,组件生态成熟 | 别用Vue CLI 5!用4.x版本,5.x创建项目时依赖加载慢,还容易报错 |
2. 开发环境搭建(step by step 实操)
很多宝子卡在“环境配置”,跟着步骤来超简单,我当初一次成功:
- 装JDK 1.8:记路径(比如D:\Java\jdk1.8.0_301),配置“JAVA_HOME”别错,不然Eclipse认不到
- 装Eclipse(社区版):选“Eclipse IDE for Enterprise Java Developers”,自带Spring Boot插件
- 装MySQL 8.0:用Navicat管理(可视化工具超方便,新建表直接选字段类型,比命令行快10倍)
- 配Vue项目:用Vue CLI 4创建项目,选“Manually select features”,勾“Router”“Vuex”“CSS Pre-processors”,启动看到“Compiled successfully”就是成功
3. 架构图一定要画!答辩加分项
用DrawIO画三层架构图(像论文里的“系统架构图”),标清“表现层-业务层-数据访问层”:比如用户点“收藏民俗”→Vue页面传请求→Spring Boot Controller接请求→Service校验权限→Mapper存数据。去年答辩时,评委特意夸这图“逻辑清晰”,比光说“我用了Spring Boot”专业多了!
三、数据库设计:别让表关联坑了你
这部分是毕设的“核心骨架”,我当初没关联“商品表”和“订单表”,查“某商品的销售记录”要写3层嵌套SQL,调试到凌晨1点😫 后来按“实体-属性-关系”设计,终于理清了。
1. 核心实体&属性(附ER图绘制技巧)
先确定“实体”(用户、商品、民俗信息),再想“属性”,别漏关键字段!我整理了必做的8张表,直接照着画ER图:
- 用户表(yonghu):id(主键)、yonghu_name(姓名)、yonghu_phone(手机号,唯一)、password(MD5加密!存明文会被导师说“不安全”)、yonghu_photo(用户头像路径)
- 商品表(shangpin):id(主键)、shangpin_name(商品名称)、shangpin_photo(商品图片路径)、shangpin_kucun_number(库存)、shangpin_new_money(现价)
- 民俗信息表(minshu):id(主键)、minshu_name(民俗标题)、minshu_photo(民俗图片路径)、minshu_types(民俗类型)、minshu_content(民俗详情)
- 订单表(shangpin_order):id(主键)、shangpin_order_uuid_number(订单号,唯一)、yonghu_id(关联用户)、shangpin_id(关联商品)、shangpin_order_true_price(实付金额)
画ER图用Visio或亿图,记住3个规则:
- 矩形代表“实体”(比如“用户”“商品”)
- 椭圆代表“属性”(比如用户的“姓名”“手机号”)
- 菱形代表“关系”(比如“用户-购买-商品”是多对多,一个用户能买多件商品,一件商品能被多个用户买) 避坑提醒:别把“民俗图片、商品图片”存数据库!我当初存二进制导致数据库崩溃,改成存“文件路径”(比如/static/photo/minshu1.jpg)才对。
2. 数据库物理设计(附建表SQL示例)
ER图画好后,转成实际表,字段类型和约束别瞎设!比如“商品价格”用DECIMAL(10,2),别用INT,不然没法存“99.99元”;“用户手机号”设UNIQUE约束,避免重复。
给宝子们贴“民俗信息表”的建表SQL,复制到Navicat就能用:
CREATE TABLE `minshu` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '民俗ID',
`minshu_name` VARCHAR(200) NOT NULL COMMENT '民俗标题',
`minshu_photo` VARCHAR(200) DEFAULT NULL COMMENT '民俗图片路径',
`minshu_types` INT DEFAULT NULL COMMENT '民俗类型:1传统技艺/2民俗节日/3特色美食',
`minshu_content` TEXT DEFAULT NULL COMMENT '民俗详情',
`create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_minshu_name` (`minshu_name`) -- 民俗标题唯一
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='民俗信息表';
3. 表关联测试!别等编码才发现错
建完表一定要测关联!比如在“订单表”插数据(用户ID=1,商品ID=1),用JOIN查询:
SELECT y.yonghu_name, s.shangpin_name, o.shangpin_order_uuid_number, o.shangpin_order_true_price
FROM shangpin_order o
JOIN yonghu y ON o.yonghu_id = y.id
JOIN shangpin s ON o.shangpin_id = s.id
WHERE o.id = 1;
如果能查出“用户名+商品名+订单号+实付金额”,说明关联没问题;如果报错“Unknown column”,大概率是外键没设对,赶紧检查表结构。
四、功能实现:核心模块代码+页面设计
不用做所有功能!先搞定4个核心模块,答辩时足够出彩。每个模块我都附了代码片段和页面设计要点,宝子们直接套就行。
1. 管理员端:民俗信息管理模块(必做!)
这是民俗网的核心功能,实现“发布民俗、修改民俗类型”,重点说“民俗图片上传”——别漏“格式校验”,我当初就是这里踩了大坑!
(1)核心代码片段(Spring Boot)
Controller层(处理民俗新增):
@RestController
@RequestMapping("/admin/minshu")
public class AdminMinshuController {
@Autowired
private MinshuService minshuService;
// 新增民俗信息
@PostMapping("/add")
public Result addMinshu(@RequestBody MinshuDTO minshuDTO, HttpSession session) {
// 1. 获取当前登录管理员
Admin admin = (Admin) session.getAttribute("loginAdmin");
if (admin == null) {
return Result.error("未登录,请先登录!");
}
// 2. 校验民俗标题是否重复
if (minshuService.existsByName(minshuDTO.getMinshuName())) {
return Result.error("该民俗标题已存在,请勿重复添加!");
}
// 3. 转换DTO为实体
Minshu minshu = new Minshu();
minshu.setMinshuName(minshuDTO.getMinshuName());
minshu.setMinshuPhoto(minshuDTO.getMinshuPhoto()); // 图片路径(前端上传后返回)
minshu.setMinshuTypes(minshuDTO.getMinshuTypes());
minshu.setMinshuContent(minshuDTO.getMinshuContent());
// 4. 保存民俗信息
minshuService.save(minshu);
return Result.success("民俗信息新增成功!");
}
// 民俗图片上传
@PostMapping("/uploadPhoto")
public Result uploadPhoto(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
try {
// 1. 校验文件格式
String fileName = file.getOriginalFilename();
if (!fileName.endsWith(".jpg") && !fileName.endsWith(".png")) {
return Result.error("仅支持JPG/PNG格式图片!");
}
// 2. 保存图片到服务器
String realPath = request.getServletContext().getRealPath("/static/photo/minshu/");
File dir = new File(realPath);
if (!dir.exists()) dir.mkdirs();
String newFileName = System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."));
file.transferTo(new File(realPath + newFileName));
// 3. 返回图片路径
String photoUrl = "/static/photo/minshu/" + newFileName;
return Result.success("上传成功!", photoUrl);
} catch (Exception e) {
e.printStackTrace();
return Result.error("图片上传失败!");
}
}
}
// 民俗DTO
@Data
public class MinshuDTO {
private String minshuName; // 民俗标题
private String minshuPhoto; // 民俗图片路径
private Integer minshuTypes; // 民俗类型
private String minshuContent; // 民俗详情
}
(2)页面设计要点(Vue)
页面标题:管理员-民俗信息新增页面
(插入图片位置:此处放“民俗信息新增页面截图”,需包含以下元素)
- 表单元素:
- 民俗标题(输入框,必填,提示“如:陕西剪纸技艺”)
- 民俗类型(下拉框:传统技艺/民俗节日/特色美食,必填)
- 民俗图片(上传框,支持JPG/PNG,必填,上传后预览缩略图)
- 民俗详情(富文本框,必填,支持换行、加粗,提示“详细介绍民俗的历史、特点等”)
- 按钮:“提交新增”(蓝色el-button--primary)和“重置”(灰色el-button)
- 提示信息:红色显“校验失败”,绿色显“提交成功”
(3)避坑提醒
- 限制图片大小!在Spring Boot配置:
spring.servlet.multipart.max-file-size=5MB spring.servlet.multipart.max-request-size=10MB - 富文本框防XSS攻击!在配置类中加过滤:
@Bean public FilterRegistrationBean<XssFilter> xssFilterRegistration() { FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new XssFilter()); registration.addUrlPatterns("/admin/minshu/add"); // 只过滤民俗新增接口 return registration; }
2. 用户端:商品订单提交模块(核心需求!)
用户用系统的核心是“买民俗相关商品”,流程别复杂:加购物车→选地址→提交订单→生成订单号,我当初加“优惠券抵扣”,代码量翻倍,其实“基础流程+订单状态跟踪”更实用。
(1)核心代码片段(Vue+Spring Boot)
Vue页面(订单提交表单):
<template>
<div class="order-form">
<el-form :model="orderForm" :rules="orderRules" ref="orderRef" label-width="120px">
<el-form-item label="收货地址" prop="addressId">
<el-select v-model="orderForm.addressId" placeholder="请选择收货地址">
<el-option
v-for="addr in addressList"
:key="addr.id"
:label="addr.addressName + ' ' + addr.addressDizhi + ' ' + addr.addressPhone"
:value="addr.id"
></el-option>
</el-select>
<el-button type="text" @click="showAddAddrDialog">+ 新增地址</el-button>
</el-form-item>
<el-form-item label="购买商品" prop="cartIds">
<el-table :data="cartList" border>
<el-table-column label="商品图片" width="100">
<template #default="scope"><img :src="scope.row.shangpinPhoto" style="width:50px;height:50px;"></template>
</el-table-column>
<el-table-column label="商品名称" prop="shangpinName"></el-table-column>
<el-table-column label="单价" prop="shangpinNewMoney" formatter="formatMoney"></el-table-column>
<el-table-column label="数量" prop="buyNumber"></el-table-column>
<el-table-column label="小计" formatter="formatSubtotal"></el-table-column>
</el-table>
</el-form-item>
<el-form-item label="实付金额">
<span class="price-red">{{ totalPrice }}</span>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitOrder">提交订单</el-button>
<el-button @click="resetForm">取消</el-button>
</el-form-item>
</el-form>
<!-- 新增地址弹窗 -->
<el-dialog title="新增收货地址" v-model="addAddrVisible" width="500px">
<!-- 新增地址表单 -->
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
orderForm: {
addressId: '',
cartIds: [] // 选中的购物车ID
},
orderRules: {
addressId: [{ required: true, message: '请选择收货地址', trigger: 'change' }]
},
addressList: [],
cartList: [],
totalPrice: '0.00',
addAddrVisible: false
}
},
mounted() {
// 获取用户收货地址
this.getAddressList();
// 获取选中的购物车商品
this.getCartList();
},
methods: {
getAddressList() {
this.$axios.get('/api/user/address/list').then(res => {
if (res.data.success) {
this.addressList = res.data.data;
}
});
},
getCartList() {
// 从URL获取选中的购物车ID
const cartIds = this.$route.query.cartIds.split(',');
this.orderForm.cartIds = cartIds;
this.$axios.post('/api/user/cart/list', { cartIds }).then(res => {
if (res.data.success) {
this.cartList = res.data.data;
// 计算实付金额
this.calcTotalPrice();
}
});
},
calcTotalPrice() {
this.totalPrice = this.cartList.reduce((sum, item) => {
return sum + item.buyNumber * Number(item.shangpinNewMoney);
}, 0).toFixed(2);
},
submitOrder() {
this.$refs.orderRef.validate(valid => {
if (valid) {
this.$axios.post('/api/user/order/add', this.orderForm).then(res => {
if (res.data.success) {
this.$message.success('订单提交成功!');
// 跳转到订单详情页
this.$router.push(`/order/detail?orderId=${res.data.data.orderId}`);
} else {
this.$message.error(res.data.msg);
}
});
}
});
},
resetForm() {
this.$refs.orderRef.resetFields();
this.$router.go(-1);
},
showAddAddrDialog() {
this.addAddrVisible = true;
},
formatMoney(row, column) {
return `¥${row[column.prop]}`;
},
formatSubtotal(scope) {
const subtotal = scope.row.buyNumber * Number(scope.row.shangpinNewMoney);
return `¥${subtotal.toFixed(2)}`;
}
}
}
</script>
(2)页面设计要点
页面标题:用户-商品订单提交页面
(插入图片位置:此处放“订单提交页面截图”,需包含以下元素)
- 收货地址区:下拉选已存地址(默认显示“默认地址”)、“新增地址”按钮(弹窗新增,不跳转)
- 商品信息区:表格显选中商品的图片、名称、单价、数量、小计,小计和单价用“¥”标注
- 订单信息区:显实付金额(红色突出,带“¥”),无其他隐藏费用
- 按钮:“提交订单”(红色el-button--danger)和“取消”(灰色el-button)
(3)避坑提醒
- 防止重复下单!用购物车ID校验(需新增订单日志表):
if (orderService.existsByCartIds(orderForm.getCartIds())) { return Result.error("该商品已下单,请勿重复操作!"); } - 扣库存前校验!避免超库存下单:
for (Integer cartId : cartIds) { Cart cart = cartService.getById(cartId); Goods goods = goodsService.getById(cart.getGoodsId()); if (goods.getStock() < cart.getBuyNumber()) { return Result.error("商品《" + goods.getName() + "》库存不足!"); } }
3. 管理员端:商品管理模块(答辩亮点!)
这个功能最能体现“民俗网属性”,导师超爱问!核心是“商品增删改查+上下架”,别漏“商品图片预览”,不然管理员没法确认商品展示效果。
页面设计要点
页面标题:管理员-商品管理页面
(插入图片位置:此处放“商品管理页面截图”,需包含以下元素)
- 筛选条件:商品名称模糊查、商品类型下拉(全部/民俗手工艺品/特色食品)、上架状态下拉(全部/上架/下架)
- 商品列表表格:列名“商品名称、商品图片、商品类型、库存、现价、上架状态、操作”,上架状态用标签显(上架绿/下架灰)
- 操作按钮:“查看详情”“修改商品”“上下架”“删除”
- 详情弹窗:点“查看详情”弹出,含商品简介、商品图片预览(点击放大)、创建时间、点击次数
五、测试别敷衍!这3步让答辩不翻车
很多宝子觉得“功能能跑就行”,结果答辩时评委一测就出问题!我当初没测“库存不足下单”,导致用户能买超库存商品,导师说“不符合电商逻辑”,当场扣分😫 测试一定要针对性做!
1. 功能测试(必测3个模块)
别全测!重点测“核心功能”,我整理了测试用例表,直接填结果:
(1)订单提交测试(表1:订单提交测试用例)
| 测试场景 | 操作步骤 | 预期结果 | 实际结果 | 测试结论 |
|---|---|---|---|---|
| 库存不足 | 选库存5的商品→买10件→提交 | 提示“商品《XXX》库存不足!” | ||
| 未选收货地址 | 加商品到购物车→直接提交订单 | 提示“请选择收货地址!” | ||
| 正常下单 | 选库存20的商品→买2件→选地址→提交 | 提示“订单提交成功!”,生成订单号,库存剩18 |
(2)民俗新增测试(表2:民俗新增测试用例)
| 测试场景 | 输入数据 | 预期结果 | 实际结果 | 测试结论 |
|---|---|---|---|---|
| 图片格式错误 | 民俗标题:陕西皮影→图片:GIF→提交 | 提示“仅支持JPG/PNG格式图片!” | ||
| 民俗标题重复 | 民俗标题:陕西剪纸→图片:JPG→提交 | 提示“该民俗标题已存在,请勿重复添加!” | ||
| 正常新增 | 民俗标题:陕西社火→图片:JPG→详情:XXX→提交 | 提示“民俗信息新增成功!”,列表显该民俗 |
(3)管理员登录测试(表3:管理员登录测试用例)
| 测试场景 | 操作步骤 | 预期结果 | 实际结果 | 测试结论 |
|---|---|---|---|---|
| 密码错误 | 账号:admin→密码:123456(正确123)→登录 | 提示“账号或密码不正确!” | ||
| 未填账号 | 账号:空→密码:123→登录 | 提示“请输入账号!” | ||
| 正常登录 | 账号:admin→密码:123→登录 | 登录成功,跳管理员首页 |
2. 兼容性测试(容易忽略的点)
别只在自己电脑测!答辩时评委可能用不同浏览器,我当初没测IE,结果民俗列表错乱,赶紧改CSS才好:
- 浏览器测试:Chrome、Firefox、Edge、IE11(重点测IE,兼容性最差)
- 分辨率测试:1920×1080、1366×768(别让页面出现横向滚动条)
3. 测试报告要写好!答辩加分
把测试结果整理成“测试报告”,含“目的、范围、用例、结果、问题总结”,导师会觉得你“做事严谨”。比如:
- 问题总结:“IE浏览器下民俗表格错乱,用table-layout:fixed解决;未登录能访问订单提交页,加拦截器控制”
- 测试结论:“核心功能(民俗管理、订单提交、登录)均通过测试,无严重bug;兼容性问题已修复,系统可正常用”
六、答辩准备:3个加分小技巧
毕设不仅要做出来,还要说清楚!我当初准备了这3点,导师直接给“良好”:
- 演示流程要顺畅:提前录演示视频(怕系统崩),按“管理员发布民俗→管理员新增商品→用户浏览民俗→用户下单”的流程来,别跳步
- 重点讲“你解决了啥问题”:比如“一开始民俗图片存数据库加载慢,改成存路径后,速度提升70%”,比光说“我用了Spring Boot”有亮点
- 准备常见问题:导师大概率问“为啥选MySQL不选Oracle”“用户变多怎么优化”,提前答:“MySQL轻量适合中小型展示类系统;用户变多就加Redis缓存热门民俗,减数据库压力”
最后:毕设通关的小私心
以上就是基于Spring Boot的中国陕西民俗网从0到1的避坑干货!毕设没那么难,关键是找对方法,别瞎做复杂功能。
需要核心源码(带注释,直接能跑)、数据库脚本(含测试数据)、ER图模板的宝子,评论区扣“中国陕西民俗网”,我私发你;卡在某个模块(比如民俗新增、订单提交),也可以留言,我看到必回!
点赞收藏这篇,下次找流程不迷路~祝宝子们毕设顺利,轻松毕业!😘