由于工作需要,新接到一个小项目,什么?项目,ofbiz走起!项目中需要用到两个小流程,什么?流程 activiti5走起~
activiti5 是原生支持spring 的,可是怎么能让它与ofbiz整合到一块呢,ofbiz确实有自己的sharp 啥的,可是弄不懂啊,资料太少了。可是ofbiz与activiti5整合的资料更少啊,没办法,面对activii5的流程编辑器的诱惑,自己想招吧!
其实整合起来并不复杂,代码量也不多,我就来一步一步说具体操作
1.下载activiti5,我是从官网下的最新版 下载下来解压,我了个去这么些jar ,其实用到的也不多,主要用的有
activiti-bpmn-converter-5.17.0.jar
activiti-bpmn-layout-5.17.0.jar
activiti-bpmn-model-5.17.0.jar
activiti-common-rest-5.17.0.jar
activiti-crystalball-5.17.0.jar
activiti-diagram-rest-5.17.0.jar
activiti-engine-5.17.0.jar
activiti-explorer-5.17.0.jar
activiti-image-generator-5.17.0.jar
activiti-json-converter-5.17.0.jar
activiti-modeler-5.17.0.jar
activiti-process-validation-5.17.0.jar
activiti-simple-workflow-5.17.0.jar
commons-lang3-3.3.2.jar
jackson-annotations-2.2.3.jar
jackson-core-2.2.3.jar
jackson-databind-2.2.3.jar
javaGeom-0.11.1.jar
joda-time-2.6.jar
mybatis-3.2.5.jar
2.我使用的是ofbiz13就是最新版本那个,下一步就是新建一个component 叫做workflow模块
我是建在了framework 下面的,架构级么哈哈,新建component 我就不多介绍了,很多资料可以参考,我新建的component 包含了一下内容:
3 导入jar 包 并且添加classpath中(也就是说在ofbiz-component.xml中包含workflow的lib文件夹),如果component创建的配置都对的话,把你新建的component 加入到component-loader中,启动一下不报错说明你添加jar包成功了。
4.我的整合思路是通过ofbiz 启动加载 acitiviti 的processEngine 并且提供一个processEngineFactory 来获取activiti 的主要接口,那么在我们业务中随时都可以调用工作流引擎了.所以第一步要正确的加载ProcessEngine
ofbiz 强大之处就体现出来了,可以使用它的container 来加载我们的processEngine,我们创建一个workflowcontainer,并实现ofbiz 的container 接口:
package com.ly.workflow;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.ofbiz.base.container.Container;
import org.ofbiz.base.container.ContainerException;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilProperties;
import java.util.Properties;
/**
* Created by bo on 15/4/14.
*/
public class WorkflowContainer implements Container {
private String name;
private String dbFile= "workflow.db.properties";
@Override
public void init(String[] args, String name, String configFile) throws ContainerException {
this.name = name;
Debug.log("---启动工作流模块---");
//获取工作流数据库配置文件
Properties jdbc=UtilProperties.getProperties(dbFile);
//配置工作流引擎
ProcessEngineConfiguration pecfg = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
pecfg.setJdbcUsername(jdbc.getProperty("username"));
pecfg.setJdbcPassword(jdbc.getProperty("password"));
pecfg.setJdbcUrl(jdbc.getProperty("url"));
pecfg.setJdbcDriver(jdbc.getProperty("driver"));
//连接池设置
pecfg.setJdbcMaxActiveConnections(Integer.valueOf(jdbc.getProperty("jdbcMaxActiveConnections")));
pecfg.setJdbcMaxIdleConnections(Integer.valueOf(jdbc.getProperty("jdbcMaxIdleConnections")));
pecfg.setJdbcMaxCheckoutTime(Integer.valueOf(jdbc.getProperty("jdbcMaxCheckoutTime")));
pecfg.setJdbcMaxWaitTime(Integer.valueOf(jdbc.getProperty("jdbcMaxWaitTime")));
//设置启动检查数据表
pecfg.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
//创建表并获取流程引擎
ProcessEngine pe = pecfg.buildProcessEngine();
//todo 加载初始化流程
//初始化工作流引擎工厂
WorkflowProcessEngineFactory.init(pe,"default");
Debug.log("---工作流引擎加载成功---");
}
@Override
public boolean start() throws ContainerException {
Debug.log("workflow-start");
return false;
}
@Override
public void stop() throws ContainerException {
Debug.log("workflow-stop");
}
@Override
public String getName() {
return null;
}
}
这里需要注意的是我们要写一个配置文件来配置工作流引擎的数据库, activiti 是有自己的一套数据库框架的,也不是他的就是ibatis。。我们就创建一个配置文件来保存工作流引擎的数据库配置,其实也可以用ofbiz自己的连接池的,如果你需要可以自己配置,我是想把ofbiz本身的业务和工作流分开放不同的数据里。
之后我们就新建一个工厂类来保存我们创建的 processEngine:
package com.ly.workflow;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.workflow.simple.converter.WorkflowDefinitionConversionFactory;
import org.activiti.workflow.simple.converter.json.SimpleWorkflowJsonConverter;
import org.ofbiz.base.lang.Factory;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilObject;
import org.ofbiz.entity.Delegator;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by bo on 15/4/14.
*/
public abstract class WorkflowProcessEngineFactory implements Factory<ProcessEngine,String> {
public static final String module = WorkflowProcessEngineFactory.class.getName();
private static ProcessEngineConfiguration pecfg = null;
private static final ConcurrentHashMap<String, ProcessEngine> processEngineCache = new ConcurrentHashMap<String, ProcessEngine>();
public static ProcessEngine getProcessEngine(String processEngineName){
if (processEngineName == null) {
processEngineName = "default";
}
ProcessEngine processEngine = processEngineCache.get(processEngineName);
if (processEngine == null) {
Debug.logInfo("没有找到工作流引擎", module);
}
return processEngine;
}
public static ProcessEngine getProcessEngine(){
return getProcessEngine("default");
}
public static RepositoryService getRepositoryService(String processEngineName){
return getProcessEngine(processEngineName).getRepositoryService();
}
public static RepositoryService getRepositoryService(){
return getRepositoryService("default");
}
public static void init(ProcessEngine pe,String name){
WorkflowProcessEngineFactory.processEngineCache.put(name,pe);
}
}
如果你有对acitiviti 的借口需求的话,可以在工厂类中添加不同的获取方法,静态方法么,那块你想用取一下就行了,当然你也可以把processEngine 放到Context 里面方便获取。
4.之后你就可以把container 放在ofbiz 启动配置里面了,我觉得ofbiz的container 就相当于spring 一样,都是容器么,但是我觉得spring把简单的东西复杂化了,用的这个费劲,ofbiz 这点要强不少哦。
启动配置的位置在framework/base/config/ofbiz-containers.xml 中,添加一条你的工作流container:
<container name="workflow-container" loaders="main" class="com.ly.workflow.WorkflowContainer"/>
这样的话你启动ofbiz 就会帮你检查是否有activiti 的数据库和表,没有的话会帮你创建出来
如果没抱错,你现在的工作流引擎就可以使用了。。。
5.当然了,光有这些远远不够,activiti 的modeler 流程编辑器才是重点,它可以让你在线定义流程,图形化,可拖动,用户不就是喜欢这种傻瓜式的么,那么我们也吧流程编辑器也整合过来
其实acitiviti 的流程编辑器就是一大堆html 和js 啥的,通过ajax 请求与后台通讯,我们可以用ofbiz自己些逻辑,而前台交给他的编辑器,首先把activiti 的流程编辑器加进来,解压下载的activiti中 的activiti-explorer.war
编辑器其实就是上图的editor-app文件夹,把它拷贝到framwork/images/web-app/images下面
之后我们需要写一个screen 用来包含编辑器需要的js css 啥的,还有要给编辑器一个流程定义ID,
其实这个页面acitivity 中也有,就是上面那个modeler.html,那简单了拷~~~
新建 一个controller
<request-map uri="ProcessDefineModeler"> <security https="true" auth="true"/> <response name="success" type="view" value="ProcessDefineModeler"/> </request-map>
放在你能访问的WEB-INF/controller.xml中
之后建一个screen 来显示我们要的编辑器
<view-map name="ProcessDefineModeler" type="screen" page="component://workflow/widget/CommonScreens.xml#ProcessDefineModeler"/>
<screen name="ProcessDefineModeler"> <section> <actions> <set field="titleProperty" value="cache"/> <set field="headerItem" value="define"/> <set field="tabButtonItem" value="ProcessDefineEditor"/> </actions> <widgets> <platform-specific> <html> <html-template location="component://workflow/templates/processDefine/ProcessDefineModeler.ftl"/> </html> </platform-specific> </widgets> </section> </screen>
把ftl 创建出来,然后把modeler.html的内容拷贝进去(注意要把引用的js 还有css 还有 angelar js 的东西改成images/editor-app路径,确保里面的文件都能通过你的ofbiz服务器找到)
<div id="main" class="wrapper full clearfix" ng-style="{height: window.height + 'px'}" ng-app="activitiModeler" ng-include="'<@ofbizContentUrl>/images/editor-app/editor.html</@ofbizContentUrl>'"> </div>
主要是个,这个其实才是真正的编辑器。。这里可能要改的东西比较多,慢慢来吧,改到你看到的页面没有错误位置, 还有就是这里要有一个必要参数传进来,就是你的流程定义ID,修改引用路径使用ofbizcontenturl
like this:
<script src="<@ofbizContentUrl>/images/editor-app/libs/es5-shim-15.3.4.5/es5-shim.js</@ofbizContentUrl>"></script>
这里做完之后我们需要一个已有流程定义ID 来进入这个页面,这样才不会抱错,所以我们先来做一个流程管理页面
用semantic ui 加上w2ui 做了一个哈。左侧读出流程定义列表,右边显示流程具体信息和对流程定义的操作
这里的一些东西可以参考 activiti 自带的explore,其实说白了就是把他的explore 给弄成ofbiz版本的了,我的方法比较笨吧。。。但是集成度比较高
让编辑流程按钮 导向我们 流程定义页面跳转
哈哈流程定义图出来了,都是应文的,现在还没空翻译它讲究看吧
现在其实你们显示的还是一堆错误,是因为流程编辑器显示出来需要我们后台提供几个服务接口的,都是ajax json 调用,我们可以用ofbiz 来写后台返回个json 数据给他
修改 editor-app/config.js 把它请求服务的路径改为我们自己的
KISBPM.URL = { getModel: function(modelId) { return ACTIVITI.CONFIG.contextRoot + '/GetProcessModelById?modelId=' + modelId; }, getStencilSet: function() { //return ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now(); return '/images/editor-app/stencilset.json'; }, putModel: function(modelId) { return ACTIVITI.CONFIG.contextRoot + '/SaveProcessModelById?modelId=' + modelId+"&" ; } };
还有app-cfg,js
'use strict'; var ACTIVITI = ACTIVITI || {}; ACTIVITI.CONFIG = { 'contextRoot' : '/workflow/control' };
你可能注意到了,编辑器还有保存功能,上面配置的一个路径就是保存功能的路径
之后你可以写一个service 还是别的什么,来处理保存逻辑
我的是这样的
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.node.ObjectNode import com.ly.workflow.WorkflowProcessEngineFactory import org.activiti.engine.ActivitiException import org.activiti.engine.RepositoryService import org.activiti.engine.repository.Model import org.apache.batik.transcoder.TranscoderInput import org.apache.batik.transcoder.TranscoderOutput import org.apache.batik.transcoder.image.PNGTranscoder import org.ofbiz.base.util.Debug String modelId = parameters.modelId; String name = parameters.name; String des = parameters.description; String svgXml = parameters.svg_xml; String jsonXml = parameters.json_xml; RepositoryService repositoryService = WorkflowProcessEngineFactory.getRepositoryService(); ObjectMapper objectMapper = new ObjectMapper(); try { Model model = repositoryService.getModel(modelId); ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo()); modelJson.put("name", name); modelJson.put("description", des); model.setMetaInfo(modelJson.toString()); model.setName(name); repositoryService.saveModel(model); repositoryService.addModelEditorSource(model.getId(), jsonXml.getBytes("utf-8")); InputStream svgStream = new ByteArrayInputStream(svgXml.getBytes("utf-8")); TranscoderInput input = new TranscoderInput(svgStream); PNGTranscoder transcoder = new PNGTranscoder(); // Setup output ByteArrayOutputStream outStream = new ByteArrayOutputStream(); TranscoderOutput output = new TranscoderOutput(outStream); // Do the transformation transcoder.transcode(input, output); final byte[] result = outStream.toByteArray(); repositoryService.addModelEditorSourceExtra(model.getId(), result); outStream.close(); } catch (Exception e) { Debug.logError(e.getMessage(),"SaveProcessModelById.groovy"); }
因为流程图是生成出来的,所以调用activiti的接口比较多,具体的查一下activiti 的官方文档 或者是 看看一个叫咖啡兔的微博,很简单。
至此 整合完毕,其实还可以进一步进行封装与优化,并且把activiti explore 中的相关功能完善进去,这是一个整合其他框架的一个思路而已,其实spring 能整合的,ofbiz都能整合。这里不得不感叹ofbiz的强大。