SpringBoot+Vue移动台账管理系统:从业务设计到全栈落地
做台账管理系统已经是两三年前的活儿了但这类项目到今天依然很典型——尤其是用 “SpringBoot Vue” 这套组合来做。前阵子整理硬盘翻出一套完整的“基于SpringBootVue的移动台账管理系统”的交付材料源码 文档 PPT恰好有人问起这种全栈项目该怎么准备索性把思路和实操梳理成一篇供准备毕设、团队内部练手或者想快速搭一套台账系统的人参考。台账这东西干过企业信息化的人都不陌生。资产管理、耗材领用、设备巡检、车辆使用、公文交接……但凡跟“记录”沾边的基本都能叫台账。早年大家用 Excel 管理一人一版传来传去改没改过都说不清领导想看一眼某个部门的汇总得等下班前的“数据接龙”。移动台账管理系统要解决的就是让这些记录数据能随时随地录入、查询、审批和统计而不是被锁在一台办公电脑的 Excel 表格里。我从头到尾拆一拆做这类项目的关键思路和落地细节。1. 项目整体设计与思路拆解1.1 选型逻辑为什么偏偏是 SpringBoot Vue先聊选型。这套系统的后端用 SpringBoot前端用 Vue几乎成了近些年中小型管理系统的事实标准组合。SpringBoot 选它的理由不用多讲内置 Tomcat不需要额外配置容器起步依赖一把梭一个mvn spring-boot:run就能跑起来。相比早期 Spring MVC 那套 XML 配置满天飞的时代SpringBoot 把开发成本降了一个量级。对于台账这类以 CRUD 为核心、附带审批和统计的业务系统它的稳定性、生态和招聘市场认知度都是最优解。用微服务杀鸡用牛刀运维成本反而会成为压垮小项目的最后一根稻草。Vue 这边的理由也类似。它对比 React 更“温和”模板语法接近 HTML学习曲线缓对于前端经验不那么深的开发者很友好。选 Vue 3 Vite Element Plus 而不是 Vue 2 Element UI原因很直白新项目不要再碰旧技术栈。Vite 冷启动秒开Element Plus 组件库对表单、表格、弹窗、分页这些后台管理场景覆盖完整几乎不需要自己造轮子。唯一要留个心眼的是Element Plus 的表格在移动端宽度不够时体验一般这个问题会留到移动端适配那部分细说。注意如果在校生做课程设计或毕设选这套技术栈还有一个隐藏优势——资料多、找参考容易。SpringBoot Vue 的文档、社区答案、现成脚手架一抓一大把遇到问题基本都能搜到解法不至于卡死在冷门技术上。1.2 台账系统区别于普通 CRUD 的地方在哪里很多人把台账系统做成一个“增删改查全家桶”技术上说没错但这恰恰是项目做得“平”的原因。台账系统的核心不在 CRUD而在这三点第一台账类型多变。不同的业务场景台账字段完全不一样。设备台账要型号、购置日期、保修期车辆台账要车牌、驾驶人、里程数物资台账要分类、库存量、供应商。如果为每类台账建一张表系统会变成表和业务的堆砌。合理的做法是“模板化”让管理员能自己创建台账类型定义字段名、字段类型用户录入时动态渲染表单。第二数据录入必须移动优先。维护台账的人往往不在电脑前。库管员在仓库里巡检员在设备旁外勤在客户现场。他们在现场掏出手机拍个照、填几个字段、提交一条台账记录这才是“移动台账”四个字的真正意义。这意味着前端要主动适配窄屏表单要精简关键按钮要大能拍照就别让用户传文件。第三数据有审核链路。台账不是日记本改错了要能追溯。很多业务场景下新增或修改一条记录需要经过复核、审批最后入库归档。所以系统要设计审批流的状态机待提交、审批中、已通过、已驳回。加上操作日志后一条记录的整个生命周期都是透明可溯的。想清楚这三点系统的价值就立住了。别上来就闷头写代码这三点是后面所有设计决策的“纲”。1.3 模块拆分先定边界再谈实现根据上面的思路系统可以拆成这些模块登录认证模块账号密码登录、验证码、Token 签发与鉴权用户与权限模块用户管理、角色管理、菜单权限分配台账模板管理台账类型定义、字段定义、模板启用/停用台账数据管理记录新增、编辑、删除、查询、批量导入导出审批流模块提交审批、审批通过/驳回、审批历史数据统计模块按台账类型、时间、部门维度统计系统管理模块操作日志、登录日志、数据字典每个模块的业务边界清晰再做页面和接口设计会顺很多。模块拆分的另一个好处是文档和 PPT 好写——每一章对应一个模块讲评审的人看起来不费劲你自己答辩也有条理。2. 数据库设计与核心接口实现2.1 表结构怎么设计才不返工数据库设计是这种项目最容易返工的地方。下面这套是经过验证、能在模板化台账场景下稳定跑的表结构表名和字段名做了通用化处理照着建就行。用户表、角色表、菜单权限表这些标准 RBAC 表的建法网上很多不展开。重点看台账领域这几张表第一张是台账模板表。字段包括id、template_code如 asset_device、template_name、status、create_time等。模板表本身不存字段定义字段定义单独存成一段 JSON 字符串放在模板表里或者放一张字段表。建议用 JSON 字段存储格式模仿如下[ {field: equipName, label: 设备名称, type: input, required: true}, {field: purchaseDate, label: 购置日期, type: date, required: true}, {field: amount, label: 购置金额, type: number}, {field: remark, label: 备注, type: textarea} ]这样做的好处是字段定义与数据存储解耦。新加一种台账只需在配置界面点几下不用改代码、改表。坏处是查询时没法用原生 SQL 在 JSON 字段里做复杂条件过滤但台账场景的查询大多可以用数据库的 JSON 查询函数解决完全够用。第二张是台账数据表。主表叫台账记录表字段包括id、template_id、record_code记录编号可用日期 序列号生成、title摘要、content_dataJSON存具体字段值、status0 草稿 / 1 审批中 / 2 已通过 / 3 已驳回、create_user、create_time、approve_user、approve_time、approve_remark。再配一张台账附件表存图片、文件路径用record_id关联。第三张是审批记录表。字段包括id、record_id、approve_user、approve_action通过/驳回、approve_remark、create_time。把所有审批历史留痕后续追溯和审计都靠它。注意content_data用 JSON 类型还是text类型MySQL 5.7 有原生 JSON 类型支持索引和部分查询函数建议用 JSON。如果担心兼容性用text也能跑只是查询时没法利用 JSON 函数。2.2 后端分层与关键实现后端采用经典三层Controller 负责接收参数和返回结果Service 写业务逻辑Mapper用 MyBatis-Plus处理数据访问。这套分层虽然朴素但足够清晰项目结构也符合多数人的阅读习惯。几个关键实现值得单独说统一返回结果类。不要每个接口返回裸对象定义一个ResultT包装。前端可以统一判断code省去一堆重复的容错代码。参考代码如下public class ResultT { private Integer code; private String message; private T data; public static T ResultT ok(T data) { ResultT r new Result(); r.code 200; r.message success; r.data data; return r; } public static T ResultT fail(Integer code, String message) { ResultT r new Result(); r.code code; r.message message; return r; } }全局异常处理。用RestControllerAdvice拦截业务异常、参数校验异常、未知异常封装成统一格式返回。这一步能避免“前端收到一个 500 的 HTML 页面”这种糟心情况。业务异常建议自定义一个BizException带错误码和错误信息Service 层直接抛出由全局处理器统一兜底。JWT 鉴权。登录成功后发一个 token前端存到 localStorage每次请求带在Authorization头里。后端写一个拦截器HandlerInterceptor或过滤器校验 token 并解析出用户信息。启动时用拦截器排除白名单登录接口、验证码接口、静态资源。密码存储一定用 BCrypt。不要用 MD5——MD5 撞库太快了随便一个彩虹表都能破。如果不引入 Spring Security也能单独用 hutool 的BCrypt工具类做加密和校验。分页查询。MyBatis-Plus 的Page对象配合分页插件几行代码搞定。注意分页插件必须在配置类里注册否则分页不生效这个坑我踩过。2.3 审批状态机的流转逻辑审批模块的代码其实没什么高深的核心就是状态机。用一个integer字段存状态配合下面的状态流转状态值含义可执行操作0草稿创建人可编辑、删除、提交审批1审批中审批人可通过/驳回创建人可撤回2已通过数据正式生效不可修改3已驳回创建人可修改后重新提交实现上就用 if 判断当前状态和用户角色决定是否允许某种操作。更规范一点的可以引入状态机框架但小项目没必要反而显得过度设计。审批通过后的“生效”动作其实就是把记录状态改为 2不需要真的复制一份数据台账场景没有“快照”需求别想复杂。2.4 开放接口的权限校验这部分容易被忽略但非常关键。后端接口必须做权限校验不能只靠前端路由守卫。前端隐藏菜单只是体验优化后端要用拦截器按角色判断接口权限。否则懂技术的人绕过前端直接调接口就能越权操作。实现方式不复杂写一个权限注解RequirePermission(ledger:record:approve)用 Spring AOP 或拦截器校验当前用户是否拥有对应权限码。权限码定义成常量配置在角色与菜单的关联表里。这样每个接口的权限声明是显式的不会出现“谁能调谁不能调全靠猜”的情况。3. 前端与移动端适配实现3.1 前端技术栈与工程结构前端技术栈建议 Vue3 Vite Element Plus Pinia Axios。工程结构上src下按模块分目录api接口封装、router路由、storePinia 状态、layout整体布局、views页面、components通用组件。页面主要分为登录页、首页仪表盘、台账列表页、台账详情/编辑页、审批页、个人中心。路由配置需要配合登录态和权限做导航守卫未登录跳/login无权限跳 403。Pinia 存用户信息和登录状态刷新后重新拉取接口恢复会话。3.2 移动端适配的几个关键原则移动端适配是最容易糊弄但也最能拉开差距的部分。原则一布局用响应式栅格尽量不要单独写一套“移动端页面”。Element Plus 的el-col宽度可以跟随屏幕宽度变化小屏时侧边栏自动隐藏导航切换成底部 Tab 或汉堡菜单。原则二表格在手机上不好用。宽表会横向溢出用户得左右滑动体验极差。更好的做法是列表页在移动端用卡片布局一张卡片显示一条记录的标题、关键字段、状态标签、操作按钮。实现方式不复杂用 CSS 媒体查询或监听窗口宽度在小于某个断点比如 768px时切换渲染模式。桌面端显示表格移动端渲染卡片列表用v-if切换两套模板结构。卡片布局的细节要注意卡片内只展示最重要的 2~3 个字段其余信息放详情页不要试图在大一屏里堆满所有内容。操作按钮做成图标加文字的样式触控面积至少 44px × 44px这是移动端交互的基础要求。原则三表单控件做“移动化”。日期选择器在手机上有原生 picker用el-date-picker的时候可以加参数让它调起系统原生控件。图片上传用input[typefile]的captureenvironment属性可以在手机上调起后置摄像头直接拍照。这些细节小程序和 App 司空见惯但 Web 项目经常被忽略做了就是加分项。原则四真机调试。开发时用电脑 Chrome 的移动模拟器只能看布局真机上还要关注触摸反馈、字体大小、安全区域iPhone 底部小黑条。最简单的办法是让电脑和手机连同一个局域网把 SpringBoot 的端口默认 8080和 Vite默认 5173都改为监听0.0.0.0然后用手机浏览器访问电脑的局域网 IP。注意 Windows 防火墙要放行这两个端口否则手机死活连不上。3.3 图片上传与附件管理的细节台账记录经常要带现场照片比如设备铭牌、车辆剐蹭、物资到货验收。图片上传的路径规划要提前想好按日期分目录存储文件名为时间戳加随机串避免重名覆盖。保存路径不要用绝对路径配置一个upload.dir属性开发环境指向本地目录生产环境指向服务器挂载目录。文件访问要写成静态资源映射或者单独做一个“下载文件”接口接口里做权限校验。不要直接把文件目录暴露成静态资源否则未登录的人也能猜到 URL 下载全部附件。图片压缩也建议做一下手机拍照一张 3MB 起步不压缩的话列表页加载会卡成 PPT。4. 从零跑通这套项目的实操记录4.1 环境准备版本踩坑点提前说我用这套环境跑过 N 遍最省心的组合如下JDK 1.8别用 17除非代码里明确兼容SpringBoot 2.7.x 对 JDK 8 最稳Maven 3.6 或 3.8Node.js 18Vite 5 需要 18直接上 Node 20 也行MySQL 5.7 / 8.0MySQL 8 注意驱动要配com.mysql.cj.jdbc.DriverRedis 可以不用。台账系统用 JWT 的话不需要 session 共享没必要引入 Redis 增加部署复杂度4.2 导入与启动五步走第一步创建数据库并导入。源码里一般有db.sql直接用 Navicat 或命令行执行。导入时如果报错优先检查字符集sql 文件用 UTF-8库字符集设置 utf8mb4。第二步改配置。后端application.yml里配数据库用户名密码。如果改了端口号记得前端的代理配置也要同步。Vite 开发服务器的代理配置在vite.config.js的server.proxy里后端接口前缀/api转发到http://localhost:8080。第三步启动后端。IDE 里直接跑main方法即可。启动过程中最常报的是端口被占用用netstat -ano查一下把占用端口的进程结束或者改后端端口。第四步启动前端。npm install装依赖npm run dev跑开发服务器。npm install如果报错八成是 Node 版本太老或 registry 源的问题换镜像源能解决一半问题。第五步访问。浏览器打开http://localhost:5173管理员账号输入默认密码。如果打开白屏先看 Console 有无 JS 报错接口全部 404检查代理配置和后端是否真的启动。4.3 跑通核心业务闭环建议拿到源码后不要急着改代码先把一个完整的业务闭环跑通这样对系统的数据流向会非常清晰。用管理员账号登录进入台账模板管理创建一个“设备台账”模板字段定义为设备名称input、购置日期date、金额number、备注textarea。保存后模板状态改为启用。注册一个普通用户角色用这个用户登录。在台账数据管理页面选择“设备台账”新增一条记录填写设备名称、购置日期、金额保存。此时这条记录状态为 0草稿。点“提交审批”。切回管理员账号可以在另一个浏览器窗口登录避免被强制下线进入审批列表看到这条待审批记录。点“通过”填写审批意见。回到台账记录列表发现记录状态变为 2已通过。到这一步核心业务闭环已经走通对系统各模块的职责和相互依赖就有了直观理解。之后再去看代码带着问题看比盲目翻仓库有效率得多。5. 文档和 PPT怎么组织才是加分项5.1 文档结构项目文档不是说明书很多人把文档写成“复制粘贴代码说明书”——每个类都贴一段代码然后写“本类实现了 XXXX”。评委和导师翻两页就失去耐心。真正加分的文档结构是这样第一章绪论。写行业背景和管理痛点。重点突出“为什么需要移动台账系统”至少交代两个真实场景库管员仓库现场记录、审批人移动端审批。然后写国内外现状不用写得很外交辞令能说出“Excel 管理无法多人协作、无法移动填报、无法留痕”这三条就比空话强。第二章需求分析。功能需求用用例图 用例表呈现非功能需求别漏了性能、安全、易用性。台账场景性能不用吹太高支撑 500 并发足够安全要写密码加密、操作日志、权限控制。第三章系统设计。放三张图系统架构图前后端分离架构、功能模块图、数据库 E-R 图。这三张图是文档里最值钱的东西一定要画清楚。架构图别画成“浏览器—SpringBoot—MySQL”这种三框流水账应该包含前端、后端、拦截器、统一异常、数据库尽量细化。第四章系统实现。这里不要贴大段代码精选核心代码片段配流程图说明思路。比如审批状态机的几个状态转移、JWT 拦截器的执行流程每段代码 10~20 行足够后面加两句话说明“为什么这样实现”。第五章系统测试。写功能测试用例表覆盖登录、模板配置、记录增删改查、审批流、权限拦截这几个核心模块。加上简单的性能测试并发 50 下发登录接口看响应时间就比光写“测试全部通过”有说服力。5.2 PPT答辩演示时要讲“故事”而不是“目录”PPT 控制在 10 页左右结构和文档对应但每页只说一个重点第 1 页系统名称 一句话定位“面向现场作业的移动台账管理平台”。第 2 页背景与痛点。用“旧方式 vs 新方式”的对比讲不要念大段文字。第 3 页系统功能总览一张功能架构图。第 4 页技术架构一张图说明前后端、数据库、鉴权方式。第 5 页核心业务流程时序图——从提交到审批入库。第 6 页系统截图 2~3 张选移动端界面截图最加分。第 7 页核心代码片段 1~2 段讲“难点怎么解决的”。第 8 页测试结果摘要。第 9 页总结与展望。第 10 页QA。答辩演示的核心就一句话演示时先讲业务痛点和系统价值再讲技术实现最后做 Demo。千万别一上来就打开 IDEA 刷代码评审最关心的不是你的代码写了几百行而是你的系统解决了什么问题。5.3 源码交付README 写清楚三件事源码交付不要只丢一个仓库地址README 至少写三块内容环境要求版本列表JDK/Node/MySQL、启动步骤创建库、改配置、启动后端、启动前端、默认账号和权限说明。我见过太多人源码拿到手第一步就卡在数据库起不来写得越详细后续质疑“这个项目是不是跑不起来”的声音就越少。6. 常见问题与排查技巧实录6.1 启动与部署期高频问题问题现象排查顺序处理办法前端npm install一直报错换源、删 node_modules、看 Node 版本用镜像源删除依赖目录重装后端报数据库连接失败MySQL 服务状态、账号密码、驱动版本检查 MySQL 是否启动确认 URL 和驱动类名加时区参数前端访问接口跨域报错Vite proxy、后端 CORS、代理是否生效开发环境用 Vite 代理生产环境用 Nginx 反代打好的 jar 包运行后静态资源 404前端未打包进后端将前端dist目录复制到后端resources/static或单独部署前端6.2 业务逻辑与权限的经典坑Q普通用户能访问管理员接口怎么办A后端接口必须做权限校验不能只靠前端路由守卫。前端隐藏菜单只是体验后端要用拦截器按角色判断接口权限否则懂技术的人绕过前端直接调接口就捅破天了。Q审批通过的记录还能编辑怎么办A这是状态机没做好。后端修改接口里必须判断 status只有 status 为 0草稿或 3已驳回的记录允许编辑status 为 1审批中和 2已通过应拒绝修改。否则审批流程就是摆设。Q操作日志记不全A可以在 Service 层统一记录用一个自定义注解标记需要记录日志的方法AOP 切面自动捕获用户、时间、操作类型、参数快照。不要在 Controller 里逐段手写日志代码改一处漏一处。6.3 移动端体验的几个真实经验第一次在 iPhone Safari 上打开页面时输入框点击会被放大影响体验。解决方案是在 HTML head 里加 viewport metawidthdevice-width, initial-scale1.0。还有就是移动端点击事件有 300ms 延迟现代浏览器一般自动消除但加一句touch-action: manipulation的 CSS 更保险。真机调试时如果手机访问不到电脑90% 的原因不是代码问题而是防火墙或网段隔离。公司或学校的 WiFi 经常做设备隔离两个设备看似连同一个 WiFi实际不通。这时候最简单的办法是手机开热点电脑连手机热点再访问。7. 这套项目还能怎么扩展如果做完基础功能还想往上走几个扩展方向供参考一是接入工作流引擎。当审批链路变成多级普通员工 → 主管 → 经理手写状态机就开始吃力了可以引入流程引擎。不过对多数毕设和内部小系统单级审批完全够用别过度设计。二是增加导入导出能力。台账场景里 Excel 导入导出是刚需导入用 POI 解析导出用模板下载 数据填充。这个功能在工作汇报里非常显眼因为它是“减轻用户工作量”的最好证明。三是做数据可视化大屏。把台账记录按时间、部门、状态汇总成 ECharts 图表投屏到办公室的电视上能一下子让系统从“demo”变成“能汇报的系统”。实现不难前端加两个图表组件后端加几个统计接口。四是考虑轻量离线能力。移动网络不稳定的场景可以研究一下在本地暂存记录、网络恢复后自动同步的方案。这个方向工作量比较大但做好了能称得上“创新点”。我个人在实际操作中的体会是这类全栈项目最难的不是某个技术点而是把“台账管理”这四个字的业务逻辑想透。技术栈大家都在用能让你的系统区别于别人作品的往往是你对业务流程的理解深度、对移动端体验的重视、以及文档里能不能讲清楚“为什么这样设计”。把这三点做扎实源码 文档 PPT 就是一个真正拿得出手的完整作品。最后再分享一个小技巧跑完项目后用手机流量访问一次自己的系统模拟一个最普通的现场用户——不会 F12、不懂接口、只看页面好不好用。如果手机上的体验能让你自己满意这个项目就离优秀不远了。