毕业设计实战:基于Spring Boot的中国陕西民俗网设计与实现,从需求到测试全流程拆解,新手也能轻松通关!

50 阅读16分钟

毕业设计实战:基于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 实操)

很多宝子卡在“环境配置”,跟着步骤来超简单,我当初一次成功:

  1. 装JDK 1.8:记路径(比如D:\Java\jdk1.8.0_301),配置“JAVA_HOME”别错,不然Eclipse认不到
  2. 装Eclipse(社区版):选“Eclipse IDE for Enterprise Java Developers”,自带Spring Boot插件
  3. 装MySQL 8.0:用Navicat管理(可视化工具超方便,新建表直接选字段类型,比命令行快10倍)
  4. 配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个规则:

  1. 矩形代表“实体”(比如“用户”“商品”)
  2. 椭圆代表“属性”(比如用户的“姓名”“手机号”)
  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点,导师直接给“良好”:

  1. 演示流程要顺畅:提前录演示视频(怕系统崩),按“管理员发布民俗→管理员新增商品→用户浏览民俗→用户下单”的流程来,别跳步
  2. 重点讲“你解决了啥问题”:比如“一开始民俗图片存数据库加载慢,改成存路径后,速度提升70%”,比光说“我用了Spring Boot”有亮点
  3. 准备常见问题:导师大概率问“为啥选MySQL不选Oracle”“用户变多怎么优化”,提前答:“MySQL轻量适合中小型展示类系统;用户变多就加Redis缓存热门民俗,减数据库压力”

最后:毕设通关的小私心

以上就是基于Spring Boot的中国陕西民俗网从0到1的避坑干货!毕设没那么难,关键是找对方法,别瞎做复杂功能。

需要核心源码(带注释,直接能跑)、数据库脚本(含测试数据)、ER图模板的宝子,评论区扣“中国陕西民俗网”,我私发你;卡在某个模块(比如民俗新增、订单提交),也可以留言,我看到必回!

点赞收藏这篇,下次找流程不迷路~祝宝子们毕设顺利,轻松毕业!😘