This is the 10th day of my participation in the More text Challenge. For more details, see more text Challenge
>>>> 😜😜😜 Making: 👉 github.com/black-ant
A. The preface
This document will open the Activiti series of documents, so the content of this article is mainly based on process use, for more clarity, we will analyze from Task to outer layer >>>
Let’s look at the Process instance creation and configuration processing later
2. Overall use
2.1 the Maven rely on
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0. Beta 2</version>
</dependency>
<! -- Add the following DAO framework because you need to use the database -->
<! -- DAO -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<! -- PS: This package is primarily for building a DataSource-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Copy the code
2.2 application. Yml
PS: There is no need to create a database. In Activiti, tables are created by default.
spring:
datasource:
url: jdbc:mysql:/ / 127.0.0.1:3306 / activiti007? useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&nullCatalogMeansCurrent=true
username : root
password : 123456
driver-class-name: com.mysql.jdbc.Driver
activiti:
database-schema-update: true
server:
port: 8086
Copy the code
The following table is created by default:
2.3 Preparations
Activiti is bound to the user by default. You need to perform the following configurations:
Add two users to the cache
@Configuration
public class SecurityConfiguration {
private Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
@Bean
public UserDetailsService myUserDetailsService(a) {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
logger.info("> Registering new user: " + "root" + " with the following Authorities[ 'ACTIVE' , 'ADMIN' ]");
// Build the Group information
List<SimpleGrantedAuthority> groupList = new ArrayList<>();
// Note that this permission is required
groupList.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER"));
groupList.add(new SimpleGrantedAuthority("ADMIN"));
// Prepare two users: Root and Admin
inMemoryUserDetailsManager.createUser(new User("root", passwordEncoder().encode("123456"), groupList));
inMemoryUserDetailsManager.createUser(new User("admin", passwordEncoder().encode("123456"), groupList));
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder(a) {
return newBCryptPasswordEncoder(); }}Copy the code
Mock login tool class
@Component
public class SecurityUtil {
private Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
public void logInAs(String username) {
UserDetails user = userDetailsService.loadUserByUsername(username);
logger.info("> User Security Configuration (1) : simple verify whether the user exists [{}]", username);
if (user == null) {
throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
}
logger.info("-- -- -- -- -- - > user Security configuration (2), and simulation in the Security log object: {} < -- -- -- -- -- -- --", username);
SecurityContextHolder.setContext(new SecurityContextImpl(new UsernamePasswordAuthenticationToken(user.getUsername(), "123456")));
logger.info("-- -- -- -- -- - > user security configuration (3), set in the Activiti objects: {} < -- -- -- -- -- -- --", username); org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); }}Copy the code
2.4 A simple flow
@RestController
public class StartController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private ProcessRuntime processRuntime; // The implementation process defines the related operations
@Autowired
private TaskRuntime taskRuntime; // Implement task-related operations
@Autowired
private SecurityUtil securityUtil;//SpringSecurity related utility classes
@RequestMapping("/test")
public String test(a) {
logger.info("------> [Enter StartController successfully] <-------");
return "Success !";
}
@GetMapping("/info")
public String getInfd(a) {
Page<ProcessDefinition> processDefinitionPage = processRuntime
.processDefinitions(Pageable.of(0.10));
logger.info("------> Number of process definitions available: [{}] <-------", processDefinitionPage.getTotalItems());
for (ProcessDefinition pd : processDefinitionPage.getContent()) {
logger.info("------> Process definition: [{}] <-------", pd);
}
return "success";
}
@GetMapping("/startFlow")
public String startFlow(a) {
securityUtil.logInAs("root");
ProcessInstance pi = processRuntime.start(ProcessPayloadBuilder
.start()
// The.bpm file defined in processers
.withProcessDefinitionKey("SimpleProcess")
.build());// Start the process instance
logger.info("------> Process instance ID: + [{}] <-------", pi.getId());
return "Start the process";
}
@GetMapping("/selectFlow")
public String selectFlow(a) {
securityUtil.logInAs("root");
Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0.10));
if (taskPage.getTotalItems() > 0) {
taskPage.getContent().forEach(item -> {
logger.info("------> Remaining tasks :[{}] <-------", JSONObject.toJSONString(item));
});
} else {
logger.info("------> All tasks completed <-------", taskPage.getContent());
}
return "Query Flow:" + taskPage.getTotalItems();
}
@GetMapping("/doFlow")
public String doFlowBusiness(a) {
logger.info("------> [Entering doFlowBusiness process] <-------");
securityUtil.logInAs("root");
Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0.10));
logger.info("------> Task start complete <-------");
if (taskPage.getTotalItems() > 0) {
for (Task task : taskPage.getContent()) {
logger.info("------> Loop processing tasks [{}] <-------", task.getName());
// Pick up the task
taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());
// Execute the task
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
}
}
logger.info("------> Query task result <-------");
Page<Task> taskPage2 = taskRuntime.tasks(Pageable.of(0.10));
if (taskPage2.getTotalItems() > 0) {
logger.info("------> Remaining tasks :[{}] <-------", taskPage2.getContent());
} else {
logger.info("------> All tasks completed <-------", taskPage2.getContent());
}
return "Success: Do Flow Business processing completed";
}
@GetMapping("deleteFlow")
public String deleteFlow(a) {
// PS: If there are multiple users, you need to switch the user
// securityUtil.logInAs("admin");
Page<Task> temTaskList = taskRuntime.tasks((Pageable.of(0.10)));
temTaskList.getContent().forEach(item -> {
try {
logger.info("------> Step 4 item: delete Task :{} <-------", item.getId());
taskRuntime.delete(TaskPayloadBuilder.delete().withTaskId(item.getId()).build());
} catch (Exception e) {
logger.error("E----> error :{} -- content :{}", e.getClass(), e.getMessage()); }});return "success"; }}Copy the code
3. Task core process
@Component
public class ActivitiTaskRuntimeService implements ApplicationRunner {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private static String taskId = "MyTask001";
@Autowired
private TaskRuntime taskRuntime;
@Autowired
private SecurityUtil securityUtil;
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("-- -- -- -- -- - > [open a complete Activiti process], simulated first login a user < -- -- -- -- -- -- --");
// PS: Activiti relies on Spring Security by default
securityUtil.logInAs("root");
deleteTask();
// Create the process
createTask();
// Query the object
getTaskInfo();
selectTaskInfo();
selectTaskInfoByUserId("admin");
selectTaskInfoByUserId("root");
// Execute the process
doTask();
// Query the process again
getTaskInfo();
selectTaskInfo();
}
public void getTaskInfo(a) {
try {
// Step 2: Query information about a single Task
Task temTask = taskRuntime.task(taskId);
logger.info("-- -- -- -- -- - > Step 2 query ID: {} - the corresponding Task: {} < -- -- -- -- -- -- --", taskId, JSONObject.toJSONString(temTask));
} catch (NotFoundException e) {
logger.error("E----> Current Task is completed, error :{} -- content :{}", e.getClass(), e.getMessage()); }}/** * Query the current Task case */
public void selectTaskInfo(a) {
// Step 2: Query information about all known tasks
Pageable pageable = Pageable.of(0.10);
Page<Task> temTaskList = taskRuntime.tasks(pageable);
temTaskList.getContent().forEach(item -> {
logger.info("-- -- -- -- -- - > Step 2-1 query series number - [] {} - the corresponding Task: {} < -- -- -- -- -- -- --", temTaskList.getTotalItems(), JSONObject.toJSONString(item));
});
}
/** * Correspond to the client to query their own task */
public void selectTaskInfoByUserId(String assignee) {
// Step 2: Query information about all known tasks
Pageable pageable = Pageable.of(0.10);
Page<Task> temTaskList = taskRuntime.tasks(pageable, TaskPayloadBuilder.tasks().withAssignee(assignee).build());
temTaskList.getContent().forEach(item -> {
logger.info("-- -- -- -- -- - > Step 2-2 query assignee: {} series number - [] {} - the corresponding Task: {} < -- -- -- -- -- -- --", assignee, temTaskList.getTotalItems(), JSONObject.toJSONString(item));
});
}
/** * Create a Task */
public void createTask(a) {
logger.info("------> Step 1: Create a Task to start <-------");
CreateTaskPayload taskPayloadBuilder = TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
// Set the user group of the current Task
.withGroup("ADMIN")
.withPriority(10)
.build();
Task temTask = taskRuntime.create(taskPayloadBuilder);
logger.info("-- -- -- -- -- - > Step 1 create a second Task, note that here set the Assignee < -- -- -- -- -- -- --");
CreateTaskPayload taskPayloadBuilderTo = TaskPayloadBuilder.create()
.withName("Second Team Task")
.withDescription("This is something really important hava Assignee")
// Set the user group of the current Task
.withGroup("ADMIN")
.withAssignee("admin")
.withPriority(10)
.build();
taskRuntime.create(taskPayloadBuilderTo);
this.taskId = temTask.getId();
}
/** * Execute a Task */
public void doTask(a) {
logger.info("-- -- -- -- -- - > Step 3-1: declare a Task start claimed < -- -- -- -- -- -- --");
taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(taskId).build());
logger.info("-- -- -- -- -- - > Step 3-3: to complete a Task starts to complete < -- -- -- -- -- -- --");
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskId).build());
}
/** * delete Task: PS: */
public void deleteTask(a) {
logger.info("------> Step 4: Delete all tasks <-------");
Pageable pageable = Pageable.of(0.10);
Page<Task> temTaskList = taskRuntime.tasks(pageable);
temTaskList.getContent().forEach(item -> {
try {
logger.info("------> Step 4 item: delete Task :{} <-------", item.getId());
taskRuntime.delete(TaskPayloadBuilder.delete().withTaskId(item.getId()).build());
} catch (Exception e) {
logger.error("E----> error :{} -- content :{}", e.getClass(), e.getMessage()); }}); securityUtil.logInAs("admin");
Pageable pageableAdmin = Pageable.of(0.10);
Page<Task> temTaskListAdmin = taskRuntime.tasks(pageable);
temTaskListAdmin.getContent().forEach(item -> {
try {
logger.info("------> Step 4 item: delete Task :{} <-------", item.getId());
taskRuntime.delete(TaskPayloadBuilder.delete().withTaskId(item.getId()).build());
} catch (Exception e) {
logger.error("E----> error :{} -- content :{}", e.getClass(), e.getMessage()); }}); securityUtil.logInAs("root"); }}Copy the code
3.1 TaskRuntime module
Interface in
C- TaskRuntime
public interface TaskRuntime {
TaskRuntimeConfiguration configuration(a);
Task task(String taskId);
Page tasks(Pageable pageable);
Page tasks(Pageable pageable, GetTasksPayload payload);
Task create(CreateTaskPayload payload);
Task claim(ClaimTaskPayload payload);
Task release(ReleaseTaskPayload payload);
Task complete(CompleteTaskPayload payload);
Task update(UpdateTaskPayload payload);
Task delete(DeleteTaskPayload payload); . }Copy the code
Methods effect
- Task Task (String taskId) : obtains a Task by id
- Page tasks(Pageable pageable); Obtain all tasks of the current authenticated user
- Page Tasks (Pageable Pageable,GetTasksPayload GetTasksPayload) : Gets all the tasks that apply the filter in the Payload
- Task Create (CreateTaskPayload CreateTaskPayload) : Creates a Task
- Task Claim (ClaimTaskPayload ClaimTaskPayload) : Declares a Task
- IllegalStateException is thrown if there is no authenticated user
- IllegalStateException is thrown if the currently authenticated user is not a candidate user
- The current method does not support impersonation and will always accept currently authenticated users
- After the declaration, the task should be in the assigned state
- Task Release (ReleaseTaskPayload ReleaseTaskPayload) : Releases a previously declared Task
- Task Complete (CompleteTaskPayload CompleteTaskPayload) : Sets a variable in the payload to complete the selected Task
- This method also checks whether the task is assigned to the currently authenticated user before it completes
- This method returns a shallow Task object that contains the basic information needed to verify that the Task is complete
- Task Update (UpdateTaskPayload UpdateTaskPayload) : updates the details of the Task
- Task DELETE (DeleteTaskPayload DeleteTaskPayload) : deletes a Task
3.2 Task object
Task is the core flow object in the process. Take a look at the parameters of this object:
public interface Task extends TaskInfo {
/** * The default priority for creating a new task */
int DEFAULT_PRIORITY = 50;
/** The name or title of the task */
void setName(String name);
/** Set an optional localization name for the task
void setLocalizedName(String name);
/** Modify the task description */
void setDescription(String description);
/** Set the optional localization description for the task
void setLocalizedDescription(String description);
/** Set the importance/urgency of the task */
void setPriority(int priority);
/** * userId of the person responsible for this task. */
void setOwner(String owner);
/** * specifies the userId of the person to whom this task is delegated
void setAssignee(String assignee);
/** The current delegate state of the task
DelegationState getDelegationState(a);
/** The current delegate state of this task. * /
void setDelegationState(DelegationState delegationState);
/** Change the due date of the task */
void setDueDate(Date dueDate);
/** * Change the category of the task. This is an optional field that allows tasks to be marked as belonging to a category. * /
void setCategory(String category);
/** ID of the parent task */
void setParentTaskId(String parentTaskId);
/** Modify task tenantId */
void setTenantId(String tenantId);
/** Change the form key of the task */
void setFormKey(String formKey);
/** indicates whether the task is suspended. */
boolean isSuspended(a);
}
Copy the code
3.3 TaskRuntimeImpl module
TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl TaskRuntimeImpl
Step 1: Triggering a Delete
In a service, a method is invoked to delete a Task
public void deleteTask(a) {
logger.info("------> Step 4: Delete all tasks <-------");
// Set the current user
securityUtil.logInAs("admin");
Pageable pageableAdmin = Pageable.of(0.10);
Page<Task> temTaskListAdmin = taskRuntime.tasks(pageable);
temTaskListAdmin.getContent().forEach(item -> {
taskRuntime.delete(TaskPayloadBuilder.delete().withTaskId(item.getId()).build());
});
}
Copy the code
PS: here we do a special operation -> Securityutil.loginas (“admin”);
This is because the operation of Task is divided by permission, and the corresponding personnel can only operate their own Task
Step 2: Call TaskRuntimeImpl # delete
public Task delete(DeleteTaskPayload deleteTaskPayload) {
// Get a Task
Task task;
try {
task = task(deleteTaskPayload.getTaskId());
} catch (IllegalStateException ex) {
throw new IllegalStateException("T....");
}
// Obtain the Userid of the current authentication
String authenticatedUserId = securityManager.getAuthenticatedUserId();
// Verify that you are trying to delete a task for which you are the assignee or owner
if ((task.getAssignee() == null|| task.getAssignee().isEmpty() || ! task.getAssignee().equals(authenticatedUserId)) && (task.getOwner() ==null|| task.getOwner().isEmpty() || ! task.getOwner().equals(authenticatedUserId))) {throw new IllegalStateException("...");
}
// Create the same Task from the original data
TaskImpl deletedTaskData = new TaskImpl(task.getId(),
task.getName(),
Task.TaskStatus.DELETED);
// Set Reason to cause
if(! deleteTaskPayload.hasReason()) { deleteTaskPayload.setReason("Cancelled by " + authenticatedUserId);
}
// Run Service -> PS:0001
taskService.deleteTask(deleteTaskPayload.getTaskId(),
deleteTaskPayload.getReason(),
true);
return deletedTaskData;
}
// PS:0001 Call taskService -> TaskServiceImpl
public void deleteTask(String taskId, String deleteReason, boolean cancel) {
commandExecutor.execute(new DeleteTaskCmd(taskId, deleteReason, false, cancel));
}
Copy the code
There are two things to note:
- C-deletetaskcmd: This object is a command object. Guess this is a command mode
- C – commandExecutor object
Take a look at what the object does:
// commandExecutor is an interface with three methods
C- commandExecutor :
M- CommandConfig getDefaultConfig(a): Get the default CommandConfig, or use M- <T> T if not providedexecute(CommandConfig config, Command<T> command): Runs the M- <T> T command using the specified CommandConfigexecute(Command<T> command): Use the default CommandConfig command to run the c-commandexecutorImpl i-commandexecutor command// Let's see, what is implemented
public <T> T execute(CommandConfig config, Command<T> command) {
// The first is the LogInterceptor
return first.execute(config, command);
}
Copy the code
First. Execute (config, command); At this point, you actually start calling the interceptor chain
Step 3: The invocation of the interceptor chain
The generation of the interception chain is shown later, but what is being done here
// When we analyze the Delete process, we can see that it goes through an interception chain, as shown in the figure below:
- CommandContextInterceptor
- CommandInvoker
- DebugCommandInvoker
- CommandInvoker
- JtaRetryInterceptor
- JtaTransactionInterceptor
- LoggingCommandInvoker
- SpringTransactionInterceptor
- TotalExecutionTimeCommandInterceptor
- TransactionContextInterceptor
- RetryInterceptor
Copy the code
Not all of these interception chains will go, and the main ones are as follows:
- Step 1: SpringTransactionInterceptor: control the transaction
- Step 2: CommandContextInterceptor: ready for container
- Step 3: TransactionContextInterceptor: build TransactionContext
- Step 4: Prepare the DbSqlSession in CommandInvoker and execute the processing thread using executeOperation # runnable.run()
- NeedsActiveTaskCmd Executes the TaskCmd
- Step 6: Initiate execute with CompleteTaskCmd. (PS: The Command type is in Command mode.)
- Step End: TaskEntityManagerImpl executes the specific DB operation
conclusion
This article has basically introduced the main process, and the following operations will be in-depth:
- SpringConfiguration operation
- Overall Process
- Custom operation processing