Java工作流管理系统(activity6.0)
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万才需要经过它审核
- 当金额大于10万,传给工作流节点为:
发起人–》经费来源部门–》领导审核 - 当金额小于等于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)相关推荐
- 【自学笔记】简单java电话本管理系统v1.0源码
我是一个java初学者,所以很多地方都写的很糟,首先谢谢 "唐"给我的练习题,这是完成所有功能后第一时间发的,所以很多该提取的方法和类都没有提取,主要是能够更清晰的看到整个结构,希 ...
- 2019最全Activity6.0工作流的介绍
1.Activity是什么? 工作流(Wor kFlow)是对工作流程及其各操作步骤之间业务规则的抽象,概括描述 工作流建模:即将工作流程中的工作如何前后组织在一起的逻辑和规则,在计算机中以恰当的模型 ...
- 基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署
基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA工作流流程编辑OA系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S ...
- 计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档)
计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java工作流流程编辑OA系统(源码+系统+mysql数据库+Lw文档) 本源码技术栈: 项目架构 ...
- 基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA酒店管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...
- J2EE工作流管理系统jBPM详解(一)
一.jBPM入门简介 概述 工作流业务流程管理技术是基于SOA技术实现的一个核心部分.使用工作流能够在软件开发和业务两个层次受益: 1.方便开发 工作流管理系统能够简化企业级软件开发甚至维护. ◆降 ...
- 基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA家教管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...
- 基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 基于java汽配管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 本源码技术栈: 项目架构 ...
- 计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档)
计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java办公自动化管理系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构:B/S ...
最新文章
- API 2.0Switching Basemaps
- [导入]C#优化字符串操作【月儿原创】
- Python3 爬虫学习笔记 C12【验证码对抗系列 — 图形验证码】
- 关于token你需要知道的
- 藏红花怎么推广?百度下拉词|抖音下拉词框|信息流推广-三剑合璧
- python装饰器理解_Python装饰器理解(新手)
- [CQOI2015]选数
- moment.js的方法总结
- Qt_IOS环境搭建 Qt for ios Projector ERROR:This mkspec requires Xcode 4.3 or later
- sql语句之case when的用法
- 计算机等级考试一级宝典,计算机等级考试一级通关宝典.doc
- Sick编码器CanOpen通信
- The Flee Plan of Groundhog(DFS)
- 渗透测试的理论部分1——渗透测试方法论
- win10怎么关闭443端口(超详细)
- 2018南京大学计算机系夏令营上机考试(一)
- 内存的永久保存区内存溢出解决
- 云计算的特点与产生、云计算体系结构、新摩尔定律、云计算优势
- mysql 时间格式处理
- python定义一个类savingaccount表示银行账户_Python实现信用卡系统(支持购物、转账、存取钱)...
热门文章
- You have to use a classifier to attach supplemental artifacts to the project instead of replacing th
- 一起来学习网站SEO优化工作流程到底怎么做?
- 2022最新百度网盘无限扩容方法技术分享-免费扩100T
- 如何调节B站倍速播放
- 卧槽!迅雷的代码结构竟然被扒了精光!
- 计算机二进制存储单位,计算机中的存储单位你清楚吗
- [IOS/Swift]'Project Name' was compiled with optimization
- 南极大冒险/零下八度/南极物语/8只雪橇犬
- java面试题题目与解析(自己网上找的):java208
- 使用Microsoft Teams Rooms和Teams设备提升混合体验