處理依賴關係html
集成Activiti以前,必須搞清楚其中的依賴關係,才能在Gradle裏進行配置.java
依賴關係:web
例如,其中activiti-engine依賴於activiti-bpmn-converter,而activiti-bpmn-converter又依賴於activiti-bpmn-modelspring
那麼這如下的引用都是要設置的,缺一不可,不然portlet會沒法注入進OSGi容器apache
org.activiti:activiti-engine:jar:5.xx.0
+- org.activiti:activiti-bpmn-converter:jar:5.xx.0:compile
| \- org.activiti:activiti-bpmn-model:jar:5.xx.0:compile
| +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile
| \- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile
| \- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile
+- org.activiti:activiti-process-validation:jar:5.xx.0:compile
+- org.activiti:activiti-image-generator:jar:5.xx.0:compile
+- org.apache.commons:commons-email:jar:1.2:compile
| +- javax.mail:mail:jar:1.4.1:compile
| \- javax.activation:activation:jar:1.1:compile
+- org.apache.commons:commons-lang3:jar:3.3.2:compile
+- org.mybatis:mybatis:jar:3.2.5:compile
+- org.springframework:spring-beans:jar:4.0.6.RELEASE:compile
| \- org.springframework:spring-core:jar:4.0.6.RELEASE:compile
+- joda-time:joda-time:jar:2.6:compile
+- org.slf4j:slf4j-api:jar:1.7.6:compile
+- org.slf4j:jcl-over-slf4j:jar:1.7.6:compileapi
接下來,須要完成Gradle的設置,mybatis
所有:mvc
dependencies { compile 'com.liferay.portal:com.liferay.portal.kernel:2.0.0' compile 'com.liferay.portal:com.liferay.util.bridges:2.0.0' compile 'com.liferay.portal:com.liferay.util.taglib:2.0.0' compile 'com.liferay:com.liferay.application.list.api:1.0.0' compile 'javax.portlet:portlet-api:2.0' compile 'javax.servlet:javax.servlet-api:3.0.1' compile 'org.osgi:org.osgi.service.component.annotations:1.3.0' compile 'org.osgi:org.osgi.compendium:5.0.0' compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.2.3' compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.2.3' compileOnly group: "jstl", name: "jstl", version: "1.2" compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.3.2' compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.6' compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.6' compile group: 'commons-logging', name: 'commons-logging', version: '1.2' compile group: 'org.joda', name: 'joda-convert', version: '1.2' compile group: 'joda-time', name: 'joda-time', version: '2.6' compile group: 'org.apache.commons', name: 'commons-email', version: '1.4' compile group: 'com.sun.mail', name: 'javax.mail', version: '1.5.2' compile group: 'javax.activation', name: 'activation', version: '1.1.1' compile group: 'org.mybatis', name: 'mybatis', version: '3.3.0' compile group: 'org.springframework', name: 'spring-core', version: '4.1.5.RELEASE' compile group: 'org.springframework', name: 'spring-beans', version: '4.1.5.RELEASE' compile 'org.springframework:spring-webmvc:4.1.5.RELEASE' compile 'org.springframework:spring-webmvc-portlet:4.1.5.RELEASE' compile group: 'org.activiti', name: 'activiti-bpmn-model', version: '5.21.0' compile group: 'org.activiti', name: 'activiti-bpmn-converter', version: '5.21.0' compile group: 'org.activiti', name: 'activiti-engine', version: '5.21.0' testCompile 'junit:junit:4.+' }
Portlet javaapp
ProcessListPortlet:jsp
package com.lifiti.portlet; import java.io.IOException; import java.util.List; import javax.portlet.Portlet; import javax.portlet.PortletException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import org.activiti.engine.repository.ProcessDefinition; import org.osgi.service.component.annotations.Component; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; import com.liferay.portal.kernel.util.ParamUtil; @Component(immediate = true, property = { "com.liferay.portlet.display-category=category.sample", "com.liferay.portlet.instanceable=true", "javax.portlet.display-name=Process List", "javax.portlet.init-param.template-path=/", "javax.portlet.init-param.view-template=/process/processList.jsp", "javax.portlet.resource-bundle=content.Language", "javax.portlet.security-role-ref=power-user,user" }, service = Portlet.class) public class ProcessListPortlet extends BpmBasePortlet { @Override public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException { List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list(); request.setAttribute("processDefinitionList", processDefinitionList); super.render(request, response); } }
jsp頁面
<%@ include file="/init.jsp" %> <portlet:renderURL var="render"> <portlet:param name="mvcRenderCommandName" value="/porcess/bpmn" /> </portlet:renderURL> <table width="100%" class="table table-bordered table-hover table-condensed"> <thead> <tr> <th><liferay-ui:message key="ProcessDef"/></th> <th><liferay-ui:message key="DeplyID"/></th> <th><liferay-ui:message key="ProcessName"/></th> <th><liferay-ui:message key="ProcessDefKey"/></th> <th><liferay-ui:message key="Version"/></th> <th>BPMN</th> <th><liferay-ui:message key="ImageResource"/></th> <th width="80"><liferay-ui:message key="Operation"/></th> <th width="80"><liferay-ui:message key="Start"/></th> </tr> </thead> <tbody>
<c:forEach items="${processDefinitionList }" var="pd">
<portlet:actionURL var="viewURL" name="imageAction">
<portlet:param name="mvcRenderCommandName" value="/process/viewResource" />
<portlet:param name="pdid" value="${pd.id }" />
<portlet:param name="diagramResourceName" value="${pd.diagramResourceName }" />
</portlet:actionURL>
<portlet:renderURL var="viewXML">
<portlet:param name="mvcRenderCommandName" value="/porcess/bpmn" />
<portlet:param name="pdid" value="${pd.id }" />
<portlet:param name="resourceName" value="${pd.resourceName }" />
</portlet:renderURL>
<tr>
<td>${pd.id }</td>
<td>${pd.deploymentId }</td>
<td>${pd.name }</td>
<td>${pd.key }</td>
<td>${pd.version }</td>
<td><aui:button href="<%= viewXML %>" value="View XML" /></td>
<td><aui:button href="<%= viewURL %>" value="${pd.diagramResourceName eq null?'-':'png' }"/> </td>
</tr>
</c:forEach>
</tbody> </table>
須要注意的是,還須要把jar文件放置在osgi的modules目錄下,很是重要
查看BPMN描述文件
jsp 定義,其中mvcRenderCommandName定義了Action的URL地址,在MVCRenderCommand類中將會對應
<%@ include file="/init.jsp" %>
<aui:input name="xml" type="textarea" label ="XML:" value="${bpmnOutput}"></aui:input>
MVCRenderCommand 連接處理JAVA類
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCRenderCommand; import javax.portlet.PortletException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import org.osgi.service.component.annotations.Component; @Component( immediate = true, property = { "javax.portlet.name=com_lifiti_portlet_ProcessListPortlet", "mvc.command.name=/respository/viewBPMN" }, service = MVCRenderCommand.class ) public class BladeMVCRenderCommand implements MVCRenderCommand { @Override public String render( RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException { ... //處理邏輯 Here ... return "/process/viewBPMN.jsp"; } }
一些通用類
未來會把它們獨立出一個工程,暫時先放在一個工程裏
BPM Portlet基類
package com.lifiti.portlet; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; import com.lifiti.util.ActivitiUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import org.activiti.engine.FormService; import org.activiti.engine.HistoryService; import org.activiti.engine.IdentityService; import org.activiti.engine.ManagementService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; public class BpmBasePortlet extends MVCPortlet{ protected Log _log = LogFactoryUtil.getLog(getClass()); protected ProcessEngine processEngine = null; protected RepositoryService repositoryService; protected RuntimeService runtimeService; protected TaskService taskService; protected HistoryService historyService; protected IdentityService identityService; protected ManagementService managementService; protected FormService formService; public BpmBasePortlet() { super(); processEngine = ActivitiUtils.getProcessEngine(); repositoryService = processEngine.getRepositoryService(); runtimeService = processEngine.getRuntimeService(); taskService = processEngine.getTaskService(); historyService = processEngine.getHistoryService(); identityService = processEngine.getIdentityService(); managementService = processEngine.getManagementService(); formService = processEngine.getFormService(); } public ByteArrayOutputStream inputStream2ByteArrayOutputStream(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int i = -1; while ((i = is.read()) != -1) { baos.write(i); } return baos; } }
Activiti通用日誌事件記錄(監聽器):
public class BpmJobEventListener implements ActivitiEventListener { @Override public void onEvent(ActivitiEvent event) { switch (event.getType()) { case JOB_EXECUTION_SUCCESS: _log.info("A job done!"); ...... break; case JOB_EXECUTION_FAILURE: _log.error("A job has failed..."); break; default: _log.info("Event received: " + event.getType()); } } @Override public boolean isFailOnException() { return false; } }
所有的監聽類型清單:
http://activiti.org/userguide/index.html#eventDispatcherEventTypes
經過RuntimeService來註冊和刪除監聽器
註冊監聽: void addEventListener(ActivitiEventListener listenerToAdd); void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types); 刪除監聽: void removeEventListener(ActivitiEventListener listenerToRemove);
這樣一個Portlet就開發出來了,感受靠拖拽放在頁面,再設置訪問權限有些繁瑣,咱們還想把它直接放進控制面板裏。
界面:
XML模板察看
點擊PNG按鈕,查看流程圖,我嘗試用InputStream把圖片資源以流的形式輸出到ServletResponse的OutStream流,結果失敗,還嘗試另存爲PNG,輸出有亂碼。
因而想了2個替代解決方案
一、寫一個獨立的Activiti的rest服務,用來獨立輸出PNG;
二、利用Activiti自帶的rest服務
用第一方式的實現,端口爲8070,注意須要注入2個url參數,分別是pdid和resourceName
用Activiti自帶的rest服務,端口8082
URL例如http://localhost:8082/activiti-rest/service/repository/deployments/262561/resources
其中262561就是流程部署ID,即deploymentId
本篇結束。
Activiti的集成開發系列文章集合在這裏:
http://www.cnblogs.com/starcrm/p/6047486.html
方便索引。
SourceCode Download:
所有工程源代碼下載