SpringBoot2+Vue3企业OA系统源码拆解:RBAC权限与审批流设计实战

发布时间:2026/10/19 8:05:27

SpringBoot2+Vue3企业OA系统源码拆解:RBAC权限与审批流设计实战 1. 项目核心与适用场景最近在梳理企业信息化建设过程中常用到的业务系统Java Web 企业 OA 管理系统源码算是一个绕不开的参考样板。这套系统不是那种只写几个接口的演示工程而是把审批、考勤、公告、组织人事这些日常办公场景真正落了地的项目技术栈用的是 SpringBoot2 Vue3 MyBatis-Plus MySQL8.0源码自带数据库脚本、接口文档和部署说明。对后端同学来说可以研究 RBAC 权限模型、工作流状态机、MyBatis-Plus 的各种高阶用法对前端同学来说可以学习 Vue3 组合式 API、动态路由、按钮级权限控制这些实战技能如果你是在校生或者刚转行拿它作为毕业设计或者入职项目经验的来源也足够有分量。先说下我拿到这套源码的第一感觉目录结构清晰后端按 controller、service、mapper、entity、common 分包前端按 views、api、stores、router 划分没有那种堆在一起的分包乱象。项目文档里包含了数据库设计说明、接口定义、部署步骤这在一个开源或者卖源码的项目里其实很难得。很多源码只是给你一堆代码连表结构都摸不透更别提跑起来了。这套源码自带文档意味着你不用靠猜可以直接对照文档把环境搭起来把流程走通。那这套系统到底解决了什么问题说白了就是企业里“人、事、流程”的信息化。人指的是员工和组织架构管理事指的是请假、报销、用章、会议这类具体业务流程指的是这些事的审批流转。系统把这些原本靠纸质单据、口头沟通的事情搬到线上每一次提交、审批、驳回都有迹可循。这也是我为什么把这篇博文定位成“源码级拆解”的原因光看功能列表没意义关键是弄懂底层怎么实现才能在自己的项目里复刻同样的能力。2. 技术选型背后的取舍2.1 为什么是 SpringBoot2 而不是 SpringBoot3这个项目用了 SpringBoot2很多人会问现在不是 SpringBoot3 都出来了吗这里面的逻辑很简单企业 OA 类系统追求的是稳定和生态兼容。SpringBoot2 基于 Spring5主流版本的 MyBatis-Plus、工作流框架、各种生成工具在 SpringBoot2 下的整合资料最多踩坑成本最低。SpringBoot3 基于 Spring6 和 Jakarta EE很多老框架的命名空间都改了包名从 javax 换成 jakarta虽然新发展方向是 SpringBoot3但你要是在企业内网部署环境里跑的可能还是 JDK8SpringBoot2 JDK8 的组合几乎不会出问题。这套源码选 SpringBoot2 还有一个务实的原因它可以和低版本的基础组件兼容比如 Redis、RabbitMQ 的旧客户端甚至可以直接内嵌 Tomcat 跑在普通服务器上不需要容器化改造。如果你公司里的服务器资源紧张一个 java -jar 命令就能起来运维成本非常低。我在实际项目中用过 SpringBoot2.3 和 2.7整体体验差别不大2.7 支持一些新特性但核心的自动配置、AOP 切面、定时任务这些东西都是通用的。2.2 Vue3 组合式 API 带来的开发效率提升前端选择 Vue3 可以说是现代企业管理系统的主流趋势。Vue3 的 Composition API 把业务逻辑按功能组织不再像 Vue2 那样把 data、methods、computed 拆散。比如一个审批列表你可以把列表数据、查询条件、分页参数、加载状态全都聚合在一个 setup 函数里逻辑清晰也方便复用。配合 script setup 语法代码量比 Vue2 少了很多。这套系统里前端大概用了这些核心依赖Vue3、Vue Router 4、Pinia或 Vuex、Element Plus、Axios。Element Plus 是 Element UI 的 Vue3 版本表单、表格、弹窗、树组件都齐特别适合后台管理界面。拿到源码后你会发现它的页面不是那种花哨的 H5 风格而是典型的后台管理布局左侧菜单、顶部导航栏、中间内容区这种结构是 OA 系统最经典的界面模型用户上手成本低。2.3 MyBatis-Plus 为什么比 JPA 和原生 MyBatis 更合适在这个项目里持久层框架选了 MyBatis-Plus它本质上是 MyBatis 的增强工具只做增强不做修改。用它的最大好处是单表 CRUD 不需要写 SQL只要继承 BaseMapper 接口insert、update、selectById 这些方法就自动有了。在企业 OA 系统里像用户表、部门表、通知表这类基础表的数据操作百分之八十都是单表操作用 MyBatis-Plus 可以省下大量重复的 XML 编写。你可能会问那复杂的多表查询怎么办这就是 MyBatis-Plus 灵活的地方它依然支持自定义 SQL你可以在 mapper 的 XML 文件里写 join、子查询、动态条件。而且它提供了分页插件只需要配置一个拦截器就能自动拼接 limit 语句。我还注意到这套源码里用到了 MyBatis-Plus 的自动填充功能来处理 createTime、updateTime 字段不用每个插入操作都手动 set 当前时间这种细节非常实用。2.4 MySQL8.0 带来的特性支撑选 MySQL8.0 不是跟风而是它在窗口函数、通用表表达式、隐藏索引、字符集排序规则这些方面比 5.7 强太多。OA 系统里的审批流程表经常要统计每个人发起了多少次申请、平均审批时长是多少用窗口函数一条 SQL 就能做出来。MySQL8.0 的 utf8mb4 字符集默认排序规则改成了 utf8mb4_0900_ai_ci对中文排序更友好而且支持 emoji 存储对企业内网办公场景来说完全够用。这套源码的数据库脚本会包含建表语句和初始数据运行的时候要注意 MySQL 的时区参数设置。连接串上建议加上 serverTimezoneAsia/Shanghai不然插入时间会出现 8 小时的偏差。MySQL8.0 默认用了 caching_sha2_password 加密规则如果客户端驱动版本太老可能会连不上所以 pom 里的 mysql-connector-java 版本要保证配套。3. 系统功能全景拆解3.1 用户管理与权限模型一个标准的 OA 系统第一个要解决的问题就是“谁能用什么功能”。这套系统采用的是 RBAC基于角色的访问控制模型核心就是用户、角色、权限菜单/按钮三张表再加上用户角色关联表、角色权限关联表。用户表通常包含用户ID、用户名、密码、姓名、手机号、邮箱、部门ID、岗位、状态、创建时间等。密码肯定不能明文存储源码里用了 BCrypt 加密每次登录比对的是 BCrypt 算法生成的哈希值。角色表就是常说的“管理员”“普通员工”“部门经理”“总经理”这类。权限表在这个项目里其实就是菜单表每个菜单项代表一个前端路由和一个后端接口的访问权限。比如一个“请假审批”菜单对应的后端接口可能是 /leave/approve用户能不能看到这个菜单、能不能调用这个接口完全取决于该用户角色是否拥有这个菜单的权限。权限控制的实现分前后端两层。前端在路由守卫里动态加载当前用户的菜单生成可访问的路由表没有权限的页面直接不注册后端通过 Spring Security 或者拦截器校验接口权限就算有人绕过前端直接调接口也会被拦截下来。源码里大概率用的是 JWT 做身份认证登录成功后返回一个 token前端把 token 存在本地每次请求在 header 里带上后端拦截器验证 token 合法后把用户信息放入 ThreadLocal后续业务代码直接从上下文取当前用户即可。3.2 审批流程设计请假、报销、用章审批流程是 OA 系统的灵魂。这块的实现方式有很多种复杂的可以接 Activiti/Flowable 工作流引擎但那种框架重、表多、学习曲线陡轻量一点的做法就是源码里用的“状态机 审批记录”方案。拿请假流程举例员工提交请假申请生成一条请假单记录状态为“待审批”。如果配置了直接主管审批那么该主管登录系统后在待办列表里能看到这条申请。主管点击同意后状态更新为“已通过”如果公司规定超过三天还需要总经理审批那就再加一层顺序流。这个业务用一张表就能表达关键字段是当前节点approval_node、审批状态status、审批人approver_id、审批意见approval_comment、审批时间approval_time。每次审批动作更新主表状态同时往审批记录表里插入一条流水这样整个过程的轨迹就完整了。这种设计的好处是灵活度虽不如流程引擎但胜在轻量可控适合那些流程相对固定的企业。如果后续要支持“会签”“或签”“驳回重新提交”完全可以在现有表结构上扩展不用引入整个流程引擎。源码里的工作流模块大概率会有一个流程模板配置表把每个业务的节点顺序配出来这样就避免把流程写死在代码里业务部门调整审批顺序时管理员直接改配置就行。3.3 组织架构与部门管理企业 OA 离不开组织架构树。部门表通常采用父子关系设计字段包含部门ID、父部门ID、部门名称、负责人、排序号。在 MySQL 里实现树形结构有两种常见方案一种是 adjacency list也就是这种父子ID方式查询子部门需要递归另一种是 nested set用左右值编码查询方便但维护复杂。在 OA 系统这种部门层级不深通常不超过五层的场景下父子ID方案最实用。前后端数据呈现上后端返回一个树状结构的 JSON前端用 Element Plus 的 el-tree 组件展示。后端组装树之前要注意数据结构的映射一般会把 List 集合转成 Map然后遍历建立父子引用复杂度控制在 O(n)。这个操作虽然不难但写出来很容易出错特别是父节点 ID 为 null 的情况。源码里肯定有类似 TreeUtil 的工具类读者可以重点关注一下。3.4 公告通知与文件管理公告通知模块解决的是企业信息发布问题。数据表包括公告表、附件表和阅读记录表。公告表有标题、内容、发布人、发布时间、置顶标志、状态等字段。阅读记录表用来记录每个用户什么时候看过哪条公告这样发布人就能知道“谁还没看”对于重要通知可以催办。这个模块看起来简单但里面有一个细节值得学习内容字段用的是富文本 HTML 存储前端展示时要警惕 XSS 攻击源码里大概率会对 HTML 内容做白名单过滤。文件管理相关的功能比如附件上传、头像上传、Excel 导出在 OA 系统里出现频率很高。后端文件上传通常用 MultipartFile 接收保存路径要配置成可配置的绝对路径而不是写死相对路径。文件名必须做处理最简单的方式是 UUID 原始文件名拼接避免中文文件名和重名问题。数据库里只存文件的相对路径或者访问 URL文件本身放在本地磁盘或对象存储中。这套源码如果带文档应该会说明文件保存目录怎么改如果没有部署时一定要自己配置好。3.5 日程会议与内部办公辅助日程管理模块用于个人任务安排和部门共享日历表结构包括日程时间、内容、参与人、提醒时间。会议管理需要处理预订会议室的冲突会议室表、预订表、参与人表是基本配置。预订时判断时间区间是否重叠本质就是查询“已有记录中存在 开始时间 新结束时间 且 结束时间 新开始时间”的数据这条 SQL 写出后整个模块的核心逻辑就通了。日程会议模块在很多源码里做得比较简陋但我认为它就是最能体现“业务完整性”的地方。如果你准备拿这套源码做二次开发不妨把日历视图、根据与会人自动产生待办提醒这些功能加进去这会让你的系统在答辩或面试时多出几个可讲的亮点。4. 后端核心实现细节4.1 JWT 认证与拦截器配置我在源码的 common 包里大概率能看到一个 JWT 工具类里面封装了生成 token、解析 token 的方法。JWT 由三部分组成header、payload、signature。这里有几个关键参数需要注意过期时间、签名密钥、自定义声明。源码里签名密钥一般会写在 yml 配置文件里实际项目中必须使用足够复杂的密钥并且通过环境变量注入不要直接提交到代码仓库。拦截器的作用是拦截所有需要登录的请求取出 header 中的 token如果 token 不存在或者已过期直接返回 401 错误。如果验证通过把用户ID、用户名解析出来放进 ThreadLocal。这里有一个我踩过的坑如果你在拦截器里使用了 ThreadLocal 存用户信息一定要在请求完成后清理掉否则线程池复用线程时下一个请求会拿到上一个用户的身份造成严重的数据越权。源码里可以在 afterCompletion 方法里看到 remove 操作。4.2 MyBatis-Plus 自动填充与逻辑删除自动填充功能是 MyBatis-Plus 一个特别实用的特性。你可以定义一个 MetaObjectHandler 类重写 insertFill 和 updateFill 方法给公共字段统一赋值。比如 createTime 在插入时自动填当前时间updateTime 在更新时自动填当前时间创建人、更新人也可以从用户上下文里取。这样业务代码里就不需要显式 set 这些字段避免了遗漏和重复。逻辑删除在国内企业项目里几乎是标配也就是删除记录时不是真的 delete而是把 del_flag 字段置为 1。MyBatis-Plus 支持在实体字段上加上 TableLogic 注解全局配置里指定逻辑未删除的值和已删除的值。从此你的 select 语句会默认带上 del_flag 0 的条件delete 操作会变成 update。配置这个功能时要注意有些需要物理删除的场景比如清理临时表如果也走了逻辑删除表数据会无限膨胀。源码里可以在数据量大的日志表上考虑物理删除核心业务表才用逻辑删除。4.3 分页插件与查询条件构造MyBatis-Plus 的分页插件需要手动配置一个 MybatisPlusInterceptor Bean并添加 PaginationInnerInterceptor。配置完成后使用 new Page(current, size) 即可完成分页查询。这里有个细节分页插件默认会在 count 查询时自动优化去掉不必要的 order by 和 join 条件如果你的 SQL 特别复杂count 查询依然可能很慢这时可以手动指定 count SQL。条件构造器 QueryWrapper 是 MyBatis-Plus 的灵魂。LambdaQueryWrapper 更是推荐使用因为字段名直接对应实体类的 Lambda 表达式可以避免写错列名导致运行时报错。比如查询待审批的请假申请可以这样写lambdaQuery().eq(LeaveApply::getStatus, 0).eq(LeaveApply::getApproverId, userId)。要特别注意如果查询条件里有 or 和 and 混用一定要用 nested() 或者加括号明确优先级否则生成的 SQL 条件会出乎意料。4.4 文件上传与本地存储文件上传在后端主要靠 MultipartFile接口接收参数类型设置为 MultipartFile file配合文件大小限制配置。SpringBoot 默认上传文件大小限制是 1MB实际 OA 系统里上传附件经常几十兆所以要在 yml 里设置 spring.servlet.multipart.max-file-size 和 max-request-size。源码里如果没有修改这两个配置部署后第一次传大文件就会报错这也是一个很容易踩的坑。存储路径推荐使用按日期分目录的方式比如 /upload/2025/01/20/uuid.jpg这样方便检修时定位文件。前端上传时可以通过文件流的二进制方式直接传给后端也可以用 base64传文但 base64 会增大约三分之一的空间不适合大文件。源码里如果做了进度条大概率是用 Axios 的 onUploadProgress 事件实现的这块可以前端参考。4.5 定时任务与消息通知OA 系统里免不了有定时任务比如每天下班前把未读公告提醒一遍、审批超时自动提醒。SpringBoot2 里自带的 Scheduled 注解足以处理这些简单任务。使用时要特别注意默认的 Scheduled 是单线程串行执行如果你配置了多个任务一个耗时的任务会阻塞其他任务必须配合线程池使用。源码里可以在启动类看到 EnableScheduling再自己定义一个线程池配置类。消息通知这块如果不接第三方短信服务可以在系统内部做“站内信”和“消息表”。当某个事件发生比如请假申请通过了就往消息表里插入一条记录目标用户下次登录后拉取未读消息。这种实现非常简单可靠比 WebSocket 即时推送稳定得多。WebSocket 在 OA 系统里适合做在线状态、实时提醒但部署时要考虑反向代理的 websocket 升级机制一旦代理配置不对就会连接失败。5. 前端 Vue3 实战技巧5.1 动态路由与菜单权限控制前端路由权限这块是 OA 系统中比较有技术含量的点。它不是把路由表写死在代码里而是登录后从后端接口拿到当前用户的权限列表再根据权限动态注册路由。实现方式一般是在 vue-router 4 中使用 router.addRoute()在全局守卫里判断用户是否已获取过动态路由如果没有就请求权限接口然后把返回的菜单树转成路由配置。菜单数据和路由配置之间需要一个映射转换。后端返回的菜单 JSON 一般包含 path、component、name、icon、children 等信息但 component 字段存的是字符串前端要映射到实际加载的组件可以用 import.meta.glob 批量导入 views 目录下的组件然后通过动态字符串匹配到组件。这一步很关键如果路径对不上页面就是空白的。源码里你需要找到 views 目录和 menu 表的 component 值看它们是否一致。5.2 Axios 请求封装与响应拦截Axios 封装几乎是每个前端项目的必备。一个规范的请求封装应该包含baseURL 设置、请求超时时间、请求拦截器在 header 里带上 token、响应拦截器统一处理业务错误码、HTTP 错误码、token 过期跳转登录。源码里的 request.js 大概率会暴露 get、post、put、delete 等通用方法并且返回一个 Promise业务页面里直接用这个方法替拿到数据。我特别想提一个细节响应拦截器里对于文件流下载的处理。如果接口返回的是二进制流你不能用 JSON 的方式解析需要根据 responseType: blob 处理并且从 header 中获取文件名。如果后端接口出错时返回的是 JSON但前端这边按 blob 处理就会导致下载了一个无法解析的错误文件。这个坑在 OA 系统的 Excel 导出功能里特别常见。5.3 Pinia 状态管理与持久化Vue3 全家桶的状态管理已经从 Vuex 转向了 Pinia。它更轻量使用也更简洁去掉了 Vuex 里的 mutations直接在 store 里定义 state、getters、actions。OA 系统里适合放在 store 中的全局数据通常有用户信息、token、菜单权限列表、系统配置等。源码里登录成功后会把用户信息和权限列表存入 store同时通过持久化插件或手动 localStorage 同步防止刷新页面后状态丢失。在使用 Pinia 时要小心不要把太多业务数据丢到 store 里。比如当前列表的查询条件如果每个页面都存不仅内存占用大还可能造成不同页面之间数据串味。store 只保存跨页面共享的、低频更新的数据页面内的高频交互数据应该放在组件自己的响应式变量里。5.4 基于 Element Plus 的表单与表格优化Element Plus 的 el-table 在渲染大量数据时会有性能问题。如果表格列很多、行数超过几百可以使用 el-table 的 v-loading、懒加载或者分页。源码里大部分列表都会做分页查询前端只要处理当前页数据即可。有一个小优化经验如果你的表格列中有大量枚举值转换比如状态 0/1 要显示为“启用/禁用”不要在每个单元格里写模板判断而是用计算属性或者字典映射函数统一处理这样代码可维护性更高。表单校验是 OA 系统的重灾区。后端只需要验证必填和长度前端则要实时给出反馈。Element Plus 的 form 组件自带 rules 规则校验配合 validator 自定义函数可以满足大多数业务。像日期范围选择器结束日期不能早于开始日期这种跨字段校验需要注意触发方式把第一个字段值变化时执行的校验绑定到第二个字段上。6. 数据库设计要点与 MySQL8.0 性能优化6.1 核心表结构设计思路看源码时不要急着看代码先把数据库脚本打开把核心表之间的关系理清楚。以用户表、角色表、菜单表为例典型的 RBAC 设计如下sys_user用户表id、username、password、real_name、department_id、phone、email、avatar、status、create_time、update_time、del_flagsys_role角色表id、role_name、role_code、remark、statussys_menu菜单表id、parent_id、title、path、component、icon、type、sort、permission、visiblesys_user_role用户角色关联表user_id、role_idsys_role_menu角色菜单关联表role_id、menu_id这种设计非常经典扩展性也够。如果要加“数据权限”比如经理只能看本部门数据还需要一张角色数据范围表存储角色、部门ID、数据范围的枚举全部/本部门/本部门及以下/仅本人。源码里如果只有菜单权限没有数据权限那在二次开发时一定要自己补上这是企业级系统区别于演示项目的分水岭。6.2 索引设计与慢查询根治OA 系统的查询压力主要集中在待办列表、审批记录列表、公告阅读记录查询。这类查询常用条件包括用户ID、状态、创建时间所以我们要为这些字段设计合理的索引。举个例子审批表 (approver_id, status) 联合索引能够快速定位某个用户有哪些待办事项公告表 (status, publish_time) 联合索引可以加速已发布公告的排序查询。MySQL8.0 的 EXPLAIN 工具必须会用。你自己分析慢 SQL 时注意看 type 字段如果是 all 说明全表扫描需要优化如果是 ref 或 range说明用到了索引扫描。extra 列如果出现 using filesort说明排序没有走索引要看看排序字段是否被索引包含。字符集和排序规则必须全局统一表与表连接时如果字符集不一致会影响索引使用。另外搜索框里的模糊查询如果使用 like %keyword%索引会失效对于 OA 系统此类查询频率不高的场景可以接受真需要全文搜索再上 ES 也不迟。6.3 事务与并发控制审批操作通常涉及多个表的更新比如审批通过后要更新请假单状态、插入审批记录可能还要更新剩余年假天数。这些操作必须放到一个事务里任何一个环节失败都要回滚。SpringBoot 中使用 Transactional 注解即可但要注意事务的传播行为和回滚条件。默认情况下只在运行时异常时回滚如果把受检异常 try/catch 吞掉了事务就不会回滚这是很多线上问题产生的原因。并发场景也要考虑。比如两个人同时用会议室一个先查到有空都想预订最后谁能预订成功如果没有锁两人都申请成功就冲突了。最简单的做法是使用唯一约束比如会议室表加一个会议室ID、开始时间、结束时间的唯一索引插入时由数据库来保证不会重复。或者使用 SELECT ... FOR UPDATE 对会议室记录行加锁但这容易引起死锁系统设计时要综合考虑。6.4 数据库连接池配置SpringBoot2 默认使用 HikariCP 作为连接池它性能好、体积小几乎不需要改动默认配置。但是在高并发审批场景下连接池大小和超时时间要调优。参考公式连接数 ((核心线程数 * 2) 有效存储设备数量)一般 OA 系统的并发不会太高连接池设置在 20-50 即可。要注意如果某个接口执行了过多 SQL或者接口被循环调用连接池的连接会被占满新请求就会等待连接超时。遇到“connection timeout”错误时先看慢 SQL再看代码里的数据库操作是否能合并。7. 部署上线与运维避坑指引7.1 本地环境搭建全过程不管看源码还是二次开发先把环境跑通最重要。你需要准备JDK8推荐 1.8.0_202 以上因为 MySQL8 连接驱动要求 JDK8 以上、Maven 3.6、Node.js 14前端构建需要、MySQL8.0 和 Redis如果有用到缓存。具体步骤大致是先用 Navicat 或命令行执行源码包里的 sql 脚本初始化数据库然后修改后端 application.yml 里的数据库账号密码配置 Redis 地址。启动后端时观察控制台日志看到“Started Application”字样说明启动成功。接着进入前端目录执行 npm install 安装依赖再执行 npm run serve 启动开发服务浏览器访问 devServer 提供的地址。这里最容易出的问题就是端口冲突如果你本机 8080 被占了需要修改后端的 server.port 配置同时前端代理 target 也要改成对应的端口。7.2 生产环境打包与发布生产环境推荐使用 Maven 打包后端为 jar 包前端执行 npm run build 生成 dist 静态资源然后由 Nginx 托管。Nginx 配置里有几个关键点一是将根路径的请求转发到后端服务比如 /api 前缀转发到 localhost:8080前端静态资源直接映射本地目录二是配置 gzip 压缩提升首屏加载速度三是对单页应用配置 try_files $uri $uri/ /index.html否则刷新非首页路由会 404。如果你不想用 Nginx也可以用 SpringBoot 直接把前端 dist 目录放到 static 目录下然后打成单一 jar 包。这种方式适合小规模部署但灵活性不好前后端分离后的独立发布能力就没了。我个人更推荐 Nginx jar 的方案既能做负载均衡也方便后续扩展域名。7.3 日志与系统监控日志是排查线上问题的第一手资料。源码里如果配置了 logback建议把日志输出到指定目录并按天滚动常见格式包括时间、线程、Logger、级别、消息。在关键业务方法里要打日志尤其审批流程操作需要记录谁在什么时间审批了哪个单、结果是什么。如果你把日志文件打印成异步模式可以降低对业务线程的阻塞但要注意异步队列满了之后的处理策略。监控方面如果服务器资源允许可以给 JVM 加上 GC 日志参数定期查看 GC 是否频繁。OA 系统一般不会遇到特别高并发的问题但内存泄漏在 SpringBoot 应用中并不少见。你可以通过 jstat 查看老年代内存变化出现持续上涨就可能是代码里有 ThreadLocal 没有清理或者静态集合类不断添加元素。8. 常见问题排查与避坑指南8.1 跨域问题前后端分离最常遇到的就是跨域。开发环境下前端代理解决跨域是最优雅的方式。在 Vue3 的 vite.config.js 里配置 server.proxy把 /api 开头的请求转发到后端地址。如果后端也要支持跨域可以在控制器或过滤器里放行。这里注意如果使用 Spring Security跨域配置需要与 Security 配置配合在 SecurityConfig 中启用 cors否则前端请求会被拦截。我见过最折腾的情况前端代理配了后端 CORS 也配了结果 Nginx 上线之后还是报跨域。原因就是 Nginx 没有处理好需要在 Nginx 的 location 里加 add_header Access-Control-Allow-Origin *以及处理 OPTIONS 预检请求。对这套源码建议上线时 Nginx 反代 后端不开启 CORS统一由 Nginx 跨域会更干净。8.2 时区与时间显示错乱MySQL8 和 Java 之间如果时区不一致很容易出现时间差 8 小时的问题。数据库连接串必须加 serverTimezoneAsia/Shanghai同时注意 MySQL 的系统时区是否正常。后来我发现一个问题容器时区是 UTCJava 应用也是 UTC但业务上希望显示北京时间前端拿到的字符串就不是预想的时间。解决方法是统一用 GMT8 作为应用时区和数据库时区前端展示时 Messagedescriptor 不一定可靠。最简单的建议后端序列化时间时使用统一的格式比如 yyyy-MM-dd HH:mm:ss前端不做任何时区转换这样问题最少。8.3 前端白屏与路由组件加载失败部署后遇到最多的问题是首页能打开但某个子页面刷新后出现 404 或白屏。如果是 404就是 Nginx 没有配置 try_files。如果是白屏且控制台报找不到模块大概率是动态路由里的 component 路径配置和实际 views 目录不一致。源码里定义菜单时 component 字段填的是字符串比如 “/system/user/index”前端代码需要把它映射成 () import(//views/system/user/index.vue) 这样的懒加载函数。路径少一个层级或多一个后缀都会导致加载失败。8.4 依赖冲突与版本不兼容Maven 项目里依赖冲突很常见。如果你启动日志中出现 NoClassDefFoundError 或 NoSuchMethodError一般是某个 jar 包版本不兼容。比如 Druid 连接池和 SpringBoot 的版本差异或者 MyBatis-Plus 和 MyBatis 的版本不匹配。遇到这种问题先用 mvn dependency:tree 看依赖树找出冲突的版本然后用 exclusion 排除掉多余的传递依赖。前端安装依赖也有坑。npm install 有时会提示 peer 依赖冲突比如 Element Plus 要求 Vue 版本必须是 3.2 以上而你项目里锁定的 Vue 是 3.0。遇到这种情况升级 Vue 版本或者拉取源码时注意完整执行 package-lock.json 里的固定版本不要随便改。8.5 生产环境内存配置SpringBoot 应用在低配服务器上启动很困难表现为启动到一半自动停止。这是因为 JVM 默认堆内存太大比如 2G 内存的服务器默认最大堆内存可能超过 1G再加上 MetaspaceJVM 直接 OOM 了。正确做法是在启动命令里显式指定内存java -Xms256m -Xmx512m -jar app.jar控制堆内存和元空间。对于 OA 系统512M 堆内存足够支撑几百人的办公使用。9. 源码阅读与文档使用建议9.1 如何快速跑通整套系统拿到源码先不要急着看代码第一步是看文档里的“快速开始”章节。通常文档会告诉你先导入 sql修改配置再启动后端最后启动前端。流程很短但有几个细节文档不一定写MySQL 的 root 密码、Redis 的密码、前端 npm 镜像源。如果你所在网络访问 npm 官网很慢建议先执行 npm config set registry https://registry.npmmirror.com 再用。跑通之后不要急着改代码。先在系统里把“用户管理-角色管理-菜单管理”这条路走一遍。创建一个新的角色给它分配菜单再创建一个用户绑定这个角色然后用这个用户登录。这一遍下来你基本就能理解动态路由和按钮权限的整个链路后续做二次开发才有地基。9.2 从源码中学习的关键点这套源码值得学的几个层次第一层是工程化规范比如全局异常处理、结果封装类 Result、统一参数校验、分页参数传递第二层是业务代码比如审批流状态机的实现思路、组织架构树的递归构建第三层是高级特性比如 MyBatis-Plus 的自定义填充、逻辑删除、AOP 日志切面。建议阅读顺序从 common 包开始因为这里面都是基础设施理解了工具类和拦截器后面业务代码看起来会非常轻松。9.3 二次开发的扩展方向如果你是拿这套系统做毕业设计或公司内部项目有几个方向值得扩展一是接入企业微信/钉钉把审批通知推送到移动端二是增加考勤打卡模块结合定位和经纬度判断是否在公司附近打卡三是做一个报表中心用 ECharts 展示各月申请数量、审批时效统计四是将文件存储从本地迁移到对象存储提升可靠性和容量上限。这些扩展并不难而且全都是可以在面试里聊的实战经历。结尾这套源码带给我的真实体会我在实际项目中用过很多所谓的企业管理系统源码最好的评价不是“代码多”而是“能看懂敢改”。这套基于 SpringBoot2 Vue3 MyBatis-Plus MySQL8.0 的 OA 系统最让我满意的地方在于它没有用过度复杂的框架同时又把企业办公场景中那些绕不开的坑——权限、流程、组织架构、文件上传——都给出了比较合理的参考实现。尤其对刚接触前后端分离项目的开发者来说你可以先把它跑起来然后逐步模仿它的业务代码写一个自己的模块比如会议室预订从建表到写接口再到前端页面走完一遍你就掌握了企业 Web 开发的完整套路。最后再分享一个小技巧在看这种带文档的源码时先把文档里的数据库设计表和接口清单打印出来边打边对照代码而不是漫无目的地打开文件。我每次用这套方法阅读效率都会提升一倍不止。如果你也正在找一套可以上手二次开发的 OA 系统这套源码值得你花一个周末好好啃一遍。
延伸阅读

更多相关文章

2026/10/19 8:05:27

软考软件设计师:程序设计语言基础高频考点与备考策略

聊到软考软件设计师,很多考生第一反应是数据结构、算法、设计模式这些“硬骨头”,但真正把上午题基础分稳稳攥在手里的,反而是“程序设计语言基础知识”这一章。这门课听着像文科背诵,实际却和编译原理高度重叠,是典型…

2026/10/19 8:05:27

测试智能体部署实战:从需求解析到回归闭环的完整落地

聊一个我们测试团队最近实打实落地的东西——测试智能体部署。项目代号就叫“从需求解析到回归闭环”,听着挺唬人,其实就是把需求文档扔给一个AI助手,让它自己拆需求、设计用例、执行回归、汇总报告,一套流程走完,测试…

2026/10/19 8:05:27

OpenCV轮廓匹配实战:Hu矩原理、matchShapes调优与工业检测避坑指南

1. 轮廓匹配到底在解决什么问题很多人第一次接触OpenCV的轮廓形状匹配,脑子里冒出来的第一个疑问是:模板匹配不是已经能干这事了吗?matchTemplate用起来多简单,一行代码就能在图上滑窗找相似区域。但真正做过工业检测或者零件分拣…

2026/10/19 9:15:58

海康WebControl插件接入RTSP视频流的网页实时播放方案

1. 项目背景与核心问题拆解1.1 为什么需要WEB播放器方案先说结论:如果你要在网页里实时播放海康摄像头的RTSP视频流,直接用HTML5的video标签是行不通的。原因很简单,主流浏览器早就放弃了RTSP协议的原生支持,再加上H.264编码的视频…

2026/10/19 9:15:58

开放式代码审查实战:从工具链到团队协作的完整方案

1. 为什么说“开放式代码审查”值得单独开一个项目来做先说结论:open-code-review 不是一个简单的“请同事帮忙看看代码”的流程说明,它是一整套围绕“公开、透明、可追溯”的代码审查实践方案,涵盖了工具链搭建、审查规范制定、团队协作机制…

2026/10/19 9:15:58

AI驱动问卷设计:结构化生成与人工校验的实践指南

做问卷调研这些年,我越来越确信一件事:问卷没设计好,后面所有统计手段都只是补救。很多人觉得问卷设计就是“把想问的事情写成选择题”,等数据回收回来才发现,题目有歧义、选项有遗漏、跳转逻辑混乱、量表锚点不统一&a…

2026/10/19 9:15:58

SpringBoot+Vue+MySQL在线招投标系统毕业设计全流程实战指南

每年毕业设计的题目清单里,“在线招投标系统”几乎是稳定出现的面孔。这个题目的经典之处在于:它不冷门、不缺业务场景、难点可控,而且 SpringBoot Vue MySQL 这套组合本身就是不少同学简历里反复出现的技能栈。如果你正在纠结毕业设计选什…

2026/10/19 9:15:58

代码审查自动化实践:构建智能规则引擎,告别无效Review

做代码审查这件事,我在团队里忍了很久。表面上看我们在严格执行 Pull Request 流程,每个 PR 都有人点 Approve,但实际上有一大半 review 只是“LGTM”刷屏;真正认真看逻辑的少之又少,低级错误照样漏到线上,…

2026/10/19 9:10:57

无人机公路缺陷巡检:YOLOv8数据集构建到部署全程解析

无人机公路缺陷巡检,这个项目一干就是三个月。从最初带着设备在高速路边战战兢兢地调试,到后面形成一套完整的“采集—标注—训练—部署”闭环流程,中间踩过的坑比想象中要多得多。这套YOLO数据集(编号第10051期)沉淀下…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/19 0:04:56

悟空开源无代码平台实战:从实体建模到应用设计避坑指南

简介:基于悟空开源无代码平台的多种应用设计源码,面向希望在不编写代码的情况下快速搭建CRM、HRM、财务系统、ERP、SRM等业务应用的企业与技术人员,通过拖放式界面和内置模板即可完成应用定制与部署。压缩包共697个文件,约10.74MB…

2026/10/19 0:04:56

基于.NET9的多租户权限系统:数据权限与动态API落地实践

简介:这份资源是一套面向 .NET 与 Vue 全栈开发者的中台权限管理系统,后端基于 .Net9,前端采用 Vue3 Element Plus,并配套 uniapp uviewui 移动端方案,实现前后端分离。系统覆盖多租户隔离、数据权限、动态 Api、任务…

2026/10/19 0:04:56

场地预约小程序毕设实战:SSM+微信小程序+MySQL数据库设计到避坑

简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序SSMMySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑