首頁>技術>

環境:Springboot2.2.11.RELEASE + Activiti7.1.0.M6 + MySQL

環境說明:

不要透過如下方式引包

<dependencyManagement>		<dependencies>			<dependency>				<groupId>org.activiti.dependencies</groupId>				<artifactId>activiti-dependencies</artifactId>				<version>7.1.0.M6</version>				<scope>import</scope>				<type>pom</type>			</dependency>		</dependencies></dependencyManagement>

如果透過上面的方式引入會有各種問題。

正確方式:

<dependencies>		<dependency>			<groupId>org.activiti.dependencies</groupId>			<artifactId>activiti-dependencies</artifactId>			<version>7.1.0.M6</version>			<type>pom</type>		</dependency>		<dependency>			<groupId>org.activiti</groupId>			<artifactId>activiti-spring-boot-starter</artifactId>			<version>7.1.0.M6</version>		</dependency>		<dependency>			<groupId>org.springframework.boot</groupId>			<artifactId>spring-boot-starter-security</artifactId>		</dependency>		<dependency>			<groupId>org.springframework.boot</groupId>			<artifactId>spring-boot-starter-web</artifactId>		</dependency>		<dependency>			<groupId>org.mybatis.spring.boot</groupId>			<artifactId>mybatis-spring-boot-starter</artifactId>			<version>2.1.4</version>		</dependency>		<dependency>			<groupId>mysql</groupId>			<artifactId>mysql-connector-java</artifactId>			<scope>runtime</scope>		</dependency>		<dependency>			<groupId>org.springframework.boot</groupId>			<artifactId>spring-boot-starter-test</artifactId>			<scope>test</scope>			<exclusions>				<exclusion>					<groupId>org.junit.vintage</groupId>					<artifactId>junit-vintage-engine</artifactId>				</exclusion>			</exclusions>		</dependency></dependencies>

不知為何activit7中要吧這security強關聯。。。

以上是pom.xml中所要引入的依賴。

所有的表:

ACT_RE_*: 'RE’表示repository。這個字首的表包含了流程定義和流程 靜態資源(圖片、規則等等)

ACT_HI_*: 'HI’表示history。這些表包含歷史資料,比如歷史流程例項,遍歷,任務等等。

ACT_GE_*: 'GE’表示general。通用資料,用於不同場景。

資料表分類

通用資料(act_ge_*)

流程定義(act_re_*)

執行例項(act_ru_*)

歷史流程(act_hi_*)

其他

核心類ProcessEngine

    流程引擎的抽象,可以透過此類獲取需要的所有服務。

    透過ProcessEngine獲取,Activiti將不同生命週期的服務封裝在不同Service中,包括定義、部署、執行。透過服務類可獲取相關生命週期中的服務資訊。

TaskService

    流程執行過程中,每個任務節點的相關操作介面,如complete,delete,delegate等。RepositoryService

    流程定義和部署相關的儲存服務。RuntimeService

    流程執行時相關的服務,如根據流程好啟動流程例項startProcessInstanceByKey。HistoryService

    歷史記錄相關服務介面。

關於eclipse中安裝外掛就不說了,我是把外掛下載下來安裝的,線上安裝不上。

設計請假流程

在src/main/resources下新建processes資料夾,springboot下預設的流程檔案定義路徑字首及檔案字尾如下:

這裡可以在application.yml配置檔案中更改。

設計一個請假的流程holiday.bpmn

<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.pack.org">  <process id="holiday" name="holiday" isExecutable="true">    <startEvent id="startevent1" name="Start"></startEvent>    <endEvent id="endevent1" name="End"></endEvent>    <userTask id="usertask1" name="部門經理審批" activiti:assignee="${mgr}"></userTask>    <userTask id="usertask2" name="總經理審批" activiti:assignee="${top}"></userTask>    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="endevent1"></sequenceFlow>    <userTask id="usertask3" name="填寫審批單" activiti:assignee="${assignee}"></userTask>    <sequenceFlow id="flow4" sourceRef="startevent1" targetRef="usertask3"></sequenceFlow>    <sequenceFlow id="flow5" sourceRef="usertask3" targetRef="usertask1"></sequenceFlow>  </process>  <bpmndi:BPMNDiagram id="BPMNDiagram_holiday">    <bpmndi:BPMNPlane bpmnElement="holiday" id="BPMNPlane_holiday">      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">        <omgdc:Bounds height="35.0" width="35.0" x="505.0" y="60.0"></omgdc:Bounds>      </bpmndi:BPMNShape>      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">        <omgdc:Bounds height="35.0" width="35.0" x="505.0" y="550.0"></omgdc:Bounds>      </bpmndi:BPMNShape>      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">        <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="290.0"></omgdc:Bounds>      </bpmndi:BPMNShape>      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">        <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="420.0"></omgdc:Bounds>      </bpmndi:BPMNShape>      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">        <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="170.0"></omgdc:Bounds>      </bpmndi:BPMNShape>      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">        <omgdi:waypoint x="522.0" y="345.0"></omgdi:waypoint>        <omgdi:waypoint x="522.0" y="420.0"></omgdi:waypoint>      </bpmndi:BPMNEdge>      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">        <omgdi:waypoint x="522.0" y="475.0"></omgdi:waypoint>        <omgdi:waypoint x="522.0" y="550.0"></omgdi:waypoint>      </bpmndi:BPMNEdge>      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">        <omgdi:waypoint x="522.0" y="95.0"></omgdi:waypoint>        <omgdi:waypoint x="522.0" y="170.0"></omgdi:waypoint>      </bpmndi:BPMNEdge>      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">        <omgdi:waypoint x="522.0" y="225.0"></omgdi:waypoint>        <omgdi:waypoint x="522.0" y="290.0"></omgdi:waypoint>      </bpmndi:BPMNEdge>    </bpmndi:BPMNPlane>  </bpmndi:BPMNDiagram></definitions>

上面的每一個節點(任務)都動態的指派了使用者執行。

填寫審批單:${assignee};

部門經理審批: ${mgr};

總經理審批:${top};

每一個節點執行完成時都需要指明下一個節點的執行人。

配置檔案
mybatis:  mapper-locations: classpath:mapper/*.xml  type-aliases-package: com.pack.domainserver:  port: 8080spring:  activiti:    check-process-definitions: true    db-history-used: true    history-level: full    database-schema-update: true  datasource:    driverClassName: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT%2B8    username: root    password: xxxxxx    type: com.zaxxer.hikari.HikariDataSource    hikari:      minimumIdle: 10      maximumPoolSize: 200      autoCommit: true      idleTimeout: 30000      poolName: MasterDatabookHikariCP      maxLifetime: 1800000      connectionTimeout: 30000      connectionTestQuery: SELECT 1

spring.activiti.db-history-used:表示是用歷史表,如果不設定為true那麼只會生成17張表,只有設定為true後才會生成25張表。如果不生成歷史表那麼,流程圖及執行節點無法展示。

spring.activiti.history-level:對於歷史資料,儲存到何種粒度,Activiti提供了history-level屬性對其進行配置。history-level屬性有點像log4j的日誌輸出級別,該屬性有以下四個值:

none:不儲存任何的歷史資料,因此,在流程執行過程中,這是最高效的。activity:級別高於none,儲存流程例項與流程行為,其他資料不儲存。audit:除activity級別會儲存的資料外,還會儲存全部的流程任務及其屬性。audit為history的預設值。full:儲存歷史資料的最高級別,除了會儲存audit級別的資料外,還會儲存其他全部流程相關的細節資料,包括一些流程引數等。

spring.activiti.check-process-definitions:如果不設定為true,那麼流程定義必須手動進行部署。

sprint security配置,放行任何請求:

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {		@Override	protected void configure(HttpSecurity http) throws Exception {		http			.csrf().disable()			.authorizeRequests()			.antMatchers("/**")			.permitAll() ;				}	}

服務工具類HolidayService

@Servicepublic class HolidayService {	private static final Logger logger = LoggerFactory.getLogger(HolidayService.class);	@Resource	private ProcessEngine processEngine;	@Resource	private RepositoryService repositoryService ;	@Resource	private RuntimeService runtimeService ;	@Resource	private TaskService taskService ;	/**	 * <p>	 * 流程定義的部署 activiti表有哪些? 	 * act_re_deployment 流程定義部署表,記錄流程部署資訊 	 * act_re_procdef 流程定義表,記錄流程定義資訊 	 * act_ge_bytearray 資源表(bpmn檔案及png檔案)	 * </p>	 * <p>時間:2021年1月22日-下午3:33:00</p>	 * @author xg	 * @return void	 */	public void createDeploy() {		Deployment deployment = repositoryService.createDeployment()				.addClasspathResource("processes/holiday.bpmn")				.addClasspathResource("processes/holiday.png")				.name("請假申請單流程")				.key("holiday")				.category("InnerP")				.deploy();		logger.info("流程部署id: {}", deployment.getId());		logger.info("流程部署名稱: {}", deployment.getName());	}  // 注意這裡這個方法是當我們沒有開啟自動部署流程定義時,就需要手動部署。	/**	 * <p>	 * 	流程定義查詢	 * </p>	 * <p>時間:2021年1月22日-下午3:45:02</p>	 * @author xg	 * @param processDefinition	 * @return void	 */	public List<ProcessDefinition> queryProcessDefinitionByKey(String processDefinition) {		// 查詢流程定義		ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();		List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(processDefinition).list();		list.forEach(pd -> {			logger.info("------------------------------------------------");			logger.info("流程部署id:{}", pd.getDeploymentId());			logger.info("流程定義id:{}", pd.getId());			logger.info("流程定義名稱:{}", pd.getName());			logger.info("流程定義key:{}", pd.getKey());			logger.info("流程定義版本:{}", pd.getVersion());			logger.info("------------------------------------------------");		});		return list ;	}	/**	 * <p>	 * 	刪除流程	 * </p>	 * <p>時間:2021年1月22日-下午4:21:40</p>	 * @author xg	 * @return void	 */	public void deleteDeployment(String deploymentId) {		// 設定true 級聯刪除流程定義,即使該流程有流程例項啟動也可以刪除,設定為false非級別刪除方式,如果流程		repositoryService.deleteDeployment(deploymentId, true);	}	/**	 * <p>	 * 	啟動流程例項(比如使用者根據定義好的流程發起一個流程的例項(這裡的請假流程申請))	 * <p>時間:2021年1月22日-下午4:54:56</p>	 * @author xg	 * @return void	 */	public void startProcessInstanceById(String processDefinitionId) {		ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId) ;		logger.info("流程定義ID: {}", processInstance.getProcessDefinitionId());		logger.info("流程例項ID: {}", processInstance.getId());	}		/**	 * <p>	 * 	啟動流程例項,指定業務Key(方便關聯業務資料)(比如使用者根據定義好的流程發起一個流程的例項(這裡的請假流程申請))	 * 	Businesskey(業務標識)		啟動流程例項時,指定的businesskey,就會在act_ru_execution #流程例項的執行表中儲存businesskey。		Businesskey:業務標識,通常為業務表的主鍵,業務標識和流程例項一一對應。業務標識來源於業務系統。儲存業務標識就是根據業務標識來關聯查詢業務系統的資料。		比如:請假流程啟動一個流程例項,就可以將請假單的id作為業務標識儲存到activiti中,		將來查詢activiti的流程例項資訊就可以獲取請假單的id從而關聯查詢業務系統資料庫得到請假單資訊。	 * <p>時間:2021年1月22日-下午4:54:56</p>	 * @author xg	 * @return void	 */	public void startProcessInstanceToBussinessKey(String processDefinitionId, String bussinessKey) {		ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, bussinessKey);		logger.info("流程定義ID: {}", processInstance.getProcessDefinitionId());		logger.info("流程例項ID: {}", processInstance.getId());		logger.info("BussinessKey: {}", processInstance.getBusinessKey()) ;	}		/**	 *  <p>	 *  	設定assignee的取值,使用者可以在介面上設定流程的執行人	 *  </p>	 *  <p>時間:2021年1月22日-下午8:30:39</p>	 * @author xg	 * @param processDefinitionId 	 * @return void	 */	public void startProcessInstanceAssignVariables(String processDefinitionId, Map<String, Object> variables) {		ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables);		logger.info("流程定義ID: {}", processInstance.getProcessDefinitionId());		logger.info("流程例項ID: {}", processInstance.getId());		logger.info("BussinessKey: {}", processInstance.getBusinessKey()) ;	}		/**	 *  <p>	 *  	查詢指派關聯的使用者任務	 *  </p>	 *  <p>時間:2021年1月23日-上午11:39:56</p>	 * @author xg	 * @param assignee 關聯使用者	 * @return List<Task>	 */	public List<Task> queryTasks(String assignee) {		TaskQuery query = taskService.createTaskQuery() ;		return query.taskAssignee(assignee).orderByTaskCreateTime().asc().list() ;	}		public void executionTask(Map<String, Object> variables, String instanceId) {		Task task = taskService.createTaskQuery().processInstanceId(instanceId).singleResult() ;		if (task == null) {			logger.error("任務【{}】不存在", instanceId) ;			throw new RuntimeException("任務【" + instanceId + "】不存在") ;		}		taskService.complete(task.getId(), variables) ;	}}

HolidayController介面

@RestController@RequestMapping("/holidays")public class HolidayController {		@Resource	private HolidayService holidayService ;		/**	 *  <p>查詢制定key的流程審批</p>	 *  <p>時間:2021年1月23日-上午11:17:02</p>	 * @author xg	 * @param key ProcessDefinitionKey	 * @return R	 */	@GetMapping("")	public R lists(String key) {		return R.success(holidayService.queryProcessDefinitionByKey(key)) ;	}		/**	 *  <p>建立請假流程審批(私有)</p>	 *  <p>時間:2021年1月23日-上午10:31:47</p>	 * @author xg	 * @return R	 */	@GetMapping("/_deploy")	public R createDeploy() {		holidayService.createDeploy();		return R.success() ;	}		/**	 *  <p>啟動請假審批流程</p>	 *  <p>時間:2021年1月23日-上午10:32:55</p>	 * @author xg	 * @param userId	 * @param processDefinitionId 流程定義Id	 * @return R	 */	@GetMapping("/start")	public R startProcess(String userId, String processDefinitionId) {		Map<String, Object> variables = new HashMap<>() ;		variables.put("assignee", userId) ;		holidayService.startProcessInstanceAssignVariables(processDefinitionId, variables) ;		return R.success() ;	}		/**	 *  <p>	 *  	查詢指派給我的任務	 *  </p>	 *  <p>時間:2021年1月23日-上午11:41:21</p>	 * @author xg	 * @param userId 使用者Id	 * @return R	 */	@GetMapping("/tasks")	public R myTasks(String userId) {		List<Task> list = holidayService.queryTasks(userId) ;    // 注意這裡需要我們自己組裝下資料,不然會報錯。		List<Map<String, Object>> result = list.stream().map(task -> {			Map<String, Object> res = new HashMap<String, Object>() ;			res.put("id", task.getId()) ;			res.put("assignee", task.getAssignee()) ;			res.put("createTime", task.getCreateTime()) ;			res.put("bussinessKey", task.getBusinessKey()) ;			res.put("category", task.getCategory()) ;			res.put("dueDate", task.getDueDate()) ; // 到期日期			res.put("desc", task.getDescription()) ;			res.put("name", task.getName()) ;			res.put("owner", task.getOwner()) ;			res.put("instanceId", task.getProcessInstanceId()) ;			res.put("variables", task.getProcessVariables()) ;			return res ;		}).collect(Collectors.toList()) ;		return R.success(result) ;	}		/**	 *  <p>	 *  	填寫審批單	 *  </p>	 *  <p>時間:2021年1月23日-上午11:57:30</p>	 * @author xg	 * @param Map取值如下	 * @param days 請假天數	 * @param explain 審批單說明	 * @param instanceId 流程例項ID	 * @param assignee 指定下一個流程執行人	 * @return R	 */	@GetMapping("/apply")	public R fillApply(@RequestParam Map<String, Object> variables) {		String instanceId = (String) variables.remove("instanceId") ;		if (StringUtils.isEmpty(instanceId)) {			return R.failure("未知任務") ;		}		holidayService.executionTask(variables, instanceId);		return R.success() ; 	}	}

測試:

1、啟動服務

這裡放在processes中的流程定義檔案已經被自動部署上了。查看錶act_re_procdef

查詢制定key的流程審批介面:/holidays啟動請假審批流程介面:/holidays/start

引數:processDefinitionId:流程定義中的ID。userId:要處理使用者的id。

查看錶資訊:

這時候就為使用者id為:10000的生成了一個要處理的任務,填寫審批單。

查詢指派給我需要處理的任務介面:/holidays/tasks填寫審批單介面:/holidays/apply

引數:mgr:指定下一個節點處理人。explain:請假原因。days:請假天數。

這裡根據自己的業務需要去設定。

再次呼叫查詢介面userId=10002

流程已經到了部門經理。

再次呼叫/holidays/apply介面。

引數:top:指明總經理節點需要處理的userId。

再次呼叫/holidays/apply介面。(總經理處理)

查詢對應的任務表資訊,已經沒有資料了。

查詢表:act_hi_actinst

到此一個流程就走完了。下篇 檢視流程圖。

完畢!!!

13
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 讓你的 JS 程式碼變得更加優雅且可維護