小白学流程引擎-FLowable(二) — 从零搭建自己的FLowable服务 — 搭建流程服务-FLowable的新手指南

news2025/1/20 1:42:37

一、介绍

纵览Gitee搜索Flowable开源项目,大多都是已开发好的项目,而笔者从零开始搭建属于自己的Flowable引擎,并且是可以拿到生产上使用的。

二、软件架构

Springboot + Flowable + modeler + idm + Mysql
SrpingBoot version:2.7.5
Flowable version:6.3.0
Mysql version:8.0.26
JDK:8

三、SpringBoot整合Flowable

3.1 使用spring initializer快速创建spring Boot项目

步骤:
1,打开idea,创建工程:file -> newproject ,选择spring initializer;
2,然后填写项目命名后,选择JDK8,Maven;
3,选择功能模块,选Web和lombok即可;
4,点Finish,就能够自动创建工程,并能导入相应依赖了;
5,Maven加载依赖后,运行主程序类看是否成功。

3.2 pom.xml文件引入依赖配置

引入Flowable依赖,这里选择Springboot-starter,毕竟是springboot项目。
添加必要的依赖。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.79</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.flowable/flowable-spring-boot-starter -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-spring-boot-starter</artifactId>
        <version>6.3.0</version>
    </dependency>

</dependencies>

3.3 application.yml配置

在application.yml文件中加入以下配置。

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spider-flowable?charset=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    username: root
    password: 12345678

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

flowable:
  #关闭定时任务JOB
  async-executor-activate: false
  #将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  database-schema-update: true

3.4 运行项目

项目启动的时候检查如果数据库对应的表结构没有创建,会帮助我们先创建对应的表结构。到此Springboot整合Flowable就搞定了,
项目启动后,刷新数据库,你会发现多了61张表,都是以ACT为前缀的表名。
知道为什么Flowable自带的数据库的表名为啥是以ACT为前缀吗?
因为Flowable是基于Activiti6衍生出来的版本。

数据库结构如图:
在这里插入图片描述

四、定义流程文件

FLowable流程的运行,其实是用一个满足BPMN格式的XML文件来执行的,至于XML内容格式是怎么样的后续在学习。

在项目中的resources下新建一个processes文件夹,processes目录下的任何BPMN 2.0流程定义都会被自动部署。

1,在processes文件夹下新建holiday-request.bpmn20.xml文件
2,文件内容复制如下:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">

    <process id="holidayRequest" name="请假流程" isExecutable="true">
        <!--开始事件-->
        <startEvent id="startEvent"/>
        <!--顺序流,从 startEvent 到 approveTask-->
        <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
        <!--用户任务,需要 assignee 来审批-->
        <userTask id="approveTask" name="同意或驳回请求" flowable:candidateGroups="managers" flowable:assignee="admin"/>
        <!--顺序流,从 approveTask 到 decision -->
        <sequenceFlow sourceRef="approveTask" targetRef="decision"/>
        <!--排他网关-->
        <exclusiveGateway id="decision"/>
        <!--顺序流,从 decision 到 successCall-->
        <sequenceFlow sourceRef="decision" targetRef="successCall">
            <conditionExpression xsi:type="tFormalExpression">
                <!--approved 为 true 时,该顺序流生效-->
                <![CDATA[
          ${approved}
        ]]>
            </conditionExpression>
        </sequenceFlow>
        <!--顺序流,从 decision 到 failedCall-->
        <sequenceFlow sourceRef="decision" targetRef="failedCall">
            <conditionExpression xsi:type="tFormalExpression">
                <!--approved 为 false 时,该顺序流生效-->
                <![CDATA[
          ${!approved}
        ]]>
            </conditionExpression>
        </sequenceFlow>
        <!--服务任务,审批通过 -->
        <serviceTask id="successCall" name="审批通过调用服务"
                     flowable:class="com.example.spiderFlowable.core.delegate.ApprovalSuccessDelegate"/>
        <sequenceFlow sourceRef="successCall" targetRef="holidayApprovedTask"/>
        <userTask id="holidayApprovedTask" name="审批通过"/>
        <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
        <!--服务任务,审批驳回 -->
        <serviceTask id="failedCall" name="审批驳回调用服务"
                     flowable:class="com.example.spiderFlowable.core.delegate.ApprovalFailDelegate"/>
        <sequenceFlow sourceRef="failedCall" targetRef="rejectEnd"/>
        <!--结束事件-->
        <endEvent id="approveEnd"/>
        <endEvent id="rejectEnd"/>
    </process>
</definitions>

五、运行项目并测试

咱来测试一下功能,小试牛刀,更多功能在后面文章再细谈。
在test文件夹下新建测试类SpiderFlowableTest,代码如下。

package com.example.spiderFlowable;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xiong.bo
 * @version 1.0
 * @date 2022/11/27 10:41 上午
 */

@SpringBootTest
public class SpiderFlowableTest {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;

    /**
     * 模拟-部署流程
     * 说明:
     * 流程定义有版本的概念,bpmn文件有改动,需要部署后才生效
     */
    @Test
    void createDeployment() {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/holiday-request.bpmn20.xml")
                .deploy();
        System.out.println(deployment.getId());
        System.out.println(JSON.toJSONString(deployment));
    }

    /**
     * 获取流程定义
     */
    @Test
    void getProcessDefinition() {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId("17504")
                .singleResult();
        System.out.println("definitionId:" + processDefinition.getId());
        System.out.println("definition:" + JSONUtil.toJsonStr(processDefinition));
    }

    /**
     * 启动流程
     * 模拟用户发起一个请假流程
     */
    @Test
    void startProcessDefinition() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("employee", "李四");
        variables.put("nrOfHolidays", "4");
        variables.put("description", "外出请假");
        //启动流程实例有多个方法,这里调用流程key的方法来启动
        ProcessInstance holidayProcessInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
        System.out.println("processInstanceId:" + holidayProcessInstance.getProcessInstanceId());
    }

    /**
     * 获取任务
     * 用户发起流程后,相关的人员能够查询该任务
     *
     */
    @Test
    void getTask(){
        List<Task> tasks = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                //值为admin是管理员可以查看所有的,测试
                .taskCandidateOrAssigned("admin")
                .list();
        System.out.println("You have " + tasks.size() + " tasks:");
        for (int i = 0; i < tasks.size(); i++) {
            Task task = tasks.get(i);
            System.out.println((i + 1) + ") " + "taskId: " + task.getId() + ", taskName: " + task.getName());
        }
    }

    /**
     * 审批任务
     * 说明:
     * 1,变量approved同流程定义文件里面顺序流定义的变量
     * 2,taskId是上一个获取用户任务的taskId值,也就是要指定哪一个用户任务往下执行
     */
    @Test
    void completeTask(){
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", true);
        String taskId = "20008";
        taskService.complete(taskId,variables);
    }

    /**
     * 查看历史任务
     * 说明:
     * taskAssignee: 分配人
     * finished:已完成状态的
     *
     */
    @Test
    void historyTask(){
        List<HistoricActivityInstance> hisList = historyService.createHistoricActivityInstanceQuery()
                .taskAssignee("admin")
                .finished()
                .list();

        hisList.stream().forEach(e -> System.out.println(JSONUtil.toJsonStr(e)));
    }
}

1,部署流程

	 /**
     * 模拟-部署流程
     * 说明:
     * 流程定义有版本的概念,bpmn文件有改动,需要部署后才生效
     */
    @Test
    void createDeployment() {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/holiday-request.bpmn20.xml")
                .deploy();
        System.out.println(deployment.getId());
        System.out.println(JSON.toJSONString(deployment));
    }

运行结果:

27501
ps: System.out.println(JSON.toJSONString(deployment));输出内容太多这里不贴上了

2,获取流程定义

	/**
     * 获取流程定义
     */
    @Test
    void getProcessDefinition() {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId("17504")
                .singleResult();
        System.out.println("definitionId:" + processDefinition.getId());
        System.out.println("definition:" + JSONUtil.toJsonStr(processDefinition));
    }

运行结果:

definitionId:holidayRequest:5:17506
definition:{"name":"请假流程","key":"holidayRequest","version":5,"category":"http://www.flowable.org/processdef","deploymentId":"17504","resourceName":"processes/holiday-request.bpmn20.xml","tenantId":"","isGraphicalNotationDefined":false,"hasStartFormKey":false,"suspensionState":1,"derivedVersion":0,"id":"holidayRequest:5:17506","revision":1,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"suspensionState":1,"category":"http://www.flowable.org/processdef"}}

3,启动流程

	/**
     * 启动流程
     * 模拟用户发起一个请假流程
     */
    @Test
    void startProcessDefinition() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("employee", "李四");
        variables.put("nrOfHolidays", "4");
        variables.put("description", "外出请假");
        //启动流程实例有多个方法,这里调用流程key的方法来启动
        ProcessInstance holidayProcessInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
        System.out.println("processInstanceId:" + holidayProcessInstance.getProcessInstanceId());
    }

运行结果:

processInstanceId:30001

4,获取用户任务

	/**
     * 获取任务
     * 用户发起流程后,相关的人员能够查询该任务
     *
     */
    @Test
    void getTask(){
        List<Task> tasks = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                //值为admin是管理员可以查看所有的,测试
                .taskCandidateOrAssigned("admin")
                .list();
        System.out.println("You have " + tasks.size() + " tasks:");
        for (int i = 0; i < tasks.size(); i++) {
            Task task = tasks.get(i);
            System.out.println((i + 1) + ") " + "taskId: " + task.getId() + ", taskName: " + task.getName());
        }
    }

运行结果:

You have 4 tasks:
1) taskId: 10008, taskName: 同意或驳回请求
2) taskId: 12508, taskName: 同意或驳回请求
3) taskId: 20008, taskName: 同意或驳回请求
4) taskId: 7508, taskName: 同意或驳回请求

5,审批任务

	/**
     * 审批任务
     * 说明:
     * 1,变量approved同流程定义文件里面顺序流定义的变量
     * 2,taskId是上一个获取用户任务的taskId值,也就是要指定哪一个用户任务往下执行
     */
    @Test
    void completeTask(){
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", true);
        String taskId = "20008";
        taskService.complete(taskId,variables);
    }

运行结果:
结果回调了 ApprovalSuccessDelegate ,打印出"审批通过了"

6,查看历史任务

	/**
     * 查看历史任务
     * 说明:
     * taskAssignee: 分配人
     * finished:已完成状态的
     *
     */
    @Test
    void historyTask(){
        List<HistoricActivityInstance> hisList = historyService.createHistoricActivityInstanceQuery()
                .taskAssignee("admin")
                .finished()
                .list();

        hisList.stream().forEach(e -> System.out.println(JSONUtil.toJsonStr(e)));

    }

运行结果:

{"activityId":"approveTask","activityName":"同意或驳回请求","activityType":"userTask","executionId":"20005","assignee":"admin","taskId":"20008","tenantId":"","processInstanceId":"20001","processDefinitionId":"holidayRequest:5:17506","startTime":1669521326282,"endTime":1669521596820,"durationInMillis":270538,"id":"20007","revision":2,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"executionId":"20005","durationInMillis":270538,"endTime":1669521596820,"assignee":"admin","taskId":"20008"}}
{"activityId":"approveTask","activityName":"同意或驳回请求","activityType":"userTask","executionId":"30005","assignee":"admin","taskId":"30008","tenantId":"","processInstanceId":"30001","processDefinitionId":"holidayRequest:6:27503","startTime":1669643905412,"endTime":1669644033366,"durationInMillis":127954,"id":"30007","revision":2,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"executionId":"30005","durationInMillis":127954,"endTime":1669644033366,"assignee":"admin","taskId":"30008"}}

最基本的完成一个流程的核心功能在上面列举了,先部署流程,再启动流程,再获取任务,再完成某一个任务。

六、总结

其实你会发现,流程引擎并没有那么神秘,它强大的功能,就是通过满足BPM2.0规范的xml文件和数据库进行流转的,后面文章在学习BPM2.0规范和Flowable数据库各个表的大致作用等。

以上代码已放到笔者的Gitee仓库地址:https://gitee.com/xiongbomy/spider-flowable.git
欢迎大家star和fork。
建议大家fork此项目到你个人仓库,方便你测试或者基于此开发属于你的流程引擎,当然,基于此进行二次扩展,再拿到公司当内部系统也是可以的,只要不商用拿去卖钱~

题外话,笔者在公司主要负责公司内部的流程引擎系统的开发,使用的是Flowable,后续会记录学习Flowable的笔记,一是让自己的知识形成体系化,二是让更多想要学习Flowable的同学们得到一点点帮助也好。

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

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

相关文章

牛客网verilog刷题知识点盘点(75道题的版本)

牛客网verilog刷题知识点盘点(75道题的版本) 还有几个坑没填 任务和函数 1.任务和函数必须在模块内定义&#xff0c;其作用范围仅适用于该模块&#xff0c;可以在模块内多次调用。 2.任务和函数中可以声明局部变量&#xff0c;如寄存器&#xff0c;时间&#xff0c;整数&…

企业云工如何高效居家协同办公?试试这个方法

近日的疫情反扑让全国各地的防疫压力增加&#xff0c;并且甚至很多地方不知道的啥时候就要被居家隔离&#xff0c;所以在新的防疫背景下&#xff0c;居家就顺理成章地成为一种常态化的学习和工作方式。 现在越来越多公司也将日常业务搬到了线上&#xff0c;以保证疫情期间公司的…

基于ssm的旅游网站的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

vue——路由

目录 一、介绍路由 1、路由是什么 Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成&#xff0c;让用 Vue.js 构建单页应用变得轻而易举。 2、为什么要使用路由 3、主要用途 二、安装路由 1、安装命令 2、配置文件 3、在main.js 中进行挂载 三、案例展示 …

Linux服务器配置与管理(基于Centos7.2)任务目标(五)

文章目录一、知识目标二、能力目标二、任务实施任务一&#xff1a;安装Apache任务二&#xff1a;配置简单Web站点任务三&#xff1a;配置基于主机名的虚抛主机任务四&#xff1a;安装vsftpd任务五&#xff1a;匿名用户访问FTP服务器任务六&#xff1a;本地用户配置一、知识目标…

HummerRisk 使用场景-混合云安全治理(2)--阿里云安全最佳实践

背景&#xff1a; 阿里云安全最佳实践&#xff0c;是基于众多客户上云的成功案例萃取而成的最优化企业上云指导。每个最佳实践包括使用场景、多产品部署架构及部署手册。 最佳实践目前覆盖23种常用场景&#xff0c;目前有200篇最佳实践&#xff0c;涉及100款以上阿里云产品的…

20221128-1Spring_day02(资料来自黑马程序)

Spring_day02 今日目标 掌握IOC/DI配置管理第三方bean掌握IOC/DI的注解开发掌握IOC/DI注解管理第三方bean完成Spring与Mybatis及Junit的整合开发 1&#xff0c;IOC/DI配置管理第三方bean 前面所讲的知识点都是基于我们自己写的类&#xff0c;现在如果有需求让我们去管理第三方…

安卓讲课笔记5.11 菜单

文章目录零、本讲学习目标一、导入新课二、新课讲解&#xff08;一&#xff09;菜单概述1、选项菜单2、上下文菜单3、子菜单&#xff08;二&#xff09;选项菜单案例演示1、创建安卓应用2、准备图片素材3、字符串资源文件4 、主布局资源文件5、主界面类实现功能6、启动应用&…

2. Vue3 Composition API

Composition API 1.Composition API 接下来我们来介绍一下Vue3中新增的Composition API如何使用。注意Composition API仅仅是Vue3中新增的API&#xff0c;我们依然可以使用Options API。先来实现一下之前演示的获取鼠标位置的案例。做这个案例之前&#xff0c;需要先介绍一下…

MybatisPlus简单使用与自定义sql以及通过自定义sql实现多表联查的分页查询

MybatisPlus简单使用与自定义sql以及通过自定义sql实现多表联查的分页查询前言1. mybatis的简单使用2. MybatisPlus 的简单使用2.1 入门2.1.1 简单配置2.1.2 入门例子2.1.3 测试2.2 MybatisPlus自带封装的增删改查2.2.1 傻瓜式使用2.2.2 批量添加数据3 MybatisPlus 动态查询sql…

计算机网络---数据链路层扩展的以太网

&#xff08;一&#xff09;在物理层扩展以太网 使用光纤扩展&#xff1a;主机使用光纤和一对光纤调制解调器连接到集线器 使用集线器扩展&#xff1a;主机使用光纤和一对光纤调制解调器连接到集线器 使用集线器扩展的优缺点 优点 &#xff1a;使原来属于不同碰撞域&#xff0…

Nodejs -- Express中间件的概念及基本使用

文章目录1 中间件的概念1.1 什么是中间件1.2 现实生活中的例子1.3 Express中间件的调用流程1.4 Express的中间件的格式1.5 next函数的作用2 Express中间件初体验2.1 定义中间件函数2.2 全局生效的中间件2.3 定义全局中间件的简化形式2.4 中间件的作用2.5 定义多个全局中间件2.6…

机器学习-(手推)线性回归3-正则化-岭回归(Ridge)-频率角度贝叶斯角度

一、正则化-岭回归-频率角度 回顾&#xff1a; Loss Function&#xff1a; 过拟合的解决方法&#xff1a; ①最直接&#xff1a;加数据 ②降维&#xff08;特征选择/特征提取&#xff08;PCA&#xff09;&#xff09; ③正则化&#xff08;对参数空间&#xff0c;例如w的约…

预处理,编译,汇编,链接,全过程。

编译&#xff0c;链接&#xff0c;全过程。背景知识预处理&#xff1a;1.宏定义指令&#xff0c;如#define MAX 1&#xff1b;2.条件编译指令&#xff0c;如#ifdef、 #ifndef、#else、#elif、#endif等。3.头文件包含指令&#xff0c;如#include等。4.特殊符号&#xff0c;预编译…

SQL explain解析器

EXPLAIN 参数前言字段参数id 查询编号select_type 关联类型SIMPLEPRIMARYUNION & UNION RESULTDERIVEDSUBQUERYDEPENDENTUNCACHEABLEMATERIALIZEDtable 表名partitions 数据的分区信息type 关联类型system & consteq_refreffulltextref_or_nullindex_mergeunique_subqu…

必备表格软件-FineReport正则表达式简介

1. 概述 1.1 应用场景 有时候我们需要用到正则表达式进行信息的校验。 例如有一张使用了「文本控件」的查询报表&#xff0c;输入「销售员」姓名后可查询销售员的销售情况&#xff0c;此时希望设置销售员文本控件的填入信息校验内容为&#xff1a;若填入内容不是中文或中文的…

【无标题】接口测试用例设计(精华)

接口测试 请求头 请求头中的Content-Type有哪几种&#xff1a; 1.application/x-www-form-urlencoded 最常见的 POST 提交数据的方式&#xff0c;原生Form表单&#xff0c;如果不设置 enctype 属性&#xff0c;默认为application/x-www-form-urlencoded 方式提交数据。 2.appli…

Node.js 入门教程 19 package-lock.json 文件

Node.js 入门教程 Node.js官方入门教程 Node.js中文网 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录Node.js 入门教程19 package-lock.json 文件19.1 示例19 package-lock.json 文件 在版本 5 中&#xff0c;npm 引入了 package-lock.json 文…

BUUCTF Reverse/[2019红帽杯]xx

BUUCTF Reverse/[2019红帽杯]xx 先看下文件信息&#xff1a;没有加壳、64位程序 看别人wp时候发现个好东东,就是这个findcrypt插件&#xff0c;可以看加密算法的&#xff0c;具体安装可以看这个IDA7.5安装findcrypt3插件 可以看到这是tea加密 先一点点分析代码&#xff0c;输入…

48.标准输入输出流

标准输入流对象cin&#xff0c;重点掌握的函数&#xff1a; 1.cin.get() //一次只能读取一个字符 2.cin.get(一个参数) //读一个字符 3.cin.get(两个参数) //可以读字符串 这种情况下不会读取换行符&#xff0c;换行符始终留在缓冲区当中 4.cin.getline() 此函数在读取数据的…