这里实验工作流开发:使用STS作为IDE,使用Activiti作为工作流框架。
安装和使用STS的方法,此处不再赘述。
1、自动创建工作流表
创建一个Springboot项目,
修改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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.edison</groupId>
<artifactId>activiti-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>activiti-test</name>
<description>Demo project for activiti</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- activiti -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<!-- mysql -->
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
修改入口类:
package com.edison.demo;
import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = {"com.edison.demo"})
@MapperScan(basePackages = {"com.edison.demo"})
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class ActivitiTestApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiTestApplication.class, args);
}
}
修改application.properties:
server.port=8080
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_activiti?serverTimezone=Asia/Chongqing&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&autoReconnct=true&autoReconnectForPools=true&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=radar
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.edison.model
spring.activiti.check-process-definitions=false
直接在STS中启动微服务,
该服务会创建28张表,
如下:
表分类 |
表名称 |
表含义 |
事件 |
act_evt_log |
事件处理日志表 |
一般数据 |
act_ge_bytearray |
通用的流程定义和流程资源 |
act_ge_property |
系统相关属性 |
|
流程历史记录 |
act_hi_actinst |
历史的流程实例 |
act_hi_attachment |
历史的流程附件 |
|
act_hi_comment |
历史的说明性信息 |
|
act_hi_detail |
历史的流程运行中的细节信息 |
|
act_hi_identitylink |
历史的流程运行过程中用户关系 |
|
act_hi_procinst |
历史的流程实例 |
|
act_hi_taskinst |
历史的任务实例 |
|
act_hi_varinst |
历史的流程运行中的变量信息 |
|
用户用户组表 |
act_id_group |
身份信息-组信息 |
act_id_info |
身份信息-组信息 |
|
act_id_membership |
身份信息-用户和组关系的中间表 |
|
act_id_user |
身份信息-用户信息 |
|
act_procdef_info |
死信任务 |
|
流程定义表 |
act_re_deployment |
部署单元信息 |
act_re_model |
模型信息 |
|
act_re_procdef |
已部署的流程定义 |
|
运行实例表 |
act_ru_deadletter_job |
执行失败任务表 |
act_ru_event_subscr |
运行时事件 |
|
act_ru_execution |
运行时流程执行实例 |
|
act_ru_identitylink |
运行时用户关系信息 |
|
act_ru_job |
运行时作业 |
|
act_ru_suspended_job |
运行时暂停任务 |
|
act_ru_task |
运行时任务 |
|
act_ru_timer_job |
运行时定时任务 |
|
act_ru_variable |
运行时变量表 |
可能遇到的错误:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'db_activiti.act_ge_property' doesn't exist
### The error may exist in org/activiti/db/mapping/entity/Property.xml
解决方法:很可能在另外一个数据库中已经存在act_ge_property,把另外一个库中act相关的表删除后即可。
2、ACTIVITI工作流术语
(1) 业务流程
一个ProcessDefinition代表的业务流程。它用于定义流程中不同步骤的结构和行为。
(2) 流程定义
部署流程定义意味着将流程定义加载到Activiti数据库中。
(3) BPMN 2.0标准
流程定义主要由BPMN 2.0标准定义,也可以使用Java代码定义它们,定义的所有术语也可用作Java类。
(4) 流程process
一旦我们开始运行流程定义,就可以称为一个流程process。
(5) processInstance
processInstance是ProcessDefinition一个执行实例。
(6) StartEvent
一个StartEvent与每一个业务流程有关,它表示该流程的切入点,同样,有一个EndEvent表示流程的结束。我们可以定义这些事件的条件。
(7) 任务
开始和结束之间的所有步骤(或元素)称为任务,任务可以是各种类型的。最常用的任务是UserTasks和ServiceTasks。
(8)服务
RepositoryService:帮助我们实现流程定义的部署。此服务会处理与流程定义相关的静态数据。
RuntimeService:管理 ProcessInstances(当前正在运行的流程)以及流程变量
TaskService:会跟踪 UserTasks,需要由用户手动执行的任务是Activiti API的核心。我们可以使用此服务创建任务,声明并完成任务,分配任务的受让人等。
FormService:是一项可选服务,它用于定义中开始表单和任务表单。
IdentityService:管理用户和组。
HistoryService:会跟踪Activiti Engine的历史记录。我们还可以设置不同的历史级别。
ManagementService:与元数据相关,在创建应用程序时通常不需要。
DynamicBpmnService:帮助我们在不重新部署的情况下更改流程中的任何内容。
3、增加设计器插件
在线安装:在STS中Help -> Install New SoftWare-> Add:
Name: Activiti Designer
Location: http://activiti.org/designer/update/
在线安装往往会失败。
离线安装:安装失败就使用离线下载,官方提示链接:
https://github.com/Activiti/Activiti-Designer/releases
下载地址:
https://www.activiti.org/designer/archived/activiti-designer-5.18.0.zip
但是这个文件不完整,还差文件,缺失的jar包在错误提示里面有,可以从mvnreprository.com中找到。
以下链接是已经测试通过的完整文件:
https://gitee.com/radarfyh/spring-cloud-test/tree/spring-cloud-test/activiti-test
如下图,activiti-designer-5.18.0.zip文件是官网下载的,plugins.zip里面是缺失的文件,解压后放入前一个zip中。
然后在STS中Help -> Install New SoftWare-> Add:
由此可以成功安装。
安装成功后,在new建项目的other目录下可以找到:
到preferences中修改设置:
4、入门项目
(1)新建Springboot项目,POM文件引入spring-boot-starter-web、angularjs、activiti-spring-boot-starter-basic、mysql-connector-java,如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.edison</groupId>
<artifactId>activiti-test6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>activiti-test6</name>
<description>测试初始工作流项目</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>angularjs</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(2)入口类修改为:
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@RestController
public class ActivitiTest6Application {
public static void main(String[] args) {
SpringApplication.run(ActivitiTest6Application.class, args);
}
@GetMapping("/test")
public User sayHello(){
System.out.println("----采用angularjs----");
User user = new User();
user.setName("admin");
user.setPassword("123456");
return user;
}
}
(3)新增用户类:
public class User {
String id;
String name;
String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(4)新增任务描述类:
public class TaskRepresentation {
private String id;
private String name;
public TaskRepresentation(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(5)新增服务类:
@Service
public class ActivitiService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
public String start() {
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myProcess");
return instance.getId();
}
public List<Task> getTask(String uid) {
List<Task> tasks = taskService.createTaskQuery().taskAssignee(uid).list();
return tasks;
}
}
(6)新增控制类:
@RestController
@RequestMapping(value = "activiti")
public class ActivitiController {
@Autowired
private ActivitiService service;
@RequestMapping(value = "start", method = RequestMethod.GET)
public String start() {
return service.start();
}
@RequestMapping(value = "task", method = RequestMethod.GET)
public List<TaskRepresentation> getTask(@RequestParam(value = "uid") String uid) {
List<Task> tasks = service.getTask(uid);
List<TaskRepresentation> dtos = new ArrayList<>();
for (Task task : tasks) {
dtos.add(new TaskRepresentation(task.getId(), task.getName()));
}
return dtos;
}
}
(7)新增审批流程(activiti diagram),如下:
其中流程id为myProcess,审批任务的审核者Assignee为admin。
(8)新增前端页面index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>流程测试首页</title>
</head>
<!--<script type="text/javascript" src="js/angular.js"></script>-->
<script type="text/javascript"
src="webjars/angularjs/1.7.2/angular.min.js"></script>
<script type="text/javascript" src="controller/userController.js"></script>
<body>
<h1>测试activiti</h1>
<div ng-app="myApp" >
<div ng-controller="userController" ng-init="queryTasks()">
<h2>待我审核的任务</h2>
<table border="2">
<tr>
<td>id</td>
<td>名称</td>
</tr>
<tr ng-repeat="vacTask in vacTaskList">
<td>{{vacTask.id}}</td>
<td>{{vacTask.name}}</td>
</tr>
</table>
<h4>{{title}}{{number}}</h4>
</div>
</div>
</body>
</html>
(9)新增angularjs的控制器userController.js:
var app=angular.module("myApp",[]);
app.controller("userController",function ($scope,$http) {
$scope.vacTaskList = [];
$scope.queryTasks = function () {
$http.get(
"/activiti/task?uid=admin"
).then(function (response) {
$scope.vacTaskList = response.data;
$scope.title = "任务数量为:";
$scope.number=$scope.vacTaskList.length;
})
};
})
(10)新增配置文件application.yml,如下:
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://localhost:3306/act5?serverTimezone=Asia/Chongqing&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&autoReconnct=true&autoReconnectForPools=true&allowMultiQueries=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: radar
# activiti default configuration
activiti:
database-schema-update: true
check-process-definitions: true
process-definition-location-prefix: classpath:/processes/
# process-definition-location-suffixes:
# - **.bpmn
# - **.bpmn20.xml
history-level: full
(11)使用chrome测试:
(12)可能遇到的错误
错误:Could not update Activiti database schema: unknown version from database: '6.0.0.4'
解决办法:删除以前的activiti表:
错误:Cannot instantiate interface org.springframework.context.ApplicationContextInitializer
详细提示:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.0.4.RELEASE:run (default-cli) on project activiti-test1: An exception occurred while running. null: InvocationTargetException: Cannot instantiate interface org.springframework.context.ApplicationContextInitializer : org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer: org.springframework.core.KotlinDetector.isKotlinReflectPresent()Z -> [Help 1]
解决办法:编译通过后,这是使用mvn spring-boot:run出现的错误
错误:Description Resource Path Location Type
Failed to read artifact descriptor for com.fasterxml.jackson.core:jackson-core:jar:2.9.6
解决办法:这是POM提示的错误,在本地仓库中找到_remote.repositories,把其中两个的远程仓库指定为私服alfresco,或者其他服,例如私服nexus,*服central
如果项目太多,删除他们,只剩一个,这样可以解决各个项目之间的影响,猜测是STS的bug。STS的版本为:4.5.1.RELEASE
错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
......
java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
解决方案:
在注解@SpringBootApplication后面加入exclude,如下:
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
注意import 的包不要错了,应该引入:
import org.activiti.spring.boot.SecurityAutoConfiguration;