SpringBoot整合Flowable/Activiti

SpringBoot版本: 2.0.1.RELEASE

Flowable版本: 6.3.1

Activiti版本: 6.0.0

一.添加pom依赖

    因为之前我整合的时候有报错关于sqlsession的错误,后面查询文章才发现flowable要排除掉mybatis,又没说具体排除哪一个,所以我这干脆全部排除了

<!-- Flowable dependencies --><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-engine</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-rest</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-cmmn-spring</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-dmn-spring</artifactId><version>6.3.1</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency>

<!--activiti modeler start--><dependency><groupId>org.activiti</groupId><artifactId>activiti-json-converter</artifactId><version>6.0.0</version><exclusions><exclusion><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId></exclusion></exclusions></dependency>

二.yml配置flowable/Activiti相关配置项

  至于层级关系,都是和spring同级的,我一般放在mybatis配置项下面,类似下面这样

  flowable:#关闭定时任务JOBasync-executor-activate: false#  将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。database-schema-update: true# activiti 模块activiti:# 解决启动报错:class path resource [processes/] cannot be resolved to URL because it does not existcheck-process-definitions: false# 检测身份信息表是否存在db-identity-used: true# 默认为false# false:项目启动时,如果数据库中没有表将抛出异常(上线后使用)# true:项目启动时,如果数据库中没有表将自动生成(开发和测试时使用)database-schema-update: true

 三.数据库配置项中url添加&nullCatalogMeansCurrent=true配置

        因为我之前用过activiti工作流,如果不加这个配置工作流会默认查询整个数据库连接下所有的库,只要发现有相关的act表就会认为已经自动生成了. 导致你在A库有了工作流的表之后想在B库再去自动生成就会发现生成不了.加上这个配置就可以了,不知道flowable影不影响,我都习惯给加上了

#  nullCatalogMeansCurrent=true
#  因为mysql使用schema标识库名而不是catalog,因此mysql会扫描所有的库来找表,
#  如果其他库中有相同名称的表,activiti就以为找到了,本质上这个表在当前数据库中并不存在。
#  解决办法就是在数据库链接的配置后面加上 nullCatalogMeansCurrent=true,标识之搜索当前链接的库。
url: jdbc:mysql://192.168.*.*:3306/flowable?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true

四.启动项目 自动生成数据表

        这个会根据flowable的版本而来 实际可能不一致 我的flowable版本是6.3.1,生成了66张表

Activiti版本是6.0.0,生成了28张表

一些常用的需要关注的表的含义(注明了注释)

 

五.IDEA中安装Flowable/Activiti插件

        安装插件: Flowable BPMN visualizer / Activiti BPMN visualizer

        然后在resources目录下新建processes目录

        右键新建一个基于BOMN 2.0协议的文件

        绘制流程图 

 

        注意: flowable/Activiti都会将处于processes目录下的符合后缀名要求的文件自动部署

                 不想要这个功能你可以修改目录名或者查询网站搜索下相关的关闭命令

六.工作流提供的几个Service

Flowable和Activiti都给我们提供了几个Service

因为本身Flowable的团队就是从Activiti团队中过来的,所以Service的命名及使用基本都是一致的,会一个就会另一个

    // 运行时执行管理Service@Autowiredprivate RuntimeService runtimeService;// 工作流任务管理Service@Autowiredprivate TaskService taskService;// 管理流程定义Service@Autowiredprivate RepositoryService repositoryService;// 核心类 可以理解为流程引擎对象@Autowiredprivate ProcessEngine processEngine;// 历史管理Service@Autowiredprivate HistoryService historyService;

七.常用方法

因为几乎所有业务都需要用到"PROC_INST_ID_" 也就是 "流程实例Id"

以及当前任务id-TASK_ID

所以我建议把这两个id都放在业务表中和你的业务表一对一关联(一般都是一个业务开一个流程实例)

1.动态部署

(提供一个文件,通过repositoryService创建部署对象去读取xml文件的内容来自动部署)

部署完之后ACT_RE_DEPLOYMENT,ACT_RE_PROCDEF两个表中会有数据

MultipartFile file; // 提供一个二进制文件对象
Deployment deployment = null;try{DeploymentBuilder deploymentBuilder =repositoryService.createDeployment()
.name(Objects.requireNonNull(file.getOriginalFilename()).substring(0, file.getOriginalFilename().indexOf(".bpmn20.xml"))).addInputStream(file.getOriginalFilename(),file.getInputStream());deployment = deploymentBuilder.deploy();}catch (Exception e){e.printStackTrace();throw new CustomException("文件部署失败");}// 部署完后可以获取部署ID
// 根据部署ID查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
System.out.println("流程【"+processDefinition.getName()+"】部署成功, 部署ID为: "+processDefinition.getDeploymentId()+"流程定义Key为: "+processDefinition.getKey());

2.流程启动

Map<String, Object> variables = new HashMap<>();variables.put("startUser", SecurityUtils.getLoginUser().getUser().getUserId().toString());variables.put("data", processInit.getData());variables.put("remark", processInit.getRemark());ProcessInstance processInstance = null;try{// 根据部署ID查询流程定义ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(processInit.getDeployId()).singleResult();//启动流程实例,同时还要指定业务标识businessKey  项目Id//第一个参数:是指流程定义key//第二个参数:业务标识businessKeyprocessInstance = runtimeService.startProcessInstanceByKey(processDefinition.getKey(),processInit.getWorkId().toString(),variables);runtimeService.setProcessInstanceName(processInstance.getId(),processDefinition.getName());

        启动后ACT_RU_EXECUTION会看到流程实例当前执行的节点概况,包括历史节点和当前时节点

PROC_INST_ID_是流程实例Id 

 

这两个表也可以看到实例相关节点信息

 

3.执行下一任务节点并添加审核备注

核心方法为: 

taskService.complete(task.getId());

需要注意的是:如果没有执行人,需要先认领任务而后才去审核任务

SysUser user = SecurityUtils.getLoginUser().getUser();String taskId; // 当前任务IdString processInstanceId; // 流程实例IdProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();String businessKey = processInstance.getBusinessKey(); // 流程实例的业务Id-businessKey// 获取当前待办任务Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskId(taskId).singleResult();if(task == null){throw new CustomException(CustomExceptionEnums.DATA_NOT_FOUND);}String assignee = task.getAssignee();if(StringUtils.isEmpty(assignee)){// 如果没有执行人 需要先认领任务taskService.claim(task.getId(),user.getUserId().toString());}if(StringUtils.isNotEmpty(processApproved.getRemark())){// 添加审批备注taskService.addComment(taskId, processInstanceId, ActivityCommentType.APPROVED_REMARK.getType(), processApproved.getRemark());}// 完成当前任务taskService.complete(task.getId());

 通过后可通过taskService获取下一个任务节点Id

// 获取下一个任务ID
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();

4.获取待办/已办

因为Activiti和Flowable中并没有获取待办任务和已办任务的直接方法可以调用

所以需要我们自己写sql语句来获取

需要用到以下的表

待办任务所需

"ACT_RU_TASK"运行时任务节点表

"ACT_RU_IDENTITYLINK"运行时流程人员表

"ACT_HI_PROCINST"历史流程实例表

已办任务所需

"ACT_HI_TASKINST"历史任务节点表

"ACT_HI_PROCINST"历史流程实例表

然后我自己通过union将结果合并,并通过task_status来区分待办和已办

-- 待办和已办union all查询
select * from
(
select 0 as task_status,
RES.ID_ as task_id,RES.NAME_ as task_name,RES.CREATE_TIME_ as start_time,null as end_time,RES.PROC_INST_ID_ as process_instance_id,RES.ASSIGNEE_ as assignee,P.BUSINESS_KEY_  as business_key ,P.NAME_ as process_instance_name ,I.TYPE_ as type,I.USER_ID_ as user_id, I.GROUP_ID_ as group_id ,RES.TASK_DEF_KEY_ as task_def_key
from ACT_RU_TASK RES 
left join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES.ID_ 
left join ACT_HI_PROCINST P on P.PROC_INST_ID_ = RES.PROC_INST_ID_ UNION ALLselect 1 as task_status,
RES.ID_ as task_id,RES.NAME_ as task_name,RES.START_TIME_ as start_time,RES.END_TIME_ as end_time,RES.PROC_INST_ID_ as process_instance_id,RES.ASSIGNEE_ as assignee,P.BUSINESS_KEY_  as business_key ,P.NAME_ as process_instance_name ,null as type,null as user_id, null as group_id,RES.TASK_DEF_KEY_ as task_def_key
from ACT_HI_TASKINST RES 
left join ACT_HI_PROCINST P on P.PROC_INST_ID_ = RES.PROC_INST_ID_  and RES.END_TIME_ is not null
)v

然后可以通过条件查询,比如"执行人","执行部门","任务节点定义key"等来进行查询

(task_status : 待办/已办)

(assignee : 执行人Id)

(task_def_key : 任务节点定义key)

(type : 表示候选用户 

  • candidate: 表示候选用户或用户组。在任务尚未被领取时,这些用户或用户组可以领取任务。
  • participant: 表示任务的参与者。通常情况下,当任务被领取后,参与者就是具体执行任务的用户。
  • owner: 表示任务的所有者。在某些情况下,任务可能会指定一个所有者,通常是在任务创建时指定,这个所有者有特殊权限或责任来处理任务。

)

(group_id  : 部门Id)

(start_time : 任务节点生成时间)

(end_time : 任务节点完成时间)

比如以下的where条件可以用作待办任务的筛选查询

WHERE v.task_status = 0 and v.assignee = '1'  and v.task_def_key=  'sid-5db27d85-b516-4784-8b58-0f5c9e1c3235' or (v.assignee is null and v.type = 'candidate' and (v.user_id = '1' or v.group_id IN ( '土整中心','123' ) )) order by v.start_time desc

比如以下的where条件可以用作已办任务的筛选查询 

WHERE v.task_status = 1 and v.assignee = '1' and v.task_def_key=  'sid-8abc3887-40c5-49c2-b8c0-b4d3fdefb7a0' and v.end_time is not null order by v.end_time desc


5. 通过taskId获取该任务的备注

/*** 通过taskId获取该任务的备注* @param taskId 任务Id* @param commentType 备注类型* @return 备注详情*/@Overridepublic List<Comment> getCommentByTaskId(String taskId,String commentType){if(StringUtils.isNotEmpty(commentType)){// 带有type筛选return taskService.getTaskComments(taskId, commentType);}return taskService.getTaskComments(taskId);}

6.查询截止目前可驳回的节点列表

我的逻辑是查询当前已完成的用户任务,不包括"开始"节点(因为"开始"节点不是用户任务)

然后有一些特殊情况需要处理:

        比如多次驳回,因为每一次驳回实际上都是将当前任务节点完成然后再加一条"目标驳回任务节点"用作下一个节点

        比如多次驳回之后取最新的节点,不可能出现可驳回列表中出现两个key相同的节点,这不符合逻辑

/*** 查询截止目前可驳回的节点列表* @param processInstanceId 流程ID* @return 结果*/@Overridepublic List<ActHistoricActivityInstanceVo> getAllActInstByInstanceIdToSimple(String processInstanceId,String taskDefKey){// 只要用户任务// 目前已完成的用户任务List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().activityType("userTask").finished().list();// 流程定义时的用户任务ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();String processDefinitionId = processInstance.getProcessDefinitionId();ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();// 定义时的所有节点Collection<FlowElement> flowElements = repositoryService.getBpmnModel(processDefinitionId).getMainProcess().getFlowElements();List<ActHistoricActivityInstanceVo> userTasks = new ArrayList<>();// 循环for (HistoricActivityInstance historicActivityInstance : userTask) {for (FlowElement flowElement : flowElements) {if (flowElement instanceof UserTask) {UserTask definitionUserTask = (UserTask) flowElement;String activityName = definitionUserTask.getName();String activityId = definitionUserTask.getId();String activityTaskDefKey = definitionUserTask.getId();// 可以查看其他用户任务属性,如Assignee、Candidate Users、Candidate Groups等// 获取任务定义对象信息// 入参taskDefKey对应的对象SysProcessTaskDef processTaskDef = sysProcessTaskDefMapper.selectSysProcessTaskDefById(taskDefKey);// 当前循环体中taskDefKey对应的对象SysProcessTaskDef currentTaskDef = sysProcessTaskDefMapper.selectSysProcessTaskDefById(activityTaskDefKey);if(currentTaskDef.getSort() >= processTaskDef.getSort()){// 不能驳回到后面的任务去(防止二次提交后可驳回的任务列表乱套)continue;}// 如果Id匹配 就加入自定义集合返回if(activityId.equals(historicActivityInstance.getActivityId()) && !activityTaskDefKey.equals(taskDefKey)){ActHistoricActivityInstanceVo activityInstanceVo = new ActHistoricActivityInstanceVo();activityInstanceVo.setActivityId(activityId);activityInstanceVo.setActivityName(activityName);// 对重复的跳过 (针对多次驳回导致存在多个相同节点的情况)
//                        if(userTasks.contains(activityInstanceVo)) continue;ActHistoricActivityInstanceVo actHistoricActivityInstanceVo = userTasks.stream().filter(u -> u.getActivityId().equals(activityInstanceVo.getActivityId())).findAny().orElse(null);if(actHistoricActivityInstanceVo != null && actHistoricActivityInstanceVo.getStartTime().compareTo(historicActivityInstance.getStartTime()) < 0){// 存在并且时间早于这一次就删除 (针对多次驳回导致存在多个相同节点的情况,取最新的节点审核情况)userTasks.remove(actHistoricActivityInstanceVo);}// 转换赋值BeanUtils.copyProperties(historicActivityInstance, activityInstanceVo);// 获取type为isFillSteps的comment(是否为填报步骤:提交填报时的那个步骤)List<Comment> comments = taskService.getTaskComments(activityInstanceVo.getTaskId(), "isFillSteps");if(comments != null && comments.size() > 0){activityInstanceVo.setFillSteps(true);}userTasks.add(activityInstanceVo);}}}}if(userTasks.size() > 0){userTasks = userTasks.stream().sorted(Comparator.comparing(ActHistoricActivityInstanceVo::getStartTime)).collect(Collectors.toList());}return userTasks;}

 

7.驳回到指定节点

提供流程实例Id,当前任务Id,驳回目标任务Id

/*** 驳回到指定节点* @param actRollbackIo 驳回对象*/@Override@Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)public void rejectToNode(ActRollbackIo actRollbackIo){String processInstanceId = actRollbackIo.getProcessInstanceId();String currentTaskId = actRollbackIo.getTaskId(); // 当前任务String targetTaskId = actRollbackIo.getTargetTaskId(); // 驳回目标任务//  获取该流程所有的活动实例List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();String processDefinitionId = processInstance.getProcessDefinitionId();//  当前任务Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();//  驳回目标任务HistoricTaskInstance targetTask = historyService.createHistoricTaskInstanceQuery().finished().taskId(targetTaskId).singleResult();if(currentTask == null || targetTask == null){throw new CustomException(CustomExceptionEnums.MISSING_DATA_ERROR);}try{//  当前活动HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);//  驳回目标活动HistoricActivityInstance targetActivity = hisActivityList.stream().filter(e -> targetTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);//  获取xml文件对象BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);//  获取驳回目标活动节点FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(targetActivity.getActivityId());//  获取当前活动节点FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());//  临时保存当前活动的原始方向List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());//  清理活动方向currentFlowNode.getOutgoingFlows().clear();//  建立新方向SequenceFlow newSequenceFlow = new SequenceFlow();newSequenceFlow.setId("newSequenceFlowId");newSequenceFlow.setSourceFlowElement(currentFlowNode);newSequenceFlow.setTargetFlowElement(targetFlowNode);List<SequenceFlow> newSequenceFlowList = new ArrayList<>();newSequenceFlowList.add(newSequenceFlow);//  当前节点指向新的方向currentFlowNode.setOutgoingFlows(newSequenceFlowList);//  完成当前任务taskService.claim(currentTaskId,SecurityUtils.getLoginUser().getUser().getUserId().toString());taskService.complete(currentTaskId);//  重新查询当前任务Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();String assignee = (StringUtils.isNull(actRollbackIo.getAssignee())) ? targetTask.getAssignee() : actRollbackIo.getAssignee().toString();if (null != nextTask) {System.out.println("最新任务=="+nextTask);taskService.setAssignee(nextTask.getId(), assignee);}else{throw new CustomException(CustomExceptionEnums.OPERATION_FAILED);}//  恢复原始方向currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}

8.撤回 删除流程

    /*** 撤回 删除流程* @param processInstanceId 流程实例Id* @param fillId 任务填报Id* @param message 撤回备注信息*/@Override@Transactional(rollbackFor = Throwable.class)public int revoke(String processInstanceId,Long fillId,String message){runtimeService.deleteProcessInstance(processInstanceId, message);historyService.deleteHistoricProcessInstance(processInstanceId);return landProjectFillService.cleanProcessInstance(fillId);}

后续有新的方法再来补充

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java SE】继承

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 继承1.1 继承是什么1.2 继承的意义1.3 继承的语法1.4 继承的方式1.5 子类中访问父类成员1.5.1 子类中访问…

js类型转换

类型转换只有这四种&#xff0c;例如如果要对象转数字&#xff0c;那么就需要先把对象转成原始类型&#xff0c;再从原始类型转到数字。 空数组转原始类型是一个空字符串。空对象转原始类型是[object Object]。 let a {} console.log(a);// NaN //等价于 a->原始 然后原始…

北京大学创新推出ManipLLM黑科技 | 大幅提升机器人操作的鲁棒性与智能性

机器人操作依赖于准确预测接触点和执行器方向以确保成功操作。然而&#xff0c;基于学习的机器人操作&#xff0c;在模拟器中仅针对有限类别进行训练&#xff0c;往往难以实现泛化&#xff0c;特别是在面临大量类别时。 因此&#xff0c;作者提出了一种创新的方法&#xff0c;…

网络安全基础之网络协议与安全威胁

OSI(OpenSystem Interconnect)&#xff0c;即开放式系统互联。 一般都叫OSI参考模型&#xff0c;是ISO(国际标准化组织)组织在1985年研究的网络互联模型。 网络协议的简介&#xff1a; 定义&#xff1a;协议是网络中计算机或设备之间进行通信的一系列规则集合。 什么是规则?…

Android操作sqlite数据库

Sqlite数一种轻量级的关系型数据库&#xff0c;android里面可以用来持久化存储一些用户数据。 一、SQLiteOpenHelper方式 SQLiteOpenHelper是原生的数据库帮助类&#xff0c;继承这个类&#xff0c;用来创建&#xff0c;更新数据库的操作 public class MySqliteOpenHelper e…

算法整理:链表

链表定义 struct ListNode { int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {} }; 链表的遍历&#xff1a;ListNode phead; while(p!null) pp.next; 找到链表的尾结点&#xff1a;phead; while(p.next!null)pp.next; 链表节点的个数&#xff1a; phead…

蓝桥杯真题:七段码

import java.util.Scanner; import java.util.ArrayList; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args){// 连接关系图int[][] map new int[][]{{0, 1, 0, 0, 0, 1, 0},{1, 0, 1, 0, 0, 0, 1},{0, 1, 0, 1, 0, 0…

通讯录项目实现

引言&#xff1a;通过顺序表的逻辑实现通讯录。这里就不讲关于顺序表的函数了。如果有不明白的可以看我写的顺序表的博客。 目录 顺序表与通讯录的比较 各源文件文件大榄 Contact.c中通讯录相关函数的定义 初始化和销毁通讯录 添加联系人&#xff1a; 删除联系人&#xf…

c++的学习之路:10、string(2)

本章主要说一下模拟实现string类的部分功能&#xff0c;文章末附上所有代码。 目录 一、构造函数与析构函数 二、拷贝构造 三、c_str 四、【】和迭代器的遍历与访问 五、size 六、判断 七、reserve 八、push_back 九、resize 十、append 十一、 十二、insert 十…

Redis的5大常见数据类型的用法

上一篇文章我们讲了Redis的10大应用场景&#xff0c;这一篇文章就针对Redis的常用数据结构进行一个说明&#xff0c;通过示例的形式演示每一种数据结构如何使用。 当涉及Redis的数据操作时&#xff0c;不同数据类型对应的不同数据结构&#xff0c;如下就对5大常用的数据类型进行…

Transformer,革命性的深度学习架构

Transformer 是一种革命性的深度学习架构&#xff0c;专门设计用于处理序列数据&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;任务中表现卓越。它由 Vaswani 等人在 2017 年发表的论文《Attention is All You Need》中首次提出&#xff0c;打破了当时基于循环神…

2024最新版Android studio安装入门教程(非常详细)

目录 JDK安装与配置 一、下载JDK 二、JDK安装 三、JDK的环境配置 四、JDK的配置验证 Android studio安装 Android studio连接手机真机调试&#xff08;以华为鸿蒙为例&#xff09; 一、新建一个android项目 二、进入项目面板 三、配置Android Studio 四、安装手机驱…

【linux】进程替换的应用|shell解释器的实现

当我们学过了进程替换之后&#xff0c;本篇文章可以根据进程替换的知识带你自主实现一个shell命令行 实现步骤 1.显示命令行提示 2.读取输入指令以及对应选项 3.分割第二步的指令以及选项到命令行参数表中 4.处理内建命令 5.进程替换 1.显示命令行提示 我们通过观察bash的命令行…

Linux 文件相关命令

一、查看文件命令 1&#xff09;浏览文件less 默认查看文件的前 10 行。 less /etc/services ##功能说明&#xff1a; #1.默认打开首屏内容 #2.按【回车】按行访问 #3.按【空格】按屏访问 #4.【从上向下】搜索用/111,搜索包含111的内容&#xff0c;此时按n继续向下搜&#x…

JAVAEE之IoCDI

Spring 是⼀个 IoC&#xff08;控制反转&#xff09;容器&#xff0c;作为容器, 那么它就具备两个最基础的功能&#xff1a; • 存 • 取 Spring 容器管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由 Spring来负责对象的创建…

想学网络安全,从哪里开始?网络安全的学习路线

网络安全学习路线&#xff1a; 想学习网络安全专业的知识&#xff0c;想当黑客&#xff0c;但是不知道该从哪里开始学。 我给你一个路线&#xff01; 清晰图片和大纲&#xff1a;https://docs.qq.com/doc/DU1lpVFpSbWVrd2p3

面试官:为什么忘记密码要重置,而不是告诉我原密码?

前端训练营&#xff1a;1v1私教&#xff0c;终身辅导计划&#xff0c;帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ Hello&#xff0c;大家好&#xff0c;我是 Sunday。 最近有个同学在面试中遇到了一个很有意思的问题&#xff0c;我相信大多…

蓝桥杯23年第十四届省赛-异或和之和|拆位、贡献法

题目链接&#xff1a; 蓝桥杯2023年第十四届省赛真题-异或和之和 - C语言网 (dotcpp.com) 1.异或和之和 - 蓝桥云课 (lanqiao.cn) 参考题解&#xff1a; 蓝桥杯真题讲解&#xff1a;异或和之和 &#xff08;拆位、贡献法&#xff09;-CSDN博客 洛谷P9236 [蓝桥杯 2023 省 A]…

【T5中的激活函数】GLU Variants Improve Transformer

【mT5中的激活函数】GLU Variants Improve Transformer 论文信息 阅读评价 Abstract Introduction Gated Linear Units (GLU) and Variants Experiments on Text-to-Text Transfer Transformer (T5) Conclusion 论文信息 名称内容论文标题GLU Variants Improve Transfo…

flutter获取手机中的系统路径信息

https://www.bilibili.com/video/BV1wE421g7sw获取系统中的路径 获取系统中的路径&#xff0c;并在这个路径中创建一个文本文件【str.txt】 然后进行写入【str.txt】 再读取这个文件【str.txt】 手机没有开通root权限无法看到写入到【应用程序文档目录】路径中的文件 用来…