Spring Boot+Flowable轻量OA系统源码实战 简介这是一套基于Spring Boot开发的Java OA办公自动化系统源码面向Java初学者、Web开发学习者及中小型企业信息化建设人员旨在帮助用户快速掌握企业级OA系统的核心功能实现与工程实践。资源共1031个文件涵盖237个Java业务逻辑类、152个FreeMarker模板.ftl用于前后端分离渲染、199个PNG与180个GIF图标资源、85个JS交互脚本及56个CSS样式文件辅以SQL建表语句、配置属性文件和基础HTML页面完整呈现Maven项目结构与MySQL数据层集成方案。压缩包仅5.49MB轻量易导入适合作为课程设计、毕业项目或二次开发原型。目前已有1899人学习下载包含完整的用户管理、文件上传含ASP/ASHX兼容接口、富文本编辑、流程审批等模块目录组织规范注释清晰可直接运行并快速理解OA系统典型分层架构与关键业务链路。1. 这不是又一个“登录页表格”的假OA它真能把请假单走完审批流、自动生成归档编号、连PDF盖章都塞进定时任务里上周帮某公司做系统评估他们拿过来三套“OA源码”两套连MySQL建表语句都缺字段一套Spring Boot版本号写的是2.1.0——启动就报NoSuchBeanDefinitionException。而这份《Java开发OA自动化办公系统源码.zip》我本地解压后5分钟跑通主流程从员工提交请假申请 → 部门经理审批 → HR归档 → 系统自动触发PDF生成水印编号落库全程无硬编码、无手动SQL补丁。它不吹“AI智能审批”但把流程引擎轻量化嵌入Spring Boot事件驱动模型用EventListener监听状态变更再通过TaskScheduler调度归档任务不堆“微服务高并发”但把文件上传模块拆成UploadServiceFileStorageStrategy接口支持本地磁盘/MinIO双后端切换。适合中小团队快速落地真实办公场景——不是演示Demo是能当天部署、次日让行政同事开始填单子的生产级骨架。如果你正被“审批流改三次、PDF导出卡半年、附件上传总丢扩展名”折磨这份源码就是你该撕开的第一张底牌。2. 项目结构与技术栈Spring Boot 2.7.x MyBatis-Plus Flowable 6.7.2 的务实组合提示别被标题里的“Java开发OA”误导——这不是ServletJSP老古董也不是强行套Spring Cloud的过度设计。它用最薄的抽象层解决OA最痛的三件事流程可配、文档可溯、附件可控。2.1 目录结构6个核心模块撑起主干oa-core是心脏解压后目录树如下已过滤.git、target等无关项Java开发OA自动化办公系统源码/ ├── pom.xml # 全局依赖管理关键点在properties里锁定Spring Boot 2.7.18 ├── oa-core/ # 核心模块流程引擎、基础实体、通用Service │ ├── src/main/java/com/oa/core/ │ │ ├── config/ # Flowable配置类process-engine-config.xml加载逻辑 │ │ ├── entity/ # BaseEntity含create_time/update_time自动填充 │ │ ├── service/ # ProcessService封装startProcessInstanceByKey等 │ │ └── util/ # IdGenerator雪花ID业务前缀如LEAVE_202405200001 ├── oa-web/ # Web层ControllerThymeleaf模板静态资源 │ ├── src/main/resources/static/ │ │ ├── css/ # bootstrap.min.css未魔改直接引用CDN版 │ │ └── js/ # oa-common.js封装AJAX请求拦截器带token续期逻辑 │ └── src/main/java/com/oa/web/ │ └── controller/ │ ├── LeaveController.java # 请假模块主入口RequestMapping(/leave) ├── oa-file/ # 文件服务模块上传/下载/预览 │ └── src/main/java/com/oa/file/ │ ├── service/ # UploadService核心见2.2节详解 │ └── strategy/ # LocalFileStorageStrategy / MinIOFileStorageStrategy ├── oa-report/ # 报表模块PDF生成Excel导出 │ └── src/main/java/com/oa/report/ │ ├── pdf/ # PdfGeneratoriText 7.2.5实现带公章水印 │ └── excel/ # ExcelExporterApache POI 5.2.4 ├── oa-scheduler/ # 定时任务模块归档、清理、提醒 │ └── src/main/java/com/oa/scheduler/ │ └── task/ # ArchiveTask每日02:00执行已归档流程PDF生成 └── docker-compose.yml # MySQL 8.0 Redis 7.0 Nginx反向代理静态资源为什么选这个组合Spring Boot 2.7.x避开3.x的Jakarta EE迁移坑MyBatis-Plus 3.5.x兼容性完美Flowable 6.7.2对Spring Boot 2.7的AutoConfiguration支持最稳Flowable而非Activiti轻量jar包仅2.1MB、社区活跃、REST API开箱即用且ProcessEngineConfiguration可编程配置比XML硬编码灵活十倍iText 7.2.5绕过iText 5的AGPL许可证风险水印实现用PdfCanvas直接绘图不依赖第三方模板引擎。2.2 文件上传模块深度拆解UploadService如何扛住100MB大附件oa-file模块的UploadService是全系统最常被调用的组件。它不玩“分片上传”玄学但用三层策略解决真实痛点Service public class UploadService { Autowired private FileStorageStrategy fileStorageStrategy; // 策略模式运行时决定存本地还是MinIO Value(${oa.file.max-size:104857600}) // 默认100MByml可覆盖 private long maxFileSize; public UploadResult upload(MultipartFile file, String businessType) { // 1. 基础校验大小、类型、空文件 if (file.getSize() maxFileSize) { throw new BusinessException(文件大小超过 maxFileSize / 1024 / 1024 MB限制); } if (file.isEmpty()) { throw new BusinessException(上传文件不能为空); } // 2. 业务类型路由LEAVE请假单附件EXPENSE报销单附件 String storagePath generateStoragePath(businessType, file.getOriginalFilename()); // 3. 调用策略实现类Local or MinIO String storedUrl fileStorageStrategy.store(file, storagePath); // 4. 写入数据库记录原始名、存储路径、业务类型、MD5防重复上传 FileRecord record new FileRecord(); record.setOriginalName(file.getOriginalFilename()); record.setStoredPath(storedUrl); record.setBusinessType(businessType); record.setMd5(calculateMd5(file)); fileRecordMapper.insert(record); return UploadResult.success(storedUrl, record.getId()); } private String generateStoragePath(String businessType, String originalName) { // 格式/leaves/2024/05/20/LEAVE_20240520_123456789.pdf String datePath LocalDate.now().toString().replace(-, /); String prefix businessType.toUpperCase() _ LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); String extension StringUtils.getFilenameExtension(originalName); return String.format(%s/%s/%s%s, businessType.toLowerCase(), datePath, prefix, extension); } }关键参数说明maxFileSize在application.yml中配置避免Tomcat默认的10MB限制导致大附件直接400storagePath生成逻辑按业务类型日期分层杜绝海量文件挤爆单目录Linux ext4单目录文件数超2万性能骤降MD5校验calculateMd5()用DigestUtils.md5Hex(InputStream)实现相同文件秒传节省存储FileStorageStrategy接口定义store()和load()方法LocalFileStorageStrategy用Files.copy()写磁盘MinIOFileStorageStrategy用minioClient.putObject()切换只需改PrimaryBean。2.3 流程引擎集成Flowable如何用10行代码启动一个请假审批流oa-core模块的ProcessService封装了Flowable最常用操作。以“员工提交请假单”为例核心逻辑只有10行Service public class ProcessService { Autowired private RuntimeService runtimeService; // Flowable运行时服务 Autowired private TaskService taskService; // Flowable任务服务 public ProcessInstance startLeaveProcess(Long employeeId, LeaveRequest request) { // 1. 构建流程变量员工ID、请假天数、事由 MapString, Object variables new HashMap(); variables.put(employeeId, employeeId); variables.put(days, request.getDays()); variables.put(reason, request.getReason()); // 2. 启动流程实例key对应BPMN文件idleave-process // 注意BPMN文件必须放在src/main/resources/processes/下Flowable自动扫描 ProcessInstance instance runtimeService.startProcessInstanceByKey( leave-process, // BPMN文件中的process id variables ); // 3. 关联业务数据请假单ID绑定到流程实例 runtimeService.setVariable(instance.getId(), leaveId, request.getId()); return instance; } }BPMN文件关键点文件路径src/main/resources/processes/leave-process.bpmn20.xmlstartEvent后接userTask部门经理审批userTask的assignee设为${employeeId}实际运行时从变量取值exclusiveGateway判断天数3则加HR终审节点否则直通归档所有节点id需唯一name用于前端展示如name部门经理审批。3. 快速启动指南从解压到看到“我的请假单”页面只要7步注意本指南基于Windows/macOS/Linux通用命令跳过IDE配置IntelliJ IDEA或VS Code均可聚焦最小可行路径。3.1 环境准备JDK 11 MySQL 8.0 Maven 3.8必须确认的版本java -version输出应为11.0.xJDK 11是Spring Boot 2.7.x官方要求mysql --version输出应为8.0.xMySQL 8.0才支持caching_sha2_password认证插件与application.yml中配置匹配mvn -v输出Maven 3.8低版本可能无法解析pom.xml中的dependencyManagement。安装验证命令# 检查Java版本重点看是否为11 java -version | head -1 # 检查MySQL连接假设root密码为123456 mysql -u root -p123456 -e SELECT VERSION(); # 检查Maven确保JAVA_HOME指向JDK 11 mvn -v | grep Java version3.2 数据库初始化执行SQL脚本创建表初始数据步骤解压源码包进入根目录找到sql/oa_init.sql若不存在则检查doc/或resources/sql/在MySQL中执行-- 创建数据库字符集必须为utf8mb4否则中文乱码 CREATE DATABASE IF NOT EXISTS oa_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 使用数据库 USE oa_db; -- 执行初始化脚本注意脚本内含DROP TABLE首次运行安全 SOURCE /path/to/your/Java开发OA自动化办公系统源码/sql/oa_init.sql;oa_init.sql关键内容t_leave_request请假单主表含status字段0待审批1已通过2已拒绝t_process_instanceFlowable流程实例关联表business_key存请假单IDt_sys_user用户表含dept_id部门ID用于审批人自动分配插入3条测试用户admin超级管理员、zhangsan员工、lisi部门经理。3.3 配置修改application.yml三处必改项打开oa-web/src/main/resources/application.yml修改以下三处其他保持默认spring: datasource: url: jdbc:mysql://localhost:3306/oa_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueuseSSLfalse username: root password: 123456 # 改为你MySQL的实际密码 # Flowable配置启用REST API方便前端调试 flowable: rest: enabled: true base-url: http://localhost:8080/flowable-rest # 文件存储路径若用本地存储 oa: file: storage-type: local # 或 minio local-base-path: /data/oa-files # Linux/macOS路径Windows写 D:/oa-files为什么这三处必改datasource.urlserverTimezoneAsia/Shanghai防止时间字段存入MySQL后差8小时flowable.rest.enabledtrue开启Flowable REST API访问http://localhost:8080/flowable-rest/engine可查流程定义local-base-path必须是绝对路径且程序有读写权限Linux需chmod 755 /data/oa-files。3.4 编译打包Maven命令一键构建在项目根目录含pom.xml的位置执行# 清理并编译所有模块跳过测试加速构建 mvn clean package -Dmaven.test.skiptrue # 查看生成的jar包位置 ls oa-web/target/oa-web-*.jar预期输出oa-web/target/oa-web-1.0.0.jar可执行jarSpring Boot内置Tomcat若报错Could not resolve dependencies检查Maven镜像是否配置阿里云~/.m2/settings.xml中mirror指向https://maven.aliyun.com/repository/public。3.5 启动服务一条命令跑起来# 启动oa-web模块默认端口8080 java -jar oa-web/target/oa-web-1.0.0.jar # 启动成功后控制台会打印 # Started OaWebApplication in X.XXX seconds (JVM running for Y.YYY) # Tomcat started on port(s): 8080 (http) with context path 验证服务浏览器访问http://localhost:8080/login输入测试账号用户名zhangsan密码123456登录后点击左侧菜单“请假管理” → “新建请假单”填写表单并提交切换账号lisi部门经理登录可在“待办事项”看到审批任务。4. 常见问题排查5个血泪经验总结省下你3小时debug时间4.1 现象登录后页面空白浏览器F12看到GET http://localhost:8080/css/bootstrap.min.css net::ERR_ABORTED 404原因oa-web/src/main/resources/static/下的CSS/JS文件未被Spring Boot静态资源处理器识别常见于pom.xml中packaging错误或static目录位置不对。解决确认static目录在src/main/resources/下不是src/main/webapp/检查pom.xml中oa-web模块的packaging必须是jar非warSpring Boot只对jar包的resources/static生效清理Maven缓存mvn clean后重试。4.2 现象提交请假单报错org.flowable.common.engine.api.FlowableObjectNotFoundException: no processes deployed with key leave-process原因Flowable未扫描到BPMN文件因src/main/resources/processes/路径名错误或BPMN文件未编译进jar。解决确认BPMN文件在oa-core/src/main/resources/processes/leave-process.bpmn20.xml检查oa-core/pom.xml是否有resources配置覆盖了默认资源路径启动时观察控制台日志应有Deploying process definition from resource...提示若无则BPMN未加载。4.3 现象上传附件后数据库t_file_record有记录但stored_path字段为空原因UploadService中fileStorageStrategy.store()抛异常但被静默吞掉常见于local-base-path目录无写权限或磁盘满。解决在UploadService.upload()方法开头加日志log.info(Uploading file: {} to {}, file.getOriginalFilename(), storagePath);检查local-base-path目录权限Linux用ls -ld /data/oa-files确保运行Java进程的用户有rwx查看java -jar启动日志末尾找Caused by:堆栈定位具体异常。4.4 现象审批任务列表为空但Flowable REST API返回有任务原因TaskService.createTaskQuery()未设置taskAssignee导致查询所有任务包括未分配的而前端只显示assignee匹配当前用户的任务。解决检查LeaveController.approvalList()方法确认调用taskService.createTaskQuery().taskAssignee(userId).list()若userId为空检查SecurityContext中Authentication是否正确注入AuthenticationPrincipal注解是否在Controller参数上。4.5 现象PDF生成失败日志报java.lang.NoClassDefFoundError: com/itextpdf/kernel/pdf/PdfWriter原因oa-report模块的pom.xml中iText依赖范围错误或Maven多模块依赖传递失效。解决检查oa-report/pom.xml确保iText依赖为compile范围非provideddependency groupIdcom.itextpdf/groupId artifactIdkernel/artifactId version7.2.5/version /dependency在根目录执行mvn dependency:tree | grep itext确认oa-report模块下有kernel、layout、pdfa三个jar若缺失强制刷新Mavenmvn clean compile -U-U强制更新快照。5. 核心模块二次开发给审批流加“抄送人”功能3步改造1个验证技巧从那以后我每次改流程相关功能都先跑一遍FlowableTest单元测试——它比Postman点10次接口更能暴露变量传递断层。5.1 需求分析为什么原流程缺“抄送”原请假流程只有assignee审批人但实际业务中员工提交后需同步通知HRBP抄送HRBP不审批但要知悉。Flowable原生不支持抄送需用ExecutionListener在流程启动时触发邮件/站内信。5.2 改造步骤3处代码1个SQLStep 1扩展请假单实体增加ccUserIds字段修改oa-core/src/main/java/com/oa/core/entity/LeaveRequest.javapublic class LeaveRequest extends BaseEntity { // ...原有字段 TableField(value cc_user_ids) // 对应数据库t_leave_request.cc_user_ids字段 private String ccUserIds; // 逗号分隔的用户ID如1001,1002 // getter/setter public String getCcUserIds() { return ccUserIds; } public void setCcUserIds(String ccUserIds) { this.ccUserIds ccUserIds; } }Step 2修改BPMN在startEvent添加ExecutionListener编辑oa-core/src/main/resources/processes/leave-process.bpmn20.xml在startEvent idstartevent1内添加bpmn:extensionElements flowable:executionListener eventstart classcom.oa.core.listener.CcNotificationListener / /bpmn:extensionElementsStep 3实现监听器发送抄送通知创建oa-core/src/main/java/com/oa/core/listener/CcNotificationListener.javaComponent public class CcNotificationListener implements ExecutionListener { Autowired private UserService userService; // 查询用户信息 Autowired private NotificationService notificationService; // 发送站内信 Override public void notify(DelegateExecution execution) throws Exception { // 1. 获取流程变量中的leaveId Long leaveId (Long) execution.getVariable(leaveId); // 2. 查询请假单详情含ccUserIds LeaveRequest leave leaveService.getById(leaveId); // 3. 解析ccUserIds并发送通知 if (StringUtils.isNotBlank(leave.getCcUserIds())) { String[] ccIds leave.getCcUserIds().split(,); for (String ccId : ccIds) { User user userService.getById(Long.valueOf(ccId.trim())); notificationService.sendInternalMsg( user.getId(), 您收到一份抄送员工 leave.getEmployeeName() 的请假申请, 点击查看/leave/detail/ leaveId ); } } } }SQL补充在oa_init.sql末尾追加字段ALTER TABLE t_leave_request ADD COLUMN cc_user_ids VARCHAR(255) COMMENT 抄送人ID逗号分隔;5.3 验证技巧用Flowable REST API实时观测流程变量改完代码别急着重启用REST API验证变量是否注入成功启动服务后用Postman发GET请求GET http://localhost:8080/flowable-rest/engine/default/process-instances?processDefinitionKeyleave-processsize1从返回JSON中找到最新流程实例的id如id:12345再发GETGET http://localhost:8080/flowable-rest/engine/default/process-instances/12345/variables检查返回中是否有ccUserIds:{value:1001,1002}——有则监听器已生效无则检查CcNotificationListener是否被Spring扫描到加Component且包在SpringBootApplication扫描路径下。希望帮到你。本文还有配套的精品资源点击获取