activity6.0工作流系统知识点文章

第一章 activity流程部署(自动部署与动态BPMN部署)
第二章 activity变量使用
第三章 activity权限控制(代办任务查询)
第四章 activity审核任务(签领、完成任务、跳过节点、新增节点、设置委托人)
第五章 activity节点任意跳转(包含多实例)
第六章 activity新增节点(包含多实例)
第七章 activity多实例节点
第八章 activity流程监听器在项目中使用
第九章 activity自定义增删查改


文章目录

  • activity6.0工作流系统知识点文章
  • 前言
  • 一、工作流管理系统
      • 1.部分源码功能分析
        • 1、动态创建bpmn,并创建流程实例
        • 2、查询代办任务
        • 3、审核任务(签领、任意跳过节点、新增节点、完成任务)
        • 4、历史流程数据查询
        • 5、激活或挂起
        • 6、修改节点办理人(代办)
      • 2.提供的接口方式
    • 2.业务系统对接工作流功能(工作流客户端)
      • 1.流程节点配置
      • 2.流程待办任务与审核页面
      • 3.流程监控(终止流程、跳过、增减节点、修改审批人等)
  • 三、测试用例
    • 发起流程->查询待办任务->审核(新增节点、跳过节点、多实例参数赋值)->获取历史流程信息
  • 参考资料

前言

提示:流程设计器相对比较专业,客户一般不会用,也使得程序复杂化,加大维护成本。通过业务系统实现配置节点,动态构建流程BPMN文件来代替流程设计器,操作简单易用。

 工作流只是协助进行业务流程管理,对业务系统的业务流程进行自动化管理。没有工作流管理系统对业务系统影响不大,只不过有了工作流可以更好的管理业务流程,提高系统的可扩展性。作为流程管理,工作流可以独立部署为独立程序,通过接口与业务系统进行对接。下面我分两部分进行分析,一个是工作流管理系统,另一个是业务系统对接工作流功能(也可称为工作流客户端)。

工作流系统核心功能:
1、动态创建bpmn,并创建流程实例
2、查询代办任务
3、审核任务(签领、任意跳过节点、新增节点、完成任务)
4、历史流程数据查询

业务系统对接工作流功能:
1、定义业务流程,配置流程节点
2、审核流程任务(查询代办任务,完成流程任务)
3、监控流程(对在运行中的流程终止、新增任务、跳过任务等)

程序实现方式:
为了简化流程,对工作流制定规则如下:
1、动态创建bpmn固定为:开始节点—用户节点—排它网关—满足下一个用户节点或不满足结束节点。如图:

备注:如果需要控制特殊流向,可通过任意跳转、新增节点等来实现。

2、用户节点关键属性(审核人、候选人、候选组),设置为全局参数,来实现用户数据权限。
2.1第一个节点为发起人,流程启动时自动完成(谁发起就作为发起人)。
2.1候选组(组内人员都看到,其中一个审核通过即完成)
2.3候选人只有一个审核人时为单实例节点,候选人有多个审核人为多实例节点
备注:不采用activity提供的用户与组功能,减少系统复杂度。

举个例子:
报销单据审批流程,配置如下:发起人–》经费来源部门–》领导审核

要求:“经费来源部门”节点,需要经费大于10万才需要经过它审核

  1. 当金额大于10万,传给工作流节点为:
    发起人–》经费来源部门–》领导审核
  2. 当金额小于等于10万,传给工作流节点为:
    发起人–》领导审核

在创建流程实例前确认金额,工作流客户端确认好流程节点,就完成基本流程实例。
如果流程已发起,可通过流程监控对现有的流程进行终止、新增节点、跳过节点等等。

那如果创建流程前不知道,该如何做呢?
可以通过任意跳过节点、新增节点等功能控制代码,实现特殊流程流向;
还不满足的,你还可以通过流程设计器进行设置,把bpmn放在resources\processes路径下即可,然后特殊处理(特殊情况,自行扩展)。


一、工作流管理系统

工作流管理系统是独立部署,通过接口为业务系统提供api。如果业务系统也为Java,可以考虑采用RMI,目前工作流管理系统就是采用rmi接口。

系统采用SpringBoot2.3.4+activity6.0,源码结构图如下:

备注:具体功能,有兴趣可以通过下载源码进行研究

1.部分源码功能分析

1、动态创建bpmn,并创建流程实例

// 创建bpmn文件并部署流程
public class BuildFlowDeploymentService {@Resource private RepositoryService repositoryService;@Resource private RuntimeService runtimeService;private static final Map<String, List<ProcessTask>> processKeyCache = Maps.newHashMap();
public String createFlowDeployment(StartProcessInput input) {log.info("开始动态创建部署流程...input = {}", input);String processId = input.getProcessDefineKey();if (processKeyCache.containsKey(processId)) {//如果配置节点一样,采用缓存配置文件,避免重复创建Set<ProcessTask> processTasks = Sets.newHashSet(processKeyCache.get(processId));Set<ProcessTask> newProcessTasks = Sets.newHashSet(input.getProcessTasks());Set<ProcessTask> diff = Sets.symmetricDifference(processTasks, newProcessTasks);if (CollectionUtils.isEmpty(diff)) return processId;processKeyCache.remove(processId);}// 1. 建立模型BpmnModel model = new BpmnModel();Process process = new Process();List<ActivitiListener> executionListeners = Lists.newArrayList(addTaskListener("start"),addTaskListener("end"));process.setExecutionListeners(executionListeners);model.addProcess(process);process.setId(processId);process.setName(input.getProcessName());process.setDocumentation(input.getProcessName());//拼接节点信息createFlowElement(process, input.getProcessTasks());//部署流程repositoryService.createDeployment().addBpmnModel(process.getId() + FILE_SUFFIX, model).name(process.getId() + "_deployment").deploy();//        createProcessBpmn(model, processId); 尽在测试时打印查看效果图使用,正式用时需要注释掉processKeyCache.put(processId, input.getProcessTasks());return processId;}
    // 流程启动,创建流程实例public String startFlow(StartProcessInput input) {Map<String, Object> vars = Maps.newHashMap();vars.putAll(input.getConditionExpression());//添加条件参数vars.put(VARS_TITLE, input.getTitle());vars.put(VARS_SEND_UNIT_NAME, input.getSendUnitName());vars.put(VARS_SEND_USER_NAME, input.getSendUserName());vars.put(VARS_TASK_UNIT_ID, input.getTaskUnitId());vars.put(VARS_USER_TASK_NAME, input.getUserTaskName());vars.put(VARS_PROCESS_DEFINITION_ID, input.getProcessDefinitionId());vars.put(VARS_SECONDARY_UNIT_ID, input.getSecondaryUnitId());vars.put(VARS_REMARK, input.getRemark());// ...自定义表单数据input.getCustomForm().forEach((key, val) -> vars.put(VARS_PREFIX_FORM_PROPERTY.concat(key), val));String businessId = input.getBusinessId() + SPLIT_COMMA + input.getSendId() + SPLIT_COMMA + input.getProcessDefinitionId();log.debug("businessId->[{}]", businessId);String processInstanceId = startProcessInstance(input.getAssignee(), input.getProcessDefineKey(),input.getClassPrefix(), businessId, vars);log.info("流程已启动, 入参信息[{}], 流程id[{}]", input, processInstanceId);setProcessName(processInstanceId, input.getProcessName());List<Task> tasks = findTaskByProcInsId(processInstanceId);if (CollectionUtils.isEmpty(tasks)) {log.error("流程配置不符合规则,设置第一个节点发起人");BusinessException.throwConstraintException("流程配置不符合规则,设置第一个节点发起人");}Task task = tasks.get(0);// 默认第一个节点发起人,永远存在值completeAutoClaimTask(task.getId(), input.getAssignee(), processInstanceId, input.getComment(), vars);log.info("任务[{}]已完成", task);return processInstanceId;}

备注:如果想了解更多内容,可查看《第一章 activity流程部署(自动部署与动态BPMN部署)》

2、查询代办任务

 /*** 获取待办列表*/public TodoTaskSearchOutput todoTaskSearch(TodoTaskSearchInput input) {TaskQuery taskQuery;//CandidateGroups、CandidateUser同时为空时,返回全部数据(流程监控)if (CollectionUtils.isEmpty(input.getCandidateGroups()) && Strings.isNullOrEmpty(input.getCandidateUser())) {taskQuery = taskService.createTaskQuery().includeProcessVariables().active().orderByTaskCreateTime();} else {if (CollectionUtils.isEmpty(input.getCandidateGroups()))throw BusinessException.withMessage(ErrorCode.ERR_10001, "角色不能为空");taskQuery = taskService.createTaskQuery()
//                .taskCandidateUser(input.getCandidateUser()).taskCandidateOrAssigned(input.getCandidateUser()).taskCandidateGroupIn(input.getCandidateGroups())//支持多个角色.includeProcessVariables().active().orderByTaskCreateTime();}// 设置查询条件taskQuery(taskQuery, input);long total = taskQuery.count();int page = Math.max(input.getPager().getPage() - 1, 0);List<Task> toClaimList = taskQuery.listPage(page * input.getPager().getSize(), input.getPager().getSize());//分页查询

备注:如果想了解更多内容,可查看《activity权限控制(代办任务查询)》

3、审核任务(签领、任意跳过节点、新增节点、完成任务)

@Transactionalpublic AuditTaskEndSearchOutput taskAudit(TaskAuditInput input) {Task task = workFlowService.getTask(input);if (task == null) throw BusinessException.with(ErrorCode.ERR_40103);log.info("任务[{}]已完成", task.getId());Map<String, Object> vars = taskAuditBuildVars(input);// 流程自带表单数据log.debug("流程自带表单数据 count = {}", input.getCustomData().size());input.getCustomData().forEach((k, v) -> vars.put(VARS_PREFIX_FORM_PROPERTY + k, v));log.info("开始为用户[{}]自动签领任务[{}]", input.getAssignee(), task.getId());workFlowService.claim(task.getId(), input.getAssignee());workFlowService.complete(task.getId(), input, vars);// 1、当审核不通过时,流程结束if (0 == input.getIsPass()) {taskNotPassService.activityCompleted(input.getId());return findAuditTaskEndSearchOutput(input);}// 2、下一个节点被删除或新增节点处理workFlowService.addOrJumpProcessTask(input);// 3、设置下一个节点委托人if (!Strings.isNullOrEmpty(input.getEntrustedAgent())) {UpdateTaskAgentInput agentInput = new UpdateTaskAgentInput();agentInput.setProcessInstanceId(input.getId());agentInput.setEntrustedAgent(input.getEntrustedAgent());agentInput.setOriginalHandler(input.getOriginalHandler());workFlowService.updateTaskAgent(agentInput);}return findAuditTaskEndSearchOutput(input);}

备注:如果想了解更多内容,可查看《activity审核任务(签领、任意跳过节点、新增节点、设置委托人、完成任务)》

4、历史流程数据查询

public FindHistoricTaskOutput findHistoricTask(ProcInsIdInput input) {FindHistoricTaskOutput result = new FindHistoricTaskOutput();List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(input.getId()).includeProcessVariables().includeTaskLocalVariables().orderByHistoricTaskInstanceStartTime().asc().list();if (CollectionUtils.isEmpty(hisTasks)) return result;
// 返回历史数据内容,这里省略

5、激活或挂起

代码如下(示例):

// 激活
runtimeService.activateProcessInstanceById(processId);// 挂起
runtimeService.suspendProcessInstanceById(processId);

6、修改节点办理人(代办)

代码如下(示例):

public void updateTaskAgent(UpdateTaskAgentInput input) {if (Strings.isNullOrEmpty(input.getEntrustedAgent())) return;Task task = taskService.createTaskQuery().processInstanceId(input.getProcessInstanceId()).singleResult();if (task == null) {log.debug("流程已结束,不需要再设置委托人");return;}log.debug("设置负责人或委托人");taskService.setAssignee(task.getId(), input.getEntrustedAgent());//委托人if (!Strings.isNullOrEmpty(input.getOriginalHandler()))taskService.setOwner(task.getId(), input.getOriginalHandler());}

2.提供的接口方式

1、RMI接口;
2、webservice服务接口

接口服务端RMI配置:

@Slf4j
@Configuration
public class RmiConfiguration implements InitializingBean {@Value("${app.rmi.registryPort}")private int registryPort;@Value("${app.rmi.servicePort}")private int servicePort;@Resource private IWorkflowEndPoint workflowPoint;@Beanpublic RmiServiceExporter workflowPointExporter() {return export(IWorkflowEndPoint.class, workflowPoint, "flow");}private RmiServiceExporter export(Class<?> serviceInterface, Object instance, String instanceName) {RmiServiceExporter exporter = new RmiServiceExporter();exporter.setServiceInterface(serviceInterface);exporter.setService(instance);exporter.setServiceName(instanceName);exporter.setRegistryPort(registryPort); //注册端口exporter.setServicePort(servicePort); //通讯端口return exporter;}@Overridepublic void afterPropertiesSet() {log.info("--------------RMI Server started@RegistryPort[{}], ServicePort[{}] ---------------------", registryPort, servicePort);}
}

以下提供接口类:

public interface IWorkflowEndPoint {/*** 启动流程*/ApiResult<String> startProcess(RmiCommand command);/*** 根据流程实例id删除流程实例*/ApiResult<String> deleteProcessInstance(RmiCommand command);/*** 开始审核任务(完成任务节点)*/ApiResult<String> taskAudit(RmiCommand command);/*** 判断流程是否即将结束(当前任务完成后结束)*/ApiResult<String> isProcessEnd(RmiCommand command);/*** 根据流程id,返回当前流程实例的历史数据*/ApiResult<String> findHistoricTask(RmiCommand command);/*** 根据业务id,返回所有历史数据并根据实例进行分组*/ApiResult<String> findMergeHisProcess(RmiCommand command);/*** 获取待办数量*/ApiResult<String> todoTaskTotal(RmiCommand command);/*** 待办列表左侧的快捷查询标签*/ApiResult<String> todoTaskQueryTags(RmiCommand command);/*** 获取待办列表*/ApiResult<String> todoTaskSearch(RmiCommand command);/*** 获取待办任务信息(审核人、候选组、单位等等)*/ApiResult<String> todoTaskInfo(RmiCommand command);/*** 获取已办--经办(曾经审核过)*/ApiResult<String> auditTaskSearch(RmiCommand command);/*** 发件(没有办理结束)*/ApiResult<String> processSendSearch(RmiCommand command);/*** 办结(办理结束)*/ApiResult<String> processEndSearch(RmiCommand command);/*** 办理激活或挂起*/ApiResult<String> activeOrSuspendProcess(RmiCommand command);/*** 修改节点办理人*/ApiResult<String> updateTaskAgent(RmiCommand command);/*** 添加节点为代办任务*/ApiResult<String> addUserTasks(RmiCommand command);/*** 自由跳转节点(跳过代办任务时需要)*/ApiResult<String> freeNodeJump(RmiCommand command);
}

2.业务系统对接工作流功能(工作流客户端)

提供截图以及备注,直观了解业务系统与工作流对接功能,这里只是简单介绍能做什么,重点在讲解工作流系统功能。

1.流程节点配置

备注:动态节点类型,用于程序控制该节点是否保留

2.流程待办任务与审核页面

首页可放一个提醒是否有代办任务

进入代办任务页面:

点击办理

3.流程监控(终止流程、跳过、增减节点、修改审批人等)

查看所有的待办任务,可以终止流程,提醒审核人等;

进入流程督办,可以对流程节点进行跳过、增减节点、修改审批人等

三、测试用例

发起流程->查询待办任务->审核(新增节点、跳过节点、多实例参数赋值)->获取历史流程信息

代码如下(示例):

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("localdev")
public class WorkFlowTestService{@Resource private WorkFlowApp workFlowApp;@Testpublic void setMngWorkflowService() {StartProcessInput input = new StartProcessInput();input.setProcessDefinitionId("leaveId");input.setProcessDefineKey("WF0007");input.setProcessName("测试请假流程");// 流程节点配置input.setProcessTasks(findTasks());input.setAssignee("ceshi");// 业务idinput.setBusinessId("businessId");// 业务需要,这个业务实现类前缀input.setClassPrefix("leave");// 单位,用于数据权限的控制,现在在哪个单位中input.setTaskUnitId(VARS_CURRENCY_UNIT_VALUE);input.setUserTaskName("节点1");input.setTitle("标题");input.setComment("备注");// 如果第二个节点为多实例时,需要传值Map<String, Object> map = Maps.newHashMap();List<String> assignList = Lists.newArrayList("multiUser1", "multiUser2", "multiUser3");map.put("assignList", assignList);map.put("loopCardinality", assignList.size());input.setConditionExpression(map);StartProcessOutput output = workFlowApp.startProcess(input);log.error("返回对象:{}", output);}/*** 从当前的待办任务直接跳转到多实例节点*/@Testpublic void jump_multi_test() {FreeNodeJumpInput input = new FreeNodeJumpInput();input.setProcessInstanceId("7");input.setTargetNodeId("taskId3");Map<String, Object> vars = Maps.newHashMap();vars.put("taskUnitId", "currencyUnitValue");List<String> assignList = Lists.newArrayList("addMultiUser1", "addMultiUser2");vars.put("assignList", assignList);vars.put("loopCardinality", assignList.size());input.setVars(vars);FreeNodeJumpOutput taskOutput = workFlowApp.freeNodeJump(input);System.out.println(taskOutput.getSendUserId());}// 历史数据查询@Testpublic void his_test() {String id = "7";ProcInsIdInput insIdInput = new ProcInsIdInput();insIdInput.setId(id);FindHistoricTaskOutput taskOutput = workFlowApp.findHistoricTask(insIdInput);System.out.println(taskOutput.getItems());}//执行任务@Testpublic void taskAudit_test() {TaskAuditInput input = new TaskAuditInput();input.setId("7");input.setIsPass(1);input.setAssignee("multiUser2");input.setIsUserForCurrentTask(true);
//        input.setCandidateGroups(Lists.newArrayList("startRole"));input.setTaskUnitId("currencyUnitValue");input.setHandleUnitName("节点multiUser2单位");input.setHandleUserName("节点multiUser2有用户");input.setNexTaskUnitId("currencyUnitValue");// 如果下一个节点为新增节点,需要设置下一个节点配置,setTaskModelList这里就是配置
//        input.setNexTaskName("新增节点");
//        input.setLastNodeId("taskId3");
//        input.setTaskModelList(findAddTasks());
//        input.setNextCandidateUser("mUser1,mUser2");
//        input.setNextCandidateGroups(Lists.newArrayList("roleEnd"));// 如果下一个节点为多实例节点
//        Map<String, Object> map = Maps.newHashMap();
//        List<String> assignList = Lists.newArrayList("multiUser1", "multiUser2", "multiUser3");
//        map.put("assignList", assignList);
//        map.put("loopCardinality", assignList.size());
//        input.setConditionExpression(map);AuditTaskEndSearchOutput output = workFlowApp.taskAudit(input);log.error("返回参数[{}]", output);}@Testpublic void isProcessEnd_test() {TaskAuditInput input = new TaskAuditInput();input.setId("7");input.setIsPass(1);input.setAssignee("multiUser3");input.setIsUserForCurrentTask(true);
//        input.setCandidateGroups(Lists.newArrayList("startRole"));input.setTaskUnitId("currencyUnitValue");input.setHandleUnitName("节点multiUser3单位");input.setHandleUserName("节点multiUser3有用户");input.setNexTaskUnitId("currencyUnitValue");input.setNexTaskName("节点2");ProcessEndOutput output = workFlowApp.isProcessEnd(input);log.info("节点是否完成:" + (output.getIsTaskCompleted() ? "是" : "否"));log.info("流程是否结束:" + (output.getIsProcessEnd() ? "是" : "否"));}//获取待办任务@Testpublic void todoTaskSearch_test() {TodoTaskSearchInput input = new TodoTaskSearchInput();input.setProcInsId("7");
//        input.setCandidateUser("user1");
//        input.setCandidateGroups(Lists.newArrayList("startRole"));TodoTaskSearchOutput output = workFlowApp.todoTaskSearch(input);log.info("返回参数[{}]", output.getItems());}/*** 测试数据*/private List<ProcessTask> findTasks() {List<ProcessTask> tasks = Lists.newArrayList();// 第一个(i = 1)节点固定为发起人for (int i = 1; i <= 4; i++) {ProcessTask task = new ProcessTask();task.setTaskId("taskId" + i);if (i == 2) {// 流程发起就确认通过率、并行等条件task.setMultiInstanceTask(true);MultiInstanceInput multiTask = new MultiInstanceInput();multiTask.setCompletionRatio(BigDecimal.valueOf(0.51));multiTask.setSequential(true);task.setMultiTask(multiTask);}if (i == 3) {task.setCandidateUser("2021001");}// 不是多实例与候选人,那默认就是根据组判断权限tasks.add(task);}return tasks;}private List<ProcessTask> findAddTasks() {List<ProcessTask> tasks = Lists.newArrayList();ProcessTask task = new ProcessTask();task.setTaskId("addTaskId1");// 流程发起就确认通过率、并行等条件task.setMultiInstanceTask(true);MultiInstanceInput multiTask = new MultiInstanceInput();multiTask.setCompletionRatio(BigDecimal.valueOf(0.51));multiTask.setSequential(false);task.setMultiTask(multiTask);tasks.add(task);return tasks;}}

参考资料

中文操作文档参考地址:
https://blog.csdn.net/Nought_Love/article/details/100081893

如果需要源码,请加入QQ群:853941918

Java工作流管理系统(activity6.0)相关推荐

  1. 【自学笔记】简单java电话本管理系统v1.0源码

    我是一个java初学者,所以很多地方都写的很糟,首先谢谢 "唐"给我的练习题,这是完成所有功能后第一时间发的,所以很多该提取的方法和类都没有提取,主要是能够更清晰的看到整个结构,希 ...

  2. 2019最全Activity6.0工作流的介绍

    1.Activity是什么? 工作流(Wor kFlow)是对工作流程及其各操作步骤之间业务规则的抽象,概括描述 工作流建模:即将工作流程中的工作如何前后组织在一起的逻辑和规则,在计算机中以恰当的模型 ...

  3. 基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S ...

  4. 计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档)

    计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档) 本源码技术栈: 项目架构 ...

  5. 基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...

  6. J2EE工作流管理系统jBPM详解(一)

    一.jBPM入门简介 概述 工作流业务流程管理技术是基于SOA技术实现的一个核心部分.使用工作流能够在软件开发和业务两个层次受益: 1.方便开发 工作流管理系统能够简化企业级软件开发甚至维护.  ◆降 ...

  7. 基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...

  8. 基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署

    基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 本源码技术栈: 项目架构 ...

  9. 计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构:B/S ...

最新文章

  1. API 2.0Switching Basemaps
  2. [导入]C#优化字符串操作【月儿原创】
  3. Python3 爬虫学习笔记 C12【验证码对抗系列 — 图形验证码】
  4. 关于token你需要知道的
  5. 藏红花怎么推广?百度下拉词|抖音下拉词框|信息流推广-三剑合璧
  6. python装饰器理解_Python装饰器理解(新手)
  7. [CQOI2015]选数
  8. moment.js的方法总结
  9. Qt_IOS环境搭建 Qt for ios Projector ERROR:This mkspec requires Xcode 4.3 or later
  10. sql语句之case when的用法
  11. 计算机等级考试一级宝典,计算机等级考试一级通关宝典.doc
  12. Sick编码器CanOpen通信
  13. The Flee Plan of Groundhog(DFS)
  14. 渗透测试的理论部分1——渗透测试方法论
  15. win10怎么关闭443端口(超详细)
  16. 2018南京大学计算机系夏令营上机考试(一)
  17. 内存的永久保存区内存溢出解决
  18. 云计算的特点与产生、云计算体系结构、新摩尔定律、云计算优势
  19. mysql 时间格式处理
  20. python定义一个类savingaccount表示银行账户_Python实现信用卡系统(支持购物、转账、存取钱)...

热门文章

  1. You have to use a classifier to attach supplemental artifacts to the project instead of replacing th
  2. 一起来学习网站SEO优化工作流程到底怎么做?
  3. 2022最新百度网盘无限扩容方法技术分享-免费扩100T
  4. 如何调节B站倍速播放
  5. 卧槽!迅雷的代码结构竟然被扒了精光!
  6. 计算机二进制存储单位,计算机中的存储单位你清楚吗
  7. [IOS/Swift]'Project Name' was compiled with optimization
  8. 南极大冒险/零下八度/南极物语/8只雪橇犬
  9. java面试题题目与解析(自己网上找的):java208
  10. 使用Microsoft Teams Rooms和Teams设备提升混合体验