Jeecg-Boot免费版集成Activiti 6工作流实战指南在开源低代码平台Jeecg-Boot的实际应用中工作流引擎的缺失常常成为项目落地的瓶颈。本文将带你从零开始通过源码级改造将Activiti 6深度集成到Jeecg-Boot免费版中特别针对单租户场景下的多租户适配、前后端联调等核心痛点提供解决方案。1. 环境准备与基础配置1.1 依赖管理首先在pom.xml中添加Activiti核心依赖注意版本兼容性dependency groupIdorg.activiti/groupId artifactIdactiviti-spring-boot-starter/artifactId version6.0.0/version /dependency dependency groupIdorg.activiti/groupId artifactIdactiviti-modeler/artifactId version6.0.0/version /dependency注意Jeecg-Boot默认使用MyBatis-Plus 3.4.0与Activiti 6.0.0存在SQL语法兼容问题建议添加如下配置解决mybatis-plus.global-config.db-config.column-format1.2 数据库初始化执行以下SQL创建Activiti基础表结构-- 使用Jeecg-Boot的DataSource自动建表 spring.activiti.database-schema-updatetrue spring.activiti.history-levelaudit常见问题排查表问题现象可能原因解决方案表前缀不生效MyBatis-Plus拦截器冲突禁用MP的SQL解析器历史表未创建history-level配置错误设置为full或audit流程定义加载失败字符集不匹配检查MySQL的utf8mb4配置2. 多租户模式适配改造2.1 租户ID自动注入创建自定义的ActivityTenantIdHandler实现TenantIdHandler接口public class ActivityTenantIdHandler implements TenantIdHandler { Override public String getCurrentTenantId() { // 从Jeecg-Boot的Token中提取租户ID return TokenUtils.getTenantId(); } }在配置类中注册处理器Bean public SpringProcessEngineConfiguration processEngineConfiguration( DataSource dataSource, PlatformTransactionManager transactionManager) { SpringProcessEngineConfiguration config new SpringProcessEngineConfiguration(); config.setTenantIdHandler(new ActivityTenantIdHandler()); // 其他配置... return config; }2.2 流程实例隔离方案针对单租户需求需要重写以下关键类CustomUserEntityManager对接Jeecg用户体系CustomGroupEntityManager处理部门映射CustomRuntimeService封装流程启动逻辑关键改造点代码示例public class CustomRuntimeService extends RuntimeServiceImpl { Override public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, MapString, Object variables) { variables.put(tenantId, TenantContext.getTenant()); return super.startProcessInstanceByKey( processDefinitionKey _ TenantContext.getTenant(), businessKey, variables ); } }3. 前后端深度集成3.1 前端页面嵌入方案在src/views/modules下新建流程管理模块template div classjeecg-container a-tabs a-tab-pane key1 tab流程设计 iframe :srcmodelerUrl stylewidth:100%;height:calc(100vh - 180px) / /a-tab-pane /a-tabs /div /template script export default { data() { return { modelerUrl: ${window._CONFIG[domianURL]}/activiti/modeler.html?token${this.$store.getters.token} } } } /script提示需要配置Nginx解决跨域问题location /activiti { proxy_pass http://localhost:8080/activiti; add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Credentials true; }3.2 接口安全改造在SecurityConfig中添加白名单Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers( /activiti/**, /modeler.html, /editor-app/** ).permitAll() // 其他配置... }Token传递拦截器示例public class ActivitiTokenInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token request.getParameter(token); if(StringUtils.isNotBlank(token)){ TokenUtils.setToken(token); } return true; } }4. 业务场景实战案例4.1 请假流程完整实现流程定义设计使用BPMN设计包含【提交】【部门审批】【HR备案】三个节点设置表单属性activiti:formProperty idleaveDays name请假天数 typelong requiredtrue/业务表关联TableName(oa_leave) public class LeaveApply extends BaseEntity { TableField(process_instance_id) private String processInstanceId; // 其他字段... }流程启动控制器PostMapping(/start) public Result? startProcess(RequestBody LeaveApply leave) { // 业务数据入库 leaveService.save(leave); // 启动流程 runtimeService.startProcessInstanceByKey( leave_process, leave.getId().toString(), Map.of(applyUser, getCurrentUsername(), days, leave.getDays()) ); return Result.ok(); }4.2 审批节点自动分配实现动态任务分配策略public class LeaveTaskAssignee implements TaskAssigneeCalculator { Override public String calculateAssignee(DelegateTask task) { String eventName task.getEventName(); if (create.equals(eventName)) { // 部门审批环节自动分配 if (dept_approve.equals(task.getTaskDefinitionKey())) { return userService.getDeptManager( TaskUtils.getVariable(task, applyUser) ); } } return null; } }在流程定义中引用userTask iddept_approve name部门审批 extensionElements activiti:taskListener eventcreate classcom.jeecg.activiti.LeaveTaskAssignee/ /extensionElements /userTask5. 性能优化与生产建议5.1 数据库连接池配置推荐使用HikariCP并调整以下参数spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.minimum-idle5 spring.datasource.hikari.idle-timeout30000 spring.activiti.async-executor-activatetrue5.2 历史数据归档策略创建定时任务清理历史数据Scheduled(cron 0 0 2 * * ?) public void archiveHistoricData() { historyService.createHistoricProcessInstanceQuery() .finished() .list() .forEach(instance - { // 归档到MongoDB mongoTemplate.save(instance, historic_process); // 删除关系型数据库记录 historyService.deleteHistoricProcessInstance(instance.getId()); }); }5.3 缓存优化方案自定义流程定义缓存Bean public ProcessDefinitionCache processDefinitionCache() { return new CustomProcessDefinitionCache() { Override protected ProcessDefinitionEntity getProcessDefinition(String processDefinitionId) { // 结合Redis实现二级缓存 String redisKey activiti:pd: processDefinitionId; ProcessDefinitionEntity pd redisTemplate.opsForValue().get(redisKey); if(pd null) { pd super.getProcessDefinition(processDefinitionId); redisTemplate.opsForValue().set( redisKey, pd, 1, TimeUnit.HOURS ); } return pd; } }; }