先說個抱歉,原來準備自己寫個例子,從頭到尾介紹內建呢,但是最近工作太忙,沒有時間從頭到尾一起做,就把原來整理的示範示例的開發過程稍微整理下給大家用作參考。
本篇文正主要介紹示範示例中表單的內建,采用的Rest的內建方式,适用于中小型項目使用,大型項目還是建議詳細研究後制定內建方案。
FoxBPM吸取了5.2開源的經驗,對任務指令的前端內建方式做了封裝,能讓使用者不做太多的修改即可友善的內建表單,當然這個是借助FoxBPM-rest包的。
下面介紹內建過程,介紹我分為兩部分,一是表單前端內建,二是業務資料處理
表單前端內建
- pom.xml中添加foxbpm-rest的依賴
<dependency> <groupId>org.foxbpm</groupId> <artifactId>foxbpm-rest</artifactId> <version>6.0.1-SNAPSHOT</version> </dependency>
- web.xml中添加rest服務配置
<listener> <listener-class>org.foxbpm.rest.common.listener.FoxBpmRestServletContextListener</listener-class> </listener> <!-- Restlet adapter --> <servlet> <servlet-name>RestletServlet</servlet-name> <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class> <init-param> <!-- Application class name --> <param-name>org.restlet.application</param-name> <param-value>org.foxbpm.rest.service.application.FoxbpmRestApplication</param-value> </init-param> </servlet> <!-- Catch all requests --> <servlet-mapping> <servlet-name>RestletServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
- 拷貝taskCommand檔案夾到自己的web項目中,裡面是任務指令用到的一些JS和html頁面等
- 修改service路徑,打開foxbpmframework.js,修改service路徑,這個路徑來自步驟2中配置的service位址,修改bpmFilePath,這個是taskCommand檔案夾的路徑
- 在自己的表單中添加JS引用,一共3個js,主意相對路徑
<script type="text/javascript" src="../taskCommand/js/foxbpmframework.js"></script> <script type="text/javascript" src="../taskCommand/js/flowCommandCompenent.js"></script> <script type="text/javascript" src="../taskCommand/js/flowCommandHandler.js"></script>
- 在需要顯示按鈕的區域加上dom容器 id為toolbar,如<div id="toolbar"></div>,這是告訴插件在哪裡繪制按鈕,當然這裡也可以不是DIV,隻要是dom容器就行
- 初始化按鈕,我的代碼如下:
$(document).ready(function() {
var _getBizKey = function() {
return $("#expenseId").val();
};
var _getTaskComment = function() {
return "";
};
var _flowCommit = function(flowInfo) {
if (confirm("确定要送出嗎?")) {
$("#flowCommandInfo").val(JSON.stringify(flowInfo));
$("#form1").submit();
}
return false;
};
var flowconfig = {
getBizKey : _getBizKey,
getTaskComment : _getTaskComment,
flowCommit : _flowCommit
};
var flowCommandCompenent = new Foxbpm.FlowCommandCompenent(flowconfig);
flowCommandCompenent.init();
});
代碼解釋:
- getBizKey():了解fixflow或activiti的使用者都應該知道,流程引擎在運轉中,隻會記錄業務資料的關聯鍵(一般是主鍵),然後通過關聯鍵打開表單,或者找到其他業務資料,在這個報帳單例子中,我用主鍵報帳單号作為關聯鍵,是以直接 return $("#expenseId").val();
- getTaskComment():這個方法是擷取處理意見,不用多解釋,放個文本框讓審批者填寫處理意見。
- flowCommit(flowInfo):這個是表單的送出動作,flowInfo是foxbpm封裝的處理任務需要的參數,這個參數隻需要原封不動的交給引擎就可以驅動引擎運轉,這個一會我會在業務資料處理部分解釋。是以這裡,我放了個<input type="hidden" name="flowInfo" id="flowInfo"/>存儲這個json字元串,跟随表單一起送出到背景。然後就是$("#form1").submit()觸發表單送出。
這時候通路表單,傳相應參數就應該能看到效果了如:http://localhost:8080/test/form.html?processDefinitionKey=ProcessTest_ych,就能看到相應的按鈕,并能觸發相應的事件。
業務資料處理
直接上Controller代碼
public void applyExpense(HttpServletResponse response, @ModelAttribute ExpenseEntity expenseEntity, @RequestParam String flowCommandInfo) throws IOException {
expenseManager.applyNewExpense(expenseEntity, flowCommandInfo);
}
- expenseEntity是報帳單實體,用的spring的pojo映射
- flowCommandInfo就是剛才js中flowCommit(flowInfo)中的json字元串
下面看expenseManager的代碼
@Transactional
public void applyNewExpense(ExpenseEntity expenseEntity,String flowCommandInfo){
expenseDao.saveExpenseEntity(expenseEntity);
if(StringUtil.isEmpty(flowCommandInfo)){
throw new RuntimeException("流程指令參數确實,請檢查請求參數");
}
//調用api執行任務指令
workFlowService.executeTaskCommandJson(flowCommandInfo);
}
- 這層也很簡單,調用實體DAO層儲存報帳單實體,然後将flowCommandInfo的json傳交給引擎處理
然後看workFlowService代碼,這個是我對foxbpm任務指令api做的一個封裝,代碼如下(可以直接拷過去用),
public void executeTaskCommandJson(String taskCommandJson) {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode params = null;
try {
params = objectMapper.readTree(taskCommandJson);
} catch (Exception e) {
throw new FoxBPMException("任務指令參數格式不正确",e);
}
JsonNode taskIdNode = params.get("taskId");
JsonNode commandIdNode = params.get("commandId");
JsonNode processDefinitionKeyNode = params.get("processDefinitionKey");
JsonNode businessKeyNode = params.get("bizKey");
JsonNode taskCommentNode = params.get("taskComment");
// 參數校驗
// 指令類型
JsonNode commandTypeNode = params.get("commandType");
JsonNode commandParamsNode = params.get("commandParams");
if (commandTypeNode == null) {
throw new FoxBPMException("commandType is null !");
}
// 指令Id
if (commandIdNode == null) {
throw new FoxBPMException("commandId is null !");
}
ExpandTaskCommand expandTaskCommand = new ExpandTaskCommand();
expandTaskCommand.setCommandType(commandTypeNode.getTextValue());
// 設定指令的id,需和節點上配置的按鈕編号對應,會執行按鈕中的腳本。
expandTaskCommand.setTaskCommandId(commandIdNode.getTextValue());
if(taskCommentNode != null){
expandTaskCommand.setTaskComment(taskCommentNode.getTextValue());
}
//設定任務指令參數
Map<String,Object> taskParams = new HashMap<String, Object>();
if(commandParamsNode != null){
Iterator<String> it = commandParamsNode.getFieldNames();
while(it.hasNext()){
String tmp = it.next();
taskParams.put(tmp, commandParamsNode.get(tmp).getTextValue());
}
}
expandTaskCommand.setParamMap(taskParams);
if (taskIdNode != null && StringUtil.isNotEmpty(taskIdNode.getTextValue())) {
expandTaskCommand.setTaskId(taskIdNode.getTextValue());
} else {
String userId = Authentication.getAuthenticatedUserId();
expandTaskCommand.setInitiator(userId);
if(businessKeyNode == null){
throw new FoxBPMException("啟動流程時關聯鍵不能為null","");
}
if(processDefinitionKeyNode == null){
throw new FoxBPMException("啟動流程時流程Key不能為null","");
}
expandTaskCommand.setBusinessKey(businessKeyNode.getTextValue());
expandTaskCommand.setProcessDefinitionKey(processDefinitionKeyNode.getTextValue());
}
taskService.expandTaskComplete(expandTaskCommand, null);
}
到這裡,業務資料的整合也結束,是不是以前5.2版本中的耦合都被解開了,代碼看上去也比較輕松了。
後面我會将workFlowService的方法重載下,可以傳變量,這樣就可以很友善的傳遞流程變量了。
仔細看上面的介紹,這次的內建遵循了高内聚,低耦合的原則,盡量少的侵入業務系統的代碼。
時間問題,代碼和master版本代碼稍微 有點沖突,master版本目前将整個表單資料都傳遞給executTaskComamnd(String formInfo)了,我這裡還沒來得及改。
有問題可以随時留言,或者社群讨論。