Activiti上手也有两三个月了,今天写一个springmvc框架整合Activiti 流程设计器的文章,我用的activiti版本是5.16。
通过Modeler设计的流程模型可以直接部署到引擎,也可以把已经部署的流程转换为Model从而在Modeler中编辑。
<dependency> <groupid>org.activiti</groupid> <artifactid>activiti-explorer</artifactid> <version>5.16</version> <exclusions> <exclusion> <artifactid>vaadin</artifactid> <groupid>com.vaadin</groupid> </exclusion> <exclusion> <artifactid>dcharts-widget</artifactid> <groupid>org.vaadin.addons</groupid> </exclusion> <exclusion> <artifactid>activiti-simple-workflow</artifactid> <groupid>org.activiti</groupid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.activiti</groupid> <artifactid>activiti-modeler</artifactid> <version>5.16</version> </dependency>
package com.isoftstone.cms.workflow.org.activiti.explorer.rest; import org.activiti.rest.common.api.DefaultResource; import org.activiti.rest.common.application.ActivitiRestApplication; import org.activiti.rest.common.filter.JsonpFilter; import org.activiti.rest.diagram.application.DiagramServicesInit; import org.activiti.rest.editor.application.ModelerServicesInit; import org.restlet.Restlet; import org.restlet.routing.Router; public class ExplorerRestApplication extends ActivitiRestApplication { public ExplorerRestApplication() { super(); } /** * Creates a root Restlet that will receive all incoming calls. */ @Override public synchronized Restlet createInboundRoot() { Router router = new Router(getContext()); router.attachDefault(DefaultResource.class); ModelerServicesInit.attachResources(router); DiagramServicesInit.attachResources(router); JsonpFilter jsonpFilter = new JsonpFilter(getContext()); jsonpFilter.setNext(router); return jsonpFilter; } }
<!-- 流程配置开始 --> <!-- Restlet adapter, used to expose modeler functionality through REST --> <servlet> <servlet-name>ExplorerRestletServlet</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>com.isoftstone.cms.workflow.org.activiti.explorer.rest.ExplorerRestApplication</param-value> </init-param> </servlet> <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.activiti.rest.service.application.ActivitiRestServicesApplication</param-value> </init-param> </servlet> <!-- Catch all service requests --> <servlet-mapping> <servlet-name>ExplorerRestletServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>RestletServlet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> <!-- 流程配置结束 -->
<!--工作流配置 开始--> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="publicDataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="databaseSchemaUpdate" value="true" /> <property name="jobExecutorActivate" value="false" /> <property name="history" value="full"/> <property name="enableDatabaseEventLogging" value="false" /> <property name="databaseType" value="mysql"/> <!-- 自定义表单字段类型 --> <!-- <property name="customFormTypes"> <list> <bean class="com.iss.itreasury.workflow.form.UsersFormType"/> </list> </property> --> <!-- 生成流程图的字体 宋体=\u5B8B\u4F53--> <property name="activityFontName" value="\u5B8B\u4F53"/> <property name="labelFontName" value="\u5B8B\u4F53"/> </bean> <!-- 事务管理器配置, 单数据源事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="publicDataSource" /> </bean> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration" /> </bean> <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> <bean id="formService" factory-bean="processEngine" factory-method="getFormService" /> <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" /> <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" /> <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" /> <bean class="com.isoftstone.cms.workflow.util.ActivtiManager" init-method="initMethod" lazy-init="false"> <property name="repositoryService" ref="repositoryService" /> <property name="runtimeService" ref="runtimeService" /> <property name="formService" ref="formService" /> <property name="identityService" ref="identityService" /> <property name="taskService" ref="taskService" /> <property name="historyService" ref="historyService" /> <property name="managementService" ref="managementService" /> </bean> <!--工作流配置 结束-->
<mvc:resources location="/editor/" mapping="/editor/**"/> <mvc:resources location="/explorer/" mapping="/explorer/**"/> <mvc:resources location="/libs/" mapping="/libs/**"/>
package com.isoftstone.cms.workflow.api; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.activiti.bpmn.converter.BpmnXMLConverter; import org.activiti.bpmn.model.BpmnModel; import org.activiti.editor.constants.ModelDataJsonConstants; import org.activiti.editor.language.json.converter.BpmnJsonConverter; import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Model; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.isoftstone.cms.common.pojo.AjaxDataEntity; import com.isoftstone.cms.component.datagrid.pojo.DataGrid; import com.isoftstone.cms.component.datagrid.pojo.DataResult; import com.isoftstone.cms.component.datagrid.pojo.DataStyle; import com.isoftstone.cms.component.datagrid.pojo.PangingParam; import com.isoftstone.cms.component.datagrid.utils.DataTypeConstant; import com.isoftstone.cms.component.datagrid.utils.PangingTools; import com.isoftstone.cms.syscore.api.BaseController; import com.isoftstone.cms.syscore.api.JSONFactory; import com.isoftstone.cms.syscore.utils.MessageResourcesUtils; import com.isoftstone.cms.syscore.utils.ServletUtils; import com.isoftstone.cms.workflow.util.ActivtiManager; @Scope("prototype") @Controller public class ModelController extends BaseController{ private static Logger logger = LoggerFactory.getLogger(ModelController.class); private ActivtiManager activtiManager = ActivtiManager.getDefaultManage(); /** * 点击菜单"模版管理"显示“流程模板列表”列表 * @param request * @param response * @param model * @return */ @RequestMapping(value = "/workflow/model/modelList.web") public String queryProvinceList(HttpServletRequest request, HttpServletResponse response) { return "/WEB-INF/jsp/workflow/model/modelList"; } /** * 打开“模版管理”列表加载列表数据 * @param request * @param response * @param model */ @SuppressWarnings({ "unchecked", "rawtypes" }) @RequestMapping(value = "/workflow/model/queryModelListInfoDataGrid.json") public void queryModelListInfoDataGrid(HttpServletRequest request, HttpServletResponse response) { PangingParam pangingParam = null; DataResult dataResult = new DataResult(); DataGrid dataGrid = null; try { pangingParam = (PangingParam) ServletUtils.getParametersToBaseEntity(request, PangingParam.class); HashMap<String, Object> map = (HashMap) ServletUtils.getParametersToHashMap(request); dataGrid = new DataGrid(); dataGrid.setPangingParam(pangingParam); /* map.put("startrow", dataGrid.getStartrow()); map.put("endrow", dataGrid.getEndrow()); map.put("rows", dataGrid.getRows()); map.put("sort", dataGrid.getSort()); map.put("order", dataGrid.getOrder()); map.put("statusid", SysConstant.RecordStatus.VALID);*/ RepositoryService repositoryService = activtiManager.getRepositoryService(); long resultCount = repositoryService.createModelQuery().count(); List<org.activiti.engine.repository.Model> resultList = repositoryService.createModelQuery().orderByCreateTime().desc().listPage((int)(pangingParam.getPage()-1), (int)dataGrid.getRows()); DataStyle dataStyle = new DataStyle(); dataStyle.setPageIndex(pangingParam.getPage()); dataStyle.setDataCount(resultCount); dataStyle.setDataList(resultList); dataStyle.addDepict("id", DataTypeConstant.STRING); dataStyle.addDepict("name", DataTypeConstant.STRING); dataStyle.addDepict("key", DataTypeConstant.STRING); dataStyle.addDepict("version", DataTypeConstant.LONG); dataStyle.addDepict("createTime", DataTypeConstant.DATETIME); dataStyle.addDepict("lastUpdateTime", DataTypeConstant.DATETIME); dataStyle.addDepict("metaInfo", DataTypeConstant.STRING); dataResult = PangingTools.buildResultPagerInfo(dataStyle); if (pangingParam.getReportExportType() == 0) { response.getWriter().write(JSONFactory.toJSONString(dataResult, userContext)); } } catch (Exception e) { e.printStackTrace(); } } /** * 跳转流程模型新增页面 * @param request * @param response * @param model * @return */ @RequestMapping(value = "/workflow/model/toAddModel.web") public String toAddModel(HttpServletRequest request, HttpServletResponse response) { return "/WEB-INF/jsp/workflow/model/modelAdd"; } /** * 新增流程模型 */ @RequestMapping(value = "/workflow/model/addModel.web", method = { RequestMethod.GET, RequestMethod.POST }) public String addModel(HttpServletRequest request, HttpServletResponse response) { String modelId =""; try { String name = request.getParameter("name"); String key = request.getParameter("key"); String description = StringUtils.defaultString(request.getParameter("description")); RepositoryService repositoryService = activtiManager.getRepositoryService(); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode editorNode = objectMapper.createObjectNode(); editorNode.put("id", "canvas"); editorNode.put("resourceId", "canvas"); ObjectNode stencilSetNode = objectMapper.createObjectNode(); stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); editorNode.put("stencilset", stencilSetNode); Model modelData = repositoryService.newModel(); ObjectNode modelObjectNode = objectMapper.createObjectNode(); modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name); modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description); modelData.setMetaInfo(modelObjectNode.toString()); modelData.setName(name); modelData.setKey(StringUtils.defaultString(key)); //存入ACT_RE_MODEL repositoryService.saveModel(modelData); //存入ACT_GE_BYTEARRAY repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8")); modelId = modelData.getId(); } catch (Exception e) { logger.error("创建模型失败:", e); } return "redirect:/service/editor?id="+ modelId; } /** * 删除流程模型 * @param request * @param response * @param model */ @RequestMapping(value = "/workflow/model/deleteModel.json", method = { RequestMethod.GET, RequestMethod.POST }) public void deleteModel(HttpServletRequest request, HttpServletResponse response, Model model) { AjaxDataEntity ajaxDataEntity = new AjaxDataEntity(); try { String modelId = getRequest().getParameter("id"); RepositoryService repositoryService = activtiManager.getRepositoryService(); repositoryService.deleteModel(modelId); getUserContext().setInfoMessage(MessageResourcesUtils.getMessage(request, "alertinfo.common.java.alert3")); } catch (Exception e) { e.printStackTrace(); getUserContext().setErrorMessage(MessageResourcesUtils.getMessage(request, "alertinfo.common.java.alert4")); }finally { try { response.getWriter().write(JSONFactory.toJSONString(ajaxDataEntity, getUserContext())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 根据Model部署 */ @RequestMapping(value = "/workflow/model/deploy.json",method = { RequestMethod.GET, RequestMethod.POST }) public void deploy(HttpServletRequest request, HttpServletResponse response) { AjaxDataEntity ajaxDataEntity = new AjaxDataEntity(); String modelId = request.getParameter("id"); RepositoryService repositoryService = activtiManager.getRepositoryService(); try { Model modelData = repositoryService.getModel(modelId); ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId())); byte[] bpmnBytes = null; BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode); bpmnBytes = new BpmnXMLConverter().convertToXML(model,"GBK"); String processName = modelData.getName() + ".bpmn20.xml"; Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes)).deploy(); //修改存入部署对象ID //Model modelData = repositoryService.createModelQuery().modelId(modelId).singleResult(); modelData.setDeploymentId(deployment.getId()); repositoryService.saveModel(modelData); getUserContext().setInfoMessage(MessageResourcesUtils.getMessage(request, "workflow.alertinfo.deploysuccess")); } catch (Exception e) { e.printStackTrace(); logger.error("根据模型部署流程失败:modelId={}", modelId, e); getUserContext().setErrorMessage(MessageResourcesUtils.getMessage(request, "workflow.alertinfo.deployfail")); }finally { try { response.getWriter().write(JSONFactory.toJSONString(ajaxDataEntity, getUserContext())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 导出model对象为指定类型 * * @param modelId * 模型ID * @param type * 导出文件类型(bpmn\json) */ @RequestMapping(value = "/workflow/model/export.web") public void export(HttpServletRequest request, HttpServletResponse response) { RepositoryService repositoryService = activtiManager.getRepositoryService(); String modelId = request.getParameter("id"); String type = "bpmn";//默认导出bpmn格式 try { org.activiti.engine.repository.Model modelData = repositoryService.getModel(modelId); BpmnJsonConverter jsonConverter = new BpmnJsonConverter(); byte[] modelEditorSource = repositoryService.getModelEditorSource(modelData.getId()); JsonNode editorNode = new ObjectMapper().readTree(modelEditorSource); BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode); // 处理异常 if (bpmnModel.getMainProcess() == null) { response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value()); response.getOutputStream().println("no main process, can't export for type: " + type); response.flushBuffer(); return; } String filename = ""; byte[] exportBytes = null; String mainProcessId = bpmnModel.getMainProcess().getId(); switch (type) { case "bpmn": { BpmnXMLConverter xmlConverter = new BpmnXMLConverter(); exportBytes = xmlConverter.convertToXML(bpmnModel,"GBK"); filename = mainProcessId + ".bpmn20.xml"; break; } case "json": { exportBytes = modelEditorSource; filename = mainProcessId + ".json"; } } ByteArrayInputStream in = new ByteArrayInputStream(exportBytes); IOUtils.copy(in, response.getOutputStream()); response.setHeader("Content-Disposition", "attachment; filename=" + filename); response.flushBuffer(); } catch (Exception e) { logger.error("导出model的xml文件失败:modelId={}, type={}", modelId, type, e); } } }