Activiti integration
TL;DR — Activiti is wired, the engine runs, no traffic flows through it. Engine bootstrapped,
act_*schema provisioned at 6.0.0.4, BPMN modeler reachable. But every workflow table is 0 rows: no BPMN, no procdefs, no instances, no tasks. Nogdsmodule.bCheck=1. Nogdsmoduleflowlink. The approval button users see (/business/doExamine) bypasses Activiti entirely and just UPDATEsbCheck=1via SQL — see Two approval paths below.
This page documents what's actually wired (concrete classes, URLs, engine state) and what would have to be true for it to do anything.
Two approval paths
xly ships two parallel approval mechanisms. They look similar from the UI but go through completely different code:
| Path | Triggered by | Backend | Activiti involvement |
|---|---|---|---|
| Simple "approve" toggle | The "审核" button on a single-row form |
POST /business/doExamine → BusinessBaseController.java:384-391 → BusinessBaseServiceImpl.doExamine() → ExamineServiceImpl (xlyBusinessService). The service runs an UPDATE that flips bCheck = 1 (and writes audit fields). |
None. grep confirms ExamineServiceImpl calls neither runtimeService, taskService, processService, nor any other Activiti API. The bCheck flag is xly's own boolean, owned by BusinessBaseServiceImpl. Used widely as a list filter (SalesOrderServiceImpl and friends do WHERE bCheck = 1 on every "show approved-only" query). |
| Multi-step BPMN workflow | A user submits a row whose module has bCheck = 1 AND a populated gdsmoduleflow row pointing at a deployed act_re_procdef
|
ProcessServiceImpl.submitApply() → runtimeService.startProcessInstanceByKey(...). Subsequent approvers act through CurrencyFlowController.complete(...) → taskService.complete(). xly mirrors state in biz_flow + biz_todo_item. |
Full Activiti. Requires a deployed BPMN (in act_re_procdef), an active process instance (in act_ru_*), and an assigned task (act_ru_task). |
In this dev DB, path 1 is the only path that runs. Path 2 has zero
configuration anywhere — no BPMN deployed, no gdsmoduleflow row, no
gdsmodule.bCheck=1 modules. So when a user clicks 审核 today, the
record gets approved via the simple-toggle path and Activiti is not
involved.
Why the second path even exists: a customer that does need a real
multi-step approval (warehouse → finance → GM, with reassignment and
delegation) gets it by deploying a BPMN through the modeler and
linking modules via gdsmoduleflow. That activates path 2 for those
modules; path 1 still handles everything else.
Activiti is wired — engine ON
Despite the dev DB being idle, the engine boots with xlyEntry:
-
xlyFlow/build.gradle:15pullsorg.activiti:activiti-spring-boot-starter-rest-api:6.0.0. That starter transitively pullsactiviti-spring-boot-starter, which triggers Spring Boot'sProcessEngineAutoConfigurationto create aSpringProcessEngineConfigurationbean. -
xlyEntry/build.gradleincludesxlyFlowasapi project(':xlyFlow'), so the starter is on the runtime classpath of thexlyEntryWAR. -
xlyEntry/.../EntryApplicationBoot.java:23-24excludes onlyorg.activiti.spring.boot.SecurityAutoConfiguration(the REST-endpoint security adapter) and Spring's ownSecurityAutoConfiguration. Activiti's main engine auto-config is NOT excluded → the engine starts. -
xlyFlow/.../activiti/config/ActivitiConfig.javais a@Configuration implements ProcessEngineConfigurationConfigurerwhose only job is to set Chinese-friendly fonts on the diagram generator (宋体for activity / annotation / label fonts) and install a customICustomProcessDiagramGenerator. -
xlyApi'sApiApplicationBootdoes NOT exclude Activiti either, but xlyApi doesn't include xlyFlow as a dep, so xlyApi has the engine'sorg.activiti.engine.identity.Userclass on classpath (used only byIdGen.javafor crypto utilities) but no Activiti auto-config kicks in there.
The 24 base act_* tables you see in the live schema are created by
the engine's auto-DDL on first boot.
Two Activiti versions on the classpath
| Module | Version | Notes |
|---|---|---|
xlyPersist, xlyApi
|
org.activiti:activiti-engine:5.17.0 |
Older 5.x line — declared in both modules. Vestigial — the runtime engine in xlyEntry's WAR is the 6.0 one pulled by xlyFlow's starter. The 5.17 declarations are dead weight on the classpath. |
xlyFlow |
org.activiti:activiti-spring-boot-starter-rest-api:6.0.0, activiti-json-converter:6.0.0
|
Newer 6.0 line — this is what runs. |
A maintainer cleaning up should drop 5.17.0 from xlyPersist and
xlyApi's build.gradle. Verified: only IdGen.java in each of
those modules touches org.activiti.engine.identity.User, and the
type signature is satisfied by the 6.0 engine too — removal is safe.
What's actually invoked from code
The 154 Java files under xlyFlow/src/main/java/com/xly/activiti/
plus the modeler subpackage are real call sites. Selected anchors:
| Activity | Class : line | Activiti API used |
|---|---|---|
| Start a process instance |
ProcessServiceImpl.submitApply() :107 |
runtimeService.startProcessInstanceByKey(module, businessKey, variables) |
| Complete a task |
CurrencyFlowController.complete(...) :167 / :200; WechatFlowPostThread :132 |
processService.complete(taskId, ...) → taskService.complete()
|
| Query active tasks |
CurrencyFlowController :409, :480 |
taskService.createTaskQuery().active().list() |
| Query running instances |
CurrencyFlowController :485, :659 |
runtimeService.createProcessInstanceQuery() |
| Save a model in the modeler |
ModelerController.create() :122 |
repositoryService.saveModel() + addModelEditorSource()
|
| Deploy a BPMN at runtime |
ModelerController.deploy() :147 |
repositoryService.createDeployment().addString(name, bpmnXml).deploy() |
| List process definitions |
ProcessDefinitionController :135 |
repositoryService.createProcessDefinitionQuery() |
| Read engine config |
ProcessActController :281 |
ProcessEngines.getDefaultProcessEngine() |
| Bridge xly users into Activiti identity |
act_id_user / act_id_group / act_id_membership are views projecting xly's sftlogininfo* schema |
xly does not write to Activiti's identity tables; the views fake them |
URLs the modeler exposes (xlyFlow controllers, on xlyEntry's port)
Because xlyFlow is consumed as a library by xlyEntry (api project(':xlyFlow')),
all xlyFlow controllers compile into the xlyEntry WAR and serve at
xlyEntry's context-path (/xlyEntry). Notable URLs:
-
POST /xlyEntry/modeler/model/{modelId}/save— save BPMN-modeler XML -
GET /xlyEntry/modeler/model/{modelId}/json— load model for editor -
GET /xlyEntry/modeler/editor/stencilset— modeler stencil definitions -
GET /xlyEntry/modeler/create//modeler/deploy/{modelId}— create + deploy -
POST /xlyEntry/complete/{taskId}/{sBrandsId}/{sSubsidiaryId}/{sUserId}— complete a task (CurrencyFlowController) -
POST /xlyEntry/completeerp/{sBrandsId}/{sSubsidiaryId}/{sUserName}— ERP-side completion variant
These are not catalogued on the Internal API page because they're rarely-touched workflow surface; treat the source as authoritative.
What CheckFlowController.java actually contains
This is a wiki-internal correction worth flagging: the class file
exists at xlyEntry/src/main/java/com/xly/web/businessweb/CheckFlowController.java
but its body is 22 lines, zero handler methods — just a
@RestController @RequestMapping(value="/checkflow") shell with no
content. Earlier versions of this wiki described /checkflow/* as
"Activiti workflow surface (approve / reject / view)"; that is not
what the file currently contains. /checkflow/* returns 404 for
any sub-path on the live system. The actual approve/reject/view
URLs come from CurrencyFlowController and friends listed above.
The act_* schema state (this dev DB)
| Table | Rows | Meaning when populated |
|---|---|---|
act_re_model |
0 | BPMN models saved in the modeler |
act_re_procdef |
0 | Deployed process definitions |
act_ru_task |
0 | Active (waiting) tasks |
act_hi_procinst |
0 | Historical process instances |
act_id_user / act_id_group / act_id_membership
|
(views) | Project xly's sftlogininfo* users into Activiti identity shape |
gdsmoduleflow |
0 | xly's link from gdsmodule to a process definition |
biz_flow |
0 | xly's per-document flow state |
biz_todo_item |
0 | Pending approver tasks (xly wrapper, not Activiti's act_ru_task) |
biz_todo_copyto |
0 | CC'd parties on a flow |
So Activiti is stone-cold idle. Engine running, schemas ready, no traffic.
What would make it move
For a flow to actually run, in roughly this order:
- An engineer or PM opens the modeler UI (modeler static assets at
xlyFlow/src/main/resources/static/modeler/, served via the/modeler/*endpoints). They draw a BPMN, save it (act_re_modelpopulated). - They click Deploy in the modeler →
ModelerController.deploy()callsrepositoryService.createDeployment().addString(name, bpmnXml).deploy()→act_re_procdefpopulated. - A
gdsmodulerow is taggedbCheck = 1and a row ingdsmoduleflowlinks the module to the deployedact_re_procdef.KEY_. - When a user saves a row on that module, the save service detects
bCheck = 1and callsProcessServiceImpl.submitApply(applyUserId, businessKey, itemName, itemContent, module, variables). That firesruntimeService.startProcessInstanceByKey(module, businessKey, variables)→act_ru_*tables populate,biz_flow+biz_todo_itemget xly-side rows. - Approvers see pending tasks in their FROUNT inbox (probably the
"审批" tab, separate from KPI Work Center). They click 通过/驳回 →
CurrencyFlowController.complete()→taskService.complete(). - When the proc instance reaches
endEvent, the row'sbChecktransitions; downstream queries that filter onbCheck = 1start seeing it.
Why xly bothered with Activiti at all
The codebase has its own biz_flow / biz_todo_item tables that
could implement a hand-rolled approval system. The decision to put
Activiti behind them buys:
- Standard BPMN modeling (the JS modeler pulls the same stencilset as Activiti Explorer).
- Free state-machine semantics — the engine handles "task A done → task B available" without xly maintaining the FSM in SQL.
- Diagram rendering (the page-as-PNG in
ProcessActController).
The cost: a second engine running in the JVM, a second DB schema with
its own DDL drift, a second authentication surface (which xly papers
over via the act_id_* views).
What this page is not
- A Slice 7 substitute. Slice 7 (deferred) would document an end-to-end traced flow against a deployment that actually runs one.
- A modeler tutorial. The modeler comes from the Activiti project; xly embeds it as static assets without modification.
- A migration plan from Activiti to anything else. That would be a larger architectural decision, not a wiki finding.