☰
SpringBoot+Vue+MySQL商铺管理系统源码剖析与本地运行指南
2026/10/13 3:42:45 网站建设 项目流程

做校园信息化项目这些年,我经手过不少类似“XX学院商铺管理系统”的实训项目。说实话,这类系统单看名字容易让人觉得“不就是增删改查嘛”,但真正上手跑一遍,你会发现里面藏着的业务逻辑、前后端联调细节、数据库设计思路,足够让一个初学者忙活好几天。这篇文章就以这个经典的 SpringBoot + Vue + MySQL 三件套组合为例,完整拆解一套商铺管理系统源码:它到底管理什么、源码该怎么看、本地怎么从零跑起来、运行中常见的坑有哪些,以及从“能运行”到“能上线”之间还差了哪几步。无论你是要拿去做课程设计、毕业设计,还是刚接触前后端分离项目想找一套完整代码练手,这篇文章都值得你花十分钟读完。

我默认你看过 Java 基础和基本的 SQL,但没怎么碰过完整项目。所以文中每一步都会解释“为什么这样做”,而不是只丢给你命令。

1. 校园商铺管理:从纸质台账到信息系统的痛点转移

1.1 这个系统服务的真实场景

先别急着打开代码,想清楚业务场景比什么都重要。一般高校的校园商业区里,少则几十家、多则上百家商铺和摊位,管理方是学校的后勤部门。过去的管理方式很原始:一份份纸质租赁合同散落在文件柜里,租金收缴记录靠 Excel,哪个合同快到期、哪个商户欠租,全凭管理员脑子记。商户换了联系方式、营业执照到期没年检,这些信息想查的时候翻半天。

这套商铺管理系统要解决的,就是把上述信息全部结构化。它面向的角色主要有两个:管理员(后勤人员)和商户。管理员负责铺位信息、合同签订、租金账单、公告发布;商户登录后基本只能查看自己的合同和缴费记录。所以系统在模块设计上,通常是这么一套:

  • 商铺管理:记录每个铺位的位置、面积、租金标准、当前状态(空闲、已出租、装修中);
  • 商户管理:维护商户名称、法人、联系电话、证照信息;
  • 合同管理:存储合同编号、关联的商铺和商户、租赁起止日期、租金金额;
  • 租金管理:按月或按季度生成缴费记录,标记已缴、待缴、逾期;
  • 公告管理:发布停水停电、临时施工、政策类通知;
  • 系统管理:用户账号、角色、菜单权限。

把这个清单和源代码里的菜单一对比,你就能很快定位每个模块对应的代码位置。

1.2 这类项目适合谁来参考

如果你正处在下面某个阶段,这套源码的参考价值会很大:

  • 准备课程设计或毕业设计,需要一个功能完整、技术栈主流的后端管理系统;
  • 刚学完 SpringBoot 和 Vue 基础,想看一个真实项目里 controller、service、mapper 是怎么分层协作的;
  • 工作需要搭建一个轻量级的内部管理后台,用这套结构当脚手架直接改造;
  • 想看明白“前后端分离”模式下接口怎么设计、跨域怎么处理、登录状态怎么保持。

当然,这里也要说清楚:这类系统本质上是“信息管理系统”,核心操作是增删改查加权限控制。它不包含复杂的支付、电商购物车、推荐算法等逻辑,但正因为业务边界清晰,反而非常适合用来建立对完整项目结构的整体认知。

2. SpringBoot + Vue + MySQL:这个技术组合为什么是校园项目的稳妥选择

2.1 三件套各自承担的角色

用一句话概括这三个组件的关系:Vue 负责用户看到和操作的页面,SpringBoot 负责处理业务逻辑和提供数据接口,MySQL 负责把数据持久化存下来。

展开来说,SpringBoot 之所以是后端首选,是因为它把 Spring 家族最繁琐的配置自动化了。以前用 SSM(Spring + SpringMVC + MyBatis)搭一个项目,要写一堆 XML 配置,光“配置文件地狱”就能劝退新人。SpringBoot 的起步依赖把常用的库打包好了,内嵌 Tomcat 让部署变成一个 java -jar 命令搞定。再加上校园课程体系普遍以 Java 为主线,SpringBoot 几乎是 Java 后端项目的默认选择。

前端方面,Vue 的学习曲线比 React 平滑,数据双向绑定让表单操作非常直观。更重要的是 Vue 生态里有 Element UI 这套现成的后台组件库,表格、表单、弹窗、分页都封装好了,开发效率极高。校园管理类系统的界面要求不高,“干净、清晰、能点能用”就达标,Element UI 刚好满足。

MySQL 更不用多说,开源免费、文档海量、主流云厂商都支持,InnoDB 引擎下事务和行锁能力足以支撑这种日常并发量不大的管理系统。

2.2 相比其他方案的取舍逻辑

有人会问:都什么年代了,为什么不用微服务、不用 Docker、不用 Redis?答案是:没必要。一个商铺管理系统的并发量,撑死了几十个人同时操作,远没到需要分布式架构的地步。微服务拆分、消息队列、缓存集群这些技术,在这里只会把简单问题复杂化,反而让新手迷失在框架里,找不到业务主线。

另一个常见对比是 JSP 老项目和前后端分离的区别。JSP 是服务端渲染,页面和后端代码耦合在一个工程里,改造和维护都比较笨重。前后端分离后,后端只输出 JSON 数据,前端负责渲染,职责清晰,也方便以后给移动端或小程序复用同一套接口。这套源码采用的就是前后端分离,这也是当前企业项目的主流形态。

我在实际带项目时见过不少同学上来就纠结“要不要加 Redis 缓存、要不要上 Docker 部署”,我的建议始终是先跑通、先理解,再考虑引入更多组件。为学习加复杂度是加法,为解决问题加复杂度才是加法——两者方向完全不同。

3. 拿到源码后的第一件事:读懂目录结构再动手

3.1 后端项目的标准分层

源码解压后,一般会看到两个根目录,比如 backend(或 server)和 frontend(或 web)。先看后端。

一个典型的 SpringBoot 后端工程,包名以 com.xxx.shop 这类形式组织,核心包结构如下:

  • controller:接收 HTTP 请求,做参数初步校验,调用 service 层,返回统一响应对象;
  • service:业务逻辑层,事务边界基本在这一层,比如“签订合同时同时更新商铺状态”这种跨表操作;
  • mapper:数据访问层,负责和 MySQL 交互,常见的是继承 MyBatis-Plus 的 BaseMapper,自带常用的增删改查方法;
  • entity(或 pojo):实体类,一张表对应一个 Java 类,字段与表结构一一对应;
  • config:配置类,比如跨域配置、MyBatis-Plus 分页插件、登录拦截器或 JWT 拦截器;
  • common(或 common/response):统一返回结果类 R,以及全局异常处理器。

拿到代码后,我建议你先打开 pom.xml 看依赖,再打开 application.yml 看配置。这两个文件能让你快速判断项目的版本信息——是 SpringBoot 2.x 还是 3.x,JDK 是 8 还是 17,数据库连接信息是什么。版本问题直接决定你本机环境该怎么装,后文会专门讲。

3.2 前端页面的模块组织

前端如果是 Vue CLI 工程,目录结构一般长这样:

  • src/api:接口调用层,每个模块一个 JS 文件,把 axios 请求封装成函数;
  • src/router:路由表,定义登录页、首页、各个管理页面的路径;
  • src/store:全局状态管理,通常存登录用户信息和 token;
  • src/views:页面组件,按模块分文件夹,比如 shop、merchant、contract、rent、system;
  • src/utils:工具函数,比如 axios 实例的封装、请求拦截器、响应拦截器;
  • vue.config.js:开发环境配置,重点是 devServer 的代理设置。

前端这块比较关键的是理解“请求是怎么发出去的”。页面里的按钮事件触发 api 目录下的函数,函数用 axios 发起 HTTP 请求到后端接口,拿到 JSON 数据后渲染到表格里。所以排查前端问题时,打开浏览器 F12 的 Network 面板,看请求有没有发出去、返回什么状态码,是最直接的思路。

3.3 核心数据表关系预览

数据库脚本里通常包含几张核心表,先理清表间关系,后面的代码就很好懂了:

  • sys_user:系统用户表,字段包括用户名、密码(一般是加密后的密文)、状态等;
  • sys_role:角色表,区分管理员和商户;
  • sys_user_role:用户和角色的关联表,多对多关系;
  • shop:商铺表,记录铺位信息;
  • merchant:商户表,记录商户主体信息;
  • contract:合同表,关联 shop_id 和 merchant_id;
  • rent_payment:租金缴费表,记录每期账单的金额和状态;
  • notice:公告表。

重点理解 shop、merchant、contract 三者之间的关系:一个商铺在不同时期可以被不同商户承租,一份合同对应一个商铺和一个商户,所以商铺和商户不直接建立外键,而是通过合同间接关联。这个设计在业务上更严谨,也避免了“一家商店只能对应一个商户”这种死板的绑定。这个关系看懂了,你再看 controller 里的新增合同接口,就会发现它内部往往要同时更新商铺状态,这就是典型的 service 层事务逻辑。

4. 本地直接运行的完整操作流:从 MySQL 建库到前端联调

4.1 环境版本对照:JDK、Node、数据库一个都不能错

项目标题里写着“可直接运行”,但“直接”是有前提的——你的本机环境必须和项目版本匹配。我根据这类项目的常见配置整理了一张版本对照表,你可以先核对自己的环境。

组件推荐版本说明
JDK1.8(8u202 以上)SpringBoot 2.x 项目最稳的版本
Maven3.6.3建议配好阿里云镜像,否则依赖下载会疯掉
MySQL5.7 或 8.0注意两个版本的驱动名不同,见下文
Node.js12.x 或 14.xVue 2 + Vue CLI 项目用太新的 Node 容易出兼容问题
IDEIDEA 或 VSCode后端用 IDEA,前端用 VSCode 即可

这里特别提醒两个“版本刺客”。第一个是 MySQL 8 的驱动类名变了:MySQL 5.x 时代用的是 com.mysql.jdbc.Driver,8.x 之后变成了 com.mysql.cj.jdbc.Driver。如果项目配置里写的是老驱动,而你本地装的是 MySQL 8,启动时就会报 ClassNotFoundException。第二个是 node-sass:很多 Vue 2 项目依赖 node-sass,它和 Node 版本强绑定,Node 版本过新大概率安装失败。遇到这种情况优先换用 Node 14,而不是盲目升级项目。

4.2 数据库初始化与配置文件修改

打开项目里的 sql 文件夹,通常会有一个 .sql 文件,名称类似 shop_db.sql。用 Navicat 或命令行执行前,先看一下文件开头:如果包含 CREATE DATABASE 语句,直接整体导入即可;如果只有建表和插入数据的语句,就要先手动建库再选择库执行。

注意:导入时如果中文注释或数据乱码,多半是文件编码和连接字符集不一致。建议建库时显式指定字符集:CREATE DATABASE shop_db DEFAULT CHARACTER SET utf8mb4;,导入前确认连接选项里选了 utf8mb4。

导入完成后,打开后端 application.yml(或 application-dev.yml),核对这几项:

spring: datasource: url: jdbc:mysql://localhost:3306/shop_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的数据库密码

url 里那串参数不是装饰品:useUnicode 和 characterEncoding 解决中文乱码,serverTimezone 解决 MySQL 8 的时区报错。经验之谈,后两者缺一不可,否则你会在启动日志里看到各种诡异的 SQL 时间错误。

4.3 后端启动步骤与验证

用 IDEA 打开 backend 目录,首次加载要等 Maven 把依赖拉完,这个过程取决于网络,可能三五分钟也可能更久。依赖下载慢的,去 settings.xml 里配阿里云镜像,这是最有效的提速方式。

依赖就绪后,找到带有 SpringBootApplication 注解的主启动类,右键运行。观察控制台日志,看到类似 “Started Application in X.XXX seconds” 的字样,说明后端启动成功。默认端口一般是 8080,浏览器直接访问 http://localhost:8080 ,如果返回一个错误页或空页面是正常的,因为后端没有页面,只有接口。你可以试着访问一个具体的接口路径来验证,比如 /api/shop/list,能返回 JSON 就说明接口通了。

4.4 前端启动与跨域联调配置

接着打开 frontend 目录,在终端执行 npm install。如果报错,优先看是不是 node-sass 相关问题,解决方案上面说过了。依赖装好后,关键一步来了:检查 vue.config.js(或 config/index.js)里的代理配置。

开发环境下的典型代理配置长这样:

module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } }

这个配置的意思是:前端开发服务器跑在 8081 端口,凡是请求路径以 /api 开头的,都转发到后端的 8080 端口。为什么需要代理?因为浏览器有同源策略,前端页面在 8081,后端接口在 8080,端口不同就是跨域。通过代理,浏览器看到的所有请求都来自 8081,跨域问题就绕开了。

配置没问题后,执行 npm run serve(具体命令看 package.json 里的 scripts),看到 “App running at” 的提示就是启动成功。浏览器访问 http://localhost:8081,此时前端页面和后端接口已经打通,输入管理员的默认账号密码就能登录系统。默认账号是什么?项目里各不相同,常见组合是 admin / 123456 或者 admin / admin123,SQL 脚本里一般都有注释说明。

4.5 运行期常见报错与处理速查

把我在实际运行这类项目时遇到的高频问题整理成了一个速查表,建议截图收藏。

现象根因处理方式
Maven 依赖一直卡住或下载失败中央仓库访问慢配置阿里云镜像仓库
启动报 ClassNotFoundException: com.mysql.jdbc.DriverMySQL 8 驱动类名变化在 pom.xml 或配置中改为 com.mysql.cj.jdbc.Driver
启动报时区异常 SQLExceptionMySQL 8 默认时区问题url 中加 serverTimezone=Asia/Shanghai
连接数据库失败:Access denied for user密码错误或权限不足核对 application.yml 中用户名密码
连接数据库失败:Can't connect to MySQL serverMySQL 服务未启动检查服务状态,确认端口 3306
后端端口被占用8080 被其他进程占用修改 server.port,或结束占用进程
前端 npm install 报 node-sass 相关错误Node 版本和 node-sass 不兼容换 Node 14,删除 node_modules 后重装
页面能打开但登录提示接口错误代理配置未生效或后端未启动检查 vue.config.js 代理,确认后端运行中
登录成功但列表数据为空数据库没有初始化数据,或接口报错被前端吞掉检查 SQL 导入结果,看 F12 网络请求返回

这些坑单个看都不难,难的是它们经常同时出现。我的建议是:严格按照“先装环境 → 再导数据 → 再启动后端 → 最后启动前端”的顺序来,每完成一步就验证一步,别一次性把前后端加数据库全部启动再排查,那样出了问题很难定位。

5. 商铺管理系统的核心业务逻辑拆解

5.1 商铺与商户的“一对多”关系设计

前文提到商铺和商户通过合同间接关联,这里展开讲一下为什么。假设一个校园商铺租给商户 A 两年,合同到期后又租给了商户 B。如果直接在 shop 表里加一个 merchant_id 字段,租约变更时就得把商铺记录里的商户字段改掉,旧的历史信息完全丢失。而通过 contract 表记录每一段租赁关系,就能保留完整的历史:这个铺位曾经租给谁、什么时间段、租金多少,一目了然。

实际编码中,实体字段大概是这种感觉:

shop: id, shop_no, name, location, area, monthly_rent, status merchant: id, merchant_name, legal_person, phone, license_no contract: id, contract_no, shop_id, merchant_id, start_date, end_date, monthly_rent, deposit

这里有个细节值得注意:合同里的 monthly_rent 是冗余存了一份的,为什么不直接取 shop 表的租金标准?因为租金可能随合同谈判浮动,或者逐年递增。合同生效期间,以后勤管理员的视角看“该收多少钱”,应该以合同约定为准,而不是商铺的挂牌价。所以每次签合同时,把谈好的最终租金写进合同记录,才是正确做法。这类“看似冗余、实为必要”的字段设计,是最容易在实际业务里踩坑的地方。

5.2 合同与租金:最容易出业务 bug 的地方

租金模块是整个系统里和钱相关的部分,逻辑必须严谨。一张租金表 rent_payment 的典型字段包括:id, contract_id, period_month(账期年月), amount, status(待缴/已缴/逾期), pay_time, operator_id。

生成账单的逻辑通常是:管理员录入合同时,系统根据合同起止日期自动按月拆分成多条租金记录;或者由管理员在“租金管理”页面手动选择合同、指定账期来生成。无论哪种方式,核心要保证一条铁律:一条合同的一个账期只能存在一条缴费记录,不能重复生成。实现上一般靠数据库唯一索引(contract_id + period_month)来兜底,而不是只靠代码逻辑判断——因为并发操作时代码判断会有漏网之鱼。

欠费和到期提醒也属于这个模块的延伸功能。到期提醒的本质就是一条 SQL:查 end_date 距离当前日期小于 30 天且状态正常的合同。很多同学一开始想不到这些“隐藏功能”,其实它们在管理场景里才是高频刚需。你可以在阅读源码时留意一下,项目里是否已经实现了类似的查询,如果没有,这正好是二次开发的切入点。

5.3 权限与公告:管理后台的基本功

既然是管理系统,权限控制就绕不开。这类项目最通用的模型是 RBAC(基于角色的访问控制):用户属于角色,角色拥有菜单权限。管理员能看系统管理菜单,商户登录后只能看到合同查询和缴费记录。前端的路由守卫会判断当前用户角色,没有权限的页面直接跳回首页;后端的拦截器或注解会校验接口权限,双重保护。

这里要提醒一点:前端隐藏入口≠安全。真正决定权限的是后端的接口校验。一个合格的商户如果直接构造请求去调用管理员的接口,后端必须能拒绝他。你可以打开项目的拦截器配置看看,如果它只处理了登录状态校验、没做角色授权校验,那说明这套源码的安全模型还有待完善——这恰恰是你可以动手改造成简历亮点的方向。

公告模块逻辑上相对独立,就是发布、编辑、下架。但它也承担着“系统内通知”的职责,比如合同到期、租金逾期时,管理员在首页看到的提醒列表,很多情况下就是通过查询公告或者其他表的统计来完成的。首页的数据统计卡片(出租率、本月应收、已收、逾期金额)看起来很唬人,本质上也就是几条聚合 SQL。

6. 直接运行不等于直接上线:安全与部署建议

6.1 默认账号密码风险

项目能跑起来只是第一步。很多同学从网上下载的源码,SQL 脚本里默认账号密码都是公开的,比如 admin/123456。如果这个系统真的用于办公环境,默认密码不换无异于把大门钥匙挂在门上。第一件事就是登录系统,在用户管理里修改管理员密码,或者直接改数据库里的密码字段。

另一个容易被忽略的点是密码的存储方式。如果项目里用的是明文存储,那必须在数据库里手动改成加密后的值。常见的做法是 MD5 加盐或 BCrypt。Spring Security 的 BCryptPasswordEncoder 是比较推荐的选择,因为它自带随机盐,同样的明文每次加密结果都不同,抗彩虹表攻击能力更强。校园项目里最常见的是 MD5 固定盐,安全性一般,但至少比明文强得多。如果源码用的是明文,建议你至少改造这一步。

6.2 配置文件中敏感信息处理

application.yml 里直接写数据库密码,在本地开发没问题,但要上线就非常危险。一旦代码仓库被分享、或者服务器配置文件被误读,数据库就等于裸奔。稳妥的做法是使用环境变量:

spring: datasource: password: ${DB_PASSWORD}

部署时在服务器上设置 DB_PASSWORD 环境变量,代码里不再出现真实密码。同理,如果项目里使用了 JWT 作为登录令牌,jwt.secret 这种密钥也绝对不能硬编码,必须从环境变量或配置中心读取。还有一点:上线时把 SpringBoot 的默认错误页面改成自定义的,避免异常堆栈直接暴露在响应里,这些细节虽然小,但都是真实项目评审时会问到的点。

6.3 前后端生产构建与部署

开发环境下 npm run serve 启动的是开发服务器,只适合调试,不适合对外提供服务。生产环境的标准做法是:

  • 后端执行 mvn clean package -DskipTests,在 target 目录生成可执行的 jar 包,然后 java -jar xxx.jar 运行;
  • 前端执行 npm run build,生成 dist 静态目录;
  • 把 dist 目录放到 Nginx 的 html 目录下,Nginx 配置里把 /api 开头的请求反向代理到后端端口。

一个最简的 Nginx 配置片段供参考:

server { listen 80; server_name your-domain; location / { root /usr/share/nginx/html; index index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; } }

这样外部用户访问 80 端口获得前端页面,请求 /api 时被转发到 SpringBoot 进程。数据库层面,生产机上要设置更复杂的密码,避免把数据库端口暴露在公网,尽量只允许应用服务器访问。定时备份用 mysqldump 做即可,命令可以写成 shell 脚本配合 crontab 定期执行,数据量不大时这是最省事的方案。

6.4 这个项目还能往哪个方向扩展

如果你打算在这套系统的基础上做二次开发,我按优先级给你几个方向:

  • 增加登录验证码和失败次数限制,这是安全评审里常见的加分项;
  • 租金账单的 Excel 导入导出,用 EasyExcel 实现,后勤人员导出每月账单做账务核销是刚需;
  • 到期提醒从“系统内公告”升级为邮件或企业微信消息推送;
  • 首页数据看板用 ECharts 画出租率趋势图和租金收入统计,视觉冲击力强,答辩效果好;
  • 给商户开放一个简单的小程序入口,查合同、看账单、在线缴费申请,这个扩展能直接把项目从“管理系统”推向“服务平台”。

这些方向不是乱加功能,而是顺着业务痛点自然生长出来的。做完任何一个,都比单纯复述“我实现了增删改查”要有说服力得多。

我在实际带项目过程中的体会是:拿到一套二手源码,跑通它只能算“会用”,真正有价值的动作是拆开它——把数据表关系画出来、把登录鉴权的链路走一遍、把合同和租金的字段设计琢磨透。这套商铺管理系统就是很好的教材,难度适中,业务真实,技术栈主流。你花一个周末把它彻底吃透,收获的绝对不只是一个能运行的项目,而是一整套“拿到新项目如何快速上手”的方法论。最后再送一个小技巧:复制任何项目前,先读 SQL 脚本里的注释和数据,那是作者留给你的最容易读到的业务说明书。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询