天天看點

FoxBPM開源工作流內建系列(二)

先說個抱歉,原來準備自己寫個例子,從頭到尾介紹內建呢,但是最近工作太忙,沒有時間從頭到尾一起做,就把原來整理的示範示例的開發過程稍微整理下給大家用作參考。

本篇文正主要介紹示範示例中表單的內建,采用的Rest的內建方式,适用于中小型項目使用,大型項目還是建議詳細研究後制定內建方案。

FoxBPM吸取了5.2開源的經驗,對任務指令的前端內建方式做了封裝,能讓使用者不做太多的修改即可友善的內建表單,當然這個是借助FoxBPM-rest包的。

下面介紹內建過程,介紹我分為兩部分,一是表單前端內建,二是業務資料處理

表單前端內建

  1. pom.xml中添加foxbpm-rest的依賴
    <dependency>
    	<groupId>org.foxbpm</groupId>
    	<artifactId>foxbpm-rest</artifactId>
    	<version>6.0.1-SNAPSHOT</version>
    </dependency>      
  2. 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>       
  3. 拷貝taskCommand檔案夾到自己的web項目中,裡面是任務指令用到的一些JS和html頁面等
  4. 修改service路徑,打開foxbpmframework.js,修改service路徑,這個路徑來自步驟2中配置的service位址,修改bpmFilePath,這個是taskCommand檔案夾的路徑
  5. 在自己的表單中添加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>
               
  6. 在需要顯示按鈕的區域加上dom容器 id為toolbar,如<div id="toolbar"></div>,這是告訴插件在哪裡繪制按鈕,當然這裡也可以不是DIV,隻要是dom容器就行
  7. 初始化按鈕,我的代碼如下:
$(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)了,我這裡還沒來得及改。

有問題可以随時留言,或者社群讨論。

繼續閱讀