SpringBoot使用activiti自定義流程demo解析


環境搭建【這里直接講解自定義流程】

集成 Activiti Modeler

下載源碼

我這里選用的是 Activiti 5.23.0 版本的頁面,下載 zip,解壓
Activiti 5.23.0 源碼

pom依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.activiti6</groupId>
	<artifactId>activiti6-demo</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.RELEASE</version>
		<relativePath/>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<druid.version>1.1.6</druid.version>
        <activiti.version>6.0.0</activiti.version>
        <apache.xmlgraphics.version>1.7</apache.xmlgraphics.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>

		<!-- mysql 驅動依賴-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!-- Druid DataSource -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>${druid.version}</version>
		</dependency>

        <!-- activiti -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>${activiti.version}</version> 
        </dependency>
        
		<dependency>
		     <groupId>org.activiti</groupId>
		     <artifactId>activiti-json-converter</artifactId>
		     <version>${activiti.version}</version>
		     <exclusions>
				<exclusion>
					<groupId>org.activiti</groupId>
      				<artifactId>activiti-bpmn-model</artifactId>
				</exclusion>
		     </exclusions>
    	</dependency>
    	
	    <dependency> 
		    <groupId>org.apache.xmlgraphics</groupId> 
		    <artifactId>batik-codec</artifactId> 
		    <version>${apache.xmlgraphics.version}</version> 
	    </dependency> 
	    <dependency> 
		    <groupId>org.apache.xmlgraphics</groupId> 
		    <artifactId>batik-css</artifactId> 
		    <version>${apache.xmlgraphics.version}</version> 
	    </dependency> 
	    <dependency> 
		    <groupId>org.apache.xmlgraphics</groupId> 
		    <artifactId>batik-svg-dom</artifactId> 
		    <version>${apache.xmlgraphics.version}</version> 
	    </dependency> 
	    <dependency> 
		    <groupId>org.apache.xmlgraphics</groupId> 
		    <artifactId>batik-svggen</artifactId> 
		    <version>${apache.xmlgraphics.version}</version> 
	    </dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>RELEASE</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.70</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

代碼集成

前端代碼集成
在項目中的 resource 文件夾下新建一個 static 文件夾

SpringBoot 能自動讀取 static 目錄下的靜態文件,因此文件夾名稱不可隨意更改

找到 activiti-webapp-explorer2 包

將 webapp 下的 diagram-viewer 文件夾,editor-app 文件夾,modeler.html 文件復制到 static 下

diagram-viewer:流程圖跟蹤組件
editor-app:目錄中包含設計器里面所有的資源:angular.js、oryx.js以及配套的插件及css
modeler.html:流程設計器的主頁面,用來引入各種web資源
路徑:Activiti-5.23.0\modules\activiti-webapp-explorer2\src\main\webapp

在這里插入圖片描述

后端代碼集成

將 Activit 5.23.0 項目中 resource 文件夾下的 stencilset.json 放到自己項目的 resource 目錄下
路徑:Activiti-5.23.0\modules\activiti-webapp-explorer2\src\main\resources
在我提供的demo中有漢化版本,這里只有國際版本
在這里插入圖片描述
找到 activiti-modeler 包

將里面的 StencilsetRestResource.java,ModelEditorJsonRestResource.java,ModelSaveRestResource.java 文件放到自己的項目里

  • StencilsetRestResource.java:用於讀取 stencilset.json 文件
  • ModelEditorJsonRestResource.java:用戶獲取流程數據
  • ModelSaveRestResource.java:用於保存流程數據
    路徑:Activiti-5.23.0\modules\activiti-modeler\src\main\java\org\activiti\rest\editor
    在這里插入圖片描述
    在這里插入圖片描述

項目結構

在這里插入圖片描述
創建流程與部署流程

package com.activiti6.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/** * 流程控制器 * zhudunfrng */
@Controller
public class ModelerController{

    private static final Logger logger = LoggerFactory.getLogger(ModelerController.class);

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;

    
	@RequestMapping("index")
	public ModelAndView index(ModelAndView modelAndView) {
        modelAndView.setViewName("index");
        modelAndView.addObject("modelList", repositoryService.createModelQuery().list());
        return modelAndView;
	}
	
    /** * 跳轉編輯器頁面 * @return */
    @GetMapping("editor")
    public String editor(){
        return "modeler";
    }
    
    
    /** * 創建模型 * @param response * @param name 模型名稱 * @param key 模型key */
    @RequestMapping("/create")
    public void create(HttpServletResponse response,String name,String key) throws IOException {
    	logger.info("創建模型入參name:{},key:{}",name,key);
        Model model = repositoryService.newModel();
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, "");
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());
        //存入表act_re_model
        repositoryService.saveModel(model);
        createObjectNode(model.getId());
        response.sendRedirect("/editor?modelId="+ model.getId());
        logger.info("創建模型結束,返回模型ID:{}",model.getId());
    }
    
    /** * 創建模型時完善ModelEditorSource,這里是對畫布的相關設置 * @param modelId */
	@SuppressWarnings("deprecation")
	private void createObjectNode(String modelId){
    	 logger.info("創建模型完善ModelEditorSource入參模型ID:{}",modelId);
    	 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);
         try {
			repositoryService.addModelEditorSource(modelId,editorNode.toString().getBytes("utf-8"));
		} catch (Exception e) {
			 logger.info("創建模型時完善ModelEditorSource服務異常:{}",e);
		}
        logger.info("創建模型完善ModelEditorSource結束");
    }
    
    /** * 發布流程///流程部署 * @param modelId 模型ID * @return */
    @ResponseBody
    @RequestMapping("/publish")
    public Object publish(String modelId){
    	logger.info("流程部署入參modelId:{}",modelId);
    	Map<String, String> map = new HashMap<String, String>();
		try {
			Model modelData = repositoryService.getModel(modelId);//獲取相應的模型信息,act_re_model
	        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());//獲取相應的流程文件信息,act_ge_bytearray
	        if (bytes == null) {//沒有相應的流程文件
	        	logger.info("部署ID:{}的模型數據為空,請先設計流程並成功保存,再進行發布",modelId);
	        	map.put("code", "FAILURE");
	            return map;
	        }
			JsonNode modelNode = new ObjectMapper().readTree(bytes);//解析相應的流程文件
			BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
			//部署
	        Deployment deployment = repositoryService.createDeployment()
	        		.name(modelData.getName())//模型名稱
	        		.addBpmnModel(modelData.getKey()+".bpmn20.xml", model)
	        		.deploy();//部署相應的流程
	        modelData.setDeploymentId(deployment.getId());//獲取流程部署后的流程id
	        repositoryService.saveModel(modelData);//保存到act_re_model表中
	        map.put("code", "SUCCESS");
		} catch (Exception e) {
			logger.info("部署modelId:{}模型服務異常:{}",modelId,e);
			map.put("code", "FAILURE");
		}
		logger.info("流程部署出參map:{}",map);
        return map;
    }
    
    /** * 撤銷流程定義 * @param modelId 模型ID * @return */
    @ResponseBody
    @RequestMapping("/revokePublish")
    public Object revokePublish(String modelId){
    	logger.info("撤銷發布流程入參modelId:{}",modelId);
    	Map<String, String> map = new HashMap<String, String>();
		Model modelData = repositoryService.getModel(modelId);//獲取相應的模型信息,act_re_model
		if(null != modelData){
			try {
				/** * 參數不加true:為普通刪除,如果當前規則下有正在執行的流程,則拋異常 * 參數加true:為級聯刪除,會刪除和當前規則相關的所有信息,包括歷史 */
				//根據流程的部署ID刪除act_re_procdef、act_re_deployment表中的數據,后面的true是將還有未完成任務的流程強制刪除
				repositoryService.deleteDeployment(modelData.getDeploymentId(),true);
				map.put("code", "SUCCESS");
			} catch (Exception e) {
				logger.error("撤銷已部署流程服務異常:{}",e);
				map.put("code", "FAILURE");
			}
		}
		logger.info("撤銷發布流程出參map:{}",map);
        return map;
    }
    
    /** * 刪除流程實例 流程正在運行中 * @param modelId 模型ID * @return */
    @ResponseBody
    @RequestMapping("/delete")
    public Object deleteProcessInstance(String modelId){
    	logger.info("刪除流程實例入參modelId:{}",modelId);
    	Map<String, String> map = new HashMap<String, String>();
		Model modelData = repositoryService.getModel(modelId);//獲取相應的模型信息,act_re_model
		if(null != modelData){
			try {
			    //流程啟動后會在act_ru_execution表中查到,根據流程定義的key進行查詢
			   ProcessInstance pi = runtimeService.createProcessInstanceQuery().processDefinitionKey(modelData.getKey()).singleResult();
			   if(null != pi) {
                    //根據流程實例ID進行刪除,act_ru_execution
				   runtimeService.deleteProcessInstance(pi.getId(), "");
				   //刪除歷史流程實例act_hi_procinst
				   historyService.deleteHistoricProcessInstance(pi.getId());
			   }
				map.put("code", "SUCCESS");
			} catch (Exception e) {
				logger.error("刪除流程實例服務異常:{}",e);
				map.put("code", "FAILURE");
			}
		}
		logger.info("刪除流程實例出參map:{}",map);
        return map;
    }

	/** * 啟動流程 */
	@RequestMapping("/start/{id}")
	public void startProcess(@PathVariable("id")String processDefinitionId){
		ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
		//從act_ru_exection中查詢
		System.out.println("流程啟動成功:\n"+"執行實例id:"+processInstance.getId()
				+"\n流程定義id:"+processInstance.getProcessDefinitionId()
				+"\n流程實例id:"+processInstance.getProcessInstanceId());
	}
}

demo源碼
部分內容引自
我的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM