diff --git a/Activiti7Demo/src/main/resources/bpmn/asdf.bpmn20.xml b/Activiti7Demo/src/main/resources/bpmn/asdf.bpmn20.xml new file mode 100644 index 0000000..2ee0a30 --- /dev/null +++ b/Activiti7Demo/src/main/resources/bpmn/asdf.bpmn20.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Activiti7Demo/src/main/resources/bpmn/leave.bpmn b/Activiti7Demo/src/main/resources/bpmn/leave.bpmn new file mode 100644 index 0000000..3007100 --- /dev/null +++ b/Activiti7Demo/src/main/resources/bpmn/leave.bpmn @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Activiti7Demo/src/main/resources/bpmn/leave.png b/Activiti7Demo/src/main/resources/bpmn/leave.png new file mode 100644 index 0000000..b975e80 Binary files /dev/null and b/Activiti7Demo/src/main/resources/bpmn/leave.png differ diff --git a/Activiti7Demo/src/main/resources/bpmn/leave1.bpmn20.xml b/Activiti7Demo/src/main/resources/bpmn/leave1.bpmn20.xml new file mode 100644 index 0000000..191731b --- /dev/null +++ b/Activiti7Demo/src/main/resources/bpmn/leave1.bpmn20.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/Activiti7Demo/src/main/resources/sadasf.bpmn20.xml b/Activiti7Demo/src/main/resources/sadasf.bpmn20.xml deleted file mode 100644 index 47d2c78..0000000 --- a/Activiti7Demo/src/main/resources/sadasf.bpmn20.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - SequenceFlow_1 - - - SequenceFlow_1 - SequenceFlow_2 - - - SequenceFlow_2 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Activiti7Demo/src/test/java/cn/whai/activiti/activiti7demo/Activiti7DemoApplicationTests.java b/Activiti7Demo/src/test/java/cn/whai/activiti/activiti7demo/Activiti7DemoApplicationTests.java index 6710353..9143f84 100644 --- a/Activiti7Demo/src/test/java/cn/whai/activiti/activiti7demo/Activiti7DemoApplicationTests.java +++ b/Activiti7Demo/src/test/java/cn/whai/activiti/activiti7demo/Activiti7DemoApplicationTests.java @@ -1,24 +1,285 @@ package cn.whai.activiti.activiti7demo; -import org.activiti.engine.ProcessEngine; -import org.activiti.engine.ProcessEngineConfiguration; -import org.activiti.engine.RepositoryService; +import org.activiti.engine.*; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.history.HistoricProcessInstanceQuery; +import org.activiti.engine.repository.Deployment; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Task; import org.activiti.spring.SpringProcessEngineConfiguration; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ContextConfiguration; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; @SpringBootTest class Activiti7DemoApplicationTests { + @Autowired + private RepositoryService repositoryService; @Test void contextLoads() { + //进行部署 + Deployment deployment = repositoryService.createDeployment() + .addClasspathResource("bpmn/leave.bpmn") + .addClasspathResource("bpmn/leave.png") + .name("请假流程") + .deploy(); + //输出部署的一些信息 + System.out.println("流程部署ID:"+deployment.getId()); + System.out.println("流程部署名称:"+deployment.getName()); + /** + * Opening JDBC Connection + * ==> Preparing: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_) values(?, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b931f093-a0bf-11ef-a8d1-6ac6acfdceec(String), 请假流程(String), null, null, (String), 2024-11-12 14:31:17.803(Timestamp), null + * <== Updates: 1 + * ==> Preparing: INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_) VALUES (?, 1, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?) + * ==> Parameters: b931f094-a0bf-11ef-a8d1-6ac6acfdceec(String), bpmn/leave.png(String), java.io.ByteArrayInputStream@3d4ea4cf(ByteArrayInputStream), b931f093-a0bf-11ef-a8d1-6ac6acfdceec(String), false(Boolean), b93217a5-a0bf-11ef-a8d1-6ac6acfdceec(String), bpmn/leave.bpmn(String), java.io.ByteArrayInputStream@655e024(ByteArrayInputStream), b931f093-a0bf-11ef-a8d1-6ac6acfdceec(String), false(Boolean) + * <== Updates: 2 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1997102220 wrapping com.mysql.cj.jdbc.ConnectionImpl@4ac2b4c6]] + * 流程部署ID:b931f093-a0bf-11ef-a8d1-6ac6acfdceec + * 流程部署名称:请假流程 + */ + } + + @Test + void queryProcessDefinition() { + + List processDefinitions = repositoryService.createProcessDefinitionQuery().list(); + for (ProcessDefinition processDefinition : processDefinitions) { + System.out.println("流程定义ID:" + processDefinition.getId()); + System.out.println("流程定义名称:" + processDefinition.getName()); + System.out.println("流程定义key:" + processDefinition.getKey()); + System.out.println("流程定义版本:" + processDefinition.getVersion()); + System.out.println("流程部署ID:" + processDefinition.getDeploymentId()); + System.out.println("流程定义资源名称:" + processDefinition.getResourceName()); + System.out.println("流程定义图片资源名称:" + processDefinition.getDiagramResourceName()); + System.out.println("流程定义描述:" + processDefinition.getDescription()); + System.out.println("流程定义分类:" + processDefinition.getCategory()); + System.out.println("======================================================"); + } + /** + * Opening JDBC Connection + * ==> Preparing: select distinct RES.* from ACT_RE_PROCDEF RES order by RES.ID_ asc LIMIT ? OFFSET ? + * ==> Parameters: 2147483647(Integer), 0(Integer) + * <== Columns: ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_ + * <== Row: Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, 1, http://www.activiti.org/processdef, Part1_Deployment, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, bpmn/leave.bpmn, bpmn/leave.png, null, 0, 1, 1, , null + * <== Total: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1566233058 wrapping com.mysql.cj.jdbc.ConnectionImpl@17796f47]] + * 流程定义ID:Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec + * 流程定义名称:Part1_Deployment + * 流程定义key:Part1_Deployment + * 流程定义版本:1 + * 流程部署ID:0c82b70d-a0c1-11ef-9820-6ac6acfdceec + * 流程定义资源名称:bpmn/leave.bpmn + * 流程定义图片资源名称:bpmn/leave.png + * 流程定义描述:null + * 流程定义分类:http://www.activiti.org/processdef + * ====================================================== + */ + } + // 流程实例 + // 流程定义(ProcessDefinition)与流程实例(ProcessInstance)是一对多关系(salvio修改) + @Autowired + private RuntimeService runtimeService; + /** + * 初始化流程实例 + */ + @Test + public void initProcessInstance() { + // 流程定义KEY + String processDefinitionKey = "Part1_Deployment"; + // 业务表KEY(用于把业务数据与Activiti7流程数据相关联) + String businessKey = "4208169753200945"; + // 参数 + Map variables = new HashMap<>(16); + ProcessInstance processInstance = this.runtimeService + .startProcessInstanceByKey(processDefinitionKey, businessKey, variables); + System.out.println("流程实例ID:" + processInstance.getProcessInstanceId()); + /** + * Opening JDBC Connection + * ==> Preparing: select * from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null) and VERSION_ = (select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null)) + * ==> Parameters: Part1_Deployment(String), Part1_Deployment(String) + * <== Columns: ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_ + * <== Row: Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, 1, http://www.activiti.org/processdef, Part1_Deployment, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, bpmn/leave.bpmn, bpmn/leave.png, null, 0, 1, 1, , null + * <== Total: 1 + * ==> Preparing: select * from ACT_RU_VARIABLE where TASK_ID_ = ? + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String) + * <== Total: 0 + * ==> Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), UserTask(String), null, null, null, admin(String), 2024-11-12 14:59:44.325(Timestamp), null, null, null, null, sid-192966db-031d-4a50-886d-379935dd9bc1(String), null, 50(Integer), null, null, (String) + * <== Updates: 1 + * ==> Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 4208169753200945(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), 2024-11-12 14:59:44.311(Timestamp), null, null, null, sid-26d6e725-878e-411d-b23d-6df4ae3cbd24(String), null, null, null, (String), null + * <== Updates: 1 + * ==> Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25ada2b-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), sid-26d6e725-878e-411d-b23d-6df4ae3cbd24(String), null, null, null, startEvent(String), null, 2024-11-12 14:59:44.314(Timestamp), 2024-11-12 14:59:44.316(Timestamp), 2(Long), null, (String), b25b4f5c-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), null, UserTask(String), userTask(String), admin(String), 2024-11-12 14:59:44.317(Timestamp), null, null, null, (String) + * <== Updates: 2 + * ==> Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) + * ==> Parameters: b25cd5fe-a0c3-11ef-8ba8-68c6acfdcef0(String), participant(String), admin(String), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String) + * <== Updates: 1 + * ==> Preparing: insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, IS_MI_ROOT_, PARENT_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, SUSPENSION_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 4208169753200945(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), null, true(Boolean), false(Boolean), true(Boolean), false(Boolean), false(Boolean), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 1(Integer), (String), null, 2024-11-12 14:59:44.311(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 1(Integer), (String), null, 2024-11-12 14:59:44.313(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer) + * <== Updates: 2 + * ==> Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), UserTask(String), null, null, 50(Integer), 2024-11-12 14:59:44.317(Timestamp), null, admin(String), null, b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), null, null, 1(Integer), (String), null, null + * <== Updates: 1 + * ==> Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25cd5fe-a0c3-11ef-8ba8-68c6acfdcef0(String), participant(String), admin(String), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null + * <== Updates: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@621103114 wrapping com.mysql.cj.jdbc.ConnectionImpl@4ac2b4c6]] + * 流程实例ID:b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0 + */ + } + + /** + * 查询流程实例 + */ + @Test + public void getProcessInstance() { + String processInstanceId = "b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0"; + ProcessInstance processInstance = this.runtimeService.createProcessInstanceQuery() + .processInstanceId(processInstanceId) + .singleResult(); + System.out.println("ProcessInstanceId:" + processInstance.getProcessInstanceId()); + System.out.println("ProcessDefinitionId:" + processInstance.getProcessDefinitionId()); + System.out.println("isEnded:" + processInstance.isEnded()); + System.out.println("isSuspended:" + processInstance.isSuspended()); + /** + * Opening JDBC Connection + * ==> Preparing: select distinct RES.* , P.KEY_ as ProcessDefinitionKey, P.ID_ as ProcessDefinitionId, P.NAME_ as ProcessDefinitionName, P.VERSION_ as ProcessDefinitionVersion, P.DEPLOYMENT_ID_ as DeploymentId, S.PROC_INST_ID_ AS PARENT_PROC_INST_ID_ from ACT_RU_EXECUTION RES inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_ left outer join ACT_RU_EXECUTION S on RES.SUPER_EXEC_ = S.ID_ WHERE RES.PARENT_ID_ is null and RES.ID_ = ? and RES.PROC_INST_ID_ = ? order by RES.ID_ asc LIMIT ? OFFSET ? + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 2147483647(Integer), 0(Integer) + * <== Columns: ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_, CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_, ProcessDefinitionKey, ProcessDefinitionId, ProcessDefinitionName, ProcessDefinitionVersion, DeploymentId, PARENT_PROC_INST_ID_ + * <== Row: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, 1, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, 4208169753200945, null, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, null, 1, 0, 1, 0, 0, 1, null, , null, 2024-11-12 14:59:44.311, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, Part1_Deployment, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, null + * <== Total: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1118158255 wrapping com.mysql.cj.jdbc.ConnectionImpl@77eb0e47]] + * ProcessInstanceId:b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0 + * ProcessDefinitionId:Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec + * isEnded:false + * isSuspended:false + */ + + // 查询流程实例列表 + List processInstanceList = this.runtimeService.createProcessInstanceQuery().list(); + if (!CollectionUtils.isEmpty(processInstanceList)) { + processInstanceList.forEach(pi -> { + System.out.println("ProcessInstanceId:" + pi.getProcessInstanceId()); + System.out.println("ProcessDefinitionId:" + pi.getProcessDefinitionId()); + System.out.println("isEnded:" + pi.isEnded()); + System.out.println("isSuspended:" + pi.isSuspended()); + }); + } + // 挂起流程实例 + this.runtimeService.suspendProcessInstanceById(processInstanceId); + // 激活流程实例 + this.runtimeService.activateProcessInstanceById(processInstanceId); + // 删除流程实例 + this.runtimeService.deleteProcessInstance(processInstanceId, "测试删除流程实例"); + } + + /** + * 任务管理 + */ + @Autowired + private TaskService taskService; + + /** + * 查询任务列表 + */ + @Test + public void listTasks() { + List taskList = this.taskService.createTaskQuery().list(); + if (!CollectionUtils.isEmpty(taskList)) { + taskList.forEach(task -> { + System.out.println("Id:" + task.getId()); + System.out.println("Name:" + task.getName()); + System.out.println("Assignee:" + task.getAssignee()); + }); + } + } + + + @Test + public void listTasksByAssignee() { + /** + * 查询Admin的代办任务 + */ + String assignee = "admin"; + List taskList = this.taskService.createTaskQuery() + .taskAssignee(assignee) + .list(); + if (!CollectionUtils.isEmpty(taskList)) { + taskList.forEach(task -> { + System.out.println("Id:" + task.getId()); + System.out.println("Name:" + task.getName()); + System.out.println("Assignee:" + task.getAssignee()); + }); + } + + + // 完成任务 + String taskId = "354b9d90-477f-11ed-abfa-e4a8dfd43d4a"; + Map variables = new HashMap<>(16); + this.taskService.complete(taskId, variables); + + + // 给定用户成为任务的受理人。 + String userId = "jason"; + taskService.claim(taskId, userId); + + // 归还任务,分配的任务回收,撤回 + taskService.unclaim(taskId); + + // 将给定任务的被分派人更改为给定的 userId。不检查身份组件是否知道该用户。 + taskService.setAssignee(taskId, userId); + } + + @Autowired + private HistoryService historyService; + + // 历史记录 + @Test + public void history() { + // 查询历史流程实例 + HistoricProcessInstanceQuery historicProcessInstanceQuery = + this.historyService + .createHistoricProcessInstanceQuery() + .orderByProcessInstanceEndTime(); + List list = historicProcessInstanceQuery.list(); + + list.forEach(historicProcessInstance -> { + System.out.println("ProcessInstanceId:" + historicProcessInstance.getId()); + System.out.println("ProcessDefinitionId:" + historicProcessInstance.getProcessDefinitionId()); + }); + + + + // 根据流程实例ID查询历史 + String processInstanceId = "0f8a9b00-479e-11ed-af85-e4a8dfd43d4a"; + List historicProcessInstances = + this.historyService + .createHistoricProcessInstanceQuery() + .processInstanceId(processInstanceId) + .list(); + historicProcessInstances.forEach(historicProcessInstance -> { + System.out.println("ProcessInstanceId:" + historicProcessInstance.getId()); + System.out.println("ProcessDefinitionId:" + historicProcessInstance.getProcessDefinitionId()); + }); + } + + + } diff --git a/Activiti7Demo/workflow.md b/Activiti7Demo/workflow.md index 42b2621..4d61c6c 100644 --- a/Activiti7Demo/workflow.md +++ b/Activiti7Demo/workflow.md @@ -55,3 +55,225 @@ BPMN(Business Process Model And Notation),业务流程模型和符号, - mysql - 在Navicat工具中创建`activiti`的数据库,用于后续的实验. + + + +### Activiti使用步骤 + +> 2.4.1 整合Activiti +> Activiti是一个工作流引擎,业务系统使用Activiti来对系统的业务流程进行自动化管理,为了方便业务系统访问(操作)Activiti的接口或功能,通常将Activiti和业务系统的环境集成在一起。 +> 2.4.2 业务流程建模 +> 使用Activiti流程建模工具(Activity-designer)定义业务流程(.bpmn文件)。 +> .bpmn文件就是业务流程定义文件,通过xml定义业务流程。 +> 如果使用其他公司开发的工作引擎一般都提供了可视化的建模工具(Process Designer)用于生成流程定义文件,建模工具操作直观,一般都支持图形化拖拽方式、多窗口的用户界面、丰富的过程图形元素、过程元素拷贝、粘贴、删除等功能。 +> 2.4.3 部署业务流程 +> 向Activiti部署业务流程定义(.bpmn文件)。 +> 使用Activiti提供的API向Activiti中部署.bpmn文件(一般情况下还需要一起部署业务流程的图片.png)。 +> 2.4.4 启动流程实例 +> 启动一个流程实例表示开始一次业务流程的运行,比如员工请假流程部署完成,如果张三要请假就可以启动一个流程实例,如果李四要请假也需要启动一个流程实例,两个流程的执行互不影响,就好比定义一个Java类,实例化两个Java对象一样,部署的流程就好比Java类,启动一个流程实例就好比new一个Java对象。 +> 2.4.5 查询待办任务 +> 因为现在系统的业务流程已经交给Activiti管理,通过Activiti就可以查询当前流程执行到哪里了,当前用户需要办理什么任务了,这些Activiti帮我们管理了,而不像传统方式中需要我们在SQL语句中的WHERE条件中指定当前查询的状态值是多少。 +> 2.4.6 处理待办任务 +> 用户查询待办任务后,就可以办理某个任务,如果这任务办理完成还需要其他用户办理,比如采购单创建后由部门经理审核,这个过程也是由Activiti帮我们完成了,不需要我们在代码中硬编码指定下一个任务办理人了 +> 2.4.7 结束流程 +> 当任务办理完成没有下一个任务/结点了,这个流程实例就完成了。 + +### Service总览 + +![img](http://42.192.130.83:9000/picgo/imgs/v2-c33ee3444141b1a2c3b45ef88db771df_1440w.jpg_repeat_1731401329594__239673.png) + +- RepositoryService Activiti的资源管理接口:管理和控制流程发布包和流程定义的操作 +- RuntimeService Activiti的流程运行管理接口:流程执行相关的信息 +- TaskService Activiti的任务管理接口: +- HistoryService Activiti的历史管理接口 +- ManagementService Activiti的引擎管理接口,管理和维护功能 + +#### 数据表解读 + +Activiti 使用到的表都是 ACT_ 开头的,表名的第二部分表示用途。 + +##### ACT_GE_ (GE) 表示 general 全局通用数据及设置,各种情况都使用的数据。 + +> #### 全局通用数据(ACT_GE_*) +> +> | ACT_GE_BYTEARRAY | 二进制数据表,存储通用的流程定义和流程资源。 | +> | ---------------- | ---------------------------------------------------- | +> | ACT_GE_PROPERTY | 系统相关属性,属性数据表存储整个流程引擎级别的数据。 | + +##### ACT_HI_ (HI) 表示 history 历史数据表,包含着程执行的历史相关数据。 + +##### ACT_RE_ (RE) 表示 repository 存储,包含的是静态信息。 + +##### ACT_RU_ (RU) 表示 runtime 运行时,运行时的流程变量,用户任务,变量,职责(job)等运行时数据。Activiti 只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录 (salvio修 + + + + + +## 流程定义 ProcessDefinition + +```java +@Autowired +private RepositoryService repositoryService; +@Test +void queryProcessDe() { + List processDefinitions = repositoryService.createProcessDefinitionQuery().list(); + for (ProcessDefinition processDefinition : processDefinitions) { + System.out.println("流程定义ID:" + processDefinition.getId()); + System.out.println("流程定义名称:" + processDefinition.getName()); + System.out.println("流程定义key:" + processDefinition.getKey()); + System.out.println("流程定义版本:" + processDefinition.getVersion()); + System.out.println("流程部署ID:" + processDefinition.getDeploymentId()); + System.out.println("流程定义资源名称:" + processDefinition.getResourceName()); + System.out.println("流程定义图片资源名称:" + processDefinition.getDiagramResourceName()); + System.out.println("流程定义描述:" + processDefinition.getDescription()); + System.out.println("流程定义分类:" + processDefinition.getCategory()); + System.out.println("======================================================"); + } + /** + * Opening JDBC Connection + * ==> Preparing: select distinct RES.* from ACT_RE_PROCDEF RES order by RES.ID_ asc LIMIT ? OFFSET ? + * ==> Parameters: 2147483647(Integer), 0(Integer) + * <== Columns: ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_ + * <== Row: Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, 1, http://www.activiti.org/processdef, Part1_Deployment, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, bpmn/leave.bpmn, bpmn/leave.png, null, 0, 1, 1, , null + * <== Total: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1566233058 wrapping com.mysql.cj.jdbc.ConnectionImpl@17796f47]] + * 流程定义ID:Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec + * 流程定义名称:Part1_Deployment + * 流程定义key:Part1_Deployment + * 流程定义版本:1 + * 流程部署ID:0c82b70d-a0c1-11ef-9820-6ac6acfdceec + * 流程定义资源名称:bpmn/leave.bpmn + * 流程定义图片资源名称:bpmn/leave.png + * 流程定义描述:null + * 流程定义分类:http://www.activiti.org/processdef + * ====================================================== + */ +} +``` + + + +## 流程实例 ProcessInstance + + + +```java +/** + * 初始化流程实例 + */ +@Test +public void initProcessInstance() { + // 流程定义KEY + String processDefinitionKey = "Part1_Deployment"; + // 业务表KEY(用于把业务数据与Activiti7流程数据相关联) + String businessKey = "4208169753200945"; + // 参数 + Map variables = new HashMap<>(16); + ProcessInstance processInstance = this.runtimeService + .startProcessInstanceByKey(processDefinitionKey, businessKey, variables); + System.out.println("流程实例ID:" + processInstance.getProcessInstanceId()); + /** + * Opening JDBC Connection + * ==> Preparing: select * from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null) and VERSION_ = (select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null)) + * ==> Parameters: Part1_Deployment(String), Part1_Deployment(String) + * <== Columns: ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_ + * <== Row: Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, 1, http://www.activiti.org/processdef, Part1_Deployment, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, bpmn/leave.bpmn, bpmn/leave.png, null, 0, 1, 1, , null + * <== Total: 1 + * ==> Preparing: select * from ACT_RU_VARIABLE where TASK_ID_ = ? + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String) + * <== Total: 0 + * ==> Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), UserTask(String), null, null, null, admin(String), 2024-11-12 14:59:44.325(Timestamp), null, null, null, null, sid-192966db-031d-4a50-886d-379935dd9bc1(String), null, 50(Integer), null, null, (String) + * <== Updates: 1 + * ==> Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 4208169753200945(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), 2024-11-12 14:59:44.311(Timestamp), null, null, null, sid-26d6e725-878e-411d-b23d-6df4ae3cbd24(String), null, null, null, (String), null + * <== Updates: 1 + * ==> Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25ada2b-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), sid-26d6e725-878e-411d-b23d-6df4ae3cbd24(String), null, null, null, startEvent(String), null, 2024-11-12 14:59:44.314(Timestamp), 2024-11-12 14:59:44.316(Timestamp), 2(Long), null, (String), b25b4f5c-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), null, UserTask(String), userTask(String), admin(String), 2024-11-12 14:59:44.317(Timestamp), null, null, null, (String) + * <== Updates: 2 + * ==> Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) + * ==> Parameters: b25cd5fe-a0c3-11ef-8ba8-68c6acfdcef0(String), participant(String), admin(String), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String) + * <== Updates: 1 + * ==> Preparing: insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, IS_MI_ROOT_, PARENT_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, SUSPENSION_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 4208169753200945(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), null, true(Boolean), false(Boolean), true(Boolean), false(Boolean), false(Boolean), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 1(Integer), (String), null, 2024-11-12 14:59:44.311(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 1(Integer), (String), null, 2024-11-12 14:59:44.313(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer) + * <== Updates: 2 + * ==> Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + * ==> Parameters: b25c87dd-a0c3-11ef-8ba8-68c6acfdcef0(String), UserTask(String), null, null, 50(Integer), 2024-11-12 14:59:44.317(Timestamp), null, admin(String), null, b25ab31a-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec(String), sid-192966db-031d-4a50-886d-379935dd9bc1(String), null, null, 1(Integer), (String), null, null + * <== Updates: 1 + * ==> Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) + * ==> Parameters: b25cd5fe-a0c3-11ef-8ba8-68c6acfdcef0(String), participant(String), admin(String), null, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), null + * <== Updates: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@621103114 wrapping com.mysql.cj.jdbc.ConnectionImpl@4ac2b4c6]] + * 流程实例ID:b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0 + */ +} + +/** + * 查询流程实例 + */ +@Test +public void getProcessInstance() { + String processInstanceId = "b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0"; + ProcessInstance processInstance = this.runtimeService.createProcessInstanceQuery() + .processInstanceId(processInstanceId) + .singleResult(); + System.out.println("ProcessInstanceId:" + processInstance.getProcessInstanceId()); + System.out.println("ProcessDefinitionId:" + processInstance.getProcessDefinitionId()); + System.out.println("isEnded:" + processInstance.isEnded()); + System.out.println("isSuspended:" + processInstance.isSuspended()); + /** + * Opening JDBC Connection + * ==> Preparing: select distinct RES.* , P.KEY_ as ProcessDefinitionKey, P.ID_ as ProcessDefinitionId, P.NAME_ as ProcessDefinitionName, P.VERSION_ as ProcessDefinitionVersion, P.DEPLOYMENT_ID_ as DeploymentId, S.PROC_INST_ID_ AS PARENT_PROC_INST_ID_ from ACT_RU_EXECUTION RES inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_ left outer join ACT_RU_EXECUTION S on RES.SUPER_EXEC_ = S.ID_ WHERE RES.PARENT_ID_ is null and RES.ID_ = ? and RES.PROC_INST_ID_ = ? order by RES.ID_ asc LIMIT ? OFFSET ? + * ==> Parameters: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0(String), 2147483647(Integer), 0(Integer) + * <== Columns: ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_, CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_, ProcessDefinitionKey, ProcessDefinitionId, ProcessDefinitionName, ProcessDefinitionVersion, DeploymentId, PARENT_PROC_INST_ID_ + * <== Row: b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, 1, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, 4208169753200945, null, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, null, b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0, null, 1, 0, 1, 0, 0, 1, null, , null, 2024-11-12 14:59:44.311, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, Part1_Deployment, Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec, Part1_Deployment, 1, 0c82b70d-a0c1-11ef-9820-6ac6acfdceec, null + * <== Total: 1 + * Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1118158255 wrapping com.mysql.cj.jdbc.ConnectionImpl@77eb0e47]] + * ProcessInstanceId:b25a64f9-a0c3-11ef-8ba8-68c6acfdcef0 + * ProcessDefinitionId:Part1_Deployment:1:0c957bc0-a0c1-11ef-9820-6ac6acfdceec + * isEnded:false + * isSuspended:false + */ + + // 查询流程实例列表 + List processInstanceList = this.runtimeService.createProcessInstanceQuery().list(); + if (!CollectionUtils.isEmpty(processInstanceList)) { + processInstanceList.forEach(pi -> { + System.out.println("ProcessInstanceId:" + pi.getProcessInstanceId()); + System.out.println("ProcessDefinitionId:" + pi.getProcessDefinitionId()); + System.out.println("isEnded:" + pi.isEnded()); + System.out.println("isSuspended:" + pi.isSuspended()); + }); + } + // 挂起流程实例 + this.runtimeService.suspendProcessInstanceById(processInstanceId); + // 激活流程实例 + this.runtimeService.activateProcessInstanceById(processInstanceId); + // 删除流程实例 + this.runtimeService.deleteProcessInstance(processInstanceId, "测试删除流程实例"); +} +``` + + + +## **流程符号** + +### 事件 Event + +![img](http://42.192.130.83:9000/picgo/imgs/v2-7abf29716c8a87df55a503f537b86230_1440w.jpg_repeat_1731401500483__988588.png) + +### **网关 GateWay** + +![img](http://42.192.130.83:9000/picgo/imgs/v2-f27e0ae9d25d13b7b0cc90fceaffd732_1440w.jpg_repeat_1731401505552__805264.png) + +- 排他网关:只有一条路径会被选择 +- 并行网关:所有路径都会被选择 +- 包容网关:可以在网关上设置条件,**为每个输出设置计算** +- 事件网关:进入等待状态,**等待事件后转为活动状态** + +### 流向 Flow + +![img](http://42.192.130.83:9000/picgo/imgs/v2-9f863cc8aa78ed965a8a50349bcd3304_1440w.jpg_repeat_1731401793171__863727.png) + +## diff --git a/ForJdk17/src/main/java/cn/whaifree/interview/ct/P1.java b/ForJdk17/src/main/java/cn/whaifree/interview/ct/P1.java new file mode 100644 index 0000000..dd64383 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/interview/ct/P1.java @@ -0,0 +1,111 @@ +package cn.whaifree.interview.ct; + +import java.util.*; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/13 21:18 + * @注释 + */ +public class P1 { + + // Method to parse configurations + private static void parseConfig(List lines, Set physical, Map> bonds, Map vlans) { + for (String line : lines) { + String[] parts = line.split(" "); + switch (parts[0]) { + case "Physical": + physical.add(parts[1]); + break; + case "Bond": + String bondName = parts[1]; + List children = new ArrayList<>(Arrays.asList(parts).subList(3, parts.length)); + Collections.sort(children); + bonds.put(bondName, children); + break; + case "VLAN": + vlans.put(parts[1], parts[2]); + break; + } + } + } + + // Method to calculate minimum steps + public static int calculateMinSteps(List currentLines, List targetLines) { + // Parsing current and target configurations + Set currentPhysical = new HashSet<>(); + Map> currentBonds = new HashMap<>(); + Map currentVlans = new HashMap<>(); + parseConfig(currentLines, currentPhysical, currentBonds, currentVlans); + + Set targetPhysical = new HashSet<>(); + Map> targetBonds = new HashMap<>(); + Map targetVlans = new HashMap<>(); + parseConfig(targetLines, targetPhysical, targetBonds, targetVlans); + + int steps = 0; + + // Step 1: Delete extra bonds and vlans in the current configuration + for (String bond : new HashSet<>(currentBonds.keySet())) { + if (!targetBonds.containsKey(bond)) { + currentBonds.remove(bond); + steps++; + } + } + for (String vlan : new HashSet<>(currentVlans.keySet())) { + if (!targetVlans.containsKey(vlan)) { + currentVlans.remove(vlan); + steps++; + } + } + + // Step 2: Add missing bonds and vlans in the current configuration + for (Map.Entry> entry : targetBonds.entrySet()) { + String bond = entry.getKey(); + List targetChildren = entry.getValue(); + if (!currentBonds.containsKey(bond)) { + currentBonds.put(bond, targetChildren); + steps++; + } else if (!currentBonds.get(bond).equals(targetChildren)) { + currentBonds.put(bond, targetChildren); + steps++; + } + } + + for (Map.Entry entry : targetVlans.entrySet()) { + String vlan = entry.getKey(); + String targetParent = entry.getValue(); + if (!currentVlans.containsKey(vlan)) { + currentVlans.put(vlan, targetParent); + steps++; + } else if (!currentVlans.get(vlan).equals(targetParent)) { + currentVlans.put(vlan, targetParent); + steps++; + } + } + + return steps; + } + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + int n = Integer.parseInt(scanner.nextLine()); + List currentLines = new ArrayList<>(); + for (int i = 0; i < n; i++) { + currentLines.add(scanner.nextLine().trim()); + } + + int m = Integer.parseInt(scanner.nextLine()); + List targetLines = new ArrayList<>(); + for (int i = 0; i < m; i++) { + targetLines.add(scanner.nextLine().trim()); + } + + int result = calculateMinSteps(currentLines, targetLines); + System.out.println(result); + + scanner.close(); + } + +} diff --git a/ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java b/ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java index 48c44ed..b01629d 100644 --- a/ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java +++ b/ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java @@ -60,6 +60,8 @@ class p2{ * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * + * 给你一个数组,你可以随意操作任意相邻的元素都+1,请问需要多少次可以让整个数组变成对称的 + * * @param arr int整型一维数组 * @return long长整型 */ @@ -80,4 +82,44 @@ class p2{ int i = dp[0][n - 1]; return i; } + + public static class Solution { + public int minOperations(int[] arr) { + int n = arr.length; + + // 如果数组长度是奇数,中心元素不参与对称操作 + int operations = 0; + + // 使用双指针,从两端往中间移动 + for (int i = 0; i < n / 2; i++) { + int left = arr[i]; + int right = arr[n - i - 1]; + + // 计算两个元素的差值 + int diff = Math.abs(left - right); + + // 如果差值是奇数,不能通过 +1 操作得到相等的数 + if (diff % 2 != 0) { + return -1; + } + + // 每次需要 diff / 2 次操作来平衡这两个元素 + operations += diff / 2; + } + + return operations; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + + // 示例测试 + int[] arr1 = {1, 2, 2, 1, 1}; + System.out.println(solution.minOperations(arr1)); // 输出: 0 + + int[] arr2 = {1, 2, 3, 4, 5}; + System.out.println(solution.minOperations(arr2)); // 输出: -1 + } + } + } diff --git a/ForJdk17/src/main/java/cn/whaifree/leetCode/LeetCode1648.java b/ForJdk17/src/main/java/cn/whaifree/leetCode/LeetCode1648.java new file mode 100644 index 0000000..2113dfa --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/leetCode/LeetCode1648.java @@ -0,0 +1,98 @@ +package cn.whaifree.leetCode; + +import com.google.common.collect.Lists; +import org.junit.Test; + +import java.util.*; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/12 11:47 + * @注释 + */ +public class LeetCode1648 { + +// @Test +// public void test() { +// int[] inventory = {1000000000}; +// int res = new Solution().maxProfit(inventory, 1000000000); +// System.out.println(res); +// } +// +// class Solution { +// +// +// /** +// * 数量最多的同色球的数量 和 球数 == MAX 的颜色的数量。 +// * +// * @param inventory +// * @param orders +// * @return +// */ +// public int maxProfit(int[] inventory, int orders) { +// +// Arrays.sort(inventory); +// +// int res = 0; +// int countOfColor = 1; +// for (int i = inventory.length - 1; i > 0; i--) { +// int end = inventory[i]; +// int start = inventory[i - 1]; +// for (int j = end; j > start; j--) { +// for (int x = 0; x < countOfColor; x++) { +// res += j; +// inventory[i]--; +// orders--; +// if (orders == 0) { +// return res; +// } +// } +// } +// countOfColor++; +// } +// +// // 最后变为 x x x x (x为最小值) +// +// +// for (int j = 0; j < inventory[0]; j++) { +// int item = inventory[0]; +// if (orders < inventory.length) { +// return res + orders * item; +// }else { +// for (int i = 0; i < item; i++) { +// res += inventory[0]; +// orders--; +// if (orders == 0) { +// return res; +// } +// } +// } +// } +// +// return res; +// +// +// // 5 2 2 1 2 1 +// +// +//// int res = 0; +//// int add = 1; +//// +//// int right = inventory.length - 1; +//// for (int i = 0; i < orders; i++) { +//// int left = right - 1; +//// +//// int leftV = inventory[left]; +//// int rightV = inventory[right]; +//// for (int j = rightV; j > leftV; j--) { +//// +//// } +//// right--; +//// } +//// return res; +// +// } +// } + +} diff --git a/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode210_207.java b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode210_207.java new file mode 100644 index 0000000..c840651 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode210_207.java @@ -0,0 +1,118 @@ +package cn.whaifree.redo.redo_all_241016; + +import org.junit.Test; + +import java.util.*; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 9:56 + * @注释 + */ +public class LeetCode210_207 { + + @Test + public void test() { + int numCourses = 2; + int[][] prerequisites = {}; + Solution solution = new Solution(); + int[] ints = solution.findOrder(numCourses, prerequisites); + System.out.println(Arrays.toString(ints)); + } + + class Solution { + public int[] findOrder(int numCourses, int[][] prerequisites) { + // prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi + + Map> map = new HashMap<>(); + int[] in = new int[numCourses]; + + for (int i = 0; i < numCourses; i++) { + map.put(i, new ArrayList<>()); + } + + for (int[] prerequisite : prerequisites) { + in[prerequisite[0]]++; + map.get(prerequisite[1]).add(prerequisite[0]); + } + + Deque deque = new ArrayDeque<>(); + // 入度炜0的 + for (int i = 0; i < in.length; i++) { + if (in[i] == 0) { + deque.push(i); + } + } + + int[] res = new int[numCourses]; + int index = 0; + while (!deque.isEmpty()) { + // 入度为0 + Integer pop = deque.pop(); + res[index++] = pop; + + List into = map.get(pop); + for (Integer i : into) { + in[i]--; + if (in[i] == 0) { + deque.add(i); + } + } + } + + if (index != numCourses) { + return new int[0]; + } + return res; + } + } + + class Solution1 { + public boolean canFinish(int numCourses, int[][] prerequisites) { + // prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi + + Map> map = new HashMap<>(); + int[] in = new int[numCourses]; + + for (int i = 0; i < numCourses; i++) { + map.put(i, new ArrayList<>()); + } + + for (int[] prerequisite : prerequisites) { + in[prerequisite[0]]++; + map.get(prerequisite[1]).add(prerequisite[0]); + } + + Deque deque = new ArrayDeque<>(); + // 入度炜0的 + for (int i = 0; i < in.length; i++) { + if (in[i] == 0) { + deque.push(i); + } + } + + int[] res = new int[numCourses]; + int index = 0; + while (!deque.isEmpty()) { + // 入度为0 + Integer pop = deque.pop(); + res[index++] = pop; + + List into = map.get(pop); + for (Integer i : into) { + in[i]--; + if (in[i] == 0) { + deque.add(i); + } + } + } + + if (index != numCourses) { + return false; + } + return true; + } + } + +} diff --git a/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode2602.java b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode2602.java new file mode 100644 index 0000000..b897c27 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode2602.java @@ -0,0 +1,59 @@ +package cn.whaifree.redo.redo_all_241016; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/16 17:01 + * @注释 + */ +public class LeetCode2602 { + + @Test + public void test() { + int[] nums = {3,1,6,8}; + int[] queries = {1,5}; + Solution solution = new Solution(); + System.out.println(solution.minOperations(nums, queries)); + } + + class Solution { + public List minOperations(int[] nums, int[] queries) { + // 1 3 6 8 + // 1 4 10 18 + Arrays.sort(nums); + // 前缀和 + long[] preSum = new long[nums.length + 1]; + for (int i = 1; i <= nums.length; i++) { + preSum[i] = preSum[i - 1] + nums[i - 1]; + } + List list = new ArrayList<>(); + for (int i = 0; i < queries.length; i++) { + long l = minOpr(preSum, nums, queries[i]); + list.add(l); + } + return list; + } + + + public long minOpr(long[] preSum, int[] nums, int queries) { + int index = Arrays.binarySearch(nums, queries); + if (index < 0) { + index = -index - 1; + } + + // 前面的次数 + long preSize = preSum[index]; + long before = (long) index * queries - preSize; + long afterSize = preSum[nums.length] - preSize; + long after = afterSize - (long) (nums.length - index) * queries; + + return (before + after); + } + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode469_1.java b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode469_1.java new file mode 100644 index 0000000..962175a --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_241016/LeetCode469_1.java @@ -0,0 +1,68 @@ +package cn.whaifree.redo.redo_all_241016; + +import org.junit.Test; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/14 17:17 + * @注释 + */ +public class LeetCode469_1 { + + @Test + public void test() { + String s = "2001:0db8:85a3:0:0:8A2E:0370:7334"; + System.out.println(new Solution().validIPAddress(s)); + } + + class Solution { + public String validIPAddress(String queryIP) { + if (queryIP.contains(":") && isIpv6(queryIP.split(":", -1))) { + return "IPv6"; + } else if (queryIP.contains(".") && isIpv4(queryIP.split("\\.", -1))) { + return "IPv4"; + } + return "Neither"; + } + + public boolean isIpv6(String[] ips) { + if (ips.length != 8) { + return false; + } + try { + for (String ip : ips) { + if (ip.isEmpty() || ip.length() > 4) { + return false; + } + int i = Integer.parseInt(ip, 16); + } + }catch (Exception e){ + return false; + } + return true; + } + + public boolean isIpv4(String[] ip) { + if (ip.length != 4) { + return false; + } + for (int i = 0; i < ip.length; i++) { + String s = ip[i]; + try { + if (s.length() > 1 && s.startsWith("0")) { + return false; + } + Integer num = Integer.valueOf(s); + if (num < 0 || num > 255) { + return false; + } + } catch (NumberFormatException e) { + return false; + } + + } + return true; + } + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/tech/GRRXReference.java b/ForJdk17/src/main/java/cn/whaifree/tech/GRRXReference.java new file mode 100644 index 0000000..6bbfcbc --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/tech/GRRXReference.java @@ -0,0 +1,103 @@ +package cn.whaifree.tech; + +import org.junit.Test; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 21:22 + * @注释 + */ +public class GRRXReference { + + @Test + public void soft() { + Object obj = new Object(); + SoftReference softRef = new SoftReference<>(obj); // 创建软引用 + + // 手动触发垃圾回收 + System.gc(); + + // 尝试获取软引用指向的对象 + Object retrievedObject = softRef.get(); + if (retrievedObject != null) { + System.out.println("对象还在内存中: " + retrievedObject); + } else { + System.out.println("对象已经被垃圾回收"); + } + + // 使 obj 可被回收 + obj = null; + + // 再次尝试获取软引用指向的对象 + System.gc(); // 强烈建议调用 GC 来验证软引用回收 + retrievedObject = softRef.get(); + if (retrievedObject != null) { + System.out.println("对象还在内存中: " + retrievedObject); + } else { + System.out.println("对象已经被垃圾回收"); + } + } + + @Test + public void weak() { + Object obj = new Object(); + WeakReference weakRef = new WeakReference<>(obj); // 创建弱引用 + + // 手动触发垃圾回收 + System.gc(); + + // 尝试获取软引用指向的对象 + Object retrievedObject = weakRef.get(); + if (retrievedObject != null) { + System.out.println("对象还在内存中: " + retrievedObject); + } else { + System.out.println("对象已经被垃圾回收"); + } + + // 使 obj 可被回收 + obj = null; + + // 再次尝试获取软引用指向的对象 + System.gc(); // 强烈建议调用 GC 来验证软引用回收 + retrievedObject = weakRef.get(); + if (retrievedObject != null) { + System.out.println("对象还在内存中: " + retrievedObject); + } else { + System.out.println("对象已经被垃圾回收"); + } + } + + @Test + public void phantom() { + // 创建一个引用队列 + ReferenceQueue queue = new ReferenceQueue<>(); + + // 创建一个对象和它的虚引用 + Object obj = new Object(); + PhantomReference phantomRef = new PhantomReference<>(obj, queue); + + System.out.println("虚引用创建完毕,obj 是:" + phantomRef.get()); + + // 使 obj 可被回收 + obj = null; + + // 手动触发垃圾回收 + System.gc(); + + // 检查引用队列中是否有虚引用指向的对象 + try { + // 只有在对象被回收后,才会从引用队列中取得虚引用 + PhantomReference refFromQueue = (PhantomReference) queue.remove(); + System.out.println("虚引用指向的对象已经被回收:" + refFromQueue); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/tech/SPI/ASPIServiceImpl.java b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/ASPIServiceImpl.java new file mode 100644 index 0000000..5b83daf --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/ASPIServiceImpl.java @@ -0,0 +1,14 @@ +package cn.whaifree.tech.SPI; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 21:31 + * @注释 + */ +public class ASPIServiceImpl implements SPIService { + @Override + public void sayHello() { + System.out.println("Hello, I am ASPIServiceImpl"); + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/tech/SPI/BSPIServiceImpl.java b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/BSPIServiceImpl.java new file mode 100644 index 0000000..b7d3b58 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/BSPIServiceImpl.java @@ -0,0 +1,14 @@ +package cn.whaifree.tech.SPI; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 21:31 + * @注释 + */ +public class BSPIServiceImpl implements SPIService { + @Override + public void sayHello() { + System.out.println("BSPIServiceImpl sayHello"); + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/tech/SPI/SPIService.java b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/SPIService.java new file mode 100644 index 0000000..72a2567 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/tech/SPI/SPIService.java @@ -0,0 +1,28 @@ +package cn.whaifree.tech.SPI; + +import java.security.Provider; +import java.util.Iterator; +import java.util.ServiceLoader; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 21:31 + * @注释 + */ +public interface SPIService { + void sayHello(); + + + static void main(String[] args) { + + + ServiceLoader load = ServiceLoader.load(SPIService.class); + Iterator iterator = load.iterator(); + while (iterator.hasNext()) { + SPIService next = iterator.next(); + next.sayHello(); + } + } +} + diff --git a/ForJdk17/src/main/java/cn/whaifree/test/FanxinTest.java b/ForJdk17/src/main/java/cn/whaifree/test/FanxinTest.java index cf00b79..3917e28 100644 --- a/ForJdk17/src/main/java/cn/whaifree/test/FanxinTest.java +++ b/ForJdk17/src/main/java/cn/whaifree/test/FanxinTest.java @@ -1,6 +1,7 @@ package cn.whaifree.test; import java.util.List; +import java.util.concurrent.Callable; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -18,6 +19,14 @@ public class FanxinTest { new LinkedBlockingQueue<>() ); + // 异步 + threadPoolExecutor.submit(new Callable() { + @Override + public Object call() throws Exception { + return null; + } + }); + } diff --git a/ForJdk17/src/main/java/cn/whaifree/test/ThreadDemo1.java b/ForJdk17/src/main/java/cn/whaifree/test/ThreadDemo1.java index 0b824b0..0d48aae 100644 --- a/ForJdk17/src/main/java/cn/whaifree/test/ThreadDemo1.java +++ b/ForJdk17/src/main/java/cn/whaifree/test/ThreadDemo1.java @@ -53,6 +53,7 @@ public class ThreadDemo1 { public static void main(String[] args) throws InterruptedException { AtomicInteger num = new AtomicInteger(9); + num.decrementAndGet(); CountDownLatch countDownLatch = new CountDownLatch(num.get()); for (int i = 0; i < 9; i++) { diff --git a/ForJdk17/src/main/java/cn/whaifree/test/io/AioServer.java b/ForJdk17/src/main/java/cn/whaifree/test/io/AioServer.java index 2f8fb01..807065f 100644 --- a/ForJdk17/src/main/java/cn/whaifree/test/io/AioServer.java +++ b/ForJdk17/src/main/java/cn/whaifree/test/io/AioServer.java @@ -142,6 +142,9 @@ class BioServer { class NioServer { public static void main(String[] args) throws IOException { + + + // 打开一个选择器 Selector selector = Selector.open(); // 打开一个服务器套接字通道 diff --git a/ForJdk17/src/main/java/cn/whaifree/test/threadpool/ScheduledThreadPoolTest.java b/ForJdk17/src/main/java/cn/whaifree/test/threadpool/ScheduledThreadPoolTest.java index 6bafa7f..92b1f75 100644 --- a/ForJdk17/src/main/java/cn/whaifree/test/threadpool/ScheduledThreadPoolTest.java +++ b/ForJdk17/src/main/java/cn/whaifree/test/threadpool/ScheduledThreadPoolTest.java @@ -14,6 +14,24 @@ import java.util.concurrent.TimeUnit; public class ScheduledThreadPoolTest { volatile static Integer i = 0; + /** + * 提交任务时,消费任务的时候检查 ScheduledFutureTask 时间 + * + * 任务提交:当用户提交一个定时任务时,ScheduledThreadPool 会将任务封装成 ScheduledFutureTask 对象,并将其放入延迟队列中。 + * + * 任务调度:线程池中的线程会从延迟队列中取出任务并执行。如果任务设置了延迟执行时间,线程会等待相应的时间后再执行任务。 + * + * 任务执行:线程执行任务时,会调用 ScheduledFutureTask 的 run 方法。run 方法会首先检查任务的取消状态,如果任务被取消,则直接返回。否则,会执行任务的 run 方法。 + * + * 周期性任务:对于周期性任务,ScheduledFutureTask 会根据任务的执行周期重新计算下一次执行的时间,并将其重新放入延迟队列中。这样,周期性任务会按照指定的周期重复执行。 + * + * 异常处理:如果任务在执行过程中抛出异常,ScheduledFutureTask 会捕获这个异常,并调用 setException 方法将异常设置到 Future 对象中。 + * + * 任务完成:当任务执行完成后,ScheduledFutureTask 会从延迟队列中移除,并更新 Future 对象的状态。 + * + * 线程回收:ScheduledThreadPool 中的线程会根据任务的执行情况进行回收。如果线程池中的线程在一段时间内没有任务可执行,它们会被回收,以减少资源消耗。 + * @param args + */ public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); diff --git a/ForJdk17/src/main/resources/META-INF/services/cn.whaifree.tech.SPI.SPIService b/ForJdk17/src/main/resources/META-INF/services/cn.whaifree.tech.SPI.SPIService new file mode 100644 index 0000000..c26efa4 --- /dev/null +++ b/ForJdk17/src/main/resources/META-INF/services/cn.whaifree.tech.SPI.SPIService @@ -0,0 +1,2 @@ +cn.whaifree.tech.SPI.ASPIServiceImpl +cn.whaifree.tech.SPI.BSPIServiceImpl diff --git a/ForJdk8/src/main/java/cn/whaifree/tech/FunctionInterfaceDemo.java b/ForJdk8/src/main/java/cn/whaifree/tech/FunctionInterfaceDemo.java index 72422e6..49a47f5 100644 --- a/ForJdk8/src/main/java/cn/whaifree/tech/FunctionInterfaceDemo.java +++ b/ForJdk8/src/main/java/cn/whaifree/tech/FunctionInterfaceDemo.java @@ -17,7 +17,9 @@ public class FunctionInterfaceDemo { public static void main(String[] args) throws InterruptedException { - HashMap map = new HashMap<>(); + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.put(null, null); +// HashMap map = new HashMap<>(); // map.put(null, null); System.out.println(map.get(null)); diff --git a/SpringCloud/GateWay/pom.xml b/SpringCloud/GateWay/pom.xml new file mode 100644 index 0000000..8ed72e7 --- /dev/null +++ b/SpringCloud/GateWay/pom.xml @@ -0,0 +1,171 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.5 + + + com.whai.springcloud + GateWay + 0.0.1-SNAPSHOT + GateWay + GateWay + + + + + + + + + + + + + + + 17 + 2023.0.3 + 3.0.0 + + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + + com.alibaba.cloud + spring-cloud-alibaba-sentinel-gateway + + + + + com.alibaba.csp + sentinel-datasource-nacos + + + + + com.alibaba.csp + sentinel-transport-simple-http + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-loadbalancer + + + + + pro.fessional + kaptcha + + + javax.servlet + javax.servlet-api + + + javax.servlet + servlet-api + + + + + + + io.springfox + springfox-swagger-ui + ${swagger.fox.version} + + + io.springfox + springfox-swagger2 + ${swagger.fox.version} + + + + + com.github.xiaoymin + knife4j-spring-ui + + + com.github.xiaoymin + knife4j-spring-boot-starter + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + src/main/java + + **/*.yml + **/*.properties + **/*.xml + + false + + + src/main/resources + + **/*.yml + **/*.properties + **/*.xml + + false + + + + + + diff --git a/SpringCloud/GateWay/src/main/java/com/whai/springcloud/gateway/GateWayApplication.java b/SpringCloud/GateWay/src/main/java/com/whai/springcloud/gateway/GateWayApplication.java new file mode 100644 index 0000000..a4e010d --- /dev/null +++ b/SpringCloud/GateWay/src/main/java/com/whai/springcloud/gateway/GateWayApplication.java @@ -0,0 +1,13 @@ +package com.whai.springcloud.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GateWayApplication { + + public static void main(String[] args) { + SpringApplication.run(GateWayApplication.class, args); + } + +} diff --git a/SpringCloud/GateWay/src/main/resources/application.properties b/SpringCloud/GateWay/src/main/resources/application.properties new file mode 100644 index 0000000..cdb7ac4 --- /dev/null +++ b/SpringCloud/GateWay/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=GateWay diff --git a/SpringCloud/GateWay/src/main/resources/bootstrap.yml b/SpringCloud/GateWay/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..5c76e09 --- /dev/null +++ b/SpringCloud/GateWay/src/main/resources/bootstrap.yml @@ -0,0 +1,48 @@ +# Tomcat +server: + port: 6880 + +# Spring +spring: + application: + # 应用名称 + name: whai-gateway + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.50.248:8848 + username: nacos + password: nacos + config: + # 配置中心地址 + server-addr: 192.168.50.248:8848 + username: nacos + password: nacos + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} +# sentinel: +# # 取消控制台懒加载 +# eager: true +# transport: +# # 配置控制台服务地址 +# dashboard: 127.0.0.1:8080 +# # 默认 8719 端口,假如被占用会自动从 8719 开始依次 +1 扫描,直至找到未被占用的端口 +# port: 8719 +# # nacos配置持久化 +# datasource: +# ds1: +# nacos: +# server-addr: 127.0.0.1:8848 +# dataId: sentinel-pmhub-gateway +# groupId: DEFAULT_GROUP +# data-type: json +# rule-type: gw-flow + +# 实时log配置,可在http://localhost:6888/ 监控中心查看实时日志 +logging: + file: + name: logs/${spring.application.name}/info.log diff --git a/SpringCloud/GateWay/src/test/java/com/whai/springcloud/gateway/GateWayApplicationTests.java b/SpringCloud/GateWay/src/test/java/com/whai/springcloud/gateway/GateWayApplicationTests.java new file mode 100644 index 0000000..e0cb730 --- /dev/null +++ b/SpringCloud/GateWay/src/test/java/com/whai/springcloud/gateway/GateWayApplicationTests.java @@ -0,0 +1,13 @@ +package com.whai.springcloud.gateway; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class GateWayApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/SpringCloud/ServiceA/pom.xml b/SpringCloud/ServiceA/pom.xml index 07d89bc..8758aa1 100644 --- a/SpringCloud/ServiceA/pom.xml +++ b/SpringCloud/ServiceA/pom.xml @@ -30,6 +30,7 @@ 17 + org.springframework.boot spring-boot-starter diff --git a/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/config/RestConfig.java b/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/config/RestConfig.java index ef59628..22f71e2 100644 --- a/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/config/RestConfig.java +++ b/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/config/RestConfig.java @@ -16,7 +16,7 @@ import org.springframework.web.client.RestTemplate; public class RestConfig { @Bean @LoadBalanced - public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { - return restTemplateBuilder.build(); + public RestTemplate restTemplate() { + return new RestTemplateBuilder().build(); } } diff --git a/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/service/BService.java b/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/service/BService.java index 8ccd2d2..5136105 100644 --- a/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/service/BService.java +++ b/SpringCloud/ServiceA/src/main/java/com/whai/springcloud/servicea/service/BService.java @@ -18,6 +18,4 @@ public interface BService { @GetMapping("/getB") String getB(@RequestParam("msg") String msg); - - } diff --git a/SpringCloud/ServiceA/src/main/resources/application.yaml b/SpringCloud/ServiceA/src/main/resources/application.yaml index a52c6ee..9491b98 100644 --- a/SpringCloud/ServiceA/src/main/resources/application.yaml +++ b/SpringCloud/ServiceA/src/main/resources/application.yaml @@ -1,5 +1,6 @@ + server: - port: 12120 + port: 12123 spring: application: name: ServiceA @@ -8,20 +9,20 @@ spring: username: nacos password: nacos discovery: - namespace: 97ff159f-6177-4aab-b735-bd75458949d4 + namespace: public group: DEFAULT_GROUP - server-addr: localhost:8848 + server-addr: 192.168.50.248:8848 config: # 配置所属命名空间的id,我们配置名称为dev的id,在命名空间列表查看id的值 - namespace: 97ff159f-6177-4aab-b735-bd75458949d4 + namespace: public # 文件名,如果没有配置则默认为 ${spring.application.name} -# prefix: springboot3-nacos + # prefix: springboot3-nacos # 配置所属分组 group: DEFAULT_GROUP # 后缀名,只支持 properties 和 yaml 类型 file-extension: yaml # nacos服务器地址 - server-addr: localhost:8848 + server-addr: ${spring.cloud.nacos.discovery.server-addr} # 配置自动刷新 refresh-enabled: true config: @@ -33,5 +34,3 @@ logging: level: com.hexadecimal: debug -hexadecimal: - name: whai diff --git a/SpringCloud/ServiceB/pom.xml b/SpringCloud/ServiceB/pom.xml index 3e7e1c3..52fa2c3 100644 --- a/SpringCloud/ServiceB/pom.xml +++ b/SpringCloud/ServiceB/pom.xml @@ -30,6 +30,8 @@ 17 + + org.springframework.boot spring-boot-starter diff --git a/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/ServiceBApplication.java b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/ServiceBApplication.java index d162e10..ddcd7f6 100644 --- a/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/ServiceBApplication.java +++ b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/ServiceBApplication.java @@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; -@SpringBootApplication +@SpringBootApplication(scanBasePackages = {"com.whai.springcloud.serviceb"}) @EnableDiscoveryClient @EnableFeignClients public class ServiceBApplication { diff --git a/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/BProviderController.java b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/BProviderController.java index d5b2131..8acdbca 100644 --- a/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/BProviderController.java +++ b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/BProviderController.java @@ -57,7 +57,7 @@ public class BProviderController { } } - @Value("${cvm.reset.ratelimit}") + @Value("${cvm.reset.ratelimit:0}") private int rateLimitCount; private void initRateLimiter() { if (rateLimitCount <= 0) { @@ -72,6 +72,11 @@ public class BProviderController { return StrUtil.format("BProviderController.getB, msg: {}, port: {}", msg, environment.getProperty("server.port")); } + @RequestMapping("/getProper") + public int getProper() { + return environment.getProperty("cvm.reset.ratelimit", Integer.class); + } + @PostMapping("/CVM/reset") diff --git a/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/ConfigController.java b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/ConfigController.java new file mode 100644 index 0000000..3d3c0ae --- /dev/null +++ b/SpringCloud/ServiceB/src/main/java/com/whai/springcloud/serviceb/controller/ConfigController.java @@ -0,0 +1,27 @@ +package com.whai.springcloud.serviceb.controller; + + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/16 14:24 + * @注释 + */ +@RestController +@RequestMapping("/config") +@RefreshScope +public class ConfigController { + + @Value("${useLocalCache:false}") + private boolean useLocalCache; + + @RequestMapping("/get") + public boolean get() { + return useLocalCache; + } +} diff --git a/SpringCloud/ServiceB/src/main/resources/application.yaml b/SpringCloud/ServiceB/src/main/resources/application.yaml index f344e0b..87841d9 100644 --- a/SpringCloud/ServiceB/src/main/resources/application.yaml +++ b/SpringCloud/ServiceB/src/main/resources/application.yaml @@ -1,4 +1,6 @@ +server: + port: 12121 spring: application: name: ServiceB @@ -7,12 +9,12 @@ spring: username: nacos password: nacos discovery: - namespace: 97ff159f-6177-4aab-b735-bd75458949d4 + namespace: public group: DEFAULT_GROUP - server-addr: localhost:8848 + server-addr: 192.168.50.248:8848 config: # 配置所属命名空间的id,我们配置名称为dev的id,在命名空间列表查看id的值 - namespace: 97ff159f-6177-4aab-b735-bd75458949d4 + namespace: public # 文件名,如果没有配置则默认为 ${spring.application.name} # prefix: springboot3-nacos # 配置所属分组 @@ -20,7 +22,7 @@ spring: # 后缀名,只支持 properties 和 yaml 类型 file-extension: yaml # nacos服务器地址 - server-addr: localhost:8848 + server-addr: ${spring.cloud.nacos.discovery.server-addr} # 配置自动刷新 refresh-enabled: true config: @@ -32,5 +34,3 @@ logging: level: com.hexadecimal: debug -hexadecimal: - name: whai diff --git a/SpringCloud/pom.xml b/SpringCloud/pom.xml index a10cf82..5852f24 100644 --- a/SpringCloud/pom.xml +++ b/SpringCloud/pom.xml @@ -32,6 +32,9 @@ 2023.0.3 + + + org.projectlombok diff --git a/SpringDemo/src/main/java/cn/whaifree/springdemo/config/TransactionConfig.java b/SpringDemo/src/main/java/cn/whaifree/springdemo/config/TransactionConfig.java new file mode 100644 index 0000000..3bdbee3 --- /dev/null +++ b/SpringDemo/src/main/java/cn/whaifree/springdemo/config/TransactionConfig.java @@ -0,0 +1,97 @@ +package cn.whaifree.springdemo.config; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.TransactionManagementConfigurer; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.sql.DataSource; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 16:37 + * @注释 + */ +@Configuration +@Slf4j +public class TransactionConfig implements TransactionManagementConfigurer { + + + @Autowired + private TransactionTemplate transactionTemplate; + + //配置事务管理器 + @Bean + public TransactionManager transactionManager(DataSource dataSource) { + DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource); + // 打印参数 + log.info("transactionManager: {}", transactionManager); + log.info("dataSource: {}", dataSource); + return transactionManager; + } + + @Resource(name="txManager1") + private PlatformTransactionManager txManager1; + + // 创建事务管理器1 + @Bean(name = "txManager1") + public PlatformTransactionManager txManager(DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Override + public TransactionManager annotationDrivenTransactionManager() { + return txManager1; + } + + @Transactional(value="txManager1") + public void addUser() { + + } + + public void addUser2() { + DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); + transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); + transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); + TransactionStatus transaction = txManager1.getTransaction(transactionDefinition); + try { + txManager1.commit(transaction); + } catch (Exception e) { + txManager1.rollback(transaction); + } + } + + /** + * 编程事务 + * TransactionTemplate + * PlatformTransactionManager + * DataSourceTransactionManager + */ + + public void adduser3() { + Object execute = transactionTemplate.execute(new TransactionCallback() { + @Override + public Object doInTransaction(TransactionStatus status) { + return null; + } + }); + } + + +} + +class Tran{ + +} diff --git a/SpringDemo/src/main/java/cn/whaifree/springdemo/controller/TestController.java b/SpringDemo/src/main/java/cn/whaifree/springdemo/controller/TestController.java index d1af2a6..4857365 100644 --- a/SpringDemo/src/main/java/cn/whaifree/springdemo/controller/TestController.java +++ b/SpringDemo/src/main/java/cn/whaifree/springdemo/controller/TestController.java @@ -64,7 +64,7 @@ public class TestController { } @Override - public Object call() throws Exception { + public Object call(){ return null; } diff --git a/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/AmountTypeHandler.java b/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/AmountTypeHandler.java new file mode 100644 index 0000000..ff663fb --- /dev/null +++ b/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/AmountTypeHandler.java @@ -0,0 +1,52 @@ +package cn.whaifree.springdemo.mybatis; + +import cn.whaifree.springdemo.mybatis.domain.AmountBig; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.*; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 10:52 + * @注释 + */ +public class AmountTypeHandler extends BaseTypeHandler { + + /** + * 该方法用于将 AmountBig 枚举类型的值设置到 PreparedStatement 中, + * @param ps + * @param i + * @param parameter + * @param jdbcType + * @throws SQLException + */ + @Override + public void setNonNullParameter(PreparedStatement ps, int i, AmountBig parameter, JdbcType jdbcType) throws SQLException { + if (parameter.equals(AmountBig.BIG)) { + ps.setDouble(i, 1000000000D); + }else { + ps.setDouble(i, 0D); + } + } + + @Override + public AmountBig getNullableResult(ResultSet rs, String columnName) throws SQLException { + double aDouble = rs.getDouble(columnName); + if (aDouble == 1000000000D) { + return AmountBig.BIG; + } + return AmountBig.SMALL; + } + + @Override + public AmountBig getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return null; + } + + @Override + public AmountBig getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return null; + } +} diff --git a/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/domain/AmountBig.java b/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/domain/AmountBig.java new file mode 100644 index 0000000..3b1a316 --- /dev/null +++ b/SpringDemo/src/main/java/cn/whaifree/springdemo/mybatis/domain/AmountBig.java @@ -0,0 +1,12 @@ +package cn.whaifree.springdemo.mybatis.domain; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/11/15 10:50 + * @注释 + */ +public enum AmountBig { + BIG, + SMALL +}