activiti初次学习

源代码地址:https://gitee.com/ZSXYX/activiti.git​

1、安装插件

首先安装下图所示activiti,不确定是哪个插件有用的,有时间可排除下
在这里插入图片描述
在resources下创建一个文件夹:processes,右键,新建
在这里插入图片描述
生成:
在这里插入图片描述
选中act.bpmn20.xml右键
在这里插入图片描述
展示如下空白面板,右键画图
在这里插入图片描述
在这里插入图片描述

画图完毕,右键保存为act.png图片
在这里插入图片描述

2、配置流程引擎

接下来,我们连接数据库,在resources下新建activiti.cfg.xml在这里插入图片描述
文件内容如下:

<bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti?serverTimezone=GMT%2B8"/>
        <property name="jdbcUsername" value="root"/>
        <property name="jdbcPassword" value="root"/>
        <!-- activiti数据库表处理策略 -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>

3、创建表

接着:在数据库中新建一个数据库
在这里插入图片描述
执行如下图,在数据库中生成25张表:
在这里插入图片描述
表名如下:
在这里插入图片描述
具体表名:
在这里插入图片描述

生成25张表

代码如下:

  /**
     * 生成 activiti的数据库表
     */
	@Test
	public void testCreateDbTable() {
		//使用classpath下的activiti.cfg.xml中的配置创建processEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		System.out.println(processEngine);
	}

4、部署流程定义

在这里插入图片描述
代码如下:

    /**
     * 部署流程定义
     * 将上面在设计器中定义的流程部署到activiti数据库中,就是流程定义部署。
     * 通过调用activiti的api将流程定义的bpmn和png两个文件一个一个添加部署到activiti中,也可以将两个文件打成zip包进行部署。
     * 单个文件部署方式
     * 分别将bpmn文件和png图片文件部署。
	 * act_re_procdef :id 中会存在一个ProcessInstanceByKey  : act
     */
	@Test
	public void testDeployment(){
//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、得到RepositoryService实例
		RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、使用RepositoryService进行部署
		Deployment deployment = repositoryService.createDeployment()
				.addClasspathResource("processes/act.bpmn20.xml") // 添加bpmn资源
				.addClasspathResource("processes/act.png")  // 添加png资源
				.name("请假申请流程")
				.deploy();
//        4、输出部署信息
		System.out.println("流程部署id:" + deployment.getId());
		System.out.println("流程部署名称:" + deployment.getName());
	}

运行后,会在数据库中生成一条:
在这里插入图片描述
如果你的activiti-spring-boot-starter是7.1.0.M5的话,多半就会报错,很明显sql少字段,这个应该是一个官方的BUG
如果运行报错:

Unknown column 'VERSION_' in 'field list'

解决方式:
在act_re_deployment 中添加两个字段:
VERSION_、PROJECT_RELEASE_VERSION_
在这里插入图片描述
2:
在这里插入图片描述

 /**
     * 3、启动流程实例
     * 针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于java类与java对象的关系,
     * 类定义好后需要new创建一个对象使用,当然可以new多个对象。对于请出差申请流程,张三发起一个出差申请单需要启动一个流程实例,
     * 出差申请单发起一个出差单也需要启动一个流程实例。
     */
	@Test
	public void testStartProcess(){
//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取RunTimeService
		RuntimeService runtimeService = processEngine.getRuntimeService();
		//启动流程的时候【动态设置每个步骤的执行人】,map的key值需要与Leave.bpmn中对应
		Map<String, Object> variables=new HashMap<String, Object>();
		variables.put("user1", "张三");
		variables.put("user2", "李四");
//        3、根据流程定义Id启动流程
		ProcessInstance processInstance = runtimeService
				.startProcessInstanceByKey("aaa","1005",variables);   //会在act_hi_varinst中新增两条数据
//        输出内容
		System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
		System.out.println("流程实例id:" + processInstance.getId());
		System.out.println("当前活动Id:" + processInstance.getActivityId());
	}

在这里插入图片描述

5、启动流程实例

在这里插入图片描述

代码如下:

   /**
     * 启动流程实例
     * 针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于java类与java对象的关系,
     * 类定义好后需要new创建一个对象使用,当然可以new多个对象。对于请出差申请流程,张三发起一个出差申请单需要启动一个流程实例,
     * 出差申请单发起一个出差单也需要启动一个流程实例。
     */
		@Test
	public void testStartProcess(){
//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取RunTimeService
		RuntimeService runtimeService = processEngine.getRuntimeService();
//        3、根据流程定义Id启动流程
		ProcessInstance processInstance = runtimeService
				.startProcessInstanceByKey("act","1001");
//        输出内容
		System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
		System.out.println("流程实例id:" + processInstance.getId());
		System.out.println("当前活动Id:" + processInstance.getActivityId());
	}

启动流程实例时,指定的businesskey,就会在act_ru_execution #流程实例的执行表中存储businesskey。会在库中生成:
Activiti的act_ru_execution中存储业务标识
在这里插入图片描述
说明:

流程实例执行,如果当前只有一个分支时,一个流程实例只有一条记录且执行表的主键id和流程实例id相同,如果当前有多个分支正在运行则该执行表中有多条记录,存在执行表的主键和流程实例id不相同的记录。不论当前有几个分支总会有一条记录的执行表的主键和流程实例id相同

一个流程实例运行完成,此表中与流程实例相关的记录删除。

SELECT * FROM act_ru_task #任务执行表,记录当前执行的任务
在这里插入图片描述
说明:启动流程实例,流程当前执行到第一个任务结点,此表会插入一条记录表示当前任务的执行情况,如果任务完成则记录删除。

SELECT * FROM act_ru_identitylink #任务参与者,记录当前参与任务的用户或组
在这里插入图片描述
SELECT * FROM act_hi_procinst #流程实例历史表
在这里插入图片描述
流程实例启动,会在此表插入一条记录,流程实例运行完成记录也不会删除。

SELECT * FROM act_hi_taskinst #任务历史表,记录所有任务
在这里插入图片描述
开始一个任务,不仅在act_ru_task表插入记录,也会在历史任务表插入一条记录,任务历史表的主键就是任务id,任务完成此表记录不删除。

SELECT * FROM act_hi_actinst #活动历史表,记录所有活动
在这里插入图片描述

在这里插入图片描述

6、查询流程实例

流程在运行过程中可以查询流程实例的状态,当前运行结点等信息。
在这里插入图片描述
代码如下:

  /**
     * 查询当前个人待执行的任务
     * 流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
     */
	@Test
	public void testFindPersonalTaskList() {
//        任务负责人
		String assignee = "zhangsan";
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        创建TaskService
		TaskService taskService = processEngine.getTaskService();
//        根据流程key 和 任务负责人 查询任务
		List<Task> list = taskService.createTaskQuery()
				.processDefinitionKey("act") //流程Key
				.taskAssignee(assignee)//只查询该任务负责人的任务
				.list();

		for (Task task : list) {

			System.out.println("流程实例id:" + task.getProcessInstanceId());
			System.out.println("任务id:" + task.getId());
			System.out.println("任务负责人:" + task.getAssignee());
			System.out.println("任务名称:" + task.getName());

		}
	}

需求:
在activiti实际应用时,查询流程实例列表时可能要显示出业务系统的一些相关信息,比如:查询当前运行的出差流程列表需要将出差单名称、出差天数等信息显示出来,出差天数等信息在业务系统中存在,而并没有在activiti数据库中存在,所以是无法通过activiti的api查询到出差天数等信息。
实现:
在查询流程实例时,通过businessKey(业务标识 )关联查询业务系统的出差单表,查询出出差天数等信息。
通过下面的代码就可以获取activiti中所对应实例保存的业务Key。而这个业务Key一般都会保存相关联的业务操作表的主键,再通过主键ID去查询业务信息,比如通过出差单的ID,去查询更多的请假信息(出差人,出差时间,出差天数,出差目的地等)
String businessKey = processInstance.getBusinessKey();
在activiti的act_ru_execution表,字段BUSINESS_KEY就是存放业务KEY的。

7、流程任务处理

任务负责人查询待办任务,选择任务进行处理,完成任务

//	任务负责人查询待办任务,选择任务进行处理,完成任务。
	@Test
	public void completTask(){
//        获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取taskService
		TaskService taskService = processEngine.getTaskService();

//        根据流程key 和 任务的负责人 查询任务
//        返回一个任务对象
		Task task = taskService.createTaskQuery()
				.processDefinitionKey("act") //流程Key
				.taskAssignee("zhangsan")  //要查询的负责人
				.singleResult();
//        完成任务,参数:任务id
		taskService.complete(task.getId());
	}

8、流程定义信息查询

查询流程相关信息,包含流程定义,流程部署,流程定义版本
在这里插入图片描述
结果:在这里插入图片描述
代码:

  // 完成任务
//	任务负责人查询待办任务,选择任务进行处理,完成任务。
	@Test
	public void completTask(){
//        获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取taskService
		TaskService taskService = processEngine.getTaskService();

//        根据流程key 和 任务的负责人 查询任务
//        返回一个任务对象
		Task task = taskService.createTaskQuery()
				.processDefinitionKey("act") //流程Key
				.taskAssignee("zhangsan")  //要查询的负责人
				.singleResult();
//        完成任务,参数:任务id
		taskService.complete(task.getId());
	}


    /**
     * 查询流程定义
     * 查询流程相关信息,包含流程定义,流程部署,流程定义版本
     */
	@Test
	public void queryProcessDefinition(){
		//        获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        repositoryService
		RepositoryService repositoryService = processEngine.getRepositoryService();
//        得到ProcessDefinitionQuery 对象
		ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//          查询出当前所有的流程定义
//          条件:processDefinitionKey =evection
//          orderByProcessDefinitionVersion 按照版本排序
//        desc倒叙
//        list 返回集合
		List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("act")
				.orderByProcessDefinitionVersion()
				.desc()
				.list();
//      输出流程定义信息
		for (ProcessDefinition processDefinition : definitionList) {
			System.out.println("流程定义 id="+processDefinition.getId());
			System.out.println("流程定义 name="+processDefinition.getName());
			System.out.println("流程定义 key="+processDefinition.getKey());
			System.out.println("流程定义 Version="+processDefinition.getVersion());
			System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
		}

	}

9、 流程删除

在这里插入图片描述
在这里插入图片描述

### The error occurred while setting parameters
### SQL: delete from ACT_RE_PROCDEF where DEPLOYMENT_ID_ = ?
### Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`activiti`.`act_ru_execution`, CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`))

说明:

使用repositoryService删除流程定义,历史表信息不会被删除

如果该流程定义下没有正在运行的流程,则可以用普通删除。

如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。

先删除没有完成流程节点,最后就可以完全删除流程定义信息

项目开发中级联删除操作一般只开放给超级管理员使用.

疑问?
当使用了级联删除仍然失败,请大神赐教
在这里插入图片描述
错误日志:

Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`activiti`.`act_ru_execution`, CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`))
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)
	at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
	... 78 more

相关代码:

	//流程删除
	@Test
	public void deleteDeployment() {
		// 流程部署id
		String deploymentId = "57501";

		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		// 通过流程引擎获取repositoryService
		RepositoryService repositoryService = processEngine.getRepositoryService();
		//删除流程定义,如果该流程定义已有流程实例启动则删除时出错
		repositoryService.deleteDeployment(deploymentId);
		//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程
		repositoryService.deleteDeployment(deploymentId, true);
	}

10 流程资源下载

现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。

解决方案有:

jdbc对blob类型,clob类型数据读取出来,保存到文件目录

使用activiti的api来实现

使用commons-io.jar 解决IO的操作

引入commons-io依赖包

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

通过流程定义对象获取流程定义资源,获取bpmn和png
在这里插入图片描述
结果:
在这里插入图片描述
说明:

deploymentId为流程部署ID
resource_name为act_ge_bytearray表中NAME_列的值
使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
最后的将输入流中的图片资源进行输出。

代码:

  /**
     * 现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,
     * 可以从数据库中把资源文件下载到本地。
     */
	@Test
	public void  queryBpmnFile() throws IOException {
//        1、得到引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取repositoryService
		RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
		List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
				.processDefinitionKey("act")
				.list();
//        4、通过流程定义信息,得到部署ID
		for (ProcessDefinition processDefinition: list) {
			String deploymentId = processDefinition.getDeploymentId();
//        5、通过repositoryService的方法,实现读取图片信息和bpmn信息
//        png图片的流
			InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
//        bpmn文件的流
			InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
//        6、构造OutputStream流
			File file_png = new File("D:\\test\\act.bpmn20.xml");
			File file_bpmn = new File("D:\\test\\act.png");
			FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
			FileOutputStream pngOut = new FileOutputStream(file_png);
//        7、输入流,输出流的转换
			IOUtils.copy(pngInput, pngOut);
			IOUtils.copy(bpmnInput, bpmnOut);
//        8、关闭流
			pngOut.close();
			bpmnOut.close();
			pngInput.close();
			bpmnInput.close();
		}
	}

11流程历史信息的查看

即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述
代码:

 /**
     * 查看历史信息
     * 即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。
     * 所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。
     */
	@Test
	public void findHistoryInfo(){
//      获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取HistoryService
		HistoryService historyService = processEngine.getHistoryService();
//        获取 actinst表的查询对象
		HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//        查询 actinst表,条件:根据 InstanceId 查询
//        instanceQuery.processInstanceId("2501");
//        查询 actinst表,条件:根据 DefinitionId 查询
		instanceQuery.processDefinitionId("act:1:52504");
//        增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
		instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//        查询所有内容
		List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//        输出
		for (HistoricActivityInstance hi : activityInstanceList) {
			System.out.println(hi.getActivityId());
			System.out.println(hi.getActivityName());
			System.out.println(hi.getProcessDefinitionId());
			System.out.println(hi.getProcessInstanceId());
			System.out.println("<==========================>");
		}
	}

12挂起、激活流程实例

某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执行。

流程定义可以对应多个流程实例

如:每月最后一天不处理出差申请,需要挂起这个流程定义下的流程实例

当有这种流程实例没有跑完的时候,如果已经被挂起,就不能继续处理了

只有当流程实例激活后,整个流程才能继续向下处理

全部流程实例挂起
操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:

流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。

测试多个实例,则可以再运行一次addBusinessKey,修改1002,表示另一个人发起出差流程申请
在这里插入图片描述
结果:在这里插入图片描述
在这里插入图片描述

再次执行:
在这里插入图片描述
在这里插入图片描述

操作数据库
act_ru_task

act_re_procdef

act_ru_execution

都修改了SUSPENSION_STATE_暂停状态
代码:

 /**
     * 全部流程实例挂起与激活
     * 全部流程实例挂起
     * 操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:
     * 流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。
     * 测试多个实例,则可以再运行一次addBusinessKey,修改1002,表示另一个人发起出差流程申请
     */
	@Test
	public void SuspendAllProcessInstance(){
//        获取流程引擎processEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取repositoryService
		RepositoryService repositoryService = processEngine.getRepositoryService();
//        查询流程定义的对象
		List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().
				processDefinitionKey("act").
				list();
		for (ProcessDefinition processDefinition : list) {
//        得到当前流程定义的实例是否都为暂停状态
			boolean suspended = processDefinition.isSuspended();
//        流程定义id
			String processDefinitionId = processDefinition.getId();
//        判断是否为暂停
			if (suspended) {
//         如果是暂停,可以执行激活操作 ,参数1 :流程定义id ,参数2:是否激活,参数3:激活时间
				repositoryService.activateProcessDefinitionById(processDefinitionId,
						true,
						null
				);
				System.out.println("流程定义:" + processDefinitionId + ",已激活");
			} else {
//          如果是激活状态,可以暂停,参数1 :流程定义id ,参数2:是否暂停,参数3:暂停时间
				repositoryService.suspendProcessDefinitionById(processDefinitionId,
						true,
						null);
				System.out.println("流程定义:" + processDefinitionId + ",已挂起");
			}
		}

	}

13单个流程实例挂起

操作流程实例对象,针对单个流程执行挂起操作
act_hi_actinst,act_hi_identitylink,act_hi_procinst,act_hi_taskinst,act_ru_identitylink,act_ru_task,act_ru_execution这些表都有流程实例id,字段名都是PROC_INST_ID_,这里我使用act_ru_execution查询**
在这里插入图片描述
在这里插入图片描述
代码:

/**
	 * 单个流程实例挂起与激活
	 */
	@Test
	public void SuspendSingleProcessInstance(){
//        获取processEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        RuntimeService
		RuntimeService runtimeService = processEngine.getRuntimeService();
//        查询流程定义的对象
		ProcessInstance processInstance = runtimeService.
				createProcessInstanceQuery().
				processInstanceId("55001").
				singleResult();
//        得到当前流程定义的实例是否都为暂停状态
		boolean suspended = processInstance.isSuspended();
//        流程定义id
		String processDefinitionId = processInstance.getId();
//        判断是否为暂停
		if(suspended){
//         如果是暂停,可以执行激活操作 ,参数:流程定义id
			runtimeService.activateProcessInstanceById(processDefinitionId);
			System.out.println("流程定义:"+processDefinitionId+",已激活");
		}else{
//          如果是激活状态,可以暂停,参数:流程定义id
			runtimeService.suspendProcessInstanceById( processDefinitionId);
			System.out.println("流程定义:"+processDefinitionId+",已挂起");
		}

	}

14测试完成个人任务,测试暂停了流程实例,是否还可以继续

在这里插入图片描述
对于已完成的任务
在这里插入图片描述

对于新建的任务
在这里插入图片描述
代码:

    /**
     * 测试完成个人任务,测试暂停了流程实例,是否还可以继续下一步,会报错“Cannot complete a suspended task”
     */
	@Test
	public void completTask1(){
//        获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取操作任务的服务 TaskService
		TaskService taskService = processEngine.getTaskService();
//        完成任务,参数:流程实例id,完成zhangsan的任务
		Task task = taskService.createTaskQuery()
				.processInstanceId("77501")
				.taskAssignee("zhangsan")
				.singleResult();


		System.out.println("流程实例id="+task.getProcessInstanceId());
		System.out.println("任务Id="+task.getId());
		System.out.println("任务负责人="+task.getAssignee());
		System.out.println("任务名称="+task.getName());
		taskService.complete(task.getId());
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/548789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 使用ping命令判断当前网络状态

一. 介绍 ping命令是用来测试和诊断网络连接问题的基本命令&#xff0c;当然我们的终端设备&#xff08;手机/平板/车机&#xff09;都可以用这个命令来判断当前网络是否有流量的状态&#xff0c;本篇文章主要介绍Linux的ping命令&#xff0c;因为Android系统也是使用了Linux内…

【面经】操作系统/Linux

1、计算机的五大单元 电脑的五大单元包括&#xff1a;输入单元、输出单元、控制单元、算数逻辑单元、存储单元五大部分。其中CPU占有控制、算术逻辑单元&#xff0c;存储单元又包含内存与辅助内存&#xff1b; 2、什么是操作系统 操作系统&#xff1a;负责管理协调我们计算机…

汽车车灯用肖特基二极管,选什么型号好?

肖特基二极管种类繁多&#xff0c;有低压降肖特基二极管、通用型肖特基二极管、快速恢复型肖特基二极管、高功率肖特基二极管、汽车级肖特基二极管等等&#xff0c;其中低压降肖特基二极管和汽车级肖特基二极管是二极管厂家东沃电子的核心优势产品。关于东沃电子推出的低压降肖…

Android 接入MQTT服务器

加入MQTT库 加入库可以直接下载对应的jar包&#xff0c;也可以在build.gradle里导入&#xff0c;然后加载进入。 这里直接在build.gradle加库 dependencies {implementation(libs.appcompat)implementation(libs.material)implementation(libs.activity)implementation(libs…

【k8s】:深入理解k8s中的亲和性(Affinity)及其在集群调度中的应用

【k8s】&#xff1a;深入理解k8s中的亲和性&#xff08;Affinity&#xff09;及其在集群调度中的应用 1、什么是亲和性&#xff1f;2、节点亲和性&#xff08;Node Affinity&#xff09;2.1 硬性节点亲和性规则&#xff08;required&#xff09;2.2 软性节点亲和性规则&#xf…

如何制作二维码电子画册?轻松入门,快速上手!

在当今数字化时代&#xff0c;二维码电子画册成为了企业推广和信息传递的重要工具之一。相比传统纸质画册&#xff0c;二维码电子画册不仅环保节能&#xff0c;而且可以通过扫描二维码轻松获取更多详细信息&#xff0c;为用户提供了更加便捷的阅读体验。 今天就教大家如何制作二…

【Java开发指南 | 第三篇】Java 空行、强制类型转换及基本数据类型

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java 空行强制类型转换Java 基本数据类型内置数据类型引用类型 Java 空行 空白行或者有注释的行&#xff0c;Java 编译器都会忽略掉。 强制类型转换 当需要将一个数据类型转换为另一个数据类型时&#xff0c…

浅尝 express + ORM框架 prisma 的结合

一、prisma起步 安装&#xff1a; npm i prisma -g查看初始化帮助信息&#xff1a; prisma init -h查看初始化帮助信息结果&#xff1a; Set up a new Prisma projectUsage$ prisma init [options] Options-h, --help Display this help message --datasource-provider …

Intewell-Hyper II_V2.1.1_工业实时操作系统软件版本发布

Intewell-Hyper II_V2.1.1_工业实时操作系统软件版本发布 Intewell-Hyper II_V2.1.1 版本号&#xff1a;V2.1.1 版本特点 新增V1.3.2分支上SHV构型合并及问题回归 版本或修改说明 增加功能&#xff1a; 1.V1.3.2分支上SHV构型合并及问题回归 2.适配NewPre3102和NewPre3101…

node+vue3的websocket前后端消息推送

nodevue3的websocket前后端消息推送 前期写web项目时&#xff0c;前端获取数据的方式一般是向后端发起数据请求&#xff0c;然后后端向前端发送数据&#xff0c;然后对数据进行渲染&#xff0c;这是最常规的一种数据通讯方式&#xff0c;适用于绝大部分前后端分离的项目 实际…

java的ConcurrentHashMap深入理解

概要 怎么保证线程安全&#xff1a; 在初始化数组时用了cas操作&#xff0c;sizectl作为占位标志(U.compareAndSwapInt(this, SIZECTL, sc, -1&#xff09;&#xff1b;获取数组中的元素是否已经有了&#xff0c;用Volatile修饰数组&#xff08;保证可见性&#xff09;&#…

边缘计算网关有哪些优势?-天拓四方

随着信息化、智能化浪潮的持续推进&#xff0c;计算技术正以前所未有的速度发展&#xff0c;而边缘计算网关作为其中的重要一环&#xff0c;以其独特的优势正在逐步改变我们的生活方式和工作模式。本文将详细解析边缘计算网关的优势。 首先&#xff0c;边缘计算网关具有显著的…

【好书推荐6】《Excel函数与公式应用大全for Excel 365 Excel 2021》

【好书推荐6】《Excel函数与公式应用大全for Excel 365 & Excel 2021》 写在最前面《Excel函数与公式应用大全for Excel 365 & Excel 2021》关键点内容简介作者简介前言/序言目录 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&…

Linux之命令行参数的原理以及实现,环境变量限时增加删除和永久增加删除以及代码获取环境变量

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 一.命令行参数 1.1main函数参数 在我们学习c语言时我们的main函数…

Vue - 5( 16000 字 Vue2 入门级教程)

一&#xff1a;Vue 初阶 1.1 组件自定义事件 在 Vue 中&#xff0c;组件间通过自定义事件进行通信是一种常见的模式。自定义事件允许子组件向父组件发送消息&#xff0c;也可以在组件内部进行事件的绑定、触发和解绑。让我们详细讲解这些知识点。 1.1.1 组件自定义事件 在 …

最前沿・量子退火建模方法(2) : Domain wall encoding讲解和python实现

前言 上篇讲的subQUBO属于方法论&#xff0c;这次讲个通过编码量子比特的方式&#xff0c;同样的约束条件&#xff0c;不同的编码&#xff0c;所需的量子比特数是不同的。有的编码方式&#xff0c;很节省量子比特。比如&#xff0c;这次要讲的Domain wall encoding。 一、Doma…

一文总结:Python的封装、继承和多态

整个程序员的生涯&#xff0c;最重要的一个知识根基就是面向对象的理解和掌握深度。如果你意识到了面向对象开发思想的重要性&#xff0c;请仔细学习这篇文章。 希望对你有帮助&#xff01; 这篇详细地解释封装、继承和多态&#xff0c;并在最后提供一个综合示例来总结这三个…

PyQt介绍——弹框介绍和使用

PyQt介绍——弹框介绍和使用 一、QMessageBox QMessageBox是一种通用的弹出式对话框&#xff0c;用于显示消息&#xff0c;允许用户通过单击不同的标准按钮对消息进行反馈 QMessageBox类提供了许多常用的弹出式对话框&#xff0c;如提示、警告、错误、询问、关于等对话框。这…

Hyper-v 新建 Windows 虚拟机卡在“Press any key to boot from CD or DVD...,无法按下任何按键

Hyper-v 新建 Windows 虚拟机卡在“Press any key to boot from CD or DVD…&#xff0c;无法按下任何按键 在显示这个界面之后点击启动&#xff0c;之后立刻狂按F2&#xff0c; 然后就能进去了

​代码混淆的原理是什么?常见代码混淆方法介绍

本文主要想你介绍代码混淆的原理&#xff0c;常见代码混淆方法&#xff0c;欢迎查阅~ 移动应用代码安全非常重要&#xff0c;代码逆向会导致代码逻辑被获取&#xff0c;进一步导致控制流被hook&#xff0c;安全防线被破&#xff0c;给APP安全带来巨大风险&#xff0c;因此开发者…
最新文章