简介:这是一套面向Java与前端全栈初学者及中级开发者的线上办公系统实战源码,基于Spring Boot与Vue.js构建,适用于远程协作、日常事务管理等企业级应用场景。资源共273个文件,涵盖63个Java后端业务与配置类、9个Vue组件文件、23个JSON配置与接口定义、19个XML配置及14个JS前端逻辑脚本,辅以Element UI风格的less样式与png界面素材,整体包体积仅1.55MB,结构紧凑、开箱即学。已有455人下载学习,适合通过真实项目掌握前后端分离开发范式。源码包含完整权限控制(OAuthFilter、ShiroConfig)、健康打卡模块(CheckinServiceImpl)、XSS防护(XssHttpServletRequestWrapper)、RESTful接口设计及JWT鉴权实践,目录层次清晰,关键模块如用户服务(UserServiceImpl)、安全过滤与路由配置均具代表性,是理解企业级办公系统架构落地的优质参考样本。 相信不少朋友和我一样,看到“基于springboot+vue开发的线上办公系统源码.zip”这个资源,第一反应是先下载,解压,然后对着一堆pom.xml、package.json和数据库脚本发呆。这个压缩包听起来简单,但里面其实藏着一套完整的前后端分离项目:Spring Boot 提供后端接口,Vue 负责前端交互,还带着数据库初始化和一系列业务模块。今天我不做单纯的代码解读,而是把它当成一个真实交付的项目,一步步拆解从设计到部署的完整链路,顺带把那些下载后解压失败、启动报错、版本炸了的坑一次说清。
如果你手里正拿着这个 zip,或者自己也想从零搭一套线上办公系统,那这篇文章可以当作一份“保姆级实操手册”。无论是拿来学习、二次开发,还是作为公司内部OA的雏形,都能少走很多弯路。
1. 项目整体设计与技术选型思路
1.1 线上办公系统的核心需求拆解
线上办公系统,说白了就是把线下那套“申请-审批-通知-归档”流程搬到线上。最常见的模块包括:员工考勤打卡、请假/加班/出差审批、报销流程、任务分派、工作汇报、公告通知、会议管理、通讯录、文件管理等。不同业务形态的OA需求不一样,但底层逻辑高度相似,都是“角色 + 流程 + 数据流转”。
源码里如果只做登录和用户管理,那只是壳子。真正能落地的线上办公系统,至少要能回答这几个问题:谁能看什么数据?一个流程从发起到结束要经历哪些节点?超时了怎么催办?历史数据如何追溯和统计?所以在看源码时,不要只盯着页面有多炫,先看它的权限模型和流程设计有没有闭环,这才是系统的灵魂。
1.2 为什么是 Spring Boot + Vue 前后端分离
这套组合在最近几年的中小型项目中几乎是标配。Spring Boot 的好处是开箱即用,内嵌 Tomcat,不用单独配应用服务器,Maven 管理依赖,极大降低了 Java 后端的上手门槛。Vue 则是目前国内前端生态最友好的框架之一,组件化开发、虚拟 DOM、响应式数据,配合 Element UI 或 Ant Design Vue,做后台管理界面效率很高。
更重要的是,前后端分离以后,后端只需要输出 JSON 接口,不需要关心页面渲染;前端通过 axios 请求接口,自己控制路由和状态。这样团队分工清晰,后端可以专心做业务逻辑和数据库设计,前端可以专心做交互体验。就算以后要出小程序端、App 端,后端接口直接复用,不用再动业务代码。
还有一个容易被忽略的理由:部署灵活。前端可以扔到 Nginx,后端打成 jar 包独立运行,支持横向扩容。相比传统的 JSP 单体应用,分离架构在维护、升级、排障上的优势太明显了。
1.3 源码包的内容结构分析
拿到 zip 后,先不要急着双击运行,先用压缩工具解压出来。解压后你会发现典型的 Maven 多模块或单模块结构。一般会包含这几个目录:
online-office/ ├── backend/ # Spring Boot 后端工程 │ ├── src/main/java │ ├── src/main/resources │ ├── pom.xml │ └── sql/ # 数据库初始化脚本 ├── frontend/ # Vue 前端工程 │ ├── src/ │ │ ├── api/ # 接口封装 │ │ ├── router/ # 路由 │ │ ├── store/ # 全局状态 │ │ ├── views/ # 页面 │ │ └── components/ # 公共组件 │ ├── package.json │ └── vue.config.js └── README.md # 项目说明这个结构非常标准。后端负责提供接口,前端负责页面展示,SQL 文件夹里是建库建表的脚本。看一个项目是否专业,先看它的包名和目录划分。如果后端一个 Controller 里塞了几千行,前端所有请求都写在 App.vue 里,那大概率是培训机构的练习项目,不是能商用的东西。
2. 后端核心实现与配置要点
2.1 Spring Boot 基础配置与多环境隔离
真实的线上办公系统,配置绝对不能写死。开发、测试、生产环境的数据库、Redis、日志级别都可能不同。正规做法是拆成三个配置文件:
# application.yml 主配置 spring: profiles: active: dev --- # application-dev.yml server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/office_dev?useUnicode=true&characterEncoding=utf8 username: root password: root --- # application-prod.yml server: port: 8080 spring: datasource: url: jdbc:mysql://192.168.1.100:3306/office_prod username: office_user password: 强密码启动时通过--spring.profiles.active=prod指定环境。这样就不会出现本地调好的密码被带到生产环境这种低级事故。很多新手直接把数据库密码写在主配置文件里,结果代码一不小心泄露到公网仓库,整个数据库裸奔。
另外一定要配置连接池参数。HikariCP 作为默认连接池,建议配好 maximum-pool-size 和 minimum-idle。想象一下,公司一百号人同时点开审批列表,如果连接池默认只有 10 个连接,瞬间就会把数据库拖垮。合理的初始值可以设为 10,最大 30,具体看业务压力。
2.2 权限认证与接口安全设计
线上办公系统里最敏感的就是数据权限。一个普通员工不应该看到全公司的薪资数据,部门主管只能看自己部门的人,管理员才能做全局操作。源码里如果直接用一个拦截器判断登录状态,远远不够。
这里推荐用 Spring Security + JWT 的组合。登录成功后签发 token,前端每次请求带上Authorization: Bearer <token>,后端通过过滤器校验 token 合法性。再加上 RBAC 权限模型,用户对应角色,角色对应菜单和操作权限。
数据库里一般会设计这几张表:
- sys_user:用户表
- sys_role:角色表
- sys_menu:菜单/权限表
- sys_user_role:用户角色关联表
- sys_role_menu:角色权限关联表
请求进来以后,先通过 token 识别用户,再根据用户的角色集合去查 menu 表中的权限标识,比如attendance:apply、approval:audit,决定该接口是否能访问。
注意:前端隐藏按钮只是优化体验,真正的权限校验必须放在后端接口上。否则别人直接伪造一个 POST 请求,就能绕过去执行越权操作。
还有两个容易被忽视的安全点:防 XSS 攻击和防 SQL 注入。Spring Boot 中可以通过全局过滤器对请求参数做 HTML 标签过滤,MyBatis 应用 #{} 占位符而不是字符串拼接。一些老项目把用户输入直接拼进 SQL,导致通过请求参数清空用户表的案例比比皆是。
2.3 审批流与考勤计算的关键实践
审批流程是办公系统里最容易翻车的部分。一个请假单,可能要走“员工提交 -> 直属主管审批 -> 部门经理审批 -> 人事备案”四个节点。源码里如果只用一张表加一个 status 字段,那只能做单级审批,多级审批会非常痛苦。
更合理的做法是拆成两张表:审批主表(记录申请单类型、申请人、当前节点)和审批记录表(记录每个节点的审批人、审批时间、意见、结果)。同时用 process_instance_id 串起整个流程。这样既能看到单子的实时状态,也能回溯历史审批链路。
考勤模块同理,别把所有打卡记录糊在一张表里。建议拆成考勤记录表和考勤汇总表。每日通过定时任务,把打卡记录计算成“正常、迟到、早退、缺卡、请假”,再按月汇总。计算规则最好用策略模式配置,因为不同公司的上下班时间、弹性规则千差万别。
生活化类比:这就像快递物流。你只关心包裹现在是“运输中”还是“已签收”,但物流系统必须记录每个转运中心的到发时间,出了纠纷才知道是哪个环节丢了。审批流也是这样,没有历史记录的单子,等于没有证据链。
3. Vue 前端实战与联调
3.1 项目初始化与核心目录解析
前端工程如果基于 Vue CLI 或 Vite 创建,目录结构相对固定。重点看src目录下的几个文件夹:
api:所有接口请求放在这里,按业务模块拆分文件,一次封装全局复用。router:路由配置。注意要用路由守卫判断用户是否登录、是否拥有权限。store:全局状态管理,比如用户信息、菜单权限、待办数量。views:页面组件。components:公共组件,比如上传组件、富文本、流程时间轴。
很多新手把所有请求写在页面上,A 页面调接口用 axios,B 页面又自己写一遍,导致接口地址改起来想哭。正确做法是统一封装 request 工具,比如:
import axios from 'axios' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_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 => response.data, error => { if (error.response && error.response.status === 401) { router.push('/login') } return Promise.reject(error) } )这样所有接口统一走这个实例,登录失效自动跳转,错误提示统一处理,省心很多。
3.2 核心页面设计思路
登录页没什么好说的,重点是登录后的工作台。工作台要把用户最关心的数据聚合起来:待办审批数、本月考勤状态、未读公告、我的日程。这些都是真实场景里使用频率最高的内容,不要做得花里胡哨,信息准确、层级清晰才是第一位。
审批页面前端要做三件事:发起申请、展示审批列表、处理审批。发起申请的关键是动态表单,不同类型的单子字段不同。比如请假单要选开始时间、结束时间、请假类型、事由;报销单要填金额、明细、发票附件。可以用 JSON schema 动态渲染表单,后端存一份表单配置表,前端根据配置生成控件,这样加新的审批类型不用重新发版。
列表页要考虑大数据量下的性能。如果直接一次性把全公司的审批单全部渲染出来,浏览器会卡死。前端分页 + 后端分页配合,每次只加载一页数据,接口参数传入 pageNum 和 pageSize,返回结果带上 total。如果数据量真的特别大,还可以考虑虚拟滚动或懒加载。
3.3 与后端联调时最容易踩的坑
前后端联调,第一大坑就是跨域。开发环境下前端口是 8081,后端口是 8080,浏览器默认禁止跨域请求。解决方式有两种:后端加 CORS 配置,前端用代理。
开发环境推荐前端代理,在vue.config.js里配置:
module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }这样前端请求/api/login就会被代理到http://localhost:8080/login,避免跨域。生产环境则用 Nginx 将/api反向代理到后端服务,同理。
第二个坑是接口返回的数据结构不统一。后端有时返回{ code: 200, data: {...} },有时又直接返回字符串,前端就得很痛苦地到处兼容。建议团队约定统一返回体:code表示业务状态码,message表示提示信息,data表示业务数据。前后端先把这个约定好,开发效率能提升一半。
4. 数据库设计与核心表结构
4.1 用户体系与组织架构设计
线上办公系统的数据模型,核心是用户和部门。用户表通常包含账号、密码(加密存储)、姓名、手机号、邮箱、部门 ID、岗位、入职日期等。不要把年龄、身份证号这种敏感信息全都塞进去,除非业务真有需求。
部门表采用 parent_id 支持树形结构,比如总部下面有技术部、产品部、市场部。这样既能往深层扩展,又能在查询时使用递归或公共表表达式(MySQL 8.0 支持WITH RECURSIVE)快速拉取某部门及其所有子部门。
用户表被去掉复杂字段后,可以这样设计:
CREATE TABLE sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50) NOT NULL, dept_id BIGINT, email VARCHAR(100), phone VARCHAR(20), status TINYINT DEFAULT 1 COMMENT '1正常 0禁用', create_time DATETIME DEFAULT CURRENT_TIMESTAMP );这里有个容易忽略的点:密码字段长度至少 64。因为目前普遍使用 BCrypt 加密,生成的哈希串长度在 60 位左右,如果字段只设了 32 位,一保存就报错。这是一个很典型的实战坑。
4.2 审批业务表设计要点
审批模块我前面提了主表和记录表,这里把字段展开。审批主表:
CREATE TABLE approval_instance ( id BIGINT AUTO_INCREMENT PRIMARY KEY, instance_no VARCHAR(32) NOT NULL COMMENT '单号,如SP20250608001', type TINYINT NOT NULL COMMENT '1请假 2报销 3出差', title VARCHAR(200) NOT NULL, applicant_id BIGINT NOT NULL, current_node INT DEFAULT 1 COMMENT '当前节点', status TINYINT DEFAULT 0 COMMENT '0审批中 1通过 2驳回 3撤回', apply_content TEXT COMMENT '完整表单JSON', create_time DATETIME DEFAULT CURRENT_TIMESTAMP );审批记录表:
CREATE TABLE approval_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, instance_id BIGINT NOT NULL, node INT NOT NULL, approver_id BIGINT NOT NULL, result TINYINT NOT NULL COMMENT '1同意 2驳回', comment TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );我的实战心得是:审批单号一定要单独生成,不要用数据库自增 ID。因为自增 ID 很容易被猜到,比如上一单是 10086,下一单是 10087,同行一看就知道你的业务量。用yyyyMMdd + 流水号既能保证时间可读,又能防止越权遍历。
4.3 索引设计与查询性能优化
办公系统查询最频繁的场景是“我的待办”和“我的申请”。这两个查询都带有用户 ID 和状态条件,所以必须建立联合索引。例如:
ALTER TABLE approval_instance ADD INDEX idx_applicant_status (applicant_id, status);如果是查询审批人相关数据,需要按审批记录表里的 approver_id 和 status 建立索引。索引不是越多越好,每一次写入都要同步更新索引,数据量大时反而拖慢速度。只给高频查询条件建索引,这是一个原则。
还有一个经常被忽略的问题:用 MySQL 的utf8mb4作为字符集,不要用utf8。因为utf8在 MySQL 里最多存 3 字节,像 emoji 这类 4 字节字符存不进去。现在很多用户名字带 emoji 或者特殊符号,一旦保存失败会直接抛异常。
5. 本地运行与部署实操
5.1 环境准备清单
在跑项目之前,先检查环境。后端需要 JDK 1.8 以上(建议 JDK 8 或 11)、Maven 3.6+、MySQL 5.7+/8.0、Redis(如果涉及缓存或验证码)、Node.js 14+ 和 npm/yarn。前端如果用了 Vite,Node 版本要求可能更高。
这里要提醒一句:Spring Boot 2.x 最高支持到 JDK 8/11,Spring Boot 3.x 必须要 JDK 17 以上。如果你本机装的是 JDK 17,却拿了一个基于 Spring Boot 2.7 的项目,会出现各种诡异报错。先看 pom.xml 里的 parent 版本,再决定用什么 JDK,这个顺序不能反。
5.2 关于 zip 解压的那点事
很多人下载完“源码.zip”,双击解压结果报file is not a zip file或invalid zip archive: could not find EOCD。先说结论:这个错表示文件不是完整的 zip 格式,大概率是文件传输过程中损坏,或者源文件本身就缺了末尾的中央目录记录。EOCD 就是 zip 文件末尾的一段固定结构,文件少了尾部,任何解压软件都读不出来。
排查步骤很简单:
- 用命令行
file online-office.zip查看文件真实格式,确认它到底是不是 zip。 - 尝试重新下载一次,最好换个浏览器或下载工具,避免断点续传造成的文件截断。
- 如果下载的是网盘资源,确认文件大小是否和页面标注一致。
- 用命令行解压时,如果出现
End-of-central-directory signature not found,基本可以确定文件损坏。
另外,Linux 服务器上解压 zip 常用命令:
unzip online-office.zip如果中文文件名乱码,可以加上-O GBK参数。但有些系统 unzip 版本不支持-O,可以改用 Python 的 zipfile 模块解压,或者用 7z 工具:
7z x online-office.zip5.3 后端启动的完整步骤
启动后端的流程是:
- 导入数据库脚本:在 MySQL 中执行
sql/init.sql,初始化表结构和基础数据。 - 修改
application-dev.yml里的数据库账号、密码。 - 启动 Redis(如果项目依赖)。
- 在
backend目录执行:
mvn spring-boot:run如果你看到控制台输出Started Application in x.xxx seconds,说明启动成功。正常接口文档可以通过http://localhost:8080/swagger-ui.html访问,如果项目集成了 Swagger。
如果 Maven 下载依赖特别慢,可以在 Maven 的settings.xml里配置阿里云镜像,速度能快好几倍。不要在本地用一个一个拷 jar 包,也不要频繁修改仓库路径,配置好镜像之后一次搞定。
5.4 前端启动的完整步骤
前端启动相对简单:
cd frontend npm install npm run serve如果npm install卡在某一个包上,可以切换 npm 镜像源:
npm config set registry https://registry.npmmirror.com启动后在浏览器访问http://localhost:8081。这里涉及一个判断:页面能打开但数据加载不出来,优先检查代理配置和接口路径。按 F12 打开控制台,看 Network 请求报什么错,再针对性排查。
如果是 Vue 3 + Vite 项目,启动命令通常是npm run dev。旧项目的vue.config.js在新版本里已经没有默认读取逻辑,要按当前框架版本选择对应配置。
注意:前后端启动顺序没有强制要求。但建议先确认后端能通,再启动前端。因为前端很多页面打开后会立刻请求接口,如果后端没启动,控制台一片红色 504 或 ECONNREFUSED,容易误判自己代码写错。
5.5 Linux 环境下的打包部署
生产环境一般部署在 Linux 服务器上。后端打包:
mvn clean package -Dmaven.test.skip=true打出来的 jar 包在target/目录下,通过java -jar online-office.jar启动。为了后台运行,推荐使用nohup:
nohup java -jar online-office.jar --spring.profiles.active=prod > run.log 2>&1 &前端执行:
npm run build生成的dist/目录,把它放到 Nginx 的 html 目录下。Nginx 配置示例:
server { listen 80; server_name your-domain.com; location / { root /opt/frontend/dist; 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; } }这里有两个关键点:try_files是为了让 Vue Router 的 history 模式刷新页面时不出现 404;proxy_pass后面的/表示把/api/xxx后缀原样转发到后端。这两个地方配错了,前端刷新白屏、接口 404 都是常事。
6. 常见问题与排查技巧实录
6.1 项目运行阶段的典型问题速查
| 现象 | 可能原因 | 处理方案 |
|---|---|---|
启动时报Invalid bound statement | MyBatis 的 mapper.xml 没有扫描到 | 检查@MapperScan包路径和mapper-locations配置 |
| 后端能启动,前端登录提示 401 | token 生成或校验失败 | 检查 JWT 的签名密钥是否一致、Redis 是否有缓存 |
| 前端页面刷新后 404 | Vue Router 使用了 history 模式,Nginx 未配置回退 | 在 Nginx 中增加try_files配置 |
Port 8080 was already in use | 端口被占用 | Linux 用lsof -i:8080查占用进程,Windows 用netstat -ano |
接口返回Invalid CORS request | 跨域配置错误 | 推荐用 Nginx 反向代理,而不是在后端允许所有来源 |
java.sql.SQLException: Access denied | 数据库账号或密码错误 | 检查 application-prod.yml 和 MySQL 用户权限 |
| 前端 npm 包安装很慢 | 镜像源默认在国外 | 切换 npmmirror 镜像 |
6.2 Spring Boot 版本过高导致的兼容性坑
Spring Boot 3.0 发布以后,很多旧源码基于 Spring Boot 2.x 写。如果强行用 Spring Boot 3.x 跑旧项目,会出现很多不兼容。
最典型的是javax.servlet包变成了jakarta.servlet,MyBatis、PageHelper 等老版本插件直接失效。还有 Redis 客户端从 Jedis 换成 Lettuce,部分配置项名称也变了。所以在导入源码之前,先打开pom.xml看spring-boot-starter-parent的版本,再决定 JDK 和依赖版本。
如果确实想在 Spring Boot 3.x 下运行旧项目,最省事的方式是把依赖库升级到适配 3.x 的版本,比如 MyBatis-Spring-Boot-Starter 3.x、Hutool 5.8+、Swagger 3 的 knife4j 等。但升级过程可能遇到隐藏变更,建议在分支上操作,不要直接在正式环境动手。
6.3 前端与后端联调时的高频 Error
联调时期最常见的错误有:
axios请求baseURL配错了,导致请求路径从/api/login变成http://localhost:8081/api/login,后端没这个接口直接 404。- 后端返回的
timestamp字段格式是yyyy-MM-dd HH:mm:ss,前端没做格式化,显示成Invalid Date。 - 分页参数名字不统一,后端要
pageNum,前端传的是page,结果第一页永远查不出来。 - 上传文件时没有设置
Content-Type: multipart/form-data,后端接不到文件。
解决办法就是养成一个习惯:接口联调前,先把后端 Swagger 页面打开,确认真实参数名和返回结构,再让前端对着写。不要靠记忆,特别是一百多个接口的大系统,一个字段不齐就要排查半天。
6.4 日志分析是排障的核心手段
很多问题不是看代码就能发现的,必须靠日志。后端启动时开启 debug 日志,可以在配置里增加:
logging: level: com.example: debug数据库操作日志可以通过 MyBatis 输出 SQL,看看实际执行的语句和参数是什么。很多时候你以为传了一个 ID,结果日志里显示id = null,那问题一目了然。
前端排障看浏览器 Network 面板,关注请求的 URL、请求头、状态码和响应体。如果接口 500,复制后端日志里的堆栈信息去搜,比自己瞎猜高效得多。我见过太多人在前端 console 里打日志,但后端根本没进 controller,说明请求都没打到后端,那应该先查代理和网络通不通。
7. 拓展与二次开发建议
7.1 在现有源码上增加业务模块
如果你拿到源码后想扩展,建议从最核心的“用起来”开始。先跑通。
然后看业务模块是否抽象得足够好。如果后端 Controller 里有大量重复代码,前端页面也复制粘贴,那改起来会非常痛苦。建议先把通用逻辑抽成 Service 层方法和公共组件,比如BaseService、BaseController、CommonTable组件,后面加模块的效率才会高。
审批模块如果要支持复杂的流程,比如会签、或签、条件分支,可以做一张流程节点配置表,把节点关系存成 JSON。不建议一上来就引入 Activiti/Flowable,工作流引擎虽然功能强,但学习成本高,对轻量办公系统来说可能过度设计。先把单路径审批做好,再逐步扩展。
7.2 前端增强:Vue 播放 m3u8 视频
办公系统里经常会有视频培训、会议录像的功能。虽然这和审批发起的核心链路没有直接关系,但作为一个高频增强点提一下。
如果要在 Vue 中播放 m3u8 视频,比较常见的做法是使用hls.js:
npm install hls.js然后在组件中:
import Hls from 'hls.js' mounted() { if (Hls.isSupported()) { const hls = new Hls() hls.loadSource('http://example.com/stream.m3u8') hls.attachMedia(this.$refs.video) } else if (this.$refs.video.canPlayType('application/vnd.apple.mpegurl')) { this.$refs.video.src = 'http://example.com/stream.m3u8' } }注意:m3u8 播放对跨域有严格限制,如果播放器加载失败,优先检查后端接口是否返回正确的Access-Control-Allow-Origin。还有,桌面浏览器普遍不支持直接原生播放 m3u8,所以你看到黑屏是很正常的,引入 Hls.js 就能解决。
7.3 持续集成与自动化部署
当项目从本地跑到服务器,下一步就是考虑自动化。写一个简单的 deploy.sh 脚本,把打包、上传、杀掉旧进程、启动新 jar 的过程串起来,能省掉大量重复劳动。
#!/bin/bash BACKEND_JAR=online-office.jar FRONTEND_DIST=frontend/dist echo "building backend..." cd backend && mvn clean package -Dmaven.test.skip=true echo "building frontend..." cd ../frontend && npm run build echo "stopping old process..." PID=$(ps -ef | grep $BACKEND_JAR | grep -v grep | awk '{print $2}') if [ -n "$PID" ]; then kill -9 $PID fi echo "starting backend..." cd ../target && nohup java -jar $BACKEND_JAR --spring.profiles.active=prod > run.log 2>&1 & echo "deploy completed."如果团队有 GitLab CI/CD 或者 Jenkins,还可以把测试、编译、镜像构建全部串联起来,实现提交代码后自动发布到测试环境。这就是从“能跑”到“能高效迭代”的分水岭。
8. 最后还是想多说几句
这套线上办公系统,技术上并不算高山仰止,但胜在覆盖面广:登录认证、权限管理、审批流、考勤统计、前后端部署、网络安全,每一个点都能延伸出很多东西。如果你手里这包源码只是用来交作业,那跑通即可;如果你打算让它真正服务一个团队,一定要把“数据权限”和“流程追溯”这两个底层逻辑吃透,否则以后每加一个角色都要改一次权限判断,每出一件纠纷都要翻半天日志,那才叫真正的噩梦。
我个人的体会是,每次跑这种源码,都不要急着按 F5。先花半小时看看数据库脚本、看看后端目录、看看前端路由,把整个项目的地图画出来,再启动。磨刀不误砍柴工,很多你以为的“报错”其实是在提醒你走错了方向。愿这篇长文能帮你少走几个连环坑,也希望你能把一套通用办公系统真正做成适合自己团队的好工具。
本文还有配套的精品资源,点击获取