看了网上一些文章,动手操作了一遍,终于学会了Activit的一些常规使用。

一、Eclipse中的Activiti插件安装

Activiti有一个Eclipse插件,Activiti Eclipse Designer,可用于图形化建模、测试、部署 BPMN 2.0的流程。这样就不
用我们自己去编写繁琐的流程文件了。具体安装方法见手册。
打开 Help-> Install New Software.在如下面板中 , 点击 Add 按钮, 然后填入下列字段:
Name: Activiti BPMN 2.0 designer
Location: http://activiti.org/designer/update/
然后一步步的安装就可以了。

点击Window--->Preferences--->Activiti--->Save Actions:将Create process definition image when saving the diagram勾选,然后保存bpmn文件的时候会自动截图。

二、实现一个请假的工作流

1、随便模拟一个请假流程:

(1)发起请假申请;
(2)经理审批:
a.如果指定时间内没审批,则自动通过;
b.审批同意;
c.审批不同意;
(3)总经理审批:
a.如果请假大于或等于3天,则总经理审批;
b.如果请假小于3天,则自动通过;
(4)流程结束。

2、新建一个Activiti Diagram文件,按照第1步的思路,拖拉控件,画流程图,并设置相关节点或连线的值

3、配置文件activiti.cfg.xml的参数,主要配置数据库的相关参数等

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
  7. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
  8. <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
  9. <property name="jdbcUsername" value="root" />
  10. <property name="jdbcPassword" value="" />
  11. <property name="databaseSchemaUpdate" value="true" />
  12. <property name="jobExecutorActivate" value="true" />
  13. <property name="activityFontName" value="宋体"/>
  14. <property name="labelFontName" value="宋体"/>
  15. </bean>
  16.  
  17. </beans>

4、代码实例,实现启动流程、审批、画历史流程图等等,详细见代码中注释

  1. package com.sc.springmvc.controller;
  2.  
  3. import java.io.File;
  4. import java.io.InputStream;
  5. import java.text.DateFormat;
  6. import java.text.SimpleDateFormat;
  7. import java.util.ArrayList;
  8. import java.util.Calendar;
  9. import java.util.Date;
  10. import java.util.HashMap;
  11. import java.util.List;
  12. import java.util.Map;
  13. import java.util.TimeZone;
  14. import java.util.zip.ZipInputStream;
  15.  
  16. import org.activiti.bpmn.model.BpmnModel;
  17. import org.activiti.engine.HistoryService;
  18. import org.activiti.engine.ProcessEngine;
  19. import org.activiti.engine.ProcessEngineConfiguration;
  20. import org.activiti.engine.ProcessEngines;
  21. import org.activiti.engine.RepositoryService;
  22. import org.activiti.engine.RuntimeService;
  23. import org.activiti.engine.TaskService;
  24. import org.activiti.engine.history.HistoricActivityInstance;
  25. import org.activiti.engine.history.HistoricProcessInstance;
  26. import org.activiti.engine.history.HistoricTaskInstance;
  27. import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
  28. import org.activiti.engine.impl.context.Context;
  29. import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
  30. import org.activiti.engine.impl.pvm.PvmTransition;
  31. import org.activiti.engine.impl.pvm.process.ActivityImpl;
  32. import org.activiti.engine.repository.ProcessDefinition;
  33. import org.activiti.engine.repository.ProcessDefinitionQuery;
  34. import org.activiti.engine.runtime.ProcessInstance;
  35. import org.activiti.image.ProcessDiagramGenerator;
  36. import org.apache.commons.io.FileUtils;
  37.  
  38. public class ActivitiDemo {
  39.  
  40. public static void main(String[] args) {
  41. ActivitiDemo demo = new ActivitiDemo();
  42. //demo.deploy();
  43. //demo.queryProcdef();
  44. //demo.startFlow();
  45. //demo.queryTask_manager();
  46. //demo.startTask_manager();
  47. //demo.queryTask_boss();
  48. //demo.startTask_boss();
  49. //demo.queryStatus();
  50.  
  51. //demo.historyTaskList();
  52. //demo.processState();
  53.  
  54. //获取流程变量
  55. //System.out.println("生成流程图:");
  56. demo.generateImage("12501");
  57. }
  58.  
  59. String currUser = "0001";
  60. String applyUser = "0002";
  61. String manager = "0003";
  62. String boss = "0005";
  63.  
  64. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
  65.  
  66. /**
  67. * 发布流程
  68. * 发布流程后,流程文件会保存到数据库中 ,插入表act_re_deployment、act_re_procdef
  69. */
  70. void deploy(){
  71. RepositoryService repositoryService = processEngine.getRepositoryService();
  72.  
  73. //手动将myleave.bpmn和myleave.png打包成myleave.zip文件(一定要是zip别压缩成rar)
  74.  
  75. //获取在classpath下的流程文件
  76. InputStream in = this.getClass().getClassLoader().getResourceAsStream("myleave.zip");
  77. ZipInputStream zipInputStream = new ZipInputStream(in);
  78. //使用deploy方法发布流程:如果是首次表不存在则生成23张表,往这4张表插入流程相关信息:act_ge_bytearray、 act_ge_property、act_re_deployment、act_re_procdef
  79. repositoryService.createDeployment()
  80. .addZipInputStream(zipInputStream)
  81. .name("myleave")
  82. .deploy();
  83. }
  84.  
  85. //获取详细的流程定义信息
  86. void queryProcdef(){
  87. RepositoryService repositoryService = processEngine.getRepositoryService();
  88. //创建查询对象
  89. ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
  90. //添加查询条件
  91. query.processDefinitionKey("leaveApply");//通过key获取
  92. // .processDefinitionName("请假申请")//通过name获取
  93. // .orderByProcessDefinitionId()//根据ID排序
  94. //执行查询获取流程定义明细
  95. List<ProcessDefinition> pds = query.list();
  96. for (ProcessDefinition pd : pds) {
  97. System.out.println("ID:"+pd.getId()+",NAME:"+pd.getName()+",KEY:"+pd.getKey()+",VERSION:"+pd.getVersion()+",RESOURCE_NAME:"+pd.getResourceName()+",DGRM_RESOURCE_NAME:"+pd.getDiagramResourceName());
  98. }
  99. }
  100.  
  101. //发布流程
  102. public void startFlow(){
  103. RuntimeService runtimeService = processEngine.getRuntimeService();
  104.  
  105. //IdentityService identityService = processEngine.getIdentityService();
  106. // 用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中
  107. //identityService.setAuthenticatedUserId(currUser);
  108. /**
  109. * 启动请假单流程 并获取流程实例
  110. * 因为该请假单流程可以会启动多个所以每启动一个请假单流程都会在数据库中插入一条新版本的流程数据
  111. * 通过key启动的流程就是当前key下最新版本的流程
  112. * 当流程发布后在 act_ru_task ,act_ru_execution, act_ru_identitylink 表中插入流程数据
  113. *
  114. */
  115.  
  116. Map<String, Object> variables = new HashMap<String, Object>();
  117. variables.put("applyUser", applyUser);
  118. variables.put("manager", manager);
  119. variables.put("days", "5");
  120. Date date = addTime(new Date(),0,0,1);
  121. variables.put("dateTime", date);//到期时间
  122.  
  123. variables.put("boss", boss);
  124.  
  125. String businessKey = "10001";//保存于表act_hi_procinst中
  126.  
  127. //参数businessKey, variables为可选参数
  128. ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveApply", businessKey, variables);
  129. System.out.println("id:"+processInstance.getId()+",activitiId:"+processInstance.getActivityId());
  130. }
  131.  
  132. //增加时间
  133. public static Date addTime(Date date, int day, int hour, int minute){
  134. Calendar ca=Calendar.getInstance();
  135. ca.setTime(date);
  136. ca.add(Calendar.DATE, day);
  137. ca.add(Calendar.HOUR_OF_DAY, hour);
  138. ca.add(Calendar.MINUTE, minute);
  139. return ca.getTime();
  140. }
  141. /**
  142. * 传入Data类型日期,返回字符串类型时间(ISO8601标准时间)
  143. * @param date
  144. * @return
  145. */
  146. public static String getISO8601Timestamp(Date date){
  147. TimeZone tz = TimeZone.getTimeZone("UTC");
  148. DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
  149. df.setTimeZone(tz);
  150. String nowAsISO = df.format(date);
  151. return nowAsISO;
  152. }
  153.  
  154. /**
  155. * 查看任务
  156. */
  157. void queryTask_manager(){
  158. //获取任务服务对象
  159. TaskService taskService = processEngine.getTaskService();
  160. //根据接受人获取该用户的任务 ,表act_ru_task的字段assignee_为待办人
  161. List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery().processDefinitionKey("leaveApply").taskAssignee(manager).list();
  162. for (org.activiti.engine.task.Task task : tasks) {
  163. //ID : 表act_hi_actinst的字段act_id_
  164. System.out.println("ID:"+task.getId()+",姓名:"+task.getName()+",接收人:"+task.getAssignee()+",开始时间:"+task.getCreateTime());
  165. //获取流程变量
  166. System.out.println("Variables:");
  167. RuntimeService runtimeService=processEngine.getRuntimeService();
  168. String excutionId = task.getExecutionId();
  169. String applyUser = String.valueOf(runtimeService.getVariable(excutionId, "applyUser"));
  170. String days = String.valueOf(runtimeService.getVariable(excutionId, "days"));
  171. String dateTime = String.valueOf(runtimeService.getVariable(excutionId, "dateTime"));
  172.  
  173. System.out.println("applyUser:" + applyUser + ",days:" + days + ",datetime:" + dateTime);
  174. }
  175.  
  176. }
  177.  
  178. /**
  179. * 启动流程:经理审批
  180. */
  181. void startTask_manager(){
  182. TaskService taskService = processEngine.getTaskService();
  183. List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery().taskAssignee(manager).list();
  184. for (org.activiti.engine.task.Task task : tasks) {
  185. //taskId 就是查询任务中的 ID
  186. String taskId = task.getId();
  187.  
  188. Map<String, Object> variables = new HashMap<String, Object>();
  189. variables.put("managerPass", "1");
  190. variables.put("boss", boss);
  191.  
  192. taskService.complete(taskId, variables);
  193. }
  194.  
  195. }
  196.  
  197. /**
  198. * 老板查看任务
  199. */
  200. void queryTask_boss(){
  201. //获取任务服务对象
  202. TaskService taskService = processEngine.getTaskService();
  203. //根据接受人获取该用户的任务
  204. List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery().taskAssignee(boss).list();
  205. for (org.activiti.engine.task.Task task : tasks) {
  206. System.out.println("ID:"+task.getId()+",姓名:"+task.getName()+",接收人:"+task.getAssignee()+",开始时间:"+task.getCreateTime());
  207.  
  208. //获取流程变量
  209. System.out.println("Variables:");
  210. RuntimeService runtimeService=processEngine.getRuntimeService();
  211. String excutionId = task.getExecutionId();
  212. String applyUser = String.valueOf(runtimeService.getVariable(excutionId, "applyUser"));
  213. String manager = String.valueOf(runtimeService.getVariable(excutionId, "manager"));
  214. String managerPass = String.valueOf(runtimeService.getVariable(excutionId, "managerPass"));
  215. String days = String.valueOf(runtimeService.getVariable(excutionId, "days"));
  216. System.out.println("applyUser:" + applyUser + ",manager:" + manager + ",days:" + days + ",managerPass:" + managerPass);
  217.  
  218. }
  219. }
  220.  
  221. /**
  222. * 老板启动流程
  223. */
  224. void startTask_boss(){
  225. TaskService taskService = processEngine.getTaskService();
  226. //根据接受人获取该用户的任务
  227. List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery().taskAssignee(boss).list();
  228. for (org.activiti.engine.task.Task task : tasks) {
  229. //taskId 就是查询任务中的 ID
  230. String taskId = task.getId();
  231. //完成请假申请任务
  232. taskService.complete(taskId );
  233. }
  234.  
  235. }
  236.  
  237. void queryStatus(){
  238. HistoryService historyService = processEngine.getHistoryService();
  239. HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId("20001").singleResult();
  240. System.out.println("Process instance end time: " + getDate(historicProcessInstance.getEndTime()));
  241. }
  242.  
  243. /**
  244. * 历史任务查询:历史活动包括所有节点(流程图圆圈)和任务(流程图矩形),而历史任务只包含任务
  245. */
  246. public void historyTaskList(){
  247. List<HistoricTaskInstance> list=processEngine.getHistoryService() // 历史相关Service
  248. .createHistoricTaskInstanceQuery() // 创建历史任务实例查询
  249. .processInstanceId("37501") // 用流程实例id查询
  250. .finished() // 查询已经完成的任务
  251. .list();
  252. for(HistoricTaskInstance hti:list){
  253. System.out.println("任务ID:"+hti.getId());
  254. System.out.println("流程实例ID:"+hti.getProcessInstanceId());
  255. System.out.println("任务名称:"+hti.getName());
  256. System.out.println("办理人:"+hti.getAssignee());
  257. System.out.println("开始时间:"+hti.getStartTime());
  258. System.out.println("结束时间:"+hti.getEndTime());
  259. System.out.println("=================================");
  260. }
  261. }
  262. /**
  263. * 查询流程状态(正在执行 or 已经执行结束)
  264. */
  265. void processState(){
  266. ProcessInstance pi=processEngine.getRuntimeService() // 获取运行时Service
  267. .createProcessInstanceQuery() // 创建流程实例查询
  268. .processInstanceId("37501") // 用流程实例id查询
  269. .singleResult();
  270. if(pi!=null){
  271. System.out.println("流程正在执行!");
  272. }else{
  273. System.out.println("流程已经执行结束!");
  274. }
  275. }
  276.  
  277. String getDate(Date d){
  278. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  279. String s = sdf.format(d);
  280. return s;
  281. }
  282.  
  283. /**https://blog.csdn.net/u011277123/article/details/77380787
  284. * 流程图对历史节点进行高亮显示
  285. * @param processInstanceId
  286. * @return
  287. */
  288. void generateImage(String processInstanceId)
  289. {
  290. HistoryService historyService = processEngine.getHistoryService();
  291. RepositoryService repositoryService = processEngine.getRepositoryService();
  292. ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
  293. //获取历史流程实例
  294. HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
  295. //获取流程图
  296. BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
  297. processEngineConfiguration = processEngine.getProcessEngineConfiguration();
  298. Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);
  299.  
  300. ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
  301. ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());
  302.  
  303. List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
  304. //高亮环节id集合
  305. List<String> highLightedActivitis = new ArrayList<String>();
  306. //高亮线路id集合
  307. List<String> highLightedFlows = getHighLightedFlows(definitionEntity,highLightedActivitList);
  308.  
  309. // 已执行完的任务节点
  310. List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished().list();
  311. for (HistoricActivityInstance hai : finishedInstances) {
  312. highLightedActivitis.add(hai.getActivityId());
  313. }
  314.  
  315. //中文显示的是口口口,设置字体就好了
  316. InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis,highLightedFlows,"宋体","宋体",null,1.0);
  317. //单独返回流程图,不高亮显示
  318. // InputStream imageStream = diagramGenerator.generatePngDiagram(bpmnModel);
  319. // 输出资源内容到相应对象
  320. try {
  321. //生成本地图片
  322. File file = new File("D:/test3.png");
  323. FileUtils.copyInputStreamToFile(imageStream, file);
  324. } catch (Exception e) {
  325. throw new RuntimeException("生成流程图异常!", e);
  326. } finally {
  327. }
  328. }
  329.  
  330. /**
  331. * 获取需要高亮的线
  332. * @param processDefinitionEntity
  333. * @param historicActivityInstances
  334. * @return
  335. */
  336. private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity, List<HistoricActivityInstance> historicActivityInstances) {
  337. List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
  338. for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
  339. // 对历史流程节点进行遍历
  340. ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstances.get(i).getActivityId());// 得到节点定义的详细信息
  341. List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点
  342. ActivityImpl sameActivityImpl1 = processDefinitionEntity.findActivity(historicActivityInstances.get(i + 1).getActivityId());
  343. // 将后面第一个节点放在时间相同节点的集合里
  344. sameStartTimeNodes.add(sameActivityImpl1);
  345. for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
  346. HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
  347. HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
  348. if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
  349. // 如果第一个节点和第二个节点开始时间相同保存
  350. ActivityImpl sameActivityImpl2 = processDefinitionEntity.findActivity(activityImpl2.getActivityId());
  351. sameStartTimeNodes.add(sameActivityImpl2);
  352. } else {
  353. // 有不相同跳出循环
  354. break;
  355. }
  356. }
  357. List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();// 取出节点的所有出去的线
  358. for (PvmTransition pvmTransition : pvmTransitions) {
  359. // 对所有的线进行遍历
  360. ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
  361. // 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示
  362. if (sameStartTimeNodes.contains(pvmActivityImpl)) {
  363. highFlows.add(pvmTransition.getId());
  364. }
  365. }
  366. }
  367. return highFlows;
  368. }
  369.  
  370. }

附,看过的一些不错Activiti文章:

http://www.mossle.com/docs/activiti/index.html

https://blog.csdn.net/a67474506/article/details/38266129

http://www.cnblogs.com/shyroke/category/1126426.html

----------------------------------------------

2019.3.20补充

实际业务中,activiti工作流的开发过程:

1、画流程图
2、数据库业务表增加一个流程实例字段proc_inst_id_
3、发起流程申请,后台保存逻辑
(1)设置流程下一步审批节点的参数Map<String, Object> variables
(2)插入或更新业务相关表,返回业务表的主键businessKey
(3)发起流程
identityService.setAuthenticatedUserId(variables.get("applyUser").toString());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("流程名称", businessKey, variables);
String processInstanceId = processInstance.getId();
(4)根据上一步返回的流程实例Id,更新业务表相应字段
4、sql获取待办任务
select
to_char(t.id_) taskId,
w.proc_inst_id_,
t.task_def_key_ taskDefinitionKey,
......
from act_ru_task t
inner join 业务表 w on w.proc_inst_id_ = t.proc_inst_id_
where t.assignee_ = 待办人
5、待办审批前端页面,根据当前是哪个流程节点写不同逻辑
<c:if test="${taskDefinitionKey eq 'xxTask'}">
经理审批......
</c:if>
<c:if test="${taskDefinitionKey eq 'yyTask'}">
老板审批......
</c:if>
6、待办审批的后台保存逻辑
(1)判断权限:任务是否属于当前人;
(2)根据流程节点值taskDefinitionKey,设置流程下一步审批节点的参数Map<String, Object> variables
(3)更新相关业务表
(4)调用工作流方法
String taskId = (String) variables.get("taskId");
identityService.setAuthenticatedUserId(当前用户主键);
taskService.addComment(taskId, 流程实例Id, 审批意见);
this.taskService.complete(taskId, variables);
//TODO判断任务是否结束,是的话则根据实际情况更新业务表

Activit工作流学习例子的更多相关文章

  1. Activiti工作流学习之概述(一)

    一.工作流介绍 我第一次听到这个词,是蒙逼的,再看百度百度,更傻眼了,完全说的不像人话啊,举几个生活中的例子,就明白多了比如:请假.报销等等,如果文字太过抽象,请看图: 二.工作流引擎 Process ...

  2. Activiti工作流学习之流程图应用详解

    Activiti工作流学习之流程图应用详解 1.目的  了解Activiti工作流是怎样应用流程图的. 2.环境准备2.1.相关软件及版本    jdk版本:Jdk1.7及以上 IDE:eclipse ...

  3. 【知识总结】Activiti工作流学习入门

    1. 我理解的工作流: 在工作中慢慢接触的业务流程,就向流程控制语言一样,一步一步都对应的不同的业务,但整体串联起来就是一个完整的业务.而且实际工作中尤其是在企业内部系统的研发中,确实需要对应许多审批 ...

  4. 工作流学习——Activiti整体认识二步曲 (zhuan)

    http://blog.csdn.net/zwk626542417/article/details/46594505 ***************************************** ...

  5. Activiti工作流学习-----基于5.19.0版本(4)

    四.使用工作流开发 org.activiti.engine.ProcessEngine提供的Service作用在工作流引擎上面,如果所示是模仿一个公司简单的审批流程,你可以下载这个Demo:Activ ...

  6. activity 工作流学习(一)

    一.了解工作流 1.工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档.信息或任务的过程自动进行,从而实 ...

  7. Activiti工作流学习笔记(四)——工作流引擎中责任链模式的建立与应用原理

    原创/朱季谦 本文需要一定责任链模式的基础,主要分成三部分讲解: 一.简单理解责任链模式概念 二.Activiti工作流里责任链模式的建立 三.Activiti工作流里责任链模式的应用 一.简单理解责 ...

  8. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

  9. javascript闭包学习例子

    javascript中的闭包个很让人头疼的概念.总结一下 闭包是指有权访问一个函数作用域中的变量的函数.创建闭包最常见的方式,是在一个函数内部创建另一个函数,用return返回出去. 使用闭包可能造成 ...

随机推荐

  1. Explorer Bo (思维 + 树链剖分)

    题意:求用最少的链覆盖所有的边用最少的总链长度. 思路:为了使得使用的链最少,我们可以知道使用的数量应该是(子叶 + 1)/ 2. 画图可知:当节点下的边数是偶数时,为了将该父节点上的边给连接上,所以 ...

  2. USMART 组件移植到STM32

    USMART是由ALIENTEK开发的一个串口调试助手组件,通过它可以通过串口调试助手,调用程序里面的任何函数并执行,单个函数最多支持10个输入参数,并支持函数返回值显示. USMART支持的参数类型 ...

  3. 20165215 学习基础和c语言基础调查

    学习基础和c语言基础调查 <做中学>读后感与技能学习心得 读后感 Don't watch the clock. Do what it does. Keep going. 不要只看时钟,要效 ...

  4. EasyUI添加进度条

    EasyUI添加进度条 添加进度条重点只有一个,如何合理安排进度刷新与异步调用逻辑,假如我们在javascript代码中通过ajax或者第三方框架dwr等对远程服务进行异步调用,实现进度条就需要做到以 ...

  5. Subversion1.8源码安装流程

    为了解决svnamin:Unrecognized record type in stream的问题,决定将Subversion1.7升级为Subversion1.8 Subversion1.8的源码安 ...

  6. 关于Weex你需要知道的一切

    QCon第一天,GMTC全球移动技术大会联席主席.手淘技术老大庄卓然(花名南天)在Keynote上宣布跨平台开发框架Weex开始内测,并将于6月份开源,同时他们也放出官网:http://alibaba ...

  7. linux系统电视盒子到底是什么

    经常看到各种大神说今天刷了什么linux系统可以干嘛干嘛了,刷了乌班图可以干嘛干嘛了,但是身为一个小白,对这种名词都是一知半解.所以这边给大家科普一下,什么是linux系统?电视盒子刷了这个可以干啥? ...

  8. mycat工作原理

    Mycat的原理并不复杂,复杂的是代码,如果代码也不复杂,那么早就成为一个传说了. Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析: ...

  9. 跨域的根本原因:JavaScript 的同源策略

    摘自:https://blog.csdn.net/liubo2012/article/details/43148705 同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin) ...

  10. 02: http

    1.1 http简介 1.什么是http 1. HTTP是一个客户端和服务器端请求和应答的标准(TCP) 2. 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法 2.http报文格式 ...