1. 程式人生 > 實用技巧 >Liferay7 BPM門戶開發之23: 瞭解內建工作流(Kaleo Workflow)

Liferay7 BPM門戶開發之23: 瞭解內建工作流(Kaleo Workflow)

參考:https://www.cnblogs.com/starcrm/p/6047344.html

Liferay7 BPM門戶開發之23: 瞭解內建工作流(Kaleo Workflow)

Liferay內建的工作流是企業版的功能,雖然簡單粗糙,但依然不支援社群版。

既然要用更強大的Activiti來替代它,那就非常有必要學習一下內建工作流的一些思想,以便借鑑。

它的特點:

  • 實體的工作流操作可以通過service layer進行整合;
  • 需要新增4個額外的欄位來跟蹤流程狀態;
  • 通過Service Builder來建立欄位,然後更新service layer;
  • 檢視層UI可以顯示實體的工作流狀態。

實體整合邏輯

比如,釋出一個實體類的工作流支援,首先添加註解:

@Component(
property = {"model.class.name=com.my.app.package.model.FooEntity"},
service = WorkflowHandler.class
)

開發XXXWorkflowHandler,實現Override 三個方法

package com.liferay.docs.foo.workflow;

...
public class FooEntityWorkflowHandler extends BaseWorkflowHandler {

    public static final String CLASS_NAME = FooEntity.class.getName();

    @Override
    public String getClassName() {

        return CLASS_NAME;
    }

    @Override
    public String getType(Locale locale) {
        return LanguageUtil.get(locale,  "model.resource" + CLASS_NAME);
    }

    @Override
    public Object updateStatus(int status,
            Map<String, Serializable> workflowContext) throws PortalException,
            SystemException {

            long userId = GetterUtil.getLong(
                (String)workflowContext.get(WorkflowConstants.CONTEXT_USER_ID));
            long fooEntityId = GetterUtil.getLong(
                (String)workflowContext.get(
                    WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));

            ServiceContext serviceContext = (ServiceContext)workflowContext.get(
                "serviceContext");

            return FooEntityLocalServiceUtil.updateStatus(
                userId, fooEntityId, status, serviceContext);

    }
}

為了記錄實體的當前流程狀態,必須要有以下4個欄位(通過Service Builder)
service.xml中新增:

<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />


比如在更新實體時,自動通過這4個欄位,把實體和流程狀態相關聯:

fooEntity.setStatus(status);
fooEntity.setStatusByUserId(user.getUserId());
fooEntity.setStatusByUserName(user.getFullName());
fooEntity.setStatusDate(serviceContext.getModifiedDate(now));

fooEntityPersistence.update(fooEntity);

啟動一個和實體關聯的流程:

WorkflowHandlerRegistryUtil.startWorkflowInstance(fooEntity.getCompanyId(),
fooEntity.getGroupId(), fooEntity.getUserId(), FooEntity.class.getName(),
fooEntity.getPrimaryKey(), fooEntity, serviceContext);


如果實體屬於Assets,那在為實體設定工作流欄位後,就可以新增任何附加的邏輯方法。
例如,如果想根據其工作流狀態來設定可見性(未審批就不顯示):

if (status == WorkflowConstants.STATUS_APPROVED) {
  assetEntryLocalService.updateEntry(
    FooEntity.class.getName(), fooEntityId, fooEntity.getDisplayDate(),
    null, true, true);
}
else {
  assetEntryLocalService.updateVisible(
    fooEntity.class.getName(), entryId, false);
}

為了在檢視中展示,需要設定finder (service.xml)

<finder name="G_S" return-type="Collection">
<finder-column name="groupId"></finder-column>
<finder-column name="status"></finder-column>
</finder>

實現一個Getter:

public List<FooEntity> getFooEntities(long groupId, int status)
throws SystemException {
return fooEntityPersistence.findByG_S(groupId,
WorkflowConstants.STATUS_APPROVED);
}

jsp UI:

<liferay-ui:search-container-results
results="<%=FooEntityLocalServiceUtil.getFooEntities(scopeGroupId,
fooEntityId(), Workflowconstants.STATUS_APPROVED, searchContainer.getStart(),
searchContainer.getEnd())%>"
...

流程設計器

這個屬於企業版功能,有點弱

這個有點意思:
設定啟動任務的簽收者,

一共有6種類型:

  • 建立者
  • 某角色
  • 角色ID
  • 通過一個程式碼段來指定
  • 特定的使用者
  • 通過資源

在Kaleo中,只有這6種節點,這實在可憐,恐怕要實現複雜的流程將依靠編寫大量的程式碼來實現。

現在知道為啥Kaleo叫workflow而不是叫BPM了吧,因為其不能實現業務流程整合,但實現僅簡單順序流程,還是沒有問題的。

  • Condition: 通過指令碼來實現條件邏輯(script包含幾種語言:Beanshell、Drl、Groovy、JavaScript、Python、Ruby),這有點不太友好和方便;
  • Fork: 並行處理
  • Join: Fork並行後的彙總,這個可以實現會籤,比如說一個節點由領導A、領導B同時稽核才能結束,往下走;
  • Join XOR: 異或邏輯的彙總,通俗的說就是實現搶籤,有點像Activiti的候選組的概念,比如說一個節點由領導A、領導B稽核,隨便一個領導先稽核了,節點就結束,往下走;
  • State: 狀態節點,比如開始、結束就是屬於這個型別;
  • Task: 任務節點,比如審批、填寫表單....

一個XML的描述檔案: