环境
- Spring Boot 2应用程序
- H2数据库(为了方便,可选mysql...)
POM文件增加以下依赖
<!--activiti整合springboot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<!--H2数据库-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
activiti-spring-boot-starter 版本控制
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.123</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
** 添加镜像源(because阿里云镜像找不到啊╭(╯^╰)╮)
<repositories>
<repository>
<id>alfresco</id>
<name>Activiti Releases</name>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
TaskRuntime
自动注入TaskRuntime
@Autowired
private TaskRuntime taskRuntime;
来让们看看这个TaskRuntime是做什么の
public class TaskRuntime {
/**
* 返回就任务配置文件,其实就是任务配置文件里只有两个属性( List<TaskRuntimeEventListener<?>> taskRuntimeEventListeners(); 任务监听事件,
* List<VariableEventListener<?>> variableEventListeners(); 变量监听事件
*/
TaskRuntimeConfiguration configuration();
/**
* 根据任务id获取任务,(前置条件用户验证透过)
*/
Task task(String taskId);
/**
* 根据分页条件获取任务,(前置条件用户验证透过)
*/
Page<Task> tasks(Pageable pageable);
/**
* 根据分页条件和过滤条件获取任务,(前置条件用户验证透过)
* GetTasksPayload{
* private String id; 任务id
* private String assigneeId; 受理人id
* private List<String> groups; 用户组
* private String processInstanceId; 流程实例id
* private String parentTaskId; 父任务id
* }
*/
Page<Task> tasks(Pageable pageable,
GetTasksPayload getTasksPayload);
/**
* 创建一个任务
* CreateTaskPayload{
* private String id;自己生成UUID
* private String name;任务名
* private String description;任务描述
* private Date dueDate;预计时间
* private int priority;优先级
* private String assignee;代理人
* private List<String> candidateGroups;可见组
* private List<String> candidateUsers;可见用户
* private String parentTaskId;父任务id
* private String formKey;表单key
* }
*/
Task create(CreateTaskPayload createTaskPayload);
/**
* 受理一个任务
* ClaimTaskPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private String assignee;受理人
* }
*/
Task claim(ClaimTaskPayload claimTaskPayload);
/**
* 释放一个任务
* ReleaseTaskPayload{
* private String id;自己生成UUID
* private String taskId;释放任务id
* }
*/
Task release(ReleaseTaskPayload releaseTaskPayload);
/**
* 完成一个任务
* CompleteTaskPayload{
* private String id; 自己生成UUID
* private String taskId;任务id
* private Map<String, Object> variables;任务的变量
* }
*/
Task complete(CompleteTaskPayload completeTaskPayload);
/**
* 保存一个任务(可以个任务设置变量)
* SaveTaskPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private Map<String, Object> variables;任务的变量
* }
*/
void save(SaveTaskPayload saveTaskPayload);
/**
* 更新任务信息
* UpdateTaskPayload{
* private String id;自己生成UUID
* private String name;任务名
* private String description;任务描述
* private Date dueDate;预计时间
* private int priority;优先级
* private String assignee;代理人
* private List<String> candidateGroups;可见组
* private List<String> candidateUsers;可见用户
* private String parentTaskId;父任务id
* private String formKey;表单key *
* }
*/
Task update(UpdateTaskPayload updateTaskPayload);
/**
* 删除一个任务
* DeleteTaskPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private String reason;原因
* }
*/
Task delete(DeleteTaskPayload deleteTaskPayload);
/**
* 增加一个变量
* CreateTaskVariablePayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private String name;要增加的key
* private Object value;要增加value
* }
*/
void createVariable(CreateTaskVariablePayload createTaskVariablePayload);
/**
* 修改一个变量
* UpdateTaskVariablePayload[
* private String id;自己生成UUID
* private String taskId;任务id
* private String name;要修改的key
* private Object value;要修改value
* }
*/
void updateVariable(UpdateTaskVariablePayload updateTaskVariablePayload);
/**
* 获取所以变量
* GetTaskVariablesPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* }
*/
List<VariableInstance> variables(GetTaskVariablesPayload getTaskVariablesPayload);
/**
* 增加可见用户
* CandidateUsersPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private List<String> candidateUsers;用户集合
* }
*/
void addCandidateUsers(CandidateUsersPayload candidateUsersPayload);
/**
* 要删除的可见用户
* CandidateUsersPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private List<String> candidateUsers;用户集合
* }
*/
void deleteCandidateUsers(CandidateUsersPayload candidateUsersPayload);
/**
* 要增加可见用户组
* CandidateGroupsPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private List<String> candidateGroups;用户组
* }
*/
void addCandidateGroups(CandidateGroupsPayload candidateGroupsPayload);
/**
* 要删除的可见用户
* CandidateGroupsPayload{
* private String id;自己生成UUID
* private String taskId;任务id
* private List<String> candidateUsers;用户集合
* }
*/
void deleteCandidateGroups(CandidateGroupsPayload candidateGroupsPayload);
/**
* 根据任务id查询可见用户集合
*/
List<String> userCandidates(String taskId);
/**
* 根据任务id查询可见用户组集合
*/
List<String> groupCandidates(String taskId);
}
新建任务
taskRuntime.create(
TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
.withGroup("activitiTeam")
.withPriority(10)
.build());
activiti Payload一般使用建造者模式构建,也就是链式调用。好方便!
创建了一个
- 名字为First Team Task的任务,
- 任务描述:This is something really important
- 用户组:activitiTeam
- 优先级:10
新建监听
@Bean
public TaskRuntimeEventListener taskAssignedListener() {
return taskAssigned
-> logger.info(
">>> Task Assigned: '"
+ taskAssigned.getEntity().getName()
+"' We can send a notification to the assignee: "
+ taskAssigned.getEntity().getAssignee());
}
当任务发生状态变化则会触发回调监听方法,也就是上边lambda表达式(就是->后面的)
例子
例子地址
https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example
SecurityUtil
@Component
public class SecurityUtil {
private Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
@Autowired
private UserDetailsService userDetailsService;
public void logInAs(String username) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
}
logger.info("> Logged in as: " + username);
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
@Override
public Object getCredentials() {
return user.getPassword();
}
@Override
public Object getDetails() {
return user;
}
@Override
public Object getPrincipal() {
return user;
}
@Override
public boolean isAuthenticated() {
return true;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
}
}
DemoApplicationConfiguration
@Configuration
public class DemoApplicationConfiguration {
private Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);
@Bean
public UserDetailsService myUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
String[][] usersGroupsAndRoles = {
{"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"},
};
for (String[] user : usersGroupsAndRoles) {
List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
DemoApplication
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(DemoApplication.class);
@Autowired
private TaskRuntime taskRuntime;
@Autowired
private SecurityUtil securityUtil;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) {
// Using Security Util to simulate a logged in user
securityUtil.logInAs("salaboy");
// Let's create a Group Task (not assigned, all the members of the group can claim it)
// Here 'salaboy' is the owner of the created task
logger.info("> Creating a Group Task for 'activitiTeam'");
taskRuntime.create(TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
.withCandidateGroup("activitiTeam")
.withPriority(10)
.build());
// Let's log in as 'other' user that doesn't belong to the 'activitiTeam' group
securityUtil.logInAs("other");
// Let's get all my tasks (as 'other' user)
logger.info("> Getting all the tasks");
Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 10));
// No tasks are returned
logger.info("> Other cannot see the task: " + tasks.getTotalItems());
// Now let's switch to a user that belongs to the activitiTeam
securityUtil.logInAs("erdemedeiros");
// Let's get 'erdemedeiros' tasks
logger.info("> Getting all the tasks");
tasks = taskRuntime.tasks(Pageable.of(0, 10));
// 'erdemedeiros' can see and claim the task
logger.info("> erdemedeiros can see the task: " + tasks.getTotalItems());
String availableTaskId = tasks.getContent().get(0).getId();
// Let's claim the task, after the claim, nobody else can see the task and 'erdemedeiros' becomes the assignee
logger.info("> Claiming the task");
taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(availableTaskId).build());
// Let's complete the task
logger.info("> Completing the task");
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(availableTaskId).build());
}
@Bean
public TaskRuntimeEventListener<TaskAssignedEvent> taskAssignedListener() {
return taskAssigned -> logger.info(">>> Task Assigned: '"
+ taskAssigned.getEntity().getName() +
"' We can send a notification to the assginee: " + taskAssigned.getEntity().getAssignee());
}
@Bean
public TaskRuntimeEventListener<TaskCompletedEvent> taskCompletedListener() {
return taskCompleted -> logger.info(">>> Task Completed: '"
+ taskCompleted.getEntity().getName() +
"' We can send a notification to the owner: " + taskCompleted.getEntity().getOwner());
}
}
详解DemoApplication
SecurityUtil和DemoApplicationConfiguration 这两类只是模拟用户登录的不重要略过
DemoApplication很重要
程序先是登录salaboy用户创建了一个
- 名为First Team Task
- 描述为This is something really important
- 用户组activitiTeam优先级为10的任务。
根据DemoApplicationConfiguration
-
可以知道other不属于activitiTeam,erdemedeiros属于activitiTeam 所以可以验证不同组的用户的任务是相互隔离的。
-
当用户erdemedeiros claim(受理)任务则会回调taskAssignedListener监听里的方法
-
当用户erdemedeiros complete(完成)任务则会回调taskCompletedListener监听里的方法
Q.E.D.