java-activiti笔记

news2024/11/15 21:53:48

版本:activiti7

 <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>7.0.0.Beta2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--activiti与springboot整合包-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.0.0.Beta2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

发布

流程图

会签

这里是将流程图通过bpmn.io插件设计好流程图,存放到服务器端

  public AjaxResult publishBpm(BpmFormVo bpmFormVo) {
        FileInputStream bpmnfileInputStream = null;
        try{
            BpmForm byId = getById(bpmFormVo.getId());
            xml=BpmFormManager.xmlnsActivitiEmpty(xml);
            xml=BpmFormManager.gatewaySupply(xml);
            activitiFlowService.delFlowByDefKey(bpmFormVo.getCode());
            repositoryService.createDeployment().addString(code+ ProcessConstants.SUFFIX, xml)
                    .name(code).key(code).deploy();
            bpmFormVo.setPublishTime(new Date());
            bpmFormVo.setState(1);
            bpmFormMapper.publishBpm(bpmFormVo);
            if("1".equals(byId.getCountersignature())){
                bpmCountersignService.bpmPublishHandle(byId,xml);
            }
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("部署失败");
        }finally {
            try {
                if(bpmnfileInputStream!=null){
                    bpmnfileInputStream.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }

        return AjaxResult.success("部署成功");
    }

重新发布需要做如下处理

    @SneakyThrows
    public void delFlowByDefKey(String code) {
        List<String> deploymentIdByName = activitiFlowMapper.getDeploymentIdByName(code+ ProcessConstants.SUFFIX);
        if(CollUtil.isEmpty(deploymentIdByName)){
            return;
        }
        for(String did:deploymentIdByName){
            repositoryService.deleteDeployment(did);
        }
    }

启动

    @Override
    public ProcessInstance startProcess(String definitionKey, String bussinessId,String userId,String userName, String projectId) {
        String bpmCode=definitionKey;
        Authentication.setAuthenticatedUserId(userId);
        Map<String, Object> map=new HashMap<>();
        map.put("state",ProcessConstants.AUDIT_YES);
        map.put("assignee",userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(definitionKey, bussinessId, map);

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee(userId) //设置任务的负责人
                .orderByTaskCreateTime().desc().list().get(0);
        if (task!=null){
            taskService.addComment(task.getId(), task.getProcessInstanceId(), "流程提交","流程提交成功!");
            startTaskComplete(bpmCode,projectId,task.getId(),null);
        }


        startLogProcessHandle(bpmCode,definitionKey,bussinessId,projectId,userId,userName,processInstance,task);
        return processInstance;
    }

将会签中的占位的数据赋值

    @Override
    public void startTaskComplete(String bpmCode,String projectId,String taskId, Map<String, Object> variables) {

        BpmForm bpmForm = bpmFormService.queryInfoByCode(bpmCode, projectId);
        if(variables==null){
            variables=new HashMap<>();
        }
        if(bpmForm!=null&&"1".equals(bpmForm.getCountersignature())){
            //会签模式
            Object xmlByKey = activitiFlowMapper.getXmlByKey(bpmForm.getResCode() + ".bpmn");
            Map<String, List<String>> stringListMap = bpmUtil.collectionUseMap(bpmForm, (byte[]) xmlByKey);
            variables.putAll(stringListMap);
        }
        if(CollUtil.isEmpty(variables)){
            taskService.complete(taskId);
        }else{
            taskService.complete(taskId,variables);
        }
    }

    @SneakyThrows
    public Map<String,List<String>> collectionUseMap(BpmForm bpmForm,byte[] resByte){
        Map<String,List<String>> result=new HashMap<>();
        if("0".equals(bpmForm.getCountersignature())){
            return result;
        }
        String resStr = new String(resByte);
        BpmnModel bpmnModel = ModelUtil.getBpmnModel(resStr);
        Collection<UserTask> allUserTaskEvent = ModelUtil.getAllUserTaskEvent(bpmnModel);
        if(CollUtil.isEmpty(allUserTaskEvent)){
            return result;
        }

        SysRoleVo sysRoleVo=new SysRoleVo();
        sysRoleVo.setProjectId(bpmForm.getProjectId());
        List<SysRoleVo> sysRoleVos = sysRoleService.queryList(sysRoleVo);

        SysDept sysDept=new SysDept();
        sysDept.setProjectId(bpmForm.getProjectId());
        List<SysDept> sysDepts = sysDeptService.queryList(sysDept);

        for(UserTask userTask:allUserTaskEvent){
            if(userTask.hasMultiInstanceLoopCharacteristics()){
                MultiInstanceLoopCharacteristics loopCharacteristics = userTask.getLoopCharacteristics();
                String inputDataItem = loopCharacteristics.getInputDataItem();
                String coll = inputDataItem.replace("${", "").replace("}", "");
                String[] groups = coll.split("_");
                if("ROLE".equals(groups[0])){
                    List<String> idListByRoleId = getIdListByRoleId(groups[1], sysRoleVos).getUserIdList();
                    if(CollUtil.isNotEmpty(idListByRoleId)){
                        result.put(coll,idListByRoleId);
                    }
                }else if("DEPT".equals(groups[0])){
                    List<String> idListByDeptId = getIdListByDeptId(groups[1], sysDepts).getUserIdList();
                    if(CollUtil.isNotEmpty(idListByDeptId)){
                        result.put(coll,idListByDeptId);
                    }
                }
            }
        }
        return result;
    }

流程审批

    @SneakyThrows
    public CompletResultVo orSignCompletHandle(String taskId, String result, String remark, String definitionKey, Map<String, Object> variables, String userName){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        taskService.addComment(taskId, task.getProcessInstanceId(), result,remark);
        if(variables==null){
            variables=new HashMap<>();
        }
        variables.put("state",result);
        taskService.complete(taskId,variables);
        CompletResultVo completResultVo=new CompletResultVo();
        boolean afterHandle = afterHandle(task, userName, remark, result);
        completResultVo.setAuditEndState(afterHandle);
        return completResultVo;
    }

    boolean afterHandle(Task task,String userName,String remark,String result){
        //存储审核日志信息
        QueryWrapper queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("process_instance_id",task.getProcessInstanceId());
        BussTask bussTask = bussTaskMapper.selectOne(queryWrapper);
        //日志记录
completByTaskLogHandle(bussTask,task,task.getProcessInstanceId(),userName,remark, result);
        //更新结束记录
        return endHandle(task.getProcessInstanceId(),bussTask,userName);
    }

判断流程结束后相关操作

    boolean endHandle(String piid,BussTask bussTask,String userName){
        List<Task> task1 = taskService.createTaskQuery().processInstanceId(piid).list();
        bussTaskMapper.updateById(bussTask);
        if(CollUtil.isEmpty(task1)){
            bussTaskMapper.updateStatus(piid,ProcessConstants.AUDIT_NO);
            endLogHandle(bussTask);
            return true;
        }
        return false;
    }

会签审批

    @SneakyThrows
    public CompletResultVo countersignCompletHandle(String taskId, String result, String remark,String definitionKey,String projectId,
                                         String userName,Long userId,BpmForm bpmForm){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String taskDefinitionKey = task.getTaskDefinitionKey();
        UserTask userTask = getUserTaskByNodeId(bpmForm.getResCode(), taskDefinitionKey);
        if(userTask==null){
            return orSignCompletHandle(taskId,result,remark,definitionKey,projectId,null,userName);
        }
        if(!userTask.hasMultiInstanceLoopCharacteristics()){
            return orSignCompletHandle(taskId,result,remark,definitionKey,projectId,null,userName);
        }

        MultiInstanceLoopCharacteristics loopCharacteristics = userTask.getLoopCharacteristics();
        String completionCondition = loopCharacteristics.getCompletionCondition();
        String codeByInfo = BpmCountersignTypeEnum.getCodeByInfo(completionCondition);

        Map<String,Object> variables=new HashMap<>();

        QueryWrapper queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("process_instance_id",task.getProcessInstanceId());
        BussTask bussTask = bussTaskMapper.selectOne(queryWrapper);
        List<LogProcess> bussList = getLogs(bussTask.getBussId(), task.getProcessInstanceId());

        List<BpmCountersignRecord> bpmCountersignRecords=new ArrayList<>();
        if(CollUtil.isNotEmpty(bussList)){
            BpmCountersignRecord bpmCountersignRecord=new BpmCountersignRecord();
            bpmCountersignRecord.setExecutionId(bussList.get(0).getExecutionId());
            bpmCountersignRecords= bpmCountersignService.queryListByExeId(bpmCountersignRecord);
        }


        BpmCountersign bpmCountersignByTaskInfo = bpmCountersignService.getBpmCountersignByTaskInfo(task.getTaskDefinitionKey(), bussTask.getDefinitionKey());
        String[] user_split = bpmCountersignByTaskInfo.getUids().split(",");

        if("all".equals(codeByInfo)){
            if(ProcessConstants.AUDIT_NO.equals(result)){
                variables.put("pass",true);
                variables.put("state",ProcessConstants.AUDIT_NO);
                taskService.complete(taskId,variables);
                countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,false,true,bussList);
            }else{
                if(user_split.length<=(bpmCountersignRecords.size()+1)){
                    variables.put("pass",true);
                    variables.put("state",ProcessConstants.AUDIT_YES);
                    taskService.complete(taskId,variables);
                    countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,true,true,bussList);
                }else{
                    variables.put("pass",false);
                    taskService.complete(taskId,variables);
                    countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,false,false,bussList);
                }
            }
        }else if("half".equals(codeByInfo)){
            if(user_split.length<=(bpmCountersignRecords.size()+1)){
                int ok_users=0;
                for(BpmCountersignRecord bpm:bpmCountersignRecords){
                    if(ProcessConstants.AUDIT_YES.equals(bpm.getAuditResult())){
                        ok_users+=1;
                    }
                }
                if(ProcessConstants.AUDIT_YES.equals(result)){
                    ok_users+=1;
                }
                String state=null;
                BigDecimal divide = new BigDecimal(ok_users).divide(new BigDecimal(user_split.length), 2, BigDecimal.ROUND_HALF_UP)
                double doubleValue = divide.doubleValue();
                if(doubleValue>=0.5){
                    state=ProcessConstants.AUDIT_YES;
                }else{
                    state=ProcessConstants.AUDIT_NO;
                }
                variables.put("state",state);
                variables.put("pass",true);
                taskService.complete(taskId,variables);
                countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,state.equals(ProcessConstants.AUDIT_YES)?true:false,true,bussList);
            }else{
                variables.put("pass",false);
                taskService.complete(taskId,variables);
                countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,false,false,bussList);
            }
        }else if("single".equals(codeByInfo)){
            if(ProcessConstants.AUDIT_YES.equals(result)) {
                variables.put("pass",true);
                variables.put("state",ProcessConstants.AUDIT_YES);
                taskService.complete(taskId,variables);
                countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,true,true,bussList);
            }else{
                if(user_split.length<=(bpmCountersignRecords.size()+1)){
                    variables.put("pass",true);
                    variables.put("state",ProcessConstants.AUDIT_NO);
                    taskService.complete(taskId,variables);
                    countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,false,true,bussList);
                }else{
                    variables.put("pass",false);
                    taskService.complete(taskId,variables);
                    countersignRecordHandle(task,bpmForm,userName,userId,bpmCountersignByTaskInfo,result,remark,bussTask,false,false,bussList);
                }
            }
        }
        CompletResultVo completResultVo=new CompletResultVo();
        List<LogProcess> bussList2 = getLogs(bussTask.getBussId(), task.getProcessInstanceId());
        String aname="";
        if(CollUtil.isNotEmpty(bussList2)){
            aname=bussList2.get(0).getAssigneeName();
        }else{
            aname= bussList.get(0).getAssigneeName();
        }
        boolean endHandle = endHandle(task.getProcessInstanceId(), bussTask, aname);
        completResultVo.setAuditEndState(endHandle);
        return completResultVo;
    }

//日志及操作记录
 /**
     *
     * @param task
     * @param bpmForm
     * @param userName
     * @param userId
     * @param bpmCountersignByTaskInfo
     * @param result 当前人的审核状态
     * @param remark
     * @param auditState 最终审核状态(会签)
     * @param isEnd 当前节点是否全部完成
     */
    void countersignRecordHandle(Task task,BpmForm bpmForm,String userName,Long userId,BpmCountersign bpmCountersignByTaskInfo,
                           String result,String remark,BussTask bussTask,boolean auditState,boolean isEnd,List<LogProcess> bussList){
        LogProcess logRecord=null;
        if(CollUtil.isEmpty(bussList)){
            logRecord=new LogProcess();
            logRecord.setProjectId(bpmForm.getProjectId());
            String myExeId=UUID.randomUUID().toString();
            logRecord.setExecutionId(myExeId);
            logRecord.setBusinessId(bussTask.getBussId());
            logRecord.setTaskId(task.getId());
            logRecord.setAssigneeName(bpmCountersignByTaskInfo.getUnames());
            logRecord.setAssignee(bpmCountersignByTaskInfo.getUids());
            logRecord.setInstanceId(task.getProcessInstanceId());
            logRecord.setDefinitionKey(bpmForm.getResCode());
            if(isEnd){
                logRecord.setStepType(auditState?ActivitiStepType.approved.getCode():ActivitiStepType.reject.getCode());
            }else{
                logRecord.setStepType(ActivitiStepType.unapproved.getCode());
            }

            logProcessMapper.insert(logRecord);
        }else{
            if(isEnd){
                logRecord = bussList.get(0);
                logRecord.setStepType(auditState?ActivitiStepType.approved.getCode():ActivitiStepType.reject.getCode());
                logProcessMapper.updateById(logRecord);
            }
        }

        BpmCountersignRecord bcr=new BpmCountersignRecord();
        bcr.setNodeId(task.getTaskDefinitionKey());
        bcr.setBpmCode(bpmForm.getCode());
        bcr.setUserId(userId+"");
        bcr.setUserName(userName);
        if(logRecord!=null){
            bcr.setLogId(logRecord.getId());
        }else{
            bcr.setLogId(bussList.get(0).getId());
        }
        bcr.setBusinessId(bussTask.getBussId());
        bcr.setAuditRemark(remark);
        bcr.setAuditResult(result);
        bcr.setExecutionId(logRecord.getExecutionId());
        bcr.setProcessInstanceId(task.getProcessInstanceId());
        bpmCountersignRecordMapper.insert(bcr);
    }

会签流程表达式枚举,全部通过即通过,半数通过即通过,一人通过即通过:

public enum BpmCountersignTypeEnum {
    all("all", "${nrOfCompletedInstances==nrOfInstances||pass==true}"),
    half("half", "${nrOfCompletedInstances/nrOfInstances&gt;=0.5&&pass==true}"),
    single("single", "${nrOfCompletedInstances>=1&&pass==true}");

    private final String code;
    private final String info;

    BpmCountersignTypeEnum(String code, String info)
    {
        this.code = code;
        this.info = info;
    }

    public static String getCodeByInfo(String info){
        if(StringUtils.isBlank(info)){
            return null;
        }
        for(BpmCountersignTypeEnum bct:BpmCountersignTypeEnum.values()){
            String elEscape = EscapeUtil.elEscape(bct.info);
            if(info.equals(elEscape)){
                return bct.code;
            }
        }
        return null;
    }

    public String getCode()
    {
        return code;
    }

    public String getInfo()
    {
        return info;
    }
}

这里:

nrOfInstances:总实例数

nrOfCompletedInstances:已完成实例数

nrOfActiviteInstances:未完成的实例数

全部通过即通过和一人通过即通过直接处理即可,state是流线走向,按比例通过时,我这里用一张表记录了每次操作,即BpmCountersignRecord,将此次记录作为流程操作记录的子关联表,executionId作为关联键。

其他

每次流程启动表act_ge_bytearray中会出现如下图的数据,这就是会签流程里面的变量数据

当流程审批结束后,var-开头的数据就会消失,hist开头的是act_hi表中相关数据

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

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

相关文章

2025年第五届国际计算机通信与信息系统会议(CCCIS 2025) 即将召开!

2025第五届计算机通信与信息系统国际会议&#xff08;CCCIS 2025&#xff09;将于2025年2月28日至3月2日在中国香港举行&#xff0c;本次会议由香港珠海学院主办&#xff0c;新加坡传感器与系统学会支持。CCCIS主要面向通信软件和网络领域的研究人员。它为这些领域研究人员之间…

springboot牙科就诊管理系统--论文源码调试讲解

2 相关技术 2.1 MySQL数据库 本设计用到的数据库就是MySQL数据库[3]&#xff0c;之所以用到这个数据库的原因很多。首先&#xff0c;从满足功能需求上面来讲&#xff0c;MySQL是符合的&#xff1b;其次&#xff0c;从学习程度来讲&#xff0c;MySQL相比其他数据库不管是从安装…

uniapp 中 web-view 向 App 传递消息

web-view向App传递消息 引入官方库 在web项目中引入官方库 uni.webview.1.5.4.js &#xff0c;可以从uniapp官方示例库中下载&#xff0c;下载后放入web项目目录下即可&#xff0c;本文放在js文件夹中&#xff0c;然后在web项目页面中引入。 官网对于uni-app使用web-view的介…

VideoPlayer插件的用法

文章目录 1. 概念介绍2. 使用方法2.1 实现步骤2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取文件类型"相关的内容&#xff0c;本章回中将介绍如何播放视频.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 播放视频是我们常用…

QT线程————

当你创建一个继承自 QObject 的类&#xff0c;并希望将其与 QThread 关联时&#xff0c;不能将这个类的实例直接作为 QThread 的父对象。这是因 为 QThread 的设计目的是运行一个独立的线程&#xff0c;而不是成为另一个对象的子对象。

Java面试八股之什么是STOMP协议

什么是STOMP协议 STOMP&#xff08;Simple Text Oriented Messaging Protocol&#xff09;是一种为消息队列和事件驱动架构设计的轻量级协议&#xff0c;主要用于在消息中间件之间进行消息交换。它的设计原则是简单、跨平台和易于实现&#xff0c;这使得STOMP成为许多实时应用…

排序算法——简单选择排序

一、算法原理 简单选择排序是一种基本的排序算法&#xff0c;其原理是每次从未排序的元素中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;然后与未排序部分的第一个元素交换位置&#xff0c;直到所有元素都被排序。 二、算法实现流程 简单选择排序法(Simple Se…

Stable Diffusion绘画 | ControlNet应用-Lineart(线稿):轻轻松松画线稿

Lineart(线稿) 专门用来提取线稿的算法。 适合对漫画图片进行提取线稿&#xff1a; 不同的预处理器&#xff1a; lineart_standard&#xff1a;适合各种类型的画面lineart_realistic&#xff1a;适合用于真人图片的线稿提取lineart_coarse&#xff1a;提取的线稿&#xff0c…

MATLAB R2023b配置Fortran编译器

MATLAB R2023b配置Fortran编译器 引言1. 安装Visual Studio 20192. 安装Intel API20243. 配置xml文件文件4. 设置环境变量5. MATLAB编译Fortran 引言 当我们需要用到MATLAB编译Fortran代码后进行调用计算时&#xff0c;整个配置流程较繁琐。下面以MATLAB R2023b为例&#xff0…

python从入门到精通:循环语句

目录 前言 1、while循环的基础语法 2、while循环的嵌套 3、for循环的基础语法 range语句&#xff1a; for循环临时变量作用域&#xff1a; 4、for循环的嵌套 5、循环中断&#xff1a;break和continue 前言 循环普遍存在于日常生活中&#xff0c;同样&#xff0c;在程序中…

k8s核心架构分析

k8s核心概念概述 Kubernetes入门&#xff1a;掌握集群核心&#xff0c;释放容器潜能 技术爱好者们&#xff0c;CD集群的核心概念是构建、部署和管理容器化应用的基石。掌握这些概念&#xff0c;不仅助你深入理解技术细节&#xff0c;更能在CD集群中自如操作&#xff0c;无论是…

基于Python大数据的电商产品评论的情感分析设计与实现,包括lda主题分析和情感分析

摘要&#xff1a;本研究基于Python大数据技术&#xff0c;对电商产品评论进行情感分析的方法进行了研究。主要使用了requests库进行爬虫获取评论数据&#xff0c;利用pandas库进行数据处理和分析&#xff0c;使用matplotlib库实现数据可视化&#xff0c;结合jieba库进行中文分词…

可视化大屏:如何get到领导心目中的“科技感”?

你如果问领导可视化大屏需要什么风格的&#xff0c;领导大概率说科技感的&#xff0c;然后你就去做了&#xff0c;结果被劈了一顿&#xff0c;什么原因&#xff1f;因为你没有get到领导心目中描述的科技感。 一、为什么都喜欢科技感 科技感在可视化大屏设计中具有以下好处&am…

企业大模型业务架构技术选型分析

AI赋能企业&#xff1a;选择适合你的大模型业务架构 现代企业中&#xff0c;大模型业务日益普及&#xff0c;主要涵盖AI Embedded、AI Copilot和AI Agent三大架构。本文深入剖析其特性与适用场景&#xff0c;为企业选择合适的大模型业务架构提供指导&#xff0c;助力企业高效应…

国内大量家用路由器惨遭DNS劫持,你中招了吗?

近期&#xff0c;D妹收到不少用户反馈&#xff0c;在访问网站或APP时都遭遇了访问失败的问题。经深入排查&#xff0c;我们监测到大量家用路由器的DNS解析配置被篡改&#xff0c;从而影响到了正常的网站和APP访问。 该情况于2024年5月开始出现&#xff0c;于8月5日集中爆发达到…

【二叉树进阶】--- 二叉搜索树转双向链表 最近公共祖先

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 数据结构 本篇博客我们继续了解一些二叉树的进阶算法。 &#x1f3e0; 二叉搜索 树转化为双向循环链表 &#x1f4cc; 题目内容 将二叉搜索树转化为排序…

负载均衡之HAProxy超全内容!!!

一、负载均衡 1.1 负载均衡概念 负载均衡&#xff08;Load Balance&#xff0c;简称 LB&#xff09;是高并发、高可用系统必不可少的关键组件&#xff0c;目标是尽力将网络流量平均分发到多个服务器上&#xff0c;以提高系统整体的响应速度和可用性。 1.2 软件负载均衡 软件…

【C++深度探索】哈希表介绍与实现

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目录…

量化策略开发步骤系列(4)参数分析和过度拟合

量化策略开发步骤系列&#xff08;4&#xff09;参数分析和过度拟合 参数分析过度拟合 这是量化交易系列文章的第二系列——量化策略开发步骤&#xff0c;第一系列请参考专栏&#xff1a; 量化交易系统。很多朋友反馈最近的文章代码太多&#xff0c;看不懂。 这一部分将实现零…

2 C 语言开发工具选择、 MinGW 的安装与配置、VS Code 的安装与配置、插件推荐

目录 1 开发工具选择 1.1 Visual Studio 1.2 Code::Block 1.3 Clion 1.4 VS Code 1.5 在线编辑工具 2 开发工具安装 2.1 安装 MinGW-w64 2.1.1 MinGW-w64 介绍 2.1.2 解压 MinGW 2.1.3 将 MinGW 添加至环境变量 2.1.4 验证安装 2.2 安装 VS Code 2.2.1 下载安装包…