工作流的定义(解决什么问题?)

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

预期的业务目标,或者促使此目标的实现”。

我的理解:工作流将一套大的业务逻辑分解成业务逻辑段, 并统一控制这些业务逻辑段的执行条件,执行顺序以及相互通信。 实现业务逻辑的分解和解耦。

什么是Activiti?

官方介绍 Activiti是一个轻量级的工作流程和业务流程管理(BPM)平台,面向业务人员,开发人员和系统管理员。它的核心是使用Java开发的极速且稳定的的BPMN 2流程引擎。它是开源的,并在

Apache许可下分发。Activiti可在任何Java应用程序,服务器,群集或云中运行。它与Spring完美集成,非常轻巧。

Activiti与JPBM比较

都是BPMN2过程建模和执行环境。 都是BPM系统(符合BPM规范)。 都是开源项目-遵循ASL协议( Apache的 软件许可)。 都源自JBoss(Activiti5是jBPM4的衍生,jBPM5则基于Drools Flow)。

都很成熟,从无到有,双方开始约始于2年半前。 都有对人工任务的生命周期管理。 Activiti5和jBPM5唯一的区别是jBPM5基于WebService - HumanTask标准来描述人工任务和管理生命周期。 如有

兴趣了解这方面的标准及其优点,可参阅WS - HT规范介绍 。 都使用了不同风格的 Oryx 流程编辑器对BPMN2建模。 jBPM5采用的是 Intalio 维护的开源项目分支。 Activiti5则使用了Signavio维护的

分支。

Activiti与JPBM技术选型比较

总结:

虽然是比较,但不一定要有胜负,只有适合自己的才是最好的,要针对具体的项目区别对待。对我们自己的项目,其实我更关注的是我们项目未来的流程引擎的执行效率以及性能,每小时几十万甚至上百万的

流程需要执行,需要多少个服务,集群、负载的策略是什么,会不会有冲突?目前这方面的资料还是比较少的,很多问题只有实际遇用到的时候才会去想办法解决。不过就我个人的感觉而言,Activiti上手比较

快,界面也比较简洁、直观,值得一试,同时activiti的社区更新与支持也更及时,暂时推荐使用activiti。

Activiti开发环境搭建

1.Eclipse插件安装

>在线安装

>离线安装

2.Idea插件安装

IDEA 在插件仓库搜索actiBPM安装即可(这个插件,我非常想吐槽,画个直线是真的难,即便在编辑器里面是直线,后面用Activiti的API生成的图也是弯的。)

Activiti为我们做了什么?

1.第一次启动流程引擎的时候由Activiti自动创建28张数据表(不同版本表单数量,可能略有差异,本教程使用的是activiti6.0);

2.提供核心7大接口调用;

3.提供工作流API,简化流程操作;

4.提供全面的可视化流程管理服务,使流程更加直观。

activiti表单介绍

1、act_ge_ 通用数据表,ge是general的缩写

2、act_hi_ 历史数据表,hi是history的缩写,对应HistoryService接口

3、act_id_ 身份数据表,id是identity的缩写,对应IdentityService接口

4、act_re_ 流程存储表,re是repository的缩写,对应RepositoryService接口,存储流程部署和流程定义等静态数据

5、act_ru_ 运行时数据表,ru是runtime的缩写,对应RuntimeService接口和TaskService接口,存储流程实例和用户任务等动态数据

Activiti核心7大API接口

1.RepositoryService:提供一系列管理流程部署和流程定义的API。

2.RuntimeService:在流程运行时对流程实例进行管理与控制。

3.TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。

4.IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。

5.ManagementService:提供对流程引擎进行管理和维护的服务。

6.HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。

7.FormService:表单服务。

使用eclipse插件 新建流程定义文件

<process id="activitiInsurancePlanProcess" name="activitiInsurancePlanProcess" isExecutable="true" isClosed="false" processType="None">
<startEvent id="startEvent" name="开始流程"></startEvent>
<sequenceFlow id="flow2" sourceRef="startEvent" targetRef="usertask2"></sequenceFlow>
<userTask id="usertask2" name="二级子公司员工" activiti:assignee="${userId}" activiti:candidateGroups="22"></userTask>
<userTask id="usertask4" name="二级子公司领导" activiti:candidateGroups="21"></userTask>
<sequenceFlow id="flow4" sourceRef="usertask2" targetRef="usertask4"></sequenceFlow>
<userTask id="usertask5" name="财务专员" activiti:candidateGroups="32"></userTask>
<sequenceFlow id="flow5" sourceRef="usertask4" targetRef="usertask5"></sequenceFlow>
<userTask id="usertask6" name="财务领导" activiti:candidateGroups="31"></userTask>
<sequenceFlow id="flow6" sourceRef="usertask5" targetRef="usertask6"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow7" sourceRef="usertask6" targetRef="endevent1"></sequenceFlow>
</process>

流程定义的xml文件只贴出process 定义部分,坐标未列出;

需要注意的几个关键参数有:

id:在撤回、驳回时,会经常用到每个节点的ID;

assignee:受理人,表示当前节点由谁处理或者受理;

candidateGroups:分配任务负责的组,查询待办任务时,相应的组所有成员均可以看到此组的待办任务,但是只有一个人能处理

以上三个参数是最基础最常见使用的最多的参数。

测试代码:

package com.dd.activiti.admin.test;

import com.huatonghh.AdminApplication;
import com.huatonghh.activiti.util.Jump2TargetFlowNodeCommand;
import com.huatonghh.common.util.SpringUtil;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricFormProperty;
import org.activiti.engine.history.HistoricVariableUpdate;
import org.activiti.engine.identity.Group;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.persistence.entity.HistoricDetailVariableInstanceUpdateEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.BeforeEach;
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; import static com.huatonghh.common.util.SpringUtil.getBean; //@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AdminApplication.class)
//@WebAppConfiguration
public class ActivitiResourceIntTest { @Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private ProcessEngine processEngine; @Autowired
IdentityService identityService; @Autowired
ManagementService managementService; // @Autowired
// private ProcessRuntime processRuntime; @BeforeEach
public void setup() {
if(repositoryService ==null){
repositoryService = (RepositoryService)SpringUtil.getBean("RepositoryService"); } } /**
* 流程定义的部署
* 影响的activiti表有哪些
* act_re_deployment 部署信息
* act_re_procdef 流程定义的一些信息
* act_ge_bytearray 流程定义的bpmn文件以及png文件
*/ // @Test
public void ActivitiDeployment(){
//1.创建ProcessEngine对象 // ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//
// //2.得到RepositoryService实例
// RepositoryService repositoryService = processEngine.getRepositoryService(); //3.进行部署
Deployment deployment = repositoryService.createDeployment()//创建Deployment对象
.addClasspathResource("processes/activitiUserRoleProcess.bpmn")//添加bpmn文件
.addClasspathResource("processes/activitiUserRoleProcess.png")//添加png文件
.name("请假申请单流程")
.deploy();//部署 //4.输出部署的一些信息
System.out.println(deployment.getName());
System.out.println(deployment.getId());
} /**
* Zip文件部署流程
* 影响的activiti表有哪些
* act_re_deployment 部署信息
* act_re_procdef 流程定义的一些信息
* act_ge_bytearray 流程定义的bpmn文件以及png文件
*/ public void ActivitiZipDeployment (){
//先将bpmn文件和png文件压缩成zip文件。但是activiti最终也是以单个文件形式保存,说明activiti进行了解压工作。 //1.创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService(); //3.进行部署
Deployment deployment = repositoryService.createDeployment()//创建Deployment对象
.addClasspathResource("diagram/holiday.bpmn")//添加bpmn文件
.addClasspathResource("diagram/holiday.png")//添加png文件
.name("请假申请单流程")
.deploy();//部署 //4.输出部署的一些信息
System.out.println(deployment.getName());
System.out.println(deployment.getId()); //用户信息初始化
//初始化4级子公司角色及以下的员工
Group group1 = identityService.newGroup("threelevel");
group1.setName("三级及以下子公司");
group1.setType("assignment");
identityService.saveGroup(group1); Group group2 = identityService.newGroup("secondlevel");
group2.setName("二级子公司");
group2.setType("assignment");
identityService.saveGroup(group2); Group group3 = identityService.newGroup("financelevel");
group3.setName("财务公司");
group3.setType("assignment");
identityService.saveGroup(group3); Group group4 = identityService.newGroup("insurancelevel");
group4.setName("保险公司");
group4.setType("assignment");
identityService.saveGroup(group4);
} /**
* 启动一个工作流流程进行流程测试
*/
@Test
public void ActivitiStartInstance() {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RunService对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.创建流程实例(关键步骤)即 启动流程实例
//需要知道流程定义的Key:holiday(找key的方法 1:bpmn文件中的id,它对应的值就是key
// 2:直接看数据库中流程定义表act_re_procdet的key值)
String userId= "sjb";
Map<String,Object> map=new HashMap<String,Object>();
map.put("userId", userId);//标识为工作流程的工作,区别其他单独使用的流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activitiUserRoleProcess",map);
runtimeService.addUserIdentityLink(processInstance.getId(), "w6", "participant");
runtimeService.addGroupIdentityLink(processInstance.getId(), "gly", "candidate");
//4.输出实例的相关信息
System.out.println("流程部署ID="+processInstance.getDeploymentId());//null
System.out.println("流程定义ID="+processInstance.getProcessDefinitionId());//holiday:1:4
System.out.println("流程实例ID="+processInstance.getId());//
System.out.println("流程活动ID="+processInstance.getActivityId());//获取当前具体执行的某一个节点的ID(null) } /**
* 查询当前用户的任务列表
*/
public void ActivitiTaskQuery () {
//lisi完成自己任务列表的查询
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//3.根据流程定义的key以及负责人assignee来实现当前用户的任务列表查询
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("lisi")
.list();//这里还有一个查询唯一结果的方法:singleResult();、还有分页查询listPage(index,limit);
//4.任务列表展示
for (Task task : taskList) {
//查的act_hi_procinst表的id
System.out.println("流程实例ID="+task.getProcessInstanceId());
//查的act_hi_taskinst表的id
System.out.println("任务ID="+task.getId());
//查的act_hi_taskinst表的Assignee_
System.out.println("任务负责人名称="+task.getAssignee());
//查的act_hi_taskinst表的NAME_
System.out.println("任务名称="+task.getName());
}
} /**
* 处理当前用户的任务列表
* 背后操作到的表:
* act_hi_actinst
* act_hi_identitylink
* act_hi_taskinst
* act_ru_execution
* act_ru_identitylink
* act_ru_task //只放当前要执行的任务
*/
public void ActivitiCompleteTask (){
/**
* 李四完成自己的任务
*/ //1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.得到TaskService对象
TaskService taskService = processEngine.getTaskService(); //3.处理任务,结合当前用户任务列表的查询操作的话,可以知道任务ID=5002(实际操作中应该与查询写在一起)
taskService.complete("5002"); } /**
* 查询流程定义信息
**/
public void QueryProcessDefinition (){ //1.创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.创建RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService(); //3.得到ProcessDefinitionQuery对象,可以认为它就是一个查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); //4.设置条件,并查询出当前的所有流程定义 查询条件:流程定义的key=holiday
//.orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序。
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("holiday")
.orderByProcessDefinitionVersion()
.desc().list(); //5.输出流程定义信息
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定义ID" + processDefinition.getId());
System.out.println("流程定义名称" + processDefinition.getName());
System.out.println("流程定义Key" + processDefinition.getKey());
System.out.println("流程定义的版本号" + processDefinition.getVersion());
}
} /**
* 删除已经部署的流程定义
* 影响的activiti表有哪些
* act_re_deployment 部署信息
* act_re_procdef 流程定义的一些信息
* act_ge_bytearray 流程定义的bpmn文件以及png文件
**/
public void DeleteProcessDefinition (){ //1.创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.创建RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService(); //3.执行删除流程定义,参数代表流程部署的id
//参数true代表级联删除,此时就会先删除没有完成的流程节点,最后就可以删除流程定义信息,false代表不级联
repositoryService.deleteDeployment("1");
} /**
* 需求
* 历史数据的查看
**/
public void HistoryQuery (){ //1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3.得到HistoricActivitiInstanceQuery对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery(); historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id
//4.执行查询
List<HistoricActivityInstance> list = historicActivityInstanceQuery
.orderByHistoricActivityInstanceStartTime()
.asc()//根据流程开始进行的时间来排序
.list(); //5.遍历查询结果
for (HistoricActivityInstance instance : list) {
System.out.println("节点ID:" + instance.getActivityId());
System.out.println("节点名称:" + instance.getActivityName());
System.out.println("流程定义ID:" + instance.getProcessDefinitionId());
System.out.println("流程实例ID:" + instance.getProcessInstanceId());
System.out.println("=================================");
}
} /**
* 工作流的挂起与激活;
*/
// @Test
public void ActivitiSuspendAndActivate() {
// 通过流程实例ID来挂起流程实例
runtimeService.suspendProcessInstanceById("activitiInsurancePlanProcess:1:42504");
// 通过流程实例ID来激活流程实例
runtimeService.activateProcessInstanceById("42504"); } /*
* 查询组用户的任务
*/
//@Test
public void ActivitiGroupTaskQuery() {
String candidateUser = "user_secondlevel";
List<Task> list = processEngine.getTaskService()// 与正在执行的任务管理相关的Service
.createTaskQuery()// 创建任务查询对象
/** 查询条件(where部分) */
// .taskAssignee(assignee)//指定个人任务查询,指定办理人
.taskCandidateUser(candidateUser)// 组任务的办理人查询
// .processDefinitionId(processDefinitionId)//使用流程定义ID查询
// .processInstanceId(processInstanceId)//使用流程实例ID查询
// .executionId(executionId)//使用执行对象ID查询
/** 排序 */
.orderByTaskCreateTime().asc()// 使用创建时间的升序排列
/** 返回结果集 */
// .singleResult()//返回惟一结果集
// .count()//返回结果集的数量
// .listPage(firstResult, maxResults);//分页查询
.list();// 返回列表
if (list != null && list.size() > 0) {
for (Task task : list) {
System.out.println("任务ID:" + task.getId());
System.out.println("任务名称:" + task.getName());
System.out.println("任务的创建时间:" + task.getCreateTime());
System.out.println("任务的办理人:" + task.getAssignee());
System.out.println("流程实例ID:" + task.getProcessInstanceId());
System.out.println("执行对象ID:" + task.getExecutionId());
System.out.println("流程定义ID:" + task.getProcessDefinitionId());
System.out.println("########################################################");
}
} else {
System.out.println("未查询到组用户的任务");
}
} //驳回至 上一节点
private void jumpBeforeNode(String taskId,String msg){
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String processInstanceId = task.getProcessInstanceId();
// 1、首先是根据流程ID获取当前任务:
List<Task> tasks = processEngine.getTaskService().createTaskQuery().processInstanceId(processInstanceId).list();
// 获取流程中已经执行的节点,按照执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceId().asc().list();
//上一节点 节点ID
HistoricActivityInstance historicActivityInstance = historicActivityInstances.get(historicActivityInstances.size()-2);
managementService.executeCommand(new Jump2TargetFlowNodeCommand(taskId, historicActivityInstance.getActivityId(),msg));
tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
//同步计划信息
for (Task ts : tasks) {
ts.setDescription(task.getDescription());
taskService.saveTask(ts);
}
} /**
* 查询 每个节点的备注信息
* @param processInstanceId
* @return
*/
private Map<String,Object> packetVariables(String processInstanceId){
Map<String,Object> historyVariables=new HashMap<String,Object>();
//查询act_hi_detail表中proc_inst_id为processInstance.getId() 的所有数据并返回
List<HistoricDetail> list=historyService.createHistoricDetailQuery().processInstanceId(processInstanceId).list();
for(HistoricDetail historicDetail:list){
if(historicDetail instanceof HistoricFormProperty){
HistoricFormProperty field=(HistoricFormProperty)historicDetail;
historyVariables.put(field.getPropertyId(), field.getPropertyValue());
System.out.println("form field:taskId="+field.getTaskId()+",="+field.getPropertyId()+"="+field.getPropertyValue());
}else if (historicDetail instanceof HistoricVariableUpdate){
HistoricDetailVariableInstanceUpdateEntity variable=(HistoricDetailVariableInstanceUpdateEntity)historicDetail;
historyVariables.put(variable.getName(), variable.getValue());
System.out.println("variable:"+variable.getVariableName()+",="+variable.getValue());
} }
return historyVariables;
} }

驳回代码

 package com.huatonghh.activiti.util;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.ActivitiEngineAgenda;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.util.ProcessDefinitionUtil; /**
* 跳转到指定节点代码
*
* @author juyanming
*
*/
public class Jump2TargetFlowNodeCommand implements Command<Void> {
private String curTaskId; private String targetFlowNodeId; private String deleteReason; public Jump2TargetFlowNodeCommand(String curTaskId, String targetFlowNodeId,String deleteReason) {
super();
this.curTaskId = curTaskId;
this.targetFlowNodeId = targetFlowNodeId;
this.deleteReason = deleteReason;
} @Override
public Void execute(CommandContext commandContext) {
System.out.println("跳转到目标流程节点:" + targetFlowNodeId);
System.out.println("驳回原因:" + deleteReason);
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
// 获取当前任务的来源任务及来源节点信息
TaskEntity taskEntity = taskEntityManager.findById(curTaskId);
ExecutionEntity executionEntity = executionEntityManager.findById(taskEntity.getExecutionId());
Process process = ProcessDefinitionUtil.getProcess(executionEntity.getProcessDefinitionId());
// 删除当前节点
taskEntityManager.deleteTask(taskEntity, deleteReason, true, true);
HistoricTaskInstanceEntity historicTaskInstance = commandContext.getDbSqlSession().selectById(HistoricTaskInstanceEntity.class,curTaskId); if (historicTaskInstance != null) {
historicTaskInstance.setDeleteReason(deleteReason);
commandContext.getDbSqlSession().update(historicTaskInstance);
} // 获取要跳转的目标节点
FlowElement targetFlowElement = process.getFlowElement(targetFlowNodeId);
executionEntity.setCurrentFlowElement(targetFlowElement);
ActivitiEngineAgenda agenda = commandContext.getAgenda();
agenda.planContinueProcessInCompensation(executionEntity); return null;
} public String getCurTaskId() {
return curTaskId;
} public void setCurTaskId(String curTaskId) {
this.curTaskId = curTaskId;
} public String getTargetFlowNodeId() {
return targetFlowNodeId;
} public void setTargetFlowNodeId(String targetFlowNodeId) {
this.targetFlowNodeId = targetFlowNodeId;
} public String getDeleteReason() {
return deleteReason;
} public void setDeleteReason(String deleteReason) {
this.deleteReason = deleteReason;
} }

工作流之activiti6新手上路的更多相关文章

  1. 活字格企业 Web 应用生成器新手上路指南

    活字格是一款企业 Web 应用生成器,使用了类 Excel 的设计界面,通过简单的拖拽操作,就能快速制作出一个 Web 信息管理系统.在整个使用过程中无需专业软件知识,没有任何技术门槛,能轻松实现各行 ...

  2. php大力力 [001节]2015-08-21.php在百度文库的几个基础教程新手上路日记 大力力php 大力同学 2015-08-21 15:28

    php大力力 [001节]2015-08-21.php在百度文库的几个基础教程新手上路日记 大力力php 大力同学 2015-08-21 15:28 话说,嗯嗯,就是我自己说,做事认真要用表格,学习技 ...

  3. OpenGL教程之新手上路

    Jeff Molofee(NeHe)的OpenGL教程- 新手上路 译者的话:NeHe的教程一共同拥有30多课,内容翔实,而且不断更新 .国内的站点实在应该向他们学习.令人吃惊的是,NeHe提供的例程 ...

  4. webpack4配置详解之新手上路初探

    前言 经常会有群友问起webpack.react.redux.甚至create-react-app配置等等方面的问题,有些是我也不懂的,慢慢从大家的相互交流中,也学到了不少. ​ 今天就尝试着一起来聊 ...

  5. Dart语言快速学习上手(新手上路)

    Dart语言快速学习上手(新手上路) // 声明返回值 int add(int a, int b) { return a + b; } // 不声明返回值 add2(int a, int b) { r ...

  6. 转-spring-boot 注解配置mybatis+druid(新手上路)-http://blog.csdn.net/sinat_36203615/article/details/53759935

    spring-boot 注解配置mybatis+druid(新手上路) 转载 2016年12月20日 10:17:17 标签: sprinb-boot / mybatis / druid 10475 ...

  7. Ocelot 新手上路

    新手上路,老司机请多多包含!Ocelot 在博园里文章特别多,但是按照其中一篇文章教程,如果经验很少或者小白,是没法将程序跑向博主的结果. 因此总结下     参考多篇文章,终于达到预期效果. Oce ...

  8. Two Sum - 新手上路

    不是计算机相关专业毕业的,从来没用过leetcode,最近在学习数据结构和算法,用leetcode练练手. 新手上路,代码如有不妥之处,尽管指出来. 今天抽空做的第一个题:Two Sum(最简单的呃呃 ...

  9. 新手上路——it人如何保持竞争力

    新手上路——如何保持竞争力 JINGZHENGLI 套用葛大爷的一句名言:21世纪什么最贵,人才.哪你是人才还是人材?还是人财或人裁?相信大家都不是最后一种.何如保持住这个光环呢?就需要我们保持我们独 ...

随机推荐

  1. 更改 Ubuntu 的 apt 源

    1.在更改apt源之前要先备份官方自带的apt源 cd /etc/apt sudo cp sources.list sources.list.bak 2. 更改 sources.list 文件 sud ...

  2. Virtualbox 设置虚拟机和物理机共享文件夹

    Virtualbox 设置虚拟机和物理机共享文件夹 概述 当我们在本地机安装好一个虚拟机后,特别是安装linux系统的朋友们,经常需要将本地机的文件传递到虚拟机中, 能实现的方式肯定是多式多样的,就本 ...

  3. JavaWeb项目前后端分离

    前戏   前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以中间加一个nodejs)有效的进行解耦, 并且前后端分离会为以后的大型分布式架构.弹性计算架构.微 ...

  4. saltstack--状态判断unless与onlyif

    saltstack状态判断unless与onlyif 很多时候我们在编写 state 文件时候需要进行判断,判断该目录或文件是否存在,判断该配置是否已经已添加,然后根据判断结果再决定命令或动作是否执行 ...

  5. (十三)Kubernetes Dashboard

    Dashboard概述 Github地址 Dashboard是Kubernetes的Web GUI,可用于在Kubernetes集群上部署容器化应用.应用排障.管理集群本身及附加的资源等.常用于集群及 ...

  6. NLP文本分类方法汇总

    模型: FastText TextCNN TextRNN RCNN 分层注意网络(Hierarchical Attention Network) 具有注意的seq2seq模型(seq2seq with ...

  7. 基于 Keil MDK 移植 RT-Thread Nano

    后文rtt代表RT-Thread 在官网公众号中,看到rtt发布了rtt nano,这个就很轻量级的rtos内核,把多余的驱动都裁剪了,因此移植工作量小,可以哪来学习一番,体验rtt之美 rtt现在也 ...

  8. 电脑按键混乱,好像被锁定了Alt键

    在知乎上找到一篇文章,https://zhuanlan.zhihu.com/p/34835461 解决了我的问题,解决办法是按住左右两边的alt+shift+ctrl

  9. ansible 批量部署准备工作

    Ansible:自动化运维工具,基于Python开发 功能{ 批量系统配置 批量程序部署 批量运行命令等等 } 准备工作: 一.操作主机安装epel源 和 ansible工具 yum -y insta ...

  10. on bind live delegate的区别

    bind()----直接绑定在元素上 live()----通过冒泡的方式绑定到元素上,更适合于列表类型的绑定,和bind()相比,支持动态数据 delegate()----精确的小范围的适用事件代理, ...