手头刚好整理完一套在线装修管理系统的全栈源码,SpringBoot后端+Vue前端+MySQL这套组合,压缩包解压、改下配置就能跑起来,前后端联调都是通的。不少读者问我要“能直接运行、又有点技术含量”的全栈项目做毕业设计或者入职作品集,我就把整个系统的设计思路、业务模块、落地过程和踩过的坑完整拆开讲一遍,想拿去做二次开发的人也省得自己重头摸索。
这套系统解决的是装修行业最典型的线上化问题:客户登记装修需求、设计师出方案、双方面谈报价、签合同、安排施工队、盯进度、最后验收售后,这些环节以前全靠微信群和Excel来回倒,信息散得到处都是。系统把所有角色装进同一个平台,业主能看到方案和进度,设计师能接单传图,施工队能提交日志,管理员在后台统一管控,每个环节状态一目了然。它不是什么炫技项目,但业务逻辑完整、技术栈主流、代码结构常规,非常适合拿来学习SpringBoot+Vue前后端分离项目的真实写法,也适合在此基础上扩展成商业项目。
1. 项目定位与全栈设计思路
1.1 装修行业为什么需要一个在线管理系统
装修行业的项目管理链条非常长,一个订单往往要经历量房、设计、报价、签约、拆改、水电、木工、油漆、安装、验收等多个阶段,参与角色包括业主、设计师、施工队长、材料员、财务和管理员。传统方式下,信息主要靠微信群语音、Excel表格、纸质单据传递,会出现几个很现实的问题:
- 业主不知道自己的房子装到哪一步了,只能反复问项目经理。
- 设计师的方案和修改记录散落在聊天记录里,时间一长就找不到最终版本。
- 报价单、合同、增项单对不齐,结算时扯皮。
- 管理层想统计在手订单量、合同金额、施工进度,只能让文员手动汇总。
这套源码就是把这些流程系统化,每个角色有独立的工作台,数据实时写入MySQL,业务状态通过前后端接口互通。你也可以把它理解成一个简化版的家装ERP,核心不是为了堆功能,而是把装修公司最痛的管理环节跑通。
1.2 技术选型:SpringBoot、Vue、MySQL为什么是主流组合
先说后端。SpringBoot是目前Java后端开发事实上的标准,内嵌Tomcat,不用单独部署容器,自带的starter机制把配置简化到极致,符合“快速上手、稳定交付”的项目需求。SpringBoot的生态成熟度也决定了招人容易、招到了能快速上手,这对个人学习和企业落地都很重要。
前端选择Vue,最大的原因是它的学习曲线比React更平缓,模板写法接近原生HTML,配合Vue CLI或者Vite脚手架可以快速搭建工程。Vue的组件化思想和响应式数据绑定非常适合做管理后台这种大量表格、表单、状态切换的页面。而且Vue的中文社区极其活跃,遇到问题搜索一下基本都有现成答案。
MySQL就更不用说了,关系型数据库里普及率最高,安装配置简单,InnoDB引擎支持事务,对装修系统这种订单、合同、资金数据强一致性的场景非常合适。这套技术栈组合起来,就是目前市面上中小型管理系统最常见的标配。
1.3 源码目录结构一览
拿到源码压缩包后,第一件事是先看清楚目录结构。标准的前后端分离项目,通常分三个核心目录:
online-decoration-system/ ├── backend/ # SpringBoot后端工程 │ ├── src/main/java │ ├── src/main/resources │ └── pom.xml ├── frontend/ # Vue前端工程 │ ├── src │ ├── package.json │ └── vue.config.js └── sql/ └── decoration_system.sql # 数据库初始化脚本后端Java代码按分层结构组织,controller负责接收前端请求,service处理业务逻辑,mapper负责数据库操作,entity实体映射数据库表,config放配置类。前端按页面功能分目录,api目录统一封装接口请求,views目录放各个页面组件,router目录配置路由跳转。数据库脚本单独放一个文件夹,避免和后端代码混在一起。
2. 后端工程拆解与SpringBoot核心设计
2.1 包结构与分层架构设计
后端工程我采用经典的三层架构,代码分层清晰是保证项目可维护性的基础。入口启动类叫DecorationApplication,和包名放在同级目录下,这是SpringBoot扫描Bean的基本要求。
com.decoration.system ├── DecorationApplication.java ├── config/ # 配置类:跨域、拦截器、MyBatis配置 ├── controller/ # 接口控制器:暴露RESTful API ├── service/ # 业务逻辑层:处理具体业务 │ └── impl/ # 业务实现类 ├── mapper/ # MyBatis数据访问层 ├── entity/ # 数据库实体类 ├── dto/ # 前后端交互数据传输对象 ├── common/ # 通用工具、统一返回结果、异常处理 └── security/ # 登录认证与权限控制这样的分包方式有几个好处:controller层非常轻薄,只做参数接收和结果封装;service层承载核心业务逻辑,方便独立单元测试;mapper层专注SQL语句,配合MyBatis使用XML文件或者注解完成数据库操作。你新增一个功能模块时,只需要按照这个结构往里面加类就行,不会牵一发动全身。
实际开发中我建议所有接口返回统一格式。比如写一个Result 类,包含code、message、data三个字段,成功时code为200,失败时code为500或者自定义错误码。配合全局异常处理器@RestControllerAdvice,可以确保前端拿到的永远是结构一致的JSON,不需要在页面里到处处理异常分支。
2.2 数据库设计与MySQL初始化脚本
装修系统的核心业务表我设计成下面这些,覆盖从需求到售后的完整链路:
| 表名 | 说明 | 核心字段 |
|---|---|---|
| sys_user | 系统用户表 | id、username、password、real_name、phone、role、status |
| decoration_demand | 装修需求登记表 | id、user_id、house_area、house_address、budget、description、status |
| design_scheme | 设计方案表 | id、demand_id、designer_id、style、content、image_url、status |
| contract_info | 合同信息表 | id、scheme_id、customer_id、designer_id、price、sign_time、status |
| construction_task | 施工任务表 | id、contract_id、team_leader、plan_start、plan_end、progress、status |
| progress_log | 施工进度日志表 | id、task_id、content、create_time |
| material_info | 材料信息表 | id、name、spec、unit、price、stock |
设计时要注意几点:一是status状态字段统一用数值,0表示待处理,1表示进行中,2表示已完成,这样一个字段就能支撑流程流转;二是金额字段用decimal(10,2),禁止用float和double,避免精度问题;三是所有表都加上create_time和update_time,方便排查数据和做统计报表。
数据库脚本在sql目录下,直接用Navicat或者命令行导入即可。脚本里除了建表语句,我还预留了三个测试账号:管理员admin、设计师designer、业主customer,密码都做了MD5加密存储,初始密码统一是123456。这样导入数据库后就能立即登录测试。
2.3 接口设计与权限控制实现
系统接口遵循RESTful风格,按资源命名,结合HTTP方法表示操作类型。登录接口是POST /api/auth/login,需求列表是GET /api/demand/list,新增需求是POST /api/demand,更新状态是PUT /api/demand/status,删除是DELETE /api/demand/{id}。
权限这块采用了JWT的方案,登录成功后后端生成一个带有效期的token返回给前端,前端把token存到localStorage里,每次请求在Header中携带Authorization字段。后端通过拦截器统一校验token,再从token中解析出用户ID和角色,决定该请求是否有权限执行。
@Component public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (StringUtils.isBlank(token)) { throw new BusinessException(401, "未登录或登录已过期"); } Claims claims = JwtUtil.parseToken(token.replace("Bearer ", "")); request.setAttribute("userId", claims.get("userId")); request.setAttribute("role", claims.get("role")); return true; } }之所以没引入Spring Security这种重量级框架,是为了让初学者能看到权限控制的底层逻辑,也方便二次开发时自由替换。真实生产环境如果要求更细粒度的权限,可以在此基础上叠加Spring Security或者Sa-Token。
3. 前端Vue工程的核心实现
3.1 前端目录结构与路由配置
前端工程是标准的Vue脚手架结构,如果拿到的版本是Vue 2 + Vue CLI,目录一般长这样。看清楚每个目录的职责,后面改东西就不会乱翻。
src/ ├── api/ # 接口请求封装文件,按模块拆分 ├── assets/ # 静态资源:图片、全局样式 ├── components/ # 公共组件:分页、弹窗、上传等 ├── router/ # 路由配置与导航守卫 ├── store/ # Vuex状态管理 ├── views/ # 页面组件 ├── App.vue # 根组件 ├── main.js # 入口文件 └── utils/ # 工具函数:token操作、日期格式化路由配置分为两部分,一部分是公开路由,比如登录页;另一部分是受保护的路由,需要登录后才能访问。在router/index.js中给受保护路由加meta.requiresAuth标记,再配合vue-router的全局前置守卫,检查本地有没有token,没有就强制跳到登录页。
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token'); if (to.meta.requiresAuth && !token) { next({ path: '/login', query: { redirect: to.fullPath } }); } else { next(); } });3.2 axios请求封装与拦截器
前后端分离后,所有HTTP请求都要经过统一出口,这样便于处理token注入、响应错误、加载动画这些公共逻辑。我在src/utils/request.js里封装了一个axios实例。
import axios from 'axios'; const service = axios.create({ baseURL: process.env.VUE_APP_BASE_URL || '/api', timeout: 10000 }); service.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = 'Bearer ' + token; } return config; }); service.interceptors.response.use( response => { const res = response.data; if (res.code !== 200) { Message.error(res.message || '请求失败'); return Promise.reject(new Error(res.message)); } return res; }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token'); router.push('/login'); } return Promise.reject(error); } );这里有两个细节值得注意。第一,baseURL通过环境变量读,开发环境走代理,生产环境走完整域名,避免硬编码;第二,响应拦截器统一处理业务错误码,页面里调用接口时不用每个都写错误提示,代码量少很多。
3.3 核心页面:从需求登记到施工进度看板
看一个管理后台项目成熟不成熟,就看它列表页做得是否完整。需求管理页面是系统的起点,业主登录后填写房屋地址、面积、预算、装修风格偏好,提交后生成一条新的demand记录,状态变成待分配。管理员在后台能看到所有未分配的需求,指派给设计师。
设计方案页面给设计师用,客户提交需求后,设计师上传方案图片、填写设计说明和初步报价。客户登录后能看到自己的方案列表,点击查看详细内容,满意就确认,不满意可以填备注退回修改。
施工进度页面是业主最关心的模块。每项施工任务开始后,施工队长会通过小程序或电脑端提交进度日志,包括当天的施工内容、现场照片、次日计划,系统的进度条会实时更新。业主在家就能了解装修进展,不用三天两头往工地跑。
4. 本地一键运行实操记录
4.1 环境准备清单
拿到源码之后不要急着双击运行,先把环境准备齐。后端需要JDK、Maven;前端需要Node.js、npm;数据库需要MySQL服务。版本对应关系如下:
| 软件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8或11 | SpringBoot 2.x建议JDK8+,更高版本也行 |
| Maven | 3.6+ | 管理Java依赖,配置阿里云镜像加速 |
| MySQL | 5.7或8.0 | 字符集选择utf8mb4 |
| Node.js | 14.x或16.x | 版本太高可能导致node-sass安装失败 |
| npm | 随Node附带 | 使用国内镜像源加速依赖下载 |
我这次用的环境是JDK8 + Maven 3.8 + MySQL 8.0 + Node 16,整个跑下来没有任何问题。如果你用的是Node 18以上,很可能会在npm install时碰到node-sass编译报错,后面我会讲怎么解决。
4.2 初始化数据库与修改配置
打开文件夹里的sql/decoration_system.sql,用Navicat或者命令行执行脚本。推荐用命令行方式,逻辑更直观。
mysql -u root -p123456 -e "create database decoration_system default character set utf8mb4 collate utf8mb4_general_ci;" mysql -u root -p123456 decoration_system < decoration_system.sql执行完后进入MySQL确认表是否创建成功:
use decoration_system; show tables;能看到sys_user、decoration_demand这些表就说明脚本执行成功。接下来修改后端配置文件application.yml,核心修改项是数据库连接信息,把url、username、password改成自己本机的配置。
spring: datasource: url: jdbc:mysql://localhost:3306/decoration_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver注意MySQL 8.0的驱动类名必须是com.mysql.cj.jdbc.Driver,MySQL 5.7可以用com.mysql.jdbc.Driver,版本不同不要照搬,否则启动时会出现ClassNotFoundException。
4.3 启动SpringBoot后端
后端启动有两种方式,一种是在IDEA里打开backend目录,等Maven把依赖下载完直接运行DecorationApplication类;另一种是在命令行手动打包运行,这种方式更贴近生产环境操作。
cd backend mvn clean package -DskipTests java -jar target/decoration-system-1.0.0.jar看到控制台输出“Started DecorationApplication in 8.13 seconds”并且监听了8080端口,说明后端启动成功。这个时候可以先测试登录接口:
curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456"}'如果返回JSON中包含token字段,后端就完全正常了。
4.4 启动Vue前端并验证联调
前端启动之前先改一个关键配置:跨域代理。在vue.config.js中配置devServer.proxy,让前端开发服务器把/api开头的请求转发到后端8080端口,避免开发阶段出现跨域问题。
module.exports = { devServer: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };然后执行安装和启动命令:
cd frontend npm install npm run serve启动成功后浏览器访问http://localhost:3000,用种子账号登录。登录进去看到工作台主页,说明前后端联调已经通了。
5. 常见问题与排查速查表
5.1 启动阶段高频报错
我自己把源码发给几批读者试用,收集到的高频问题集中在环境版本和配置上。下面整理成速查表,遇到类似报错直接对照处理:
| 现象 | 根本原因 | 解决方案 |
|---|---|---|
| 启动报ClassNotFoundException: com.mysql.jdbc.Driver | 驱动类名写错 | MySQL8改成com.mysql.cj.jdbc.Driver |
| 数据库连接失败Access denied | 密码或用户名错误 | 核对application.yml中的账号密码 |
| 端口被占用Port 8080 was already in use | 本机其他程序占用端口 | 杀掉占用进程或修改server.port端口 |
| npm install卡住或报ERR! network | npm源访问慢 | npm config set registry https://registry.npmmirror.com |
| node-sass安装失败 | Node版本和node-sass版本不兼容 | 换Node 16,或改用dart-sass替代 |
| 前端请求从Missing Token | 未正确配置axios拦截器 | 检查request.js中是否有token注入逻辑 |
| 中文乱码 | 数据库默认字符集不对 | 建库时指定utf8mb4,JDBC连接加characterEncoding=utf8 |
5.2 联调阶段容易踩的坑
前后端联调最大的坑是跨域问题。如果前端没有用devServer.proxy而是直接请求http://localhost:8080,浏览器会拦截响应,控制台报blocked by CORS policy。解决方式有两种:前端配代理,或者后端加全局跨域配置。我在后端写了CorsConfig,用@CrossOrigin也能解决,但生产环境建议由网关或者Nginx统一处理,不要在后端无脑放开跨域。
第二个坑是token过期没有统一处理,导致用户正在填写表单时突然跳登录页。我在axios响应拦截器里做了401状态码捕获,跳转前会弹出提示,这样用户体验会好一些。
第三个坑是时间格式问题。MySQL返回的日期是java.util.Date,如果没做格式化,前端拿到的是时间戳或者“2024-01-01T00:00:00.000+08:00”这种难看的格式。我用@JsonFormat注解统一处理,前端再用dayjs格式化成实际需要的样式。
5.3 部署到服务器时的注意事项
开发环境跑通后,很多人想把项目部署到云服务器上展示,这里有几个和生产环境强相关的点。后端建议打成jar包,用systemd或者docker方式运行,不要再用java -jar前台执行,关掉终端服务就挂了。前端执行npm run build生成dist目录,然后配置Nginx做静态文件服务,同时把/api请求反向代理到后端。
server { listen 80; server_name your.domain.com; location / { root /var/www/decoration-frontend; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }部署时数据库连接地址要改成服务器的内网IP,不要用localhost,避免连接的是应用服务器自己的MySQL。生产环境中JWT密钥也要单独配置,用一个足够长的随机字符串,防止密钥泄露导致token被伪造。
6. 二次开发建议与避坑经验
6.1 后续功能扩展方向
这套源码的基础架构搭得很稳,往上加功能并不难,比较有价值的扩展方向有两个。第一个方向是加消息通知模块,业主提交需求后要通知设计师,设计师方案上传后要通知业主,施工节点变更要通知管理员,通知方式可以用WebSocket实时推送,也可以接入邮件/短信服务。第二个方向是加统计分析模块,管理层需要看到每个月签约额、各工种施工完成率、客户满意度分布这些核心指标,前端用ECharts实现图表,后端写统计查询SQL,这个功能在真正的装修公司里非常加分。
再往下扩展,可以在线预约量房、电子签章、材料库存预警、工地摄像头实时监控对接,这些方向都能让系统离实际商用更进一步。设计数据库时预留了material_info表,材料模块可以直接在此基础上扩展。
6.2 维护这套项目要注意的几个原则
接手一个现有源码,最忌讳的就是上来就改。我的习惯是先启动项目,把每个页面的功能都点一遍,画出业务流程图,搞清楚字段之间的关联关系,再动手改代码。这套系统的状态流转比较清晰,0待处理、1进行中、2已完成、3已驳回,你在改状态时需要全局搜索所有使用status的地方,避免出现只改了新增接口、没改更新接口之类的疏漏。
改代码时勤用Git做版本管理,每完成一个功能点就提交一次。最好是先熟悉基础分支拉一个dev开发分支,验证没问题再合并到主干,这样即使改坏了也能随时回滚,不耽误交付。
6.3 最后分享一个我调试接口时的习惯
前后端联调阶段,不要只靠浏览器Network面板。我习惯用Apifox或者Postman把接口先全部调试通过,再对接前端代码,这样可以快速区分问题是出在后端还是前端。调试时重点关注几个点:参数名是否和一Presistent层实体保持一致、返回的JSON字段是否和前端取值完全一致、状态码是否正确。这套项目里我把所有接口都在Apifox里建了一个集合,导出成文档直接给前端同学参考,联调效率提升特别明显。你拿到源码后也可以先把接口跑一遍,对系统的理解会透彻很多。