OA 印章管理系统实战(二):底座搭建——若依 + Camunda 7.19 整合实录

调研文档写的是 SpringBoot 2.7 + Camunda 7.19 + MyBatis-Plus 3.5.x。但当我克隆了 camunda-study-demo(Gitee 明珠科技,34 Stars)整合进若依骨架时,发现三个意外。

事故现场:调研偏差 + 骨架版本意外 + 一个没人写的 Xerces 坑
意外一:SpringBoot 版本不是 2.7,是 2.5.15。 若依 3.8.6 的根 pom.xml 继承的 spring-boot-dependencies 写死了 2.5.15:
<!-- ruoyi/pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.15</version>
</dependency>
调研文档写 2.7 是我自己的记忆偏差——Camunda 7.19 官方声明支持 SpringBoot 2.3 到 3.x,2.5.15 完全在支持范围内,但版本号对不上意味着我之前脑补的"2.7 的新特性"(比如自动配置的条件注解变化)根本不存在。
意外二:没有 MyBatis-Plus,只有原生 MyBatis。 依赖树里拉出来的是:
ruoyi-common → pagehelper-spring-boot-starter:1.4.6
→ mybatis-spring-boot-starter:2.2.2
→ mybatis:3.5.9
没有 com.baomidou:mybatis-plus-*。ruoyi-oa 的 Mapper 是纯接口 + XML,没有 extends BaseMapper——这意味着我写的 OaSealApplyMapper 六个方法全是手写的,没有用到 MyBatis-Plus 的通用 CRUD。
意外三:ruoyi-admin/pom.xml 里有一行注释,我当时没注意。 真正让我花了 3 小时排查的,不是依赖冲突(Camunda starter 本身不带 MyBatis,根本没冲突),而是另一行:
<!-- JDK17下Camunda解析BPMN XSD需要Xerces(规避src-resolve校验失败) -->
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
这不是我加的,是 camunda-study-demo 的原作者加的。注释说的"JDK17 下 Camunda 解析 BPMN XSD 需要 Xerces"——我当时没理解,直到自己跑起来看到 ENGINE-09005 Could not parse BPMN process 才翻回来看:JDK 17 内置的 Xerces 有个 src-resolve 校验限制,Camunda 7.19 的 BPMN20.xsd 里有相对 import,JDK 17 内置 Xerces 默认拒绝;但用 XercesImpl 2.12.2 替换后,它的 src-resolve 行为更宽松,BPMN 就能正常解析。
三个意外,没有一个是 Camunda 和若依的依赖冲突——我之前脑补的"Camunda 自带 MyBatis 和若依 MyBatis-Plus 打架"根本不存在。Camunda starter 在 ruoyi-wowkflow/pom.xml 里就是干净的一行,没有任何 exclusion:
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter</artifactId>
</dependency>
排查:为什么 pom.xml 比调研文档写的简单得多?
我花了一天跑 mvn dependency:tree -Dincludes=org.camunda.bpm,org.mybatis,org.springframework.boot,结果:
com.ruoyi:ruoyi-admin:jar:3.8.6
├── org.springframework.boot:spring-boot-devtools:2.5.15
├── org.springframework.boot:spring-boot-starter-web:2.5.15
│ ├── spring-boot-starter:2.5.15
│ ├── spring-boot-starter-json:2.5.15
│ └── spring-boot-starter-tomcat:2.5.15
├── ruoyi-framework → spring-boot-starter-aop:2.5.15
├── ruoyi-quartz → spring-boot-starter-security:2.5.15
├── ruoyi-common → pagehelper-spring-boot-starter:1.4.6
│ └── mybatis-spring-boot-starter:2.2.2
│ └── mybatis:3.5.9
├── ruoyi-wowkflow → camunda-bpm-spring-boot-starter:7.19.0
│ └── camunda-engine-spring:7.19.0
│ └── camunda-engine:7.19.0
└── ruoyi-oa(自研)
没有任何 excluded 节点。 没有 <exclusion> 标签。没有依赖冲突警告。
为什么 Camunda starter 不会和 MyBatis 冲突?因为 Camunda starter 根本不带 MyBatis。Camunda 7.19 的持久层走的是 JPA + Hibernate(或者它自己的 MyBatis 实现,但默认不引),若依的 MyBatis 是独立的 mybatis-spring-boot-starter,两者各管各的数据源和 ORM,互不干扰。
那 pom.xml 里为什么没有 MyBatis-Plus?因为若依 3.8.6 选择了 pagehelper-spring-boot-starter + dynamic-datasource-spring-boot-starter 的组合——pagehelper 做分页、dynamic-datasource 做多数据源切换,不需要 MyBatis-Plus 也能跑。而我在 ruoyi-oa 里写 Mapper 接口时,干脆按若依的原生 MyBatis 风格写了六个手写方法,没引入 MyBatis-Plus。
底层原理:Xerces 的 src-resolve 是什么?
JDK 内置的 XML 解析器是 Xerces-J。从 JDK 13 开始,Xerces 引入了一个新特性叫 src-resolve——它是 XSD schema 验证的一部分,用来防止 XXE 攻击。具体规则:当一个 XSD 文件里出现 <xsd:import schemaLocation="Semantic/BPMNDI.xsd"> 这种相对路径引用时,JDK 13+ 内置 Xerces 默认会校验这个相对路径是否"安全"。
问题在于 Camunda 7.19 的 BPMN20.xsd 是这样的:
<!-- camunda-engine-7.19.0.jar!/org/camunda/bpm/model/bpmn/schema/BPMN20.xsd -->
<xsd:import namespace="http://www.omg.org/spec/BPMN/20100524/DI"
schemaLocation="Semantic/BPMNDI.xsd"/>
schemaLocation="Semantic/BPMNDI.xsd" 是相对于 BPMN20.xsd 所在位置的路径。但 JDK 17 内置 Xerces 的 src-resolve 校验器看到这个相对路径,会尝试在 classpath 里找 Semantic/BPMNDI.xsd——但 Camunda 的 XSD 文件在 jar 内部,classpath 扫描可能找不到,然后校验器就会静默拒绝加载这个 schema。
schema 加载失败 → Camunda 解析 BPMN 时找不到 BPMN 2.0 规范 → ENGINE-09005 Could not parse BPMN process。
解决方案:用 XercesImpl 2.12.2 替换 JDK 内置的。 XercesImpl 2.12.2 的 src-resolve 行为更宽松——它会先尝试 JDK 内置的 classpath 资源查找,找不到再用自己的 URLClassLoader 兜底。加了 xercesImpl:2.12.2 后,SpringBoot 的 XMLInputFactory / SAXParserFactory 会自动发现这个新实现并优先使用。
为什么不是 fat jar 问题? 这是我一开始搞混的两个不同的坑:
-
JDK 17 + Xerces src-resolve:
mvn spring-boot:run(普通 classpath)也会触发,解决是加 xercesImpl -
fat jar + BPMN XSD 相对 import:
java -jar(nested jar classloader)才触发,解决是改用 classpath 启动
正确姿势:pom.xml 实际需要什么?
ruoyi-wowkflow/pom.xml(Camunda 整合层):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-bom</artifactId>
<version>7.19.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter</artifactId>
<!-- 一行搞定,无 exclusion -->
</dependency>
</dependencies>
ruoyi-admin/pom.xml(应用入口,关键补充):
<!-- JDK17下Camunda解析BPMN XSD需要Xerces(规避src-resolve校验失败) -->
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
application.yml(Camunda 配置段,关键三行):
camunda:
bpm:
# fat jar 环境下 autoDeployResources 扫描 nested jar 会失败,
# 改用 OaFlowBootstrap 手动部署(第 03 章详写)
auto-deployment-enabled: false
database:
schema-update: true
# 关掉 Camunda entity 的 debug 日志(生产必须关!)
logging:
level:
org.camunda.bpm.engine.impl.persistence.entity: warn
数据说话:三种启动方式对比
启动方式
classloader
Xerces 实现
BPMN 解析
Camunda 启动
耗时
mvn spring-boot:run
URLClassLoader(平铺)
XercesImpl 2.12.2(显式引入)
✅ 142ms
✅ Process Engine default created
13.5s
java -jar ruoyi-admin.jar
LaunchedURLClassLoader(nested jar)
XercesImpl 2.12.2
❌ ENGINE-09005
❌ 秒挂
—
mvn spring-boot:run + 不加 XercesImpl
URLClassLoader
JDK 17 内置 Xerces
❌ src-resolve 拒绝
❌ 秒挂
—
三行对比就把两个坑的边界划清了:
-
第二行 vs 第一行 → fat jar 的 nested classloader 问题(第 03 章详写)
-
第三行 vs 第一行 → JDK 17 Xerces src-resolve 问题(本章)
没有 MyBatis 冲突的证据: mvn compile 无 exclusion 无警告通过。依赖树里 Camunda 7.19.0 不带 MyBatis,若依 2.5.15 的 mybatis-spring-boot-starter:2.2.2 完全独立。
面试怎么答:整合 Camunda 和 SpringBoot 要注意什么?
"我整合的是若依 3.8.6(SpringBoot 2.5.15)+ Camunda 7.19.0。核心是三个点:
第一,依赖上没什么坑。 Camunda 7.19 的 spring-boot-starter 一行就能引入,因为它不带 MyBatis——Camunda 持久层走 JPA/Hibernate 或自己的实现,若依用的原生 MyBatis 互不干扰。我最开始脑补会有 MyBatis 冲突,跑了 mvn dependency:tree 才发现根本没冲突,也不需要加 exclusion。
第二,Xerces 补充依赖是隐藏要求。 JDK 17 内置 Xerces 有个 src-resolve 校验机制,会拒绝 Camunda BPMN20.xsd 里的相对 import,导致 BPMN 解析秒挂。解决方案是显式引入 xercesImpl:2.12.2 替换掉内置的——这是 camunda-study-demo 原作者踩过的坑,pom.xml 里写了注释。
第三,auto-deployment 必须关掉。 若依的 fat jar 打包后,Camunda 的 autoDeployResources 扫描 nested jar 找不到 BPMN 文件,所以改成 auto-deployment-enabled=false,自己写一个 OaFlowBootstrap(ApplicationRunner)用 repositoryService.createDeployment().addString("seal_approve.bpmn", xml).deploy() 手动部署。启动时还做了幂等检查——如果 pearl_flow_model 里已有 def_key=seal_approve 的记录就跳过。
整合后我跑了三种启动方式做对比:classpath 模式(mvn spring-boot:run)能通,fat jar 模式不行(nested classloader),不加 Xerces 也不行。这个对比结论在部署时很重要——生产环境不能直接 java -jar,要用 classpath 或 exploded 模式启动。"
落地清单
pom.xml 关键依赖清单:
pom
依赖
版本
说明
ruoyi(根)
spring-boot-dependencies
2.5.15
若依骨架自带,不是 2.7
ruoyi-wowkflow
camunda-bom
7.19.0
BOM 版本管理
ruoyi-wowkflow
camunda-bpm-spring-boot-starter
7.19.0
一行搞定,无 exclusion
ruoyi-admin
xercesImpl
2.12.2
JDK 17 + Camunda 7.19 必须
application.yml 必须改的两处:
camunda:
bpm:
auto-deployment-enabled: false # 关掉自动部署,手动 addString
database:
schema-update: true # 首次启动自动建 ACT_* 表
logging:
level:
org.camunda.bpm.engine.impl.persistence.entity: warn # 生产关 debug
下一章第 03 章才是真正的噩梦——fat jar 下 Camunda BPMN 全炸。
