多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

办公自动化系统毕业设计实战:Spring Boot+MyBatis Plus权限与审批流设计

办公自动化系统毕业设计实战:Spring Boot+MyBatis Plus权限与审批流设计 1. 选题背后的真实考量为什么办公自动化系统依然是毕业设计的安全牌每年到了毕业设计选题季总有一批人纠结是跟风做一个短视频推荐算法、搞一个前后端分离的电商项目还是选一个看起来不那么性感但实用性很强的管理系统我当时的答案很直接做企业办公自动化系统OA系统。原因有三条现在回头看依然成立。第一这类系统是典型的业务逻辑重、算法含量低、展示效果直观的项目。毕业设计考察的重点从来不是你能不能搞出一个惊天动地的模型而是你对业务的理解、对软件工程流程的把握、对主流技术栈的熟练度。OA系统恰好把这三样都占了。第二Java技术栈在企业级应用中的生态太成熟了。Spring Boot、MyBatis Plus、MySQL这套组合在真实企业的中小型内部系统里依旧是主力。做了这个课题答辩时被问你为什么用这个技术时你能拿出真实世界的理由而不是说因为教程里这么写。第三企业办公自动化系统的业务场景足够具体。审批、考勤、通知公告、会议管理、员工通讯录——这些场景每个人都见过、用过需求不需要凭空想象答辩时的需求分析部分特别好讲。反观某些课题做完之后连这个项目到底解决什么问题都要现场编。这个课题的另一个隐形优势是资料密度大。网上能找到的课程设计、毕业设计源码很多哪怕你最终要自己动手写参考资料的丰富程度也远高于冷门课题。我当时就是先在GitHub和CSDN上收集了五六个同类项目的源码和文档做对照把模块设计和表结构梳理清楚再动手自研效率比从零开始高出一大截。不过这里要先泼一盆冷水不要抱着下载源码改个名字就能交的心态做这个课题。老师对OA系统的熟悉程度远超你的想象一问你表结构、一问流程状态怎么流转照本宣科还是真懂立马见分晓。源码可以做参考和起点但核心代码必须自己吃透、能复现、能优化。2. 系统模块怎么拆不是功能越多越好而是闭环越顺越好2.1 核心业务模块的边界划分企业办公自动化系统的功能需求看起来是无底洞人事、财务、行政、项目、客户什么都能往里塞。但毕业设计讲究的是合理范围内形成闭环我最后敲定的模块边界是六个系统管理用户管理、角色管理、菜单权限、操作日志。这是所有系统的底座没得商量必须有。审批中心请假申请、报销申请、用印申请。三种申请共用一套审批流这是整个系统的核心亮点也是最值得在论文里详细展开的部分。考勤管理打卡记录、考勤统计。这个模块的实时性要求让项目活了起来。通知公告管理员发布公告员工按部门或全员接收。功能极简但前端展示效果好答辩演示时一屏就能说清楚。会议管理会议室预定、会议邀请、冲突检测。这个模块容易做出差异化我加了时间冲突校验。个人中心待办事项、已办事项、个人资料修改。确定边界后我做的第一件事不是写代码而是画用例图和业务流程图。很多同学跳过这一步直接建表结果写到后半程发现业务关系理不清来回改表结构。用例图画完的那天我心里就有底了——每个角色的动作、与系统的交互边界都清晰了后面建表和写接口的速度反而比边写边想快了不止一倍。2.2 数据库表设计的几个关键取舍表结构是整个系统的地基地基歪了后面写多少代码都是在填坑。我设计表的时候有几个比较深的体会一是用户表、角色表、权限表的关系模型尽早确定。OA系统里最常见的权限模型是RBAC基于角色的访问控制也就是五张表用户表、角色表、权限表、用户角色关联表、角色权限关联表。这里有个容易走偏的地方很多人一开始给每张表塞十几个字段可能以后用得上的心态作祟。我的原则是能不加的字段一律不加字段冗余只出现在关联查询频繁、且数据基本不变的地方。二是审批相关的表一定要预留流程痕迹。OA系统的审批做的不是审批结果而是审批过程。我设计了审批记录表每一条审批动作都记录操作人、操作时间、审批意见、处理结果。这个设计让系统能回答谁在什么时候批了还是拒了这类溯源问题也是答辩时老师最可能追问的地方。三是状态字段用整型不用字符串。请假单的状态待提交、审批中、已通过、已驳回用0、1、2、3存评论部分再用文字解释。字符串做状态值看着直观但对于程序判断和索引很不友好这是我在开发过程中反复改出来的教训。2.3 用MyBatis Plus根据Java实体类生成建表SQL的实际操作开发过程中我用到过一个非常省事的操作用MyBatis Plus的代码生成器和自动建表能力直接从Java实体类生成数据库表。常规做法是手写SQL建表但当你定义的实体类字段多到二三十个时手写建表语句的效率就明显跟不上了。MyBatis Plus提供了一种思路先在Java类上定义好字段和注解再用工具生成对应的建表语句。具体做法不复杂。实体类里写清楚字段类型和约束比如Data TableName(oa_leave_apply) public class LeaveApply { TableId(type IdType.AUTO) private Long id; TableField(user_id) private Long userId; TableField(leave_type) private Integer leaveType; TableField(start_time) private LocalDateTime startTime; TableField(end_time) private LocalDateTime endTime; TableField(reason) private String reason; TableField(status) private Integer status; TableField(create_time) private LocalDateTime createTime; }然后配置一个自动建表或代码生成的插件或者直接用MyBatis Plus Generator把实体类、Mapper、Service、Controller一层全部反向生成出来。倒不是说依赖这个节省了多少时间而是它保证了实体类字段和表结构的一致性杜绝了手写SQL时字段名拼写不一致导致的跑批排查。这里要提醒一句代码生成器生成的CRUD只是样板代码真正的业务逻辑比如审批流的流转判断、考勤的迟到早退计算必须自己手写。生成器是帮你起跑不是帮你跑完全程。3. 后端开发中的必踩三坑登录、权限、审批流3.1 登录认证的实现思路登录认证是OA系统躲不开的第一道坎。我最初打算用Spring Security配置了两天加了一堆过滤器、配置类、UserDetailsService实现结果和JWT整合的时候各种报错搞到半夜心态都快崩了。后来换了一个轻量级的思路Sa-Token。它的核心API简单直观登录、鉴权、踢人下线的功能都有。用它做完整个认证流程只花了一个晚上。倒不是说Spring Security不好而是对于毕业设计这个量级的项目Spring Security的重量级抽象反而成了负担。最终登录验证逻辑是这样的用户提交账号密码后端用BCrypt加密算法校验密码原文校验通过后生成一个token返回给前端。前端在请求头里带上这个token后端通过拦截器统一做凭证校验解析当前用户是谁。整个链路里最重要的是三件事密码绝对不能明文存数据库用BCrypt加盐存储token要设置过期时间OA系统一般建议4到8小时太短影响办公体验太长有安全风险拦截器要放行登录接口和静态资源不然前端还没拿到token就被后端拦了。我在这个环节写过一个典型的Bug拦截器把/api/login之外的接口都拦截了结果前端拿着正确的账号密码登录却始终报401未登录。排查了很久发现是拦截器的排除路径没有生效因为我的路径匹配规则写的是/api/**但登录接口实际路径是/api/login这个排除配置本身没问题问题出在拦截器注册顺序上后来调整了配置类里的过滤器顺序就正常了。3.2 RBAC权限校验的落地方式权限校验这块很多教程喜欢讲按钮级权限接口级权限的花活但毕业设计能把角色区分这件事做实就已经很扎实。我的做法是后端接口统一做角色校验前端菜单按权限动态渲染。后端有个SaCheckPermission(system:user:add)之类的注解标注在新增用户的接口上前端则根据当前用户的权限数组决定菜单显示/隐藏。这样即使有人绕过前端直接调用接口后端依然会拒绝。关于权限设计我想多说一点权限码的设计要有规律可循。我采用模块:功能:操作的三段式命名比如oa:leave:apply、oa:leave:approve、system:user:resetPwd。这样后端代码里对着权限码就能知道控制的是什么数据库中维护权限数据时也不容易乱。3.3 审批流的状态机抽象审批流是整个系统的灵魂也是最容易写成一团乱麻的地方。我的做法是引入状态机思维不引入Flowable这类重量级工作流引擎。三种申请请假、报销、用印抽象成一个通用的流程模板每个申请单有一个当前状态每次审批动作触发一个状态迁移。状态定义如下状态值含义可执行动作0草稿提交1审批中待上级审批通过 / 驳回2已通过归档3已驳回修改后重新提交审批动作统一在ApprovalController里处理不同申请类型的差异通过策略模式封装出去。比如请假要判断假期余额够不够报销要判断发票金额是否匹配这些差异逻辑各自写在对应的策略类里审批主流程不关心具体业务规则只关心当前状态能不能执行这个动作。这个设计的价值在于答辩时你能理直气壮地说我用状态机规范了审批流程用策略模式隔离了业务差异这是明确的软件工程加分点。我在这个地方踩过的坑是状态流转出现死循环。最开始用if-else嵌套处理流转逻辑三个审批层级下来代码已经面目全非排错时看着一堆if头都是大的。后来重构为状态迁移表一个Mapkey是当前状态操作动作value是目标状态整个流转逻辑变成查表操作不到一百行代码解决的问题之前用if-else写了三百多行还漏了边界。4. 接口设计与前端联调把能跑变成好用的关键环节4.1 统一响应结构的坑与价值后端接口返回结构不统一是前后端联调时最折磨人的事。我第一次写接口时有的接口返回{code: 0, data: ...}有的返回{success: true, data: ...}前端同事其实就是另一个熬夜写代码的我被迫在axios拦截器里写一堆兼容逻辑。后来我们统一封装了ResultTData public class ResultT { private Integer code; private String message; private T data; public static T ResultT ok(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT fail(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }这样做的直接好处是前端只用判断code 200其他都算失败统一弹异常提示。项目回归测试时接口调用的代码量降低了大概三成。4.2 分页查询的两种官方姿势OA系统的列表页几乎全部要分页申请列表、用户列表、日志列表。MyBatis Plus内置分页插件用法很简单但有两个细节容易踩分页插件必须配置PaginationInnerInterceptor到MyBatis Plus的拦截器链里不配置的话分页SQL不会自动加上LIMIT查出来就是全量数据。前端传页码时约定pageNum从1开始还是从0开始一定要和后端注解对清楚。我见过太多因为PageHelper.startPage(pageNum, pageSize)和前端传的值差1导致列表少一行的案例。分页查询在实际开发里还有一个性能点不要select所有字段。OA系统的申请单列表只需要列表展示那几列详情页才需要全部字段。全部查出来在数据量小的时候看不出来但答辩演示时如果造了几千条测试数据页面的响应速度差异是肉眼可见的。4.3 联调阶段我反复改动最多的三个接口回顾整个开发过程联调阶段的返工主要集中在这三个点第一个是审批状态变更后列表状态没同步刷新。原因是前端在审批操作后没有重新请求列表数据还在用本地缓存的状态去渲染。解决办法很土但很有效审批接口调用成功后强制刷新当前列表页。第二个是时间格式的传输问题。后端返回LocalDateTime默认序列化成2024-05-20T10:30:00这种带T的格式在浏览器上显示非常丑。后来通过配置全局Jackson序列化把日期格式统一成yyyy-MM-dd HH:mm:ss一次性解决了所有页面的时间显示问题。这个操作在答辩演示时特别加分因为大多数同学的系统里时间格式都是乱的即使功能正常观感也差了。第三个是文件上传的路径问题。OA系统往往涉及附件上传比如报销单电子发票、用印申请扫描件文件存到服务器本地目录后前端访问用的是相对路径本地开发、部署到服务器两种场景下路径对不上。最后用配置类统一管理上传根路径再通过一个/files/**的静态资源映射暴露出去才算真正解决。这个点不只是联调坑也是部署阶段的坑提前用配置管理能省很多事。5. 部署、打包和答辩演示的实操细节5.1 Maven打包的常见翻车点开发环境一切正常一打包出问题这是最常见的情况。项目用Maven打包时最容易翻车的几个点是本地JDK版本和打包环境不一致。开发用JDK 17服务器用JDK 8而Maven编译配置里没有指定maven.compiler.source/target打出来的包可能在刷新环境时报UnsupportedClassVersionError。我建议在pom.xml里明确规定Java版本属性。测试代码拦截打包。默认mvn package会执行测试如果测试类里有连接数据库的用例构建时就会因为连不上库而失败。毕业设计阶段直接在pom.xml里跳过测试稳定优先。前端静态资源的合并。如果项目是前后端不分离的结构前端资源放在src/main/resources/static下打包时会自动打进jar包。我就遇到过页面样式文件被压缩后路径错乱的问题排查到最后发现是自定义了一个base标签把静态资源根路径指错了。5.2 答辩演示前必须准备的几样东西答辩演示是最容易被低估的环节。代码跑通了功能都正常不代表答辩就稳了。我总结了几条非常实在的准备事项第一准备一份干净的演示数据脚本。演示数据要覆盖各种状态审批中的单子、已驳回的单子、待我审批的单子每种至少一条。答辩现场不可能给你时间去填数据脚本一键初始化直接点到最有说服力的页面。第二把流程完整走一遍别跳着点。我见过一个同学演示考勤模块时直接跳到统计页面说这是考勤统计却忽略了打卡动作本身的操作演示。正确的演示逻辑应该是创建一个用户、用这个用户打卡、再切换管理员看统计结果形成一个完整的操作链路。第三准备好一张A0图表。所有模块的架构图、E-R图、流程图打印成一张大图摆在那里。这不是形式主义答辩时老师提问你指着图讲比对着屏幕讲要清楚十倍。5.3 部署环境配置的一次完整复盘我项目的最终部署环境是腾讯云的一台轻量服务器配置是2核4G系统Ubuntu 22.04装了MySQL 8.0和OpenJDK 8。部署过程本身不复杂但有几个点值得单独说数据库这一侧需要注意编码问题。生产库初始化时没指定utf8mb4导致中文插入后乱码。排查方法很简单不管先确认数据库、连接串、表三层的字符集是否一致。我最后统一设置了characterEncodingutf8mb4问题彻底消失。项目以jar包运行后记得设置JVM参数。java -Xms256m -Xmx512m -jar oa-system.jar控制一下内存占用4G内存的服务器跑OA系统和MySQL完全够用。还有一处当初折腾了很久的坑端口被防火墙拦截。项目默认端口8080放行后访问仍然超时最后发现是云服务器的安全组没配置入站规则。这个坑属于典型的代码没问题环境有问题如果遇到类似情况方向要优先往环境排查。6. 写在最后的一些实操心得如果让我重新做一次这个课题我会在三个地方投入更多时间第一数据库设计阶段再多花一天把所有关联关系过一遍第二审批流的策略模式一开始就设计好而不是写到一半再重构第三多花时间在演示脚本和页面细节上——这些看起来不起眼的工作最终带来的答辩收益远超多写两个功能模块。另外给各位一个非常诚恳的建议拿到任何参考源码第一件事不是看功能而是看它的数据库脚本和实体类关系。了解了表怎么设计的就了解了这个项目的地基结构剩下的无非是在上面盖楼。把这一点吃透了哪怕你完全不抄任何代码也能凭自己的理解重写出一套更好的系统。最后再分享一个关于写论文的小技巧。OA系统的论文结构里最难写的部分是系统设计这一章很多同学会写成一堆功能列表的罗列。我当时换了一个思路每个模块从业务场景→数据模型→接口设计→界面展示四个维度展开配上自己画的E-R图和流程图论文看上去真的像一篇系统设计的文章而不是功能说明书。这个方法希望也能帮到你。
返回列表