OSWorkflow 是 OpenSymphony 提供的輕量級工作流引擎,核心組件:
<osworkflow>
<persistence class="com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore">
<property key="datasource" value="jdbc/DefaultDS"/>
<!-- 序列生成策略 (MySQL 自增模擬) -->
<property key="step.sequence.increment"
value="INSERT INTO OS_STEPIDS (ID) values (null)"/>
<property key="step.sequence.retrieve"
value="SELECT count(ID) FROM OS_STEPIDS"/>
<property key="entry.sequence.increment"
value="INSERT INTO OS_ENTRYIDS (ID) values (null)"/>
<property key="entry.sequence.retrieve"
value="SELECT count(ID) FROM OS_ENTRYIDS"/>
<!-- 表/列映射 (必須與數據庫結構完全一致) -->
<property key="entry.table" value="OS_WFENTRY"/>
<property key="entry.id" value="ID"/>
<property key="entry.name" value="NAME"/>
<property key="entry.state" value="STATE"/>
<property key="history.table" value="OS_HISTORYSTEP"/>
<property key="current.table" value="OS_CURRENTSTEP"/>
<property key="historyPrev.table" value="OS_HISTORYSTEP_PREV"/>
<property key="currentPrev.table" value="OS_CURRENTSTEP_PREV"/>
<property key="step.id" value="ID"/>
<property key="step.entryId" value="ENTRY_ID"/>
<property key="step.stepId" value="STEP_ID"/>
<property key="step.actionId" value="ACTION_ID"/>
<property key="step.owner" value="OWNER"/>
<property key="step.caller" value="CALLER"/>
<property key="step.startDate" value="START_DATE"/>
<property key="step.finishDate" value="FINISH_DATE"/>
<property key="step.dueDate" value="DUE_DATE"/>
<property key="step.status" value="STATUS"/>
<property key="step.previousId" value="PREVIOUS_ID"/>
</persistence>
<factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory">
<property key="resource" value="workflows.xml"/>
</factory>
</osworkflow>
<propertysets>
<propertyset name="jdbc"
class="com.opensymphony.module.propertyset.database.JDBCPropertySet">
<arg name="datasource" value="java:comp/env/jdbc/DefaultDS"/>
<arg name="table.name" value="OS_PROPERTYENTRY"/>
<arg name="col.globalKey" value="GLOBAL_KEY"/>
<arg name="col.itemKey" value="ITEM_KEY"/>
<arg name="col.itemType" value="ITEM_TYPE"/>
<arg name="col.string" value="STRING_VALUE"/>
<arg name="col.date" value="DATE_VALUE"/>
<arg name="col.data" value="DATA_VALUE"/>
<arg name="col.float" value="FLOAT_VALUE"/>
<arg name="col.number" value="NUMBER_VALUE"/>
</propertyset>
</propertysets>
<workflows>
<workflow name="leave" type="resource" location="leave.xml"/>
</workflows>
<opensymphony-user>
<provider class="com.opensymphony.user.provider.jdbc.JDBCAccessProvider">
<property name="user.table">os_user</property>
<property name="group.table">os_group</property>
<property name="membership.table">os_membership</property>
<property name="user.name">username</property>
<property name="user.password">passwordhash</property>
<property name="group.name">groupname</property>
<property name="membership.userName">username</property>
<property name="membership.groupName">groupname</property>
<property name="datasource">java:comp/env/jdbc/DefaultDS</property>
</provider>
<!-- CredentialsProvider / ProfileProvider 同樣配置 -->
<authenticator class="com.opensymphony.user.authenticator.SmartAuthenticator"/>
</opensymphony-user>
<workflow>
<initial-actions>
<action id="1" name="提交申請">
<pre-functions>
<function type="class">
<arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status=" " status="申請中" step="1" owner="${caller}"/>
</results>
</action>
</initial-actions>
<steps>
<step id="1" name="申請中">
<actions>
<action id="2" name="批准">
<results>
<unconditional-result old-status="申請中" status="已批准" step="-1" owner="${caller}"/>
</results>
</action>
<action id="3" name="駁回">
<results>
<unconditional-result old-status="申請中" status="已駁回" step="-1" owner="${caller}"/>
</results>
</action>
</actions>
</step>
</steps>
</workflow>
| XML 元素 | 業務含義 | 關鍵屬性 |
|---|---|---|
initial-actions | 流程啟動入口,至少一個 | id 唯一標識 |
action | 導致狀態流轉的動作 | id 全局唯一、name 顯示名 |
step | 流程節點/狀態位置 (非動作) | id、name |
result | 動作執行後的結果 | conditional-result (條件) / unconditional-result (默認) |
status | 動作執行時的流程狀態 | |
old-status | 動作執行後的新狀態 | |
caller | 調用者 (當前用戶),預函數 Caller 自動注入 | 記錄於 OS_HISTORYSTEP.CALLER |
pre-functions | 動作執行前邏輯 (如權限檢查、變量準備) | |
post-functions | 動作執行後邏輯 (如發送通知、更新業務表) |
public class LeaveWFBO {
// 啟動流程:提交申請
public long send(String employee) {
Workflow workflow = new BasicWorkflow("peidw"); // caller = 員工ID
workflow.setConfiguration(new DefaultConfiguration());
long workflowId = -1;
try {
workflowId = workflow.initialize("leave", 0, null); // 初始化流程實例
workflow.doAction(workflowId, 1, null); // 執行 action 1 (提交)
} catch (Exception e) { e.printStackTrace(); }
return workflowId; // 返回流程實例 ID
}
// 處理審批:批准/駁回
public void allow(long workflowId, int actionId) { // actionId: 2=批准, 3=駁回
Workflow workflow = new BasicWorkflow("peidw");
workflow.setConfiguration(new DefaultConfiguration());
try {
workflow.doAction(workflowId, actionId, null);
} catch (Exception e) { e.printStackTrace(); }
}
}
new BasicWorkflow(caller):創建引擎實例,綁定調用者身份workflow.initialize("leave", 0, null):按名稱創建流程實例,返回 workflowId (OS_WFENTRY.ID)workflow.doAction(wfId, actionId, transientVars):執行指定動作,推進流程transientVars (Map) 傳遞臨時變量,供條件判斷/函數使用OS_STEPIDS/OS_ENTRYIDS 必須預先插入至少一行 (INSERT INTO OS_STEPIDS VALUES (0)),否則 SELECT count(ID) 返回 0 導致 ID 衝突value 必須與建表語句完全一致${caller} 變量無法解析,導致 owner 為空java:comp/env/jdbc/DefaultDS (Web 容器) vs jdbc/DefaultDS (獨立應用),需區分環境OSWorkflow 以XML 定義流程、可插拔持久化、輕量級 API 為特點,適合中小型業務流程自動化。核心掌握點:
step (狀態位置) 與 action (流轉動作) 的區別result 類型:條件 vs 無條件,old-status/status 驅動狀態機Caller 預函數注入調用者,實現審批人記錄initialize → doAction → query@Transactional / EJB CMT)通過 MySQL 實戰驗證的完整配置集,可直接作為項目啟動模板。