activiti与springboot整合
创建工程
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.0.RELEASEversion>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-spring-boot-starterartifactId>
<version>7.0.0.Beta2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.29version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root
activiti:
# false:默认值。在activiti启动时,会对比数据库表中保存的版本,如果没有表或版本不匹配,将抛出异常。(生产环境常用)
# true:activiti会对数据库中所有表进行更新操作。如果表不存在,将会创建。(开发环境常用)
# create-drop:在activiti启动时创建表,在关闭时删除表,必须手动关闭引擎才会删除表。(单元测试用)
# drop-create:在activiti启动时删除旧表,然后创建新表,不需要关闭引擎。
database-schema-update: true
#检测历史表是否存在,activiti7默认没有开启数据库历史记录,true启动数据库历史记录
db-history-used: true
#记录历史等级,可配置的历史级别有:none,activity,audit,full
# none:不保存任何的历史数据,因此在流程执行过程中,这是最高效的
# activity:级别高于none,保存流程实例与流程行为,其他数据不保存
# audit:除保存activity保存的数据外,还会保存全部的流程任务及其属性。history-level的默认值
# full:保存历史数据的最高级别,会额外保存全部流程相关的细节数据。
history-level: full
#校验流程文件,默认校验resources下的process文件夹的流程文件
check-process-definitions: false
@SpringBootApplication
public class ActivitiApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiApplication.class, args);
}
}
同之前一样,配置完成后,创建相应的Service服务即可进行操作
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ActivitiApplication.class)
public class Test01 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Test
public void deployment() {
repositoryService.createDeployment()
.name("activiti-springboot")
.addClasspathResource("bpmn/activiti-springboot.bpmn20.xml")
.deploy();
}
@Test
public void startProcess() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("assignee0", "zhangsan");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activiti-springboot", map);
System.out.println(processInstance.getProcessDefinitionKey());
}
}
在activiti7的新特性:
activiti7与springboot整合后,默认情况下就集成了springsecurity,所以我们需要准备springsecurity的相关配置。
不然会提示异常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHsy1Lmc-1658298356742)(https://cdn.jsdelivr.net/gh/le1024/image1/le/image-20211223152441669.png)]
SecurityUtil
@Slf4j
@Component
public class SecurityUtil {
@Autowired
private UserDetailsService userDetailsService;
/**
* 模拟用户登录
* @param username 用户名
*/
public void login(String username) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new IllegalArgumentException("user doesn`t exist");
}
log.info("login :" + username);
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
private static final long serialVersionUID = 3397680986162930722L;
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
public Object getCredentials() {
return user.getPassword();
}
public Object getDetails() {
return user;
}
public Object getPrincipal() {
return user;
}
public boolean isAuthenticated() {
return true;
}
public void setAuthenticated(boolean b) throws IllegalArgumentException {
}
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
}
}
SecurityConfig
@Slf4j
@Configuration
public class SecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
//添加用户
String[][] userGroupsAndRoles = {
{"jack", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"rose", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"tom", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
{"system", "password", "ROLE_ACTIVITI_USER"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"},
};
//用户信息加到内存
for (String[] user : userGroupsAndRoles) {
List<String> authorities = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
log.info("注册新用户:{},用户权限:{}", user[0], authorities);
inMemoryUserDetailsManager.createUser(
new User(
user[0],
passwordEncoder().encode(user[1]),
authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())
)
);
}
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
根据自己的需要设计,学习教程中如下:
/*
* 直接引入activiti7新增的api,通过新的api操作
*/
@Autowired
private ProcessRuntime processRuntime;
@Autowired
private TaskRuntime taskRuntime;
@Autowired
private SecurityUtil securityUtil;
@Autowired
private RepositoryService repositoryService;
/**
* 部署流程
*/
@Test
public void deployment() {
repositoryService.createDeployment()
.name("activiti-springboot")
.addClasspathResource("bpmn/activiti-springboot.bpmn20.xml")
.deploy();
}
/**
* 查看流程定义
*/
@Test
public void viewProcessDefinition() {
//需要模拟登录一个用户,不然会报异常
securityUtil.login("system");
Page<ProcessDefinition> definitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
System.out.println("可用的流程定数数量:" + definitionPage.getTotalItems());
for (ProcessDefinition definition : definitionPage.getContent()) {
System.out.println("流程定义id:" + definition.getId());
}
}
启动流程实例
/**
* 启动流程实例
*/
@Test
public void startProcess() {
//需要模拟登录一个用户
securityUtil.login("system");
//设置变量
Map<String, Object> map = new HashMap<>();
map.put("assignee0", "jack");
ProcessInstance instance = processRuntime.start(ProcessPayloadBuilder
.start()
.withProcessDefinitionKey("activiti-springboot")
.withVariables(map)
.build());
System.out.println("流程实例id:" + instance.getId());
}
查询个人任务
/**
* 查询个人任务
*/
@Test
public void queryTask() {
//执行完流程实例后分配的任务是给jack了,现在用jack登录
securityUtil.login("jack");
Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
for (Task task : taskPage.getContent()) {
System.out.println("任务id:" + task.getId());
System.out.println("任务name:" + task.getName());
}
}
完成个人任务
/**
* 完成个人任务
*/
@Test
public void completeTask() {
//执行完流程实例后分配的任务是给jack了,现在用jack登录
securityUtil.login("jack");
Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
for (Task task : taskPage.getContent()) {
//完成任务
taskRuntime.complete(TaskPayloadBuilder
.complete()
.withTaskId(task.getId())
.build());
}
}
拾取任务
需要创建一份新的流程,实现组任务,不然拾取不了
/**
* 拾取任务
* 登录人必须是任务的候选人才可以,自行配置好测试
*/
@Test
public void claimTask() {
securityUtil.login("rose");
taskRuntime.claim(TaskPayloadBuilder
.claim()
//任务id应该是查询出来的,这里直接从数据库复制了
.withTaskId("f2ca7116-63d5-11ec-b2e7-005056c00008")
.build());
System.out.println("拾取任务成功");
}