Activiti工作流引擎进阶【收藏可做笔记系列】

三、流程变量


3.1、什么是流程变量

流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti

结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。

比如:在出差申请流程流转时如果出差天数大于 3 天则由总经理审核,否则由人事直接审核, 出差天

数就可以设置为流程变量,在流程流转时使用。

注意:虽然流程变量中可以存储业务数据可以通过activiti的api查询流程变量从而实现 查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。

3.2、流程变量类型

如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无

法反序列化,需要生成 serialVersionUID。

请添加图片描述

3.3、流程变量作用域

流程变量的作用域可以是一个流程实例(processInstance),或一个任务(task),或一个执行实例

(execution)

3.3.1、globa变量

流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量

注意:

如: Global变量:userId(变量名)、zhangsan(变量值)

global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。

3.3.2、local变量

任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。

Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

3.4、流程变量的使用方法

3.4.1、在属性上使用UEL表达式

可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。

Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配

3.4.2、在连线上使用UEL表达式

可以在连线上设置UEL表达式,决定流程走向。

比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。

如果UEL表达式是true,要决定 流程执行走向。

3.5、使用Global变量控制流程

3.5.1、需求

员工创建出差申请单,由部门经理审核,部门经理审核通过后出差3天及以下由人财务直接审批,3天以上先由总经理审核,总经理审核通过再由财务审批。

请添加图片描述

3.5.2、流程定义

1)、出差天数大于等于3连线条件

请添加图片描述请添加图片描述

也可以使用对象参数命名,如evection.num:

请添加图片描述

请添加图片描述

2)、出差天数小于3连线条件

请添加图片描述

请添加图片描述

也可以使用对象参数命名,如:

请添加图片描述

请添加图片描述

3.5.3、设置global流程变量

在部门经理审核前设置流程变量,变量值为出差单信息(包括出差天数),部门经理审核后可以根据流程变量的值决定流程走向。

在设置流程变量时,可以在启动流程时设置,也可以在任务办理时设置

3.5.3.1、创建POJO对象

创建出差申请pojo对象

package com.itheima.demo.pojo;

import java.io.Serializable;

import java.util.Date;

/**

  • 出差申请 pojo

*/

public class Evection implements Serializable {

/**

  • 主键id

*/

private Long id;

/**

  • 出差申请单名称

*/

private String evectionName;

/**

  • 出差天数

*/

private Double num;

/**

  • 预计开始时间

*/

private Date beginDate;

/**

  • 预计结束时间

*/

private Date endDate;

/**

  • 目的地

*/

private String destination;

/**

  • 出差事由

*/

private String reson;

public Long getId() {

return id;

}

public void setId(Long id) {

this.id = id;

}

public String getEvectionName() {

return evectionName;

}

public void setEvectionName(String evectionName) {

this.evectionName = evectionName;

}

public Date getBeginDate() {

return beginDate;

}

public void setBeginDate(Date beginDate) {

this.beginDate = beginDate;

}

public Date getEndDate() {

return endDate;

}

public void setEndDate(Date endDate) {

this.endDate = endDate;

}

public String getDestination() {

return destination;

}

public void setDestination(String destination) {

this.destination = destination;

}

public String getReson() {

return reson;

}

public void setReson(String reson) {

this.reson = reson;

}

public Double getNum() {

return num;

}

public void setNum(Double num) {

this.num = num;

}

}

3.5.3.2、启动流程时设置变量

在启动流程时设置流程变量,变量的作用域是整个流程实例。

通过Map<key,value>设置流程变量,map中可以设置多个变量,这个key就是流程变量的名字。

/**

  • 启动流程实例,设置流程变量的值

*/

@Test

public void startProcess(){

// 获取流程引擎

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 获取RunTimeService

RuntimeService runtimeService = processEngine.getRuntimeService();

// 流程定义key

String key = “myEvection2”;

// 创建变量集合

Map<String, Object> map = new HashMap<>();

// 创建出差pojo对象

Evection evection = new Evection();

// 设置出差天数

evection.setNum(2d);

// 定义流程变量,把出差pojo对象放入map

map.put(“evection”,evection);

// 设置assignee的取值,用户可以在界面上设置流程的执行

map.put(“assignee0”,“张三”);

map.put(“assignee1”,“李经理”);

map.put(“assignee2”,“王总经理”);

map.put(“assignee3”,“赵财务”);

// 启动流程实例,并设置流程变量的值(把map传入)

ProcessInstance processInstance = runtimeService

.startProcessInstanceByKey(key, map);

// 输出

System.out.println(“流程实例名称=”+processInstance.getName());

System.out.println(“流程定义id==”+processInstance.getProcessDefinitionId());

}

/**

  • 完成任务,判断当前用户是否有权限

*/

@Test

public void completTask() {

//任务id

String key = “myEvection2”;

// 任务负责人

String assingee = “张三”;

//获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 创建TaskService

TaskService taskService = processEngine.getTaskService();

// 完成任务前,需要校验该负责人可以完成当前任务

// 校验方法:

// 根据任务id和任务负责人查询当前任务,如果查到该用户有权限,就完成

Task task = taskService.createTaskQuery()

.processDefinitionKey(key)

.taskAssignee(assingee)

.singleResult();

if(task != null){

taskService.complete(task.getId());

System.out.println(“任务执行完成”);

}

}

说明:

startProcessInstanceByKey(processDefinitionKey, variables)

流程变量作用域是一个流程实例,流程变量使用Map存储,同一个流程实例设置变量map中key相同,后者覆盖前者。

3.5.3.2、任务办理时设置变量

在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。

这里需要在创建出差单任务完成时设置流程变量

/**

  • 完成任务,判断当前用户是否有权限

*/

@Test

public void completTask() {

//任务id

String key = “myEvection2”;

// 任务负责人

String assingee = “张三”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 创建TaskService

TaskService taskService = processEngine.getTaskService();

// 创建变量集合

Map<String, Object> map = new HashMap<>();

// 创建出差pojo对象

Evection evection = new Evection();

// 设置出差天数

evection.setNum(2d);

// 定义流程变量

map.put(“evection”,evection);

// 完成任务前,需要校验该负责人可以完成当前任务

// 校验方法:

// 根据任务id和任务负责人查询当前任务,如果查到该用户有权限,就完成

Task task = taskService.createTaskQuery()

.processDefinitionKey(key)

.taskAssignee(assingee)

.singleResult();

if(task != null){

//完成任务是,设置流程变量的值

taskService.complete(task.getId(),map);

System.out.println(“任务执行完成”);

}

}

说明:

通过当前任务设置流程变量,需要指定当前任务id,如果当前执行的任务id不存在则抛出异常。

任务办理时也是通过map<key,value>设置流程变量,一次可以设置多个变量。

3.5.3.3、通过当前流程实例设置

通过流程实例id设置全局变量,该流程实例必须未执行完成。

@Test

public void setGlobalVariableByExecutionId(){

// 当前流程实例执行 id,通常设置为当前执行的流程实例

String executionId=“2601”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 获取RuntimeService

RuntimeService runtimeService = processEngine.getRuntimeService();

// 创建出差pojo对象

Evection evection = new Evection();

// 设置天数

evection.setNum(3d);

// 通过流程实例 id设置流程变量

runtimeService.setVariable(executionId, “evection”, evection);

// 一次设置多个值

// runtimeService.setVariables(executionId, variables)

}

注意:

executionId必须当前未结束 流程实例的执行id,通常此id设置流程实例 的id。也可以通runtimeService.getVariable()获取流程变量。

3.5.3.4、通过当前任务设置

@Test

public void setGlobalVariableByTaskId(){

//当前待办任务id

String taskId=“1404”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = processEngine.getTaskService();

Evection evection = new Evection();

evection.setNum(3);

//通过任务设置流程变量

taskService.setVariable(taskId, “evection”, evection);

//一次设置多个值

//taskService.setVariables(taskId, variables)

}

注意:

任务id必须是当前待办任务id,act_ru_task中存在。如果该任务已结束,会报错

也可以通过taskService.getVariable()获取流程变量。

3.5.4、测试

正常测试:

​ 设置流程变量的值大于等于3天

​ 设计流程变量的值小于3天

异常测试:

​ 流程变量不存在

​ 流程变量的值为空NULL,price属性为空

​ UEL表达式都不符合条件

​ 不设置连线的条件

3.5.5、注意事项

1、 如果UEL表达式中流程变量名不存在则报错。

2、 如果UEL表达式中流程变量值为空NULL,流程不按UEL表达式去执行,而流程结束 。

3、 如果UEL表达式都不符合条件,流程结束

4、 如果连线不设置条件,会走flow序号小的那条线

3.5.6、操作数据库表

设置流程变量会在当前执行流程变量表插入记录,同时也会在历史流程变量表也插入记录。

//当前流程变量表

SELECT * FROM act_ru_variable

记录当前运行流程实例可使用的流程变量,包括 global和local变量

Id_:主键

Type_:变量类型

Name_:变量名称

Execution_id_:所属流程实例执行id,global和local变量都存储

Proc_inst_id_:所属流程实例id,global和local变量都存储

Task_id_:所属任务id,local变量存储

Bytearray_:serializable类型变量存储对应act_ge_bytearray表的id

Double_:double类型变量值

Long_:long类型变量值

Text_:text类型变量值

#历史流程变量表

SELECT * FROM act_hi_varinst

记录所有已创建的流程变量,包括 global和local变量

字段意义参考当前流程变量表。

3.6、设置local流程变量

3.6.1、任务办理时设置

任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询。

/*

*处理任务时设置local流程变量

*/

@Test

public void completTask() {

//任务id

String taskId = “1404”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = processEngine.getTaskService();

// 定义流程变量

Map<String, Object> variables = new HashMap<String, Object>();

Evection evection = new Evection ();

evection.setNum(3d);

// 定义流程变量

Map<String, Object> variables = new HashMap<String, Object>();

// 变量名是holiday,变量值是holiday对象

variables.put(“evection”, evection);

// 设置local变量,作用域为该任务

taskService.setVariablesLocal(taskId, variables);

// 完成任务

taskService.complete(taskId);

}

​ 说明:

设置作用域为任务的local变量,每个任务可以设置同名的变量,互不影响。

3.6.2、通过当前任务设置

@Test

public void setLocalVariableByTaskId(){

// 当前待办任务id

String taskId=“1404”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = processEngine.getTaskService();

Evection evection = new Evection ();

evection.setNum(3d);

// 通过任务设置流程变量

taskService.setVariableLocal(taskId, “evection”, evection);

// 一次设置多个值

//taskService.setVariablesLocal(taskId, variables)

}

注意:

任务id必须是当前待办任务id,act_ru_task中存在。

3.6.3、 Local变量测试1

如果上边例子中设置global变量改为设置local变量是否可行?为什么?

Local变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错。

3.6.4、 Local变量测试2

在部门经理审核、总经理审核、财务审核时设置local变量,可通过historyService查询每个历史任务时将流程变量的值也查询出来。

代码如下:

// 创建历史任务查询对象

HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();

// 查询结果包括 local变量

historicTaskInstanceQuery.includeTaskLocalVariables();

for (HistoricTaskInstance historicTaskInstance : list) {

System.out.println(“==============================”);

System.out.println(“任务id:” + historicTaskInstance.getId());

System.out.println(“任务名称:” + historicTaskInstance.getName());

System.out.println(“任务负责人:” + historicTaskInstance.getAssignee());

System.out.println(“任务local变量:”+ historicTaskInstance.getTaskLocalVariables());

}

注意:查询历史流程变量,特别是查询pojo变量需要经过反序列化,不推荐使用。

四、组任务


4.1、需求

在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。

针对这种情况可以给任务设置多个候选人,可以从候选人中选择参与者来完成任务。

4.2、设置任务候选人

在流程图中任务节点的配置中设置 candidate-users(候选人),多个候选人之间用逗号分开。

请添加图片描述

查看bpmn文件

我们可以看到部门经理的审核人已经设置为 lisi,wangwu 这样的一组候选人,可以使用

activiti:candiateUsers=”用户 1,用户 2,用户 3”的这种方式来实现设置一组候选人

4.3、组任务

4.3.1、组任务办理流程
a、查询组任务

指定候选人,查询该候选人当前的待办任务。

候选人不能立即办理任务。

b、拾取(claim)任务

该组任务的所有候选人都能拾取。

将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。

如果拾取后不想办理该任务?

需要将已经拾取的个人任务归还到组里边,将个人任务变成了组任务。

c、查询个人任务

查询方式同个人任务部分,根据assignee查询用户负责的个人任务。

d、办理个人任务
4.3.2、 查询组任务

根据候选人查询组任务

@Test

public void findGroupTaskList() {

// 流程定义key

String processDefinitionKey = “evection3”;

// 任务候选人

String candidateUser = “lisi”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 创建TaskService

TaskService taskService = processEngine.getTaskService();

//查询组任务

List list = taskService.createTaskQuery()

.processDefinitionKey(processDefinitionKey)

.taskCandidateUser(candidateUser)//根据候选人查询

.list();

for (Task task : list) {

System.out.println(“----------------------------”);

System.out.println(“流程实例id:” + task.getProcessInstanceId());

System.out.println(“任务id:” + task.getId());

System.out.println(“任务负责人:” + task.getAssignee());

System.out.println(“任务名称:” + task.getName());

}

}

4.3.3 、 拾取组任务

候选人员拾取组任务后该任务变为自己的个人任务。

@Test

public void claimTask(){

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = processEngine.getTaskService();

//要拾取的任务id

String taskId = “6302”;

//任务候选人id

String userId = “lisi”;

//拾取任务

//即使该用户不是候选人也能拾取(建议拾取时校验是否有资格)

//校验该用户有没有拾取任务的资格

Task task = taskService.createTaskQuery()

.taskId(taskId)

.taskCandidateUser(userId)//根据候选人查询

.singleResult();

if(task!=null){

//拾取任务

taskService.claim(taskId, userId);

System.out.println(“任务拾取成功”);

}

}

说明:即使该用户不是候选人也能拾取,建议拾取时校验是否有资格

组任务拾取后,该任务已有负责人,通过候选人将查询不到该任务

4.3.4、 查询个人待办任务

查询方式同个人任务查询

@Test

public void findPersonalTaskList() {

// 流程定义key

String processDefinitionKey = “evection1”;

// 任务负责人

String assignee = “zhangsan”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 创建TaskService

TaskService taskService = processEngine.getTaskService();

List list = taskService.createTaskQuery()

.processDefinitionKey(processDefinitionKey)

.taskAssignee(assignee)

.list();

for (Task task : list) {

System.out.println(“----------------------------”);

System.out.println(“流程实例id:” + task.getProcessInstanceId());

System.out.println(“任务id:” + task.getId());

System.out.println(“任务负责人:” + task.getAssignee());

System.out.println(“任务名称:” + task.getName());

}

}

4.3.5、 办理个人任务

同个人任务办理

/完成任务/

@Test

public void completeTask(){

// 任务ID

String taskId = “12304”;

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

processEngine.getTaskService()

.complete(taskId);

System.out.println(“完成任务:”+taskId);

}

说明:建议完成任务前校验该用户是否是该任务的负责人。

4.3.6、 归还组任务

如果个人不想办理该组任务,可以归还组任务,归还后该用户不再是该任务的负责人

/*

*归还组任务,由个人任务变为组任务,还可以进行任务交接

*/

@Test

public void setAssigneeToGroupTask() {

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 查询任务使用TaskService

TaskService taskService = processEngine.getTaskService();

// 当前待办任务

String taskId = “6004”;

// 任务负责人

String userId = “zhangsan2”;

// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务

Task task = taskService

.createTaskQuery()

.taskId(taskId)

.taskAssignee(userId)

.singleResult();

if (task != null) {

// 如果设置为null,归还组任务,该 任务没有负责人

taskService.setAssignee(taskId, null);

}

}

说明:建议归还任务前校验该用户是否是该任务的负责人

也可以通过setAssignee方法将任务委托给其它用户负责,注意被委托的用户可以不是候选人(建议不要这样使用)

4.3.7、 任务交接

任务交接,任务负责人将任务交给其它候选人办理该任务

@Test

public void setAssigneeToCandidateUser() {

// 获取processEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 查询任务使用TaskService

TaskService taskService = processEngine.getTaskService();

// 当前待办任务

String taskId = “6004”;

// 任务负责人

String userId = “zhangsan2”;

// 将此任务交给其它候选人办理该 任务

String candidateuser = “zhangsan”;

// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务

Task task = taskService

.createTaskQuery()

.taskId(taskId)

.taskAssignee(userId)

.singleResult();

if (task != null) {

taskService.setAssignee(taskId, candidateuser);

}

}

4.3.8、 数据库表操作

查询当前任务执行表

SELECT * FROM act_ru_task

任务执行表,记录当前执行的任务,由于该任务当前是组任务,所有assignee为空,当拾取任务后该字段就是拾取用户的id

查询任务参与者

SELECT * FROM act_ru_identitylink

任务参与者,记录当前参考任务用户或组,当前任务如果设置了候选人,会向该表插入候选人记录,有几个候选就插入几个

与act_ru_identitylink对应的还有一张历史表act_hi_identitylink,向act_ru_identitylink插入记录的同时也会向历史表插入记录。任务完成

五、网关


网关用来控制流程的流向

5.1 排他网关ExclusiveGateway

5.1.1 什么是排他网关:

排他网关,用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支,

注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行。

为什么要用排他网关?

不用排他网关也可以实现分支,如:在连线的condition条件上设置分支条件。

在连线设置condition条件的缺点:如果条件都不满足,流程就结束了(是异常结束)。

如果 使用排他网关决定分支的走向,如下:

请添加图片描述

如果从网关出去的线所有条件都不满足则系统抛出异常。

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway ‘exclusivegateway1’ could be selected for continuing the process

at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

前端面试题汇总

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

条件都不满足则系统抛出异常。

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway ‘exclusivegateway1’ could be selected for continuing the process

at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-9rwUs5FC-1712488462625)]
[外链图片转存中…(img-m1mVkYQb-1712488462626)]
[外链图片转存中…(img-ZFqw58vK-1712488462626)]
[外链图片转存中…(img-J6rL3yzD-1712488462627)]
[外链图片转存中…(img-48VktjlN-1712488462627)]
[外链图片转存中…(img-WRwNrtpj-1712488462628)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-outdVc4g-1712488462628)]

总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

前端面试题汇总

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-bVQWQy5S-1712488462628)]

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值