整合Activiti Modeler到SpringMVC

1. 整合初衷

Activiti上手也有两三个月了,今天写一个springmvc框架整合Activiti 流程设计器的文章,我用的activiti版本是5.16。

通过Modeler设计的流程模型可以直接部署到引擎,也可以把已经部署的流程转换为Model从而在Modeler中编辑。

2. 整合工作

2.1下载源码

首先需要从Github下载源码: https://github.com/Activiti/Activiti;可以直接用Git克隆,也可以下载zip格式的压缩包。



2.2复制文件

复制的所有文件均在 activiti-webapp-explorer2目录中。
  1. src/main/resources中的editor.html、stencilset.json、plugins.xml到项目源码的源码根目录,保证编译之后在classes根目录
  2. src/main/webapp中的api、editor、explorer、libs到项目的webapp目录(与WEB-INF目录同级)
  3. 图片如下

2.3添加pom.xml依赖

没有测试过,我用的jar包

<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>


2.4添加ExplorerRestApplication.java类


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;
  }
}

2.5配置web.xml 

<!-- 流程配置开始 -->
    <!-- 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>
<!-- 流程配置结束 -->


2.6配置spring文件applicationContext.xml

<!--工作流配置   开始-->
     <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>
<!--工作流配置   结束-->


2.7配置spring文件DispatcherServlet-servlet.xml

配置静态资源访问路径
<mvc:resources location="/editor/" mapping="/editor/**"/>
<mvc:resources location="/explorer/" mapping="/explorer/**"/>
<mvc:resources location="/libs/" mapping="/libs/**"/>


2.8编写控制器

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);
		}
	}

}




2.9效果展示







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值