有了前面幾章,我們肯定有一定的困惑,activiti如何與實際業務整合,比如一條采購單,如何跟一個流程實例互相關聯起來?
這里就需要使用到activiti啟動流程實例時設置一個流程實例的businessKey(一般存儲我們一條采購單的id)
1,啟動流程實例設置其businessKey
/** * 啟動一個流程實例,設置其業務id */ @Test public void startProInsWithKey() { RuntimeService runtimeService = engine.getRuntimeService(); String processDefinitionKey = "purchasingflow"; //設置一個businessKey,在我實際業務中可能是一個采購單,或者訂單之類的id String businessKey ="111"; // 根據流程定義的key啟動一個流程實例 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,businessKey); System.out.println("流程實例id:" + processInstance.getId()); System.out.println("流程定義id:" + processInstance.getProcessDefinitionId()); }
一般情況下,我們是在用戶保存一條采購單的時候,啟動這個實例,並且動態獲取采購單的id(也就是用作流程實例的businessKey),並且我們還會在采購單表中保存這個流程實例的id,雙向一對一綁定,方便業務查詢
2,根據采購單的id(也就是用作流程實例的businessKey),動態的查詢出對應的流程實例
/** * 通過businessKey查詢流程實例 */ @Test public void queryProInsWithKey(){ RuntimeService runtimeService = engine.getRuntimeService(); String businessKey ="111"; ProcessInstanceQuery instanceQuery = runtimeService.createProcessInstanceQuery(); //根據其流程定義key和業務id businessKey查詢出對應的流程實例,一般只有一條 instanceQuery.processInstanceBusinessKey(businessKey); //查詢出唯一的一條流程實例 ProcessInstance processInstance = instanceQuery.singleResult(); System.out.println("流程實例id:"+processInstance.getId()); System.out.println("流程定義id:"+processInstance.getProcessDefinitionId()); }
到這里,我們就清楚了一個流程實例和實際業務數據的綁定
大家到這里也啟動了很多的流程實例了,發現我們的任務辦理人都是寫死為zhangsan,lisi之類的,那么我們可以動態的指定嗎,這就需要使用到我們的uel表達式了
首先uel表達式到底是什么呢?
UEL是java EE6規范的一部分,UEL(Unified Expression Language)即統一表達式語言,activiti支持兩個UEL表達式:UEL-value和UEL-method。我們都會分別做介紹
(一)我們先來演示uel-value
首先做個簡單的使用帶大家入門
使用步驟:(看不明白的運行下面的代碼走一遍再回頭看)
1,在任務的節點,不直接指定處理人的id,設置處理人表達式${assignee},並且重新部署流程定義
2, 啟動一個流程實例是設置啟動變量動態設置assignee的值
3,查看並驗證下一個任務的處理人是否為我們動態設置
1,首先我們設置節點
2,在啟動代碼時動態設置assignee的值
/** * 啟動流程實例時設置全局變量 */ @Test public void startProInsWithArgs(){ RuntimeService runtimeService = engine.getRuntimeService(); String processDefinitionKey = "purchasingflow"; //設置其啟動的全局變量參數,其value可以是javabean,也可以是普通字符串,數字 Map<String,Object> variables = new HashMap<String, Object>(); variables.put("assignee", "feige"); //設置流程啟動時,設置參數啟動 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("流程實例id:" + processInstance.getId()); System.out.println("流程定義id:" + processInstance.getProcessDefinitionId()); }
3,這個時候我們通過查看數據庫,查看act_ru_task當前運行的任務,查看
從上面的我們可以看到流程走到了,創建采購單,並且采購的assignee處理人為feige
因為當我們走到了創建采購單時,會從當前流程實例的全局變量查找name為assignee的值,如果查詢到,則將這個assignee的值賦給這個節點,如果我們動態設置了,但是走到這個節點前(為什么說節點前呢,因為還可以在別的時候設置變量,后面的章節會講)
沒有找到這個assignee變量的值,會報錯的,大家可以自己試一試
當然除了上面的設置方法,我們還有其他的設置方法來動態設置其節點的值嗎?答案是肯定的,啟動的流程時候的參數的value,不僅僅可以是String類型,還可以是Object對象(序列化的),Map,List,Array
我們這里采用對象做演示,執行步驟如下
1,設置流程的第一個節點動態的值為${user.userId},他會默認查找變量name為user的對應的值的getUserId獲取值,重新部署流程定義
2,啟動流程時,設置這個user的javabean到流程的全局變量中
3,查看走到這個節點的當前任務的處理人是否是我們user的userId變量的值
1,設置節點
2,設置javabean User對象並且在流程實例啟動時設置進去
public class User implements Serializable{ /** * 用於序列化 */ private static final long serialVersionUID = 7717000074223077256L; private String userId; private String sex; private String name; public User(String userId, String sex, String name) { super(); this.userId = userId; this.sex = sex; this.name = name; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
/** * 啟動流程設置一個user用戶到全局變量中 */ @Test public void startProInsWithObj(){ RuntimeService runtimeService = engine.getRuntimeService(); String processDefinitionKey = "purchasingflow"; //設置其啟動的全局變量參數,其value設置為user對象,這里寫死 User user = new User("101","男","張三"); Map<String,Object> variables = new HashMap<String, Object>(); variables.put("user", user); //設置流程啟動時,設置參數啟動 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("流程實例id:" + processInstance.getId()); System.out.println("流程定義id:" + processInstance.getProcessDefinitionId()); }
3,到這里流程實例啟動成功,我們觀察數據庫的當前任務表,觀察第一個節點的處理人是否為我們設置的101的userId
設置成功!
(二)演示uel-method
執行步驟
1,設置節點的執行人為${method.getUserNameByUserId(userId)} ,其中method方法是我們注入到spring中的一個類,userId是我們設置的全局變量
2,將method方法注入到activiti的processEngineConfiguration的bean中(在我們的activiti.cfg.xml中)
3,啟動一個流程設置全局變量userId作為啟動參數,看看是否走到這個節點的處理人是我們method方法getUserNameByUserId返回的name
好了,直接上代碼
1,設置節點,重新部署流程定義
2,method的java方法和activiti.cfg.xml的注入配置
public class CommonMethod{ public String getUserNameByUserId(int userId){ return "activiti"+userId; } }
<bean class="cn.nfcm.po.CommonMethod" id="commonmethod"></bean> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <!-- 數據源 --> <property name="dataSource" ref="dataSource" /> <!-- activiti數據庫表處理策略 --> <property name="databaseSchemaUpdate" value="true" /> <!-- 可以注入多個類到activiti的beans中,其中key對應的就是我們的類名 --> <property name="beans"> <map> <entry key="commonmethod" value-ref="commonmethod" /> </map> </property> </bean>
3,啟動一個流程實例
/** * 根據方法得到值 */ @Test public void startProInsWithMethod(){ RuntimeService runtimeService = engine.getRuntimeService(); String processDefinitionKey = "purchasingflow"; //這里設置userId為8,走到第一個節點會查找我們注入進去的commonmethod的getUserNameByUserId方法並傳遞userId Map<String,Object> variables = new HashMap<String, Object>(); variables.put("userId", 8); //設置流程啟動時,設置參數啟動 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("流程實例id:" + processInstance.getId()); System.out.println("流程定義id:" + processInstance.getProcessDefinitionId()); }
到這里我們會發現流程啟動成功,並且流程的當前任務處理人為acitiviti8,在實際的應用中因為都是spring管理的類,我們可以進行多種多樣的查詢賦值,非常方便!