当前位置: 首页 > news >正文

SpringBoot 集成 Activiti 7 工作流引擎

一. 版本信息

  1. IntelliJ IDEA 2023.3.6
  2. JDK 17
  3. Activiti 7

二. IDEA依赖插件安装

        安装BPM流程图插件,如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。

  1. 在Plugins 搜索 Activiti BPMN visualizer 安装
  2. 创建BPMN文件

  3. 使用视图模式打开bpmn.xml

三. 创建SpringBoot 集成 activiti7

  1. 使用 IDEA 创建SpringBoot项目
  2. 设置项目参数
  3. 在 pom.xml 依赖配置文件中添加(Mysql,Lombok,activiti7)依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com</groupId><artifactId>activiti-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>activiti-demo</name><description>activiti-demo</description><properties><java.version>17</java.version></properties><dependencies><!-- web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql依赖 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.2.0</version></dependency><!-- lombok依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- mybatis数据访问层 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency><!-- activiti7 工作流引擎依赖  --><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><version>7.1.0.M6</version></dependency><!-- 模块测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
    
  4. 创建本地连接的数据库
    创建数据库  activiti
    CREATE DATABASE `activiti` /*!40100 DEFAULT CHARACTER SET utf8 */;
    创建数据库表 user
    -- activiti.`user` definitionCREATE TABLE `user` (`ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`NAME` varchar(100) DEFAULT NULL COMMENT '名称',`AGE` varchar(100) DEFAULT NULL COMMENT '年龄',`CREATED_BY` varchar(32) DEFAULT NULL COMMENT '创建人名称',`CREATED_TIME` datetime DEFAULT NULL COMMENT '创建时间',`CREATED_ID` varchar(32) DEFAULT NULL COMMENT '创建人ID',`UPDATED_BY` varchar(32) DEFAULT NULL COMMENT '更新人名称',`UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新时间',`UPDATED_ID` varchar(32) DEFAULT NULL COMMENT '更新人ID',PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
    添加一条测试数据
    INSERT INTO activiti.`user`
    (ID, NAME, AGE, CREATED_BY, CREATED_TIME, CREATED_ID, UPDATED_BY, UPDATED_TIME, UPDATED_ID)
    VALUES(1, '小王', '24', NULL, NULL, NULL, NULL, NULL, NULL);
  5. 添加 application.yml 配置文件
    spring:application:name: activiti-demodatasource:#url切换数据库之后如果对应数据库名称和路径有变动,需要修改urlurl: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
    
  6. 添加 activiti.cfg.xml 配置文件(文件名不能随便改)
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans [<!ELEMENT beans (bean)*><!ATTLIST beansxmlns CDATA #REQUIREDxmlns:xsi CDATA #REQUIREDxsi:schemaLocation CDATA #REQUIRED><!ELEMENT bean (property)*><!ATTLIST beanid CDATA #REQUIREDclass CDATA #REQUIRED><!ELEMENT property (#PCDATA)><!ATTLIST propertyname CDATA #REQUIREDvalue CDATA #REQUIRED>]>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- processEnqine Activiti 的流程引擎 --><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://localhost:3306/activiti?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;useSSL=false&amp;nullCatalogMeansCurrent=true"/><property name="jdbcUsername" value="root"/><property name="jdbcPassword" value="root"/><!-- activiti 数据库表处理策略 --><!-- databaseSchemaUpdate 属性的值可以设置为以下几种 --><!-- none:这是默认值,表示不对数据库模式做任何变更,应用程序启动时不会检查数据库表结构是否与实体类匹配--><!-- true:设置为 true 时,Spring会在应用程序启动时检查数据库表结构,并在发现不匹配时自动创建或修改表结构以匹配实体类定义。这相当于执行了数据库迁移--><!-- create:与 true 类似,但 create 会在每次启动时删除并重新创建表,这可能会导致数据丢失,因此使用时需要谨慎--><!-- create-drop:在每次启动应用程序时创建表,在关闭应用程序时删除表。这通常用于测试环境--><!-- validate:在启动时验证数据库表结构是否与实体类定义匹配,如果不匹配则抛出异常,但不会自动进行任何更改--><property name="databaseSchemaUpdate" value="true"/></bean>
    </beans>
    
  7. 启动SpringBoot项目成功
  8. 开始添加一个查询数据测试接口(Controller,Service,Mapper,Entity)
    Controller类
    package com.activitidemo.act.controller;import com.activitidemo.act.entity.UserEntity;
    import com.activitidemo.act.service.impl.UserServiceImp;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import jakarta.annotation.Resource;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;/*** <p>*  前端控制器* </p>** @author ningbeibei* @since 2024-09-26*/
    @RestController
    @RequestMapping("/user-entity")
    public class UserController {@Resourceprivate UserServiceImp userService;@PostMapping("/user")public Object getUser(@RequestBody UserEntity user){QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();queryWrapper.eq("id",user.getId());return userService.getBaseMapper().selectList(queryWrapper);}}
    Service 类
    package com.activitidemo.act.service;import com.activitidemo.act.entity.UserEntity;
    import com.baomidou.mybatisplus.extension.service.IService;/*** @author ningbeibei* @since 2024-09-26*/
    public interface UserService extends IService<UserEntity> {}
    
    package com.activitidemo.act.service.impl;import com.activitidemo.act.mapper.UserMapper;
    import com.activitidemo.act.service.UserService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.springframework.stereotype.Service;
    import com.activitidemo.act.entity.UserEntity;/*** <p>* 服务实现类* </p>** @author ningbeibei* @since 2024-09-26*/
    @Service
    public class UserServiceImp extends ServiceImpl<UserMapper, UserEntity> implements UserService {
    }
    
    Mapper 类
    package com.activitidemo.act.mapper;import com.activitidemo.act.entity.UserEntity;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import org.apache.ibatis.annotations.Mapper;/*** <p>*  Mapper 接口* </p>** @author ningbeibei* @since 2024-09-26*/
    @Mapper
    public interface UserMapper extends BaseMapper<UserEntity> {}
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.activitidemo.act.entity.UserEntity"></mapper>
    
    Entity 类
    package com.activitidemo.act.entity;import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Getter;
    import lombok.Setter;import java.io.Serializable;
    import java.time.LocalDateTime;/*** @author ningbeibei* @since 2024-09-26*/
    @Getter
    @Setter
    @TableName("user")
    public class UserEntity implements Serializable {private static final long serialVersionUID = 1L;@TableField("ID")private Integer id;@TableField("NAME")private String name;@TableField("AGE")private int age;@TableField("CREATED_BY")private String createdBy;@TableField("CREATED_TIME")private LocalDateTime createdTime;@TableField("CREATED_ID")private String createdId;@TableField("UPDATED_BY")private String updatedBy;@TableField("UPDATED_TIME")private LocalDateTime updatedTime;@TableField("UPDATED_ID")private String updatedId;}
    
    目录结构
  9. 使用Postman接口测试工具,测试接口是否正常

四. Activiti 使用步骤

Activiti 主要流程操作步骤:

  1. 定义流程:按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来。
  2. 部署流程:把画好的流程定义文件,加载到数据库中,生成表的数据。
  3. 启动流程:使用 java 代码来操作数据库表中的内容。
  4. 处理任务:操作流程当中的各个任务。

1. 定义流程

2. 初始库表、定义、部署、操作任务代码

创建测试类

测试代码:

package com.activitidemo;import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.FileCopyUtils;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;@SpringBootTest
class ActivitiDemoApplicationTests {// 创建 ProcessEngine 对象
//    private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//    /**
//     * 初始化数据库表:第一种方式
//     */
//    @Test
//    public void testInitOne() {
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        System.err.println("processEngine = " + processEngine);
//    }/*** 初始化数据库表* 通过读取 activiti.cfg.xml 配置文件*/@Testpublic void testInitTwo() {ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");ProcessEngine processEngine = configuration.buildProcessEngine();System.err.println("processEngine = " + processEngine);}/*** 流程部署*/@Testpublic void testDeploy() {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取 repositoryService 对象RepositoryService repositoryService = processEngine.getRepositoryService();// 进行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("process/leave.bpmn20.xml").addClasspathResource("process/leave.bpmn20.png").name("请假流程").deploy();// 输出部署的一些信息System.out.println("流程部署ID:" + deployment.getId());System.out.println("流程部署名称:" + deployment.getName());System.out.println("流程部署成功");}/*** 启动流程实例*/@Testpublic void testStartProcess() {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取 runtimeService 对象RuntimeService runtimeService = processEngine.getRuntimeService();// 1.根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave");// 2.根据流程定义id启动流程实例
//        ProcessInstance instance = runtimeService.startProcessInstanceById("leave:1:4");// 获取流程实例的相关信息System.out.println("流程定义的id = " + instance.getProcessDefinitionId());System.out.println("流程实例的id = " + instance.getId());System.out.println("启动流程成功 ");}/*** 查询待办任务*/@Testpublic void testSelectTodoTaskList() {String assignee = "李四";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取指定用户审核任务TaskService taskService = processEngine.getTaskService();// 使用面对对象方式查询数据库List<Task> tasks = taskService.createTaskQuery().processDefinitionKey("leave").taskAssignee(assignee)// 返回多个结果.list();// 只返回一个结果// .singleResult();// 自定义 sql 查询// taskService.createNativeTaskQuery();// 获取流程实例的相关信息for (Task task : tasks) {System.out.println("流程定义的id = " + task.getProcessDefinitionId());System.out.println("流程实例的id = " + task.getProcessInstanceId());System.out.println("任务id = " + task.getId());System.out.println("任务名称 = " + task.getName());}}/*** 指定用户去完成任务待办:多人审批在这操作,改变审核人名称就行了*/@Testpublic void testCompleteTask() {String assignee = "李四";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取指定用户审核任务TaskService taskService = processEngine.getTaskService();List<Task> tasks = taskService.createTaskQuery().processDefinitionKey("leave").taskAssignee(assignee).list();if (tasks != null && !tasks.isEmpty()){// 当前流程图所限制,只能做审核同意的动作for (Task task : tasks) {taskService.complete(task.getId());}}}/*** 审批添加备注*/@Testpublic void testAddComment() {String assignee = "张三";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取指定用户审核任务TaskService taskService = processEngine.getTaskService();List<Task> tasks = taskService.createTaskQuery().processDefinitionKey("leave").taskAssignee(assignee).list();if (tasks != null && !tasks.isEmpty()) {// 当前流程图所限制,只能做审核同意的动作for (Task task : tasks) {// 添加备注taskService.addComment(task.getId(), task.getProcessInstanceId(), assignee + "表示同意");taskService.complete(task.getId());}}}/*** 查询审批历史*/@Testpublic void testSelectHistoryTask() {String processInstanceId = "2501";String assignee = "张三";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 查看历史信息HistoryService historyService = processEngine.getHistoryService();// 获取指定用户审核任务TaskService taskService = processEngine.getTaskService();// 获取历史审核信息List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery().activityType("userTask")// 指定实例的id.processInstanceId(processInstanceId).taskAssignee(assignee).finished().list();for (HistoricActivityInstance instance : userTask) {System.out.println("任务名称 = " + instance.getActivityName());System.out.println("任务开始时间 = " + instance.getStartTime());System.out.println("任务结束时间 = " + instance.getEndTime());System.out.println("任务耗时 = " + instance.getDurationInMillis());// 获取审批批注信息List<Comment> taskComments = taskService.getTaskComments(instance.getTaskId());if (!taskComments.isEmpty()){System.out.println("审批批注 = " + taskComments.get(0).getFullMessage());}}}/*** 查询流程相关信息*/@Testpublic void testDefinitionQuery() {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取仓库服务RepositoryService repositoryService = processEngine.getRepositoryService();// 获取流程定义集合List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave")// 最新的一个版本.latestVersion().list();// 遍历集合for (ProcessDefinition definition : processDefinitionList) {System.out.println("流程定义id = " + definition.getId());System.out.println("流程定义名称 = " + definition.getName());System.out.println("流程定义key = " + definition.getKey());System.out.println("流程定义版本 = " + definition.getVersion());System.out.println("流程部署id = " + definition.getDeploymentId());System.out.println("===============");}}/*** 资源文件下载*/@Testpublic void testDownloadResource() throws IOException {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取仓库服务RepositoryService repositoryService = processEngine.getRepositoryService();// 获取流程定义集合List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave")// 按照版本降序.orderByProcessDefinitionVersion()// 降序.desc().list();// 获取最新那个ProcessDefinition definition = list.get(0);// 获取部署idString deploymentId = definition.getDeploymentId();// 获取bpmn的输入流InputStream bpmnInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getResourceName());// 获取png的输入流
//        InputStream pngInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getDiagramResourceName());String resourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getResourceName();File file = new File(resourcePath);if (!file.exists()) {file.getParentFile().mkdirs();}String diagramResourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getDiagramResourceName();file = new File(diagramResourcePath);if (!file.exists()) {file.getParentFile().mkdirs();}//复制文件FileCopyUtils.copy(bpmnInputStream, Files.newOutputStream(Paths.get(resourcePath)));
//        FileCopyUtils.copy(pngInputStream, Files.newOutputStream(Paths.get(diagramResourcePath)));}/*** 删除已经部署的流程定义*/@Testpublic void testDeleteDeploy() {// 删除已经部署的流程定义String deploymentId = "45001";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取仓库服务RepositoryService repositoryService = processEngine.getRepositoryService();// 删除流程定义,如果改流程定义已有流程实例启动,则会报错
//        repositoryService.deleteDeployment(deploymentId);// 设置 true,级联删除流程定义,即使有启动的实例也可以删除repositoryService.deleteDeployment(deploymentId, true);}/*** 启动流程,需要进行 BusinessKey 绑定流程实例*/@Testpublic void testStartBindBusinessKey() {String businessKey = "1";// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();RuntimeService runtimeService = processEngine.getRuntimeService();// 根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的// 在启动流程的时候将业务key加进去ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave", businessKey);// 获取流程实例的相关信息System.out.println("流程定义id = " + instance.getProcessDefinitionId());System.out.println("流程实例id = " + instance.getId());System.out.println("业务标识 = " + instance.getBusinessKey());}/*** 跑到下一个节点,需要进行审批了,此时需要获取 BusinessKey 进而获取请假单信息*/@Testpublic void testGetBusinessKey() {// 1、获取李四的待办信息ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();TaskService taskService = processEngine.getTaskService();List<Task> task = taskService.createTaskQuery().taskAssignee("李四").processDefinitionKey("leave").list();// 2、获取 businessKey// 获取流程实例idString processInstanceId = task.get(1).getProcessInstanceId();RuntimeService runtimeService = processEngine.getRuntimeService();ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();String businessKey = processInstance.getBusinessKey();System.out.println("业务标识 = " + businessKey);}/*** 流程定义挂起与激活*/@Testpublic void testSuspendAllProcessInstance() {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取仓库服务RepositoryService repositoryService = processEngine.getRepositoryService();// 获取流程定义对象ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave").singleResult();boolean suspended = processDefinition.isSuspended();// 输出流程定义状态System.out.println("流程定义状态:" + (suspended ? "已挂起" : "已激活"));String processDefinitionId = processDefinition.getId();if (suspended) {repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);System.out.println("流程id:" + processDefinitionId + "已激活");} else {repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);System.out.println("流程id:" + processDefinitionId + "已挂起");}}/*** 流程实例挂起与激活*/@Testpublic void testProcessInstance() {// 创建 ProcessEngine 对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();RuntimeService runtimeService = processEngine.getRuntimeService();// 获取流程定义对象List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKey("leave").list();// 遍历集合for (ProcessInstance processInstance  : processInstanceList) {boolean suspended = processInstance.isSuspended();// 输出流程定义状态System.out.println("流程实例状态:" + processInstance + "," + (suspended ? "已挂起" : "已激活"));String processDefinitionId = processInstance.getId();if (suspended) {runtimeService.activateProcessInstanceById(processDefinitionId);System.out.println("流程实例id:" + processDefinitionId + "已激活");} else {runtimeService.suspendProcessInstanceById(processDefinitionId);System.out.println("流程实例id:" + processDefinitionId + "已挂起");}}}
}

相关文章:

SpringBoot 集成 Activiti 7 工作流引擎

一. 版本信息 IntelliJ IDEA 2023.3.6JDK 17Activiti 7 二. IDEA依赖插件安装 安装BPM流程图插件&#xff0c;如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。 在Plugins 搜索 Activiti BPMN visualizer 安装创建…...

UVM初学篇 -(22)UVM field_automation 域的自动化机制

field_automation机制是域的自动化的机制&#xff0c;这个机制的最大的优点是可以对一些变量进行批量的处理&#xff0c;比如对象拷贝、克隆、打印之类的变量。 一、 成员变量的注册 使用field_automation机制首先要用uvm_field 系列宏完成变量的注册&#xff0c;类中的成员变…...

STL二分查找

本课主要介绍容器部分里面的二分查找函数。涉及的函数有 3 个&#xff0c;这 3 个函数的强两个输入参数都和迭代器有关&#xff0c;或者说参数是可以迭代的&#xff0c;而第三个参数则是你要查找的值。 1. binary_search binary_search 的返回结果是 bool 值&#xff0c;如果找…...

啤酒游戏—企业经营决策沙盘

感谢黄浦区文华学院的邀请&#xff0c;今年是为南房集团开展系统思考培训的第二年。我们现在为客户设计的一整年系统思考训练中&#xff0c;会将系统环路结构图与真实议题研讨作为前置内容&#xff0c;让大家在理解整体框架后&#xff0c;再体验麻省理工学院系统动力学著名的“…...

尚硅谷-react教程-求和案例-@redux-devtools/extension 开发者工具使用-笔记

## 7.求和案例_react-redux开发者工具的使用(1).npm install redux-devtools/extension(2).store中进行配置import { composeWithDevTools } from redux-devtools/extension;export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))) src/redux/s…...

【动手学强化学习】part2-动态规划算法

阐述、总结【动手学强化学习】章节内容的学习情况&#xff0c;复现并理解代码。 文章目录 一、什么是动态规划&#xff1f;1.1概念1.2适用条件 二、算法示例2.1问题建模2.2策略迭代&#xff08;policyiteration&#xff09;算法2.2.1伪代码2.2.2完整代码2.2.3运行结果2.2.4代码…...

【python爬虫实战】爬取全年天气数据并做数据可视化分析!附源码

由于篇幅限制&#xff0c;无法展示完整代码&#xff0c;需要的朋友可在下方获取&#xff01;100%免费。 一、主题式网络爬虫设计方案 1. 主题式网络爬虫名称&#xff1a;天气预报爬取数据与可视化数据 2. 主题式网络爬虫爬取的内容与数据特征分析&#xff1a; - 爬取内容&am…...

初识Linux · 动静态库(incomplete)

目录 前言&#xff1a; 静态库 动态库 前言&#xff1a; 继上文&#xff0c;我们从磁盘的理解&#xff0c;到了文件系统框架的基本搭建&#xff0c;再到软硬链接部分&#xff0c;我们开始逐渐理解了为什么运行程序需要./a.out了&#xff0c;这个前面的.是什么我们也知道了。…...

华为OD机试 - 匿名信(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…...

通过rancher2.7管理k8s1.24及1.24以上版本的k8s集群

目录 初始化实验环境 安装Rancher 登录Rancher平台 通过Rancher2.7管理已存在的k8s最新版集群 文档中的YAML文件配置直接复制粘贴可能存在格式错误&#xff0c;故实验中所需要的YAML文件以及本地包均打包至网盘. 链接&#xff1a;https://pan.baidu.com/s/1oYX4eGoBtW_R-7i…...

text-align的属性justify

text-align常用的属性是left、center、right&#xff0c;具体的可参考css解释&#xff0c;今天重点记录的对象是justify justify 可以使文本的两端都对齐在两端对齐文本中&#xff0c;文本行的左右两端都放在父元素的内边界上。然后&#xff0c;调整单词和字母间的间隔&#x…...

使用python自制桌面宠物,好玩!——枫原万叶桌宠,可以直接打包成exe去跟朋友炫耀。。。

大家好&#xff0c;我是小黄。 今天我们使用python实现一个桌面宠物。只需要gif动态图片就行。超级简单容易上手。 #完整源代码可在下方图片免费获取 一&#xff1a;下载相关的库文件。 我们本次使用到的库文件为&#xff1a;tkinter和pyautogui 下载命令&#xff1a; pip…...

使用 ASP.NET Core 8.0 创建最小 API

构建最小 API&#xff0c;以创建具有最小依赖项的 HTTP API。 它们非常适合需要在 ASP.NET Core 中仅包括最少文件、功能和依赖项的微服务和应用。 本教程介绍使用 ASP.NET Core 生成最小 API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是使用控制器。 有关在最小 …...

气候服务平台ClimateSERV2.0简介(python)

1 简介 ClimateSERV 2.0允许开发从业者、科学家/研究人员和政府决策者可视化和下载历史降雨数据、植被状况数据以及 180 天的降雨和温度预报&#xff0c;以增进对农业和水资源供应相关问题的理解并做出改进的决策。 这些数据可以通过 Web 应用程序直接访问&#xff0c;也可以…...

Docker | centos7上对docker进行安装和配置

安装docker docker配置条件安装地址安装步骤2. 卸载旧版本3. yum 安装gcc相关4. 安装需要的软件包5. 设置stable镜像仓库6. 更新yum软件包索引7. 安装docker引擎8. 启动测试9. 测试补充&#xff1a;设置国内docker仓库镜像 10. 卸载 centos7安装docker https://docs.docker.com…...

React--》掌握Valtio让状态管理变得轻松优雅

Valtio采用了代理模式&#xff0c;使状态管理变得更加直观和易于使用&#xff0c;同时能够与React等框架无缝集成&#xff0c;本文将深入探讨Valtio的核心概念、使用场景以及其在提升应用性能中的重要作用&#xff0c;帮助你掌握这一强大工具&#xff0c;从而提升开发效率和用户…...

python爬虫百度图片

直接给代码&#xff0c;可直接用&#xff0c;个人需要修改的地方有两处&#xff1a; self.directory 这是本地存储地址&#xff0c;修改为自己电脑的地址&#xff0c;另外&#xff0c;**{}**不要删spider.json_count 10 这是下载的图像组数&#xff0c;一组有30张图像&#x…...

前端开发:Vue中数据绑定原理

Vue 中最大的一个特征就是数据的双向绑定&#xff0c;而这种双向绑定的形式&#xff0c;一方面表现在元数据与衍生数据之间的响应&#xff0c;另一方面表现在元数据与视图之间的响应&#xff0c;而这些响应的实现方式&#xff0c;依赖的是数据链&#xff0c;因此&#xff0c;要…...

CTF-RE 从0到N: TEA

TEA TEA&#xff08;Tiny Encryption Algorithm&#xff0c;轻量加密算法&#xff09; 是一种简单、快速的对称加密算法。它是一个分组加密算法&#xff0c;通常用于加密 64 位的数据块&#xff0c;并使用 128 位的密钥。TEA 是一种“费斯妥结构”&#xff08;Feistel structu…...

python 使用PIL获取图片长宽

在Python中&#xff0c;你可以使用Pillow库&#xff08;PIL的一个分支和替代品&#xff09;来获取图片的长和宽。Pillow提供了丰富的图像处理功能&#xff0c;包括获取图像的基本属性&#xff0c;如尺寸。 以下是一个简单的示例&#xff0c;展示了如何使用Pillow库来获取图片的…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...