首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,082 阅读
2
类的加载
741 阅读
3
Spring Cloud OAuth2.0
726 阅读
4
SpringBoot自动装配原理
691 阅读
5
集合不安全问题
584 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
388
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
页面
统计
关于
搜索到
388
篇与
的结果
2024-11-11
四、流程控制
1. 代码块<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>代码块</title> </head> <body> <script> /* 使用 {} 来创建代码块,可以用来将代码分组 - 同一个代码块中的代码,要么都执行,要么都不执行 let和var - 使用let声明的变量具有块作用域,无法在代码块之外访问到 - 使用var声明的变量不具有作用域 */ { let a = 1 } // console.log(a) //Uncaught ReferenceError: a is not defined { var b = 3 } console.log(b) //3 </script> </body> </html>2. if语句<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>if语句</title> </head> <body> <script> /* 流程控制语句可以用来改变程序执行的顺序 1.条件判断语句 2.条件分支语句 3.循环语句 */ /* if语句 - 语法: if (条件表达式) { 语句 } - 执行流程: if语句在执行前会先对if后的条件表达式进行求值判断,如果为true,则执行if后的语句,反之不执行 */ let a = 1 let b = 2 if (a > b) { console.log('条件表达式成立!') } //if语句只会空值紧随其后的那一行代码,如果希望控制多行代码,使用{}代码块 //if (a > b) // console.log('a > b 成立') // console.log('a和b比较大小') //一般情况下,if语句建议写完整写法 if (a > b) { console.log('a > b 成立') console.log('a和b比较大小') } //如果表达式中的值不是布尔值,会先进行类型转换,再做判断 if (100) { console.log('if (100) 表达式为真') } </script> </body> </html> 3. if-else语句<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>if-else语句</title> </head> <body> <script> /* if-else语句: - 语法: if (条件表达式) { 语句 } else { 语句 } - 执行流程: if语句在执行前会先对if后的条件表达式进行求值判断 如果为true,则执行if后的语句 反之执行else中的语句 */ let score = 90 if (score >= 90) { console.log('成绩优秀!') } else { console.log('成绩良好!') } /* if-else if-else语句: - 语法: if (条件表达式1) { 语句 } else if (条件表达式2) { 语句 } else if (条件表达式3) { 语句 } else if (条件表达式4) { 语句 ...... } else { 语句 } - 执行流程: - 自上而下的依次对if后的条件表达式进行求职判断 - 如果为true,则执行当前if后的语句,执行完则语句结束 - 反之,会继续向下判断,直至找到true为止 - 如果所有表达式都为false,则执行else中的语句 - 注:不论有多少个if-else if-else,该语句中只会有一个代码块被执行 */ let age = 66 if (age >= 90) { console.log('耄耋'); } else if (age >= 80 && age < 90) { console.log('寿伞') } else if (age >= 70 && age < 80) { console.log('古稀') } else if (age >= 60 && age < 70) { console.log('还历') } else if (age >= 50 && age < 60) { console.log('知天命') } else if (age >= 40 && age < 50) { console.log('不惑') } else if (age >= 30 && age < 40) { console.log('而立') } else if (age >= 20 && age < 30) { console.log('加冠') } else { console.log('......') } </script> </body> </html> 4. switch语句<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>switch语句</title> </head> <body> <script> /* switch语句: - 语法: switch (表达式) { case 表达式: ... case 表达式: ... case 表达式: ... } - 执行的顺序: 在执行时会依次将switch后的表达式和case后的表达式进行全等判断 如果比较结果为true,则执行当前这个case后的代码 如果比较结果为false,则继续比较其他case后的表达式,直到找到true为止 注:需注意case穿透问题,不要忘了写break */ //根据用户输入的数字显示中文 let num = +prompt('请输入一个数字') switch (num) { case 1: alert('一') break case 2: alert('二') break case 3: alert('三') break default: alert('暂时不能判断!') break } </script> </body> </html> 5. 循环语句<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>循环语句</title> </head> <body> <script> /* 循环语句: - 可以使指定的代码反复执行 - js中的三种循环语句:while语句,do-while语句,for语句 - while语句: - 语法: while (条件表达式) { ...... } - 执行流程: 先对条件表达式进行判断 如果为true,则执行循环体,执行完之后继续对条件表达式进行判断 如果为true则重复上述步骤,直到条件表达式为false时停止,此时循环结束 */ /* 一般情况下,编写循环时需要三个条件: 1. 初始表达式 2. 条件表达式 3. 更新表达式 */ //let a = 1 //while (a < 10) { // console.log('执行循环体', a) // a++ //} //console.log('循环结束') let b = 1 while (true) { if (b > 5) { break } console.log('执行循环体', b) b++ } console.log('循环结束') </script> </body> </html> 6. do-while循环<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>do-while循环</title> </head> <body> <script> /* do-while循环: - 语法: do { ...... } while (条件表达式) - 执行顺序: 先执行do后的循环体,再进行while后的条件表达式判断 如果为true,则重复上述步骤 如果为false,则循环终止 - 与while的区别: while 先判断再执行 do-while 先执行再判断 实质区别:do-while可以确保循环至少执行一次 */ let a = 1 do { console.log('执行循环体', a) a++ } while (a < 5) console.log('循环执行结束') </script> </body> </html> 7. for循环<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>for循环</title> </head> <body> <script> /* for循环: - 语法: for (初始化表达式; 条件表达式; 更新表达式) { ...... } - 执行顺序: 1. 初始化变量 2. 执行条件表达式,判断循环是否执行 3. 条件表达式如果为true,则执行循环语句 4. 更新表达式 5. 重复步骤2,直到条件表达式的值为false - 注: 初始化表达式在整个循环中,只会执行依次 for循环中的三个表达式都可以省略(此时为死循环,没有循环结束节点) 使用let初始化的变量是局部变量 */ for (let i = 0; i < 10; i++) { console.log(`第${i}次循环`) } //创建死循环的方式 //while (true) {} //for (;;) {} </script> </body> </html> 8. 循环嵌套<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>循环嵌套</title> </head> <body> <script> /* 循环嵌套:在一个循环中嵌套其他的循环 */ for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (j <= i) { document.write("* ") } } document.write("<br>"); } /* 输出结果: * * * * * * * * * * * * * * * */ </script> </body> </html> 9. break和continue<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>break和continue</title> </head> <body> <script> /* break: - 用来终止switch和循环语句 - 终止离他最近的循环 */ for (let i = 0; i < 5; i++) { console.log('外层循环', i) for (let j = 0; j < 5; j++) { console.log('内层循环', j) if (j === 2) { break } } console.log('--------------------') } /* continue: 用来跳过当前的这次循环 */ for (let i = 0; i < 5; i++) { if (i === 3) { continue } console.log('continue循环测试', i) } </script> </body> </html>
2024年11月11日
39 阅读
0 评论
0 点赞
2024-11-03
三、运算符
1. 运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>运算符</title> </head> <body> <script> /* 运算符(操作符):可以对一个或多个操作数进行运算 - 算术运算符: + 加 - 减 * 乘 / 除 ** 幂运算 % 取模(两个数相除取余数) 注:算数运算时,除了字符串的加法,其他运算的操作数是非数值时,都会先进行类型转换再运算 */ let a = 1 + 1 a = 10 -5 a = 10 * 5 a = 10 / 5 a = 10 / 0 //Infinity a = 10 ** 4 a = 16 ** .5 //开平方 a = 10 % 2 /* js是一门弱类型语言,当进行运算时会通过自动转换类型来完成运算 */ a = 10 - '5' // 10 -5 a = 10 + true // 10 + 1 a = 5 + null //5 + 0 a = 6 - undefined // 6 - Nan = Nan /* 当任意一个值和字符串做加法运算时,会先将其他值转换为字符串,再进行字符串的拼接操作 */ a = 'false' + true //'falsetrue' a = 1 + '2' //'12' console.log(a) //可以通过任意类型+空串的方法来将其转换为字符串,原理同String()函数 let b = 1 b = b + '' console.log(typeof b, b) </script> </body> </html> 2. 赋值运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>赋值运算符</title> </head> <body> <script> /* 赋值运算符用来将一个值赋值给一个变量 */ let a = 10 a += 10 //等价于 a = a + 10 /* ??= 空赋值,即:只有变量的值为null或undefined时才会进行赋值操作 */ let b = null b ??= 100 console.log(b) //100 let c = 100 c ??= 123 console.log(c) //100 </script> </body> </html> 3. 一元±<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>一元±</title> </head> <body> <script> /* 一元的± + 正号 - 负号(对数值进行符号位取反) */ let a = 1 a = +a //1 a = -a //-1 console.log(a) //当我们对非数值类型进行正负运算时,会先将其转换为数值再进行运算 let b = '123' //b = Number(b) b = +b console.log(typeof b, b) </script> </body> </html> 4. 自增自减<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>自增和自减</title> </head> <body> <script> /* 自增: - 前自增 ++a - 后自增 a++ */ let a = 1 //先用后加 //let b = a++ //console.log('a++ = ', b) //1 //console.log(a) //2 //先加后用 let b = ++a console.log('a++ = ', b) //2 console.log(a) //2 let c = 2 let result = c++ + ++c + c //2 + 4 + 4 console.log(result) /* 自减:(同理自增) - 前自减 - 后自减 */ </script> </body> </html> 5. 逻辑运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>逻辑运算符</title> </head> <body> <script> /* ! 逻辑非: - 可以对一个布尔值进行取反操作 - 如果对一个非布尔值进行取反,js会先将其转换为布尔值再取反 - 类型转换: 转换为字符串: 显示:String() 隐示:+ '' 转换为数值: 显示:Number() 隐示:+ 转换为布尔值: 显示:Boolean() 隐示:!!(取反再取反) */ let a = true console.log(!a) let b = 123 console.log(!!b) /* && 逻辑与: - 可以对两个值进行与运算 - 当&&左右都为true时,返回true,否则返回false - 与运算是短路运算,即:第一个值为false时,则直接返回false,不会再看第二个值 - 与运算是找false的运算,只要找到了第一个false,就直接返回false */ let c = true && true console.log(c) //true let d = false && true console.log(d) //false //true && alert('逻辑与运算') //alert会执行 //false && alert('逻辑与运算') /* 对于非布尔值进行与运算,js会先将其转为布尔值,再进行与运算: - 最终返回结果是原值 - 如果第一个值为false,则返回第一个值 - 如果第一个值为true,则返回第二个值 */ console.log(1 && 2) //2 console.log(1 && 0) //0 console.log(0 && Nan) //0 /* || 逻辑或: - 可以对两个值进行或运算 - 当||左右只要有一个true时,则返回true,否则返回false - 或运算也是短路运算,如果第一个值为true,则不看第二个值 - 或运算是找true的运算,只要找到了第一个true,就直接返回true */ console.log(true || false) //true console.log(false || true) //true console.log(true || true) //true console.log(false || false) //false //false || alert('逻辑或运算') //alert会执行 //true || alert('逻辑或运算') //第一个值为true,alert不会执行 //此处与逻辑与运算同理 console.log(1 || 2) // 1 console.log('abc' || null) // 'abc' console.log(Nan || 1) // 1 </script> </body> </html> 6. 关系运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>关系运算符</title> </head> <body> <script> /* 用来检查两个值之间的关系是否成立,成立 true,不成立 false > 大于 < 小于 >= 大于等于 <= 小于等于 注: - 当对非数值进行关系运算时,会先将其转换(隐式转换)为数值,再进行比较 - 当两端都是字符串时,js不会进行数值转换,而是逐位比较二者的Unicode编码 两个字符串长度不相同时,只需比较第一位(即比较一位就能出结果),利用该特性,可以对字符串进行按字母顺序排序 */ console.log('2 > 1', 2 > 1) console.log('2 > 2', 2 > 2) console.log('2 >= 2', 2 >= 2) console.log('5 >= \'10\'', 5 >= '10') console.log('1 >= true', 1 <= true) console.log('\'a\' > \'b\'', 'a' > 'b') //false console.log('\'12\' > \'2\'', '12' > '2') //false </script> </body> </html> 7. 相等运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>相等运算符</title> </head> <body> <script> /* ==: - 相等运算符 - 当比较两个不同类型的值时,会先将其转换为相同的类型(通常转换为数值)再进行比较 - null和undefined进行比较时,会返回true - Nan不和任何值相等,包括它自身 ===: - 全等运算符 - 两个不同类型的值比较时,不会自动进行类型转换 !=: - 会自动进行类型转换 !===: - 不会自动进行类型转换 */ console.log('1 == 2', 1 == 2) //false console.log('1 == \'1\'', 1 == '1') //true console.log('true == 1', true == '1') //true console.log('nul == undefined', null == undefined) //true console.log('NaN == NaN', NaN == NaN) //false console.log('1 === \'1\'', 1 === '1') //false console.log('null === undefined', null === undefined) //false console.log('1 != \'1\'', 1 != '1') //false console.log('1 !== \'1\'', 1 !== '1') //false </script> </body> </html> 8. 条件运算符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>条件运算符</title> </head> <body> <script> /* 条件运算符(三目运算): 条件表达式 ? 表达式1 : 表达式2 执行顺序:当条件表达式成立(为true)时,执行表达式1,结束;反之执行表达式2,结束 */ let a = 1 let b = 20 let result = a > b ? a : b console.log(result) </script> </body> </html> 9. 运算符的优先级<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>运算符的优先级</title> </head> <body> <script> /* js中的运算优先级与数学运算类似,加减乘除 mdn文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_precedence#%E6%B1%87%E6%80%BB%E8%A1%A8 该文档的表格中,越靠前的,优先级越高 */ </script> </body> </html>
2024年11月03日
27 阅读
0 评论
0 点赞
2024-10-28
二、数据类型
1. 数值<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>数值</title> </head> <body> <script> /* 数值(Number) - 在js中,所有的整数和浮点数都是Number类型 - js中的数值并不是无限大的,当超过一定范围后,会显示近似值 - Infinity是一个特殊的数值,表示无穷大 - 进行计算时,需注意精度的问题 */ let a = 10 a = 100 a = 99999 * 999999 a= Infinity a = 1 - 'a' //NaN(Not a number) console.log(a) /* 大整数(BigInt) - 用来表示比较大的整数 - 大整数使用n结尾,它可以表示的数字范围是无限大 */ /* 其他进制的数字 - 二进制 0b - 八进制 0o - 十六进制 0x */ let b b = 0b1010 b = 0o10 b = 0xff console.log(b) //打印时都是十进制 </script> </body> </html> 2. 类型检查<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>类型检查</title> </head> <body> <script> let a = 10 let b = 10n console.log(a) console.log(b) //typeof检查的是变量的值的类型,而不是变量的类型,在js中,变量是没有类型的 //typeof返回的结果是一个字符串 console.log(typeof a) console.log(typeof b) </script> </body> </html> 3. 字符串<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>字符串</title> </head> <body> <script> /* 字符串 - 在js中使用单引号或双引号表示字符串 - 转义字符 \ 做斜杠 \t 制表符 \n 换行 - 模板字符串 使用 ` 表示,可以跨行,引号不能跨行 */ let a = '孙笑川' a = '这是一个"字符串"' a = "这是一个\"字符串\"" console.log(a) let b = `我的名字是: 孙笑川` console.log(b) let name = '孙笑川' let str = `我的名字是${name}` console.log(str) </script> </body> </html> 4. 其他的数据类型<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>其他的数据类型</title> </head> <body> <script> /* 布尔值(Boolean) - 用于逻辑判断 - 只有true、false两个值 */ let flag = false console.log(flag) console.log(typeof flag) /* 空值(Null) - 表示空对象 - 空值只有一个,即null - 使用typeof检查空值时,会返回"object",这其实是js发展历史中的一个bug,typeof无法检查 */ let a = null console.log(a) console.log(typeof a) /* 未定义(Undefined) - 当声明一个变量没有赋值时,它的值就是undefined - 使用typeof检查时,返回的是"undefined" */ //let b let b = undefined console.log(b) /* 符号(Symbol) - 用来创建一个唯一的标识符 - 使用typeof检查时,返回的是"Symbol" */ let c = Symbol() //调用Symbol函数创建了一个符号 console.log(c) //这七种数据类型的原始值不可变(即创建之后不可修改) </script> </body> </html> 5. 类型转换 - 字符串<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>类型转换-字符串</title> </head> <body> <script> /* 将一种数据类型转换为其他类型 */ let a = 10 a = true a = 100n //a = null console.log(typeof a, a) /* 1.调用toString()方法,注意:null和undefined没有该方法 */ a = a.toString() console.log(typeof a, a) /* 2.调用String()函数 对于拥有toString()方法的值调用String()函数时,实际上就是在调用toString() 对于null、undefined等值,则是直接进行转换 */ let b = 10 b = null b = undefined console.log(typeof b, b) b = String(b) console.log(typeof b, b) </script> </body> </html> 6. 类型转换 - 数值<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>类型转换-数值</title> </head> <body> <script> /* 1.使用Number()函数 - 字符串: 如果字符串是一个合法的数字,则会自动转换为对应的数值 反之,则是 Nan 如果字符串是空串或纯空格的字符串,转换后则是0 - 布尔值: true转换为1,false转换为0 - null 转换为0 - undefined 转换为Nan 2.专门将字符串转换为数值的两个方法 - parseInt() 转换为整数 解析时会自左向右逐一读取字符串,直到读取完字符串中所有有效的整数 有些时候可以使用该方法对数值进行取整(不推荐) - parseFloat() 转换为浮点数 解析时会自左向右逐一读取字符串,直到读取完字符串中所有有效的浮点数(小数) */ let a = '123' a = 'abc' //Nan a = '11px' //Nan a = '' //0 a = ' ' //0 a = true //1 a = false //0 a = null //0 a = undefined //Nan console.log(typeof a, a) a = Number(a) console.log(typeof a, a) let b = '123' b = '123px' //123 b = 456 //当传的值不是字符串而是数值时,parseInt()会先将456转换为'456',再进行整数转换 console.log(typeof b, b) b = parseInt(b) console.log(typeof b, b) b = parseFloat(b) console.log(typeof b, b) </script> </body> </html> 7. 类型转换 - 布尔值<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>类型转换-布尔值</title> </head> <body> <script> /* 1.使用Boolean()函数将其他类型转换为布尔值 - 数字:除了0和Nan转换后是false,其余都是true - 字符串:空串转换为false,其余是true - null、undefined转换为false - 对象会转换为true 所有表示空的没有错误的值都会转换为false,即0,Nan,空串,null,undefined */ let a = 1 //true a = -1 //true a = 0 //false a = NaN //false a = Infinity //true a = 'abc' //true a = 'true' //true a = 'false' //true a = '' //false a = ' ' //true a = null //false a = undefined //false console.log(typeof a, a) a = Boolean(a) console.log(typeof a, a) </script> </body> </html>
2024年10月28日
30 阅读
0 评论
0 点赞
2024-10-24
一、JavaScript入门
参照B站李立超老师2022年JavaScript课程1. 基本语法<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>基本语法</title> </head> <body> <script> /* 1.多行注释 */ //2.单行注释 //3.js严格区分大小写 //4.在js中,多个空格和换行会被忽略 //5.js中的每条语句都应该以分号结尾(如果没写,解释器会自动添加) </script> </body> </html>2. 字面量和变量<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>字面量和变量</title> </head> <body> <script> /* 字面量:表示字面所代表的意思(在js中,所有的字面量都可以直接使用) 变量: - 可以用来“存储”字面量 - 存储的字面量可以修改 */ /* 变量的使用: - 声明变量:let 变量名 / var 变量名 - 变量的赋值: a = 10 - 使用时,声明和赋值同时进行 let a = 10 */ let a = 10 console.log(a) </script> </body> </html>3. 变量的内存<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script> /* 变量中并不存储任何值,而是存储值的内存地址 */ let a = "孙笑川"; </script> </body> </html> 4. 常量<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>常量</title> </head> <body> <script> /* 在js中,用const声明常量 常量只能赋值一次,重复赋值会报错 除常规常量外,一些对象类型的数据也会被声明为常量 */ const PI = 3.1415926 console.log(PI); </script> </body> </html>5.标识符<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>标识符</title> </head> <body> <script> /* 在js中,所有可以自主命名的内容,都可以称为是一个标识符 例:变量名、函数名、类名...... 标识符命名规范: 1.只能含有字母、数字、下划线、$,且不能以数字开头 2.不能是js中的关键字、保留字 3.一般使用小驼峰命名,类名使用大驼峰,常量使用全大写 + 下划线 */ let a = 10 let a1 = 10 let $a1_ = 10 //let ##a = 10 </script> </body> </html>
2024年10月24日
76 阅读
0 评论
0 点赞
2024-08-21
动态表单
1. 内置表单流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.FormService; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.form.FormField; import org.camunda.bpm.engine.form.StartFormData; import org.camunda.bpm.engine.repository.Deployment; 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; /** * @Author Suaxi * @Date 2024/8/20 21:02 * @Description */ @SpringBootTest public class FlowFormsTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Autowired private FormService formService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("动态表单-内置表单") .addClasspathResource("flow/40.动态表单-内置表单.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void getDeploymentData() { String processId = "Process_0fc8vlb:1:791e3a95-5ef4-11ef-9b8d-10ffe00abd05"; StartFormData startFormData = formService.getStartFormData(processId); System.out.println("FormKey: " + startFormData.getFormKey()); List<FormField> formFieldList = startFormData.getFormFields(); if (formFieldList != null && formFieldList.size() > 0) { for (FormField formField : formFieldList) { System.out.println(formField.getId() + " - " + formField.getLabel() + ": " + formField.getValue().getValue()); } } } @Test public void startFlow() { String processId = "Process_0fc8vlb:1:791e3a95-5ef4-11ef-9b8d-10ffe00abd05"; Map<String, Object> map = new HashMap<>(); map.put("reason", "有事要请假!"); map.put("days", 3); runtimeService.startProcessInstanceById(processId, map); } @Test public void startFormFlow() { String processId = "Process_0fc8vlb:1:791e3a95-5ef4-11ef-9b8d-10ffe00abd05"; Map<String, Object> map = new HashMap<>(); map.put("reason", "我要请假!"); map.put("days", 5); formService.submitStartForm(processId, map); } @Test public void getTaskFormData() { String processId = "Process_0fc8vlb:1:791e3a95-5ef4-11ef-9b8d-10ffe00abd05"; String taskId = "5fe00ff2-5ef6-11ef-859a-10ffe00abd05"; StartFormData startFormData = formService.getStartFormData(processId); List<FormField> formFieldList = startFormData.getFormFields(); if (formFieldList != null && formFieldList.size() > 0) { for (FormField formField : formFieldList) { String id = formField.getId(); System.out.println(id + ": " + taskService.getVariable(taskId, id)); } } } } 2. Camunda表单流程图测试步骤同理内置表单3. 外置表单流程图测试步骤同理内置表单启动流程后,可在组长审批节点打开外置表单
2024年08月21日
169 阅读
0 评论
0 点赞
2024-08-15
任务回退
1. 串行的回退流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/13 21:27 * @Description */ @SpringBootTest public class FlowRollbackTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("任务回退-串行的回退") .addClasspathResource("flow/35.任务回退-串行的回退.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_15y1ksp:1:f147328e-5977-11ef-8eb4-10ffe00abd05"; runtimeService.startProcessInstanceById(processId); } @Test public void taskRollback() { String processInstanceId = "076d6028-597c-11ef-98e6-10ffe00abd05"; runtimeService.createProcessInstanceModification(processInstanceId) //.startBeforeActivity("Activity_0l16yzx") //跳转到指定结点之前 .startAfterActivity("Activity_0l16yzx") //跳转到指定结点之后 .cancelAllForActivity("Activity_0azdt7x") //取消某个指定节点 .execute(); } } 此处以人事审批节点回退至项目经理审批节点为例,执行回退方法后,历史任务表数据如下补充:类别方法在活动前启动回退到这个节点 startBeforeActivity(String activityId); startBeforeActivity(String activityId, String ancestorActivityInstanceId);在活动后启动通过 startAfterActivity() 方法,跳转到指定节点之后的节点 startAfterActivity(String activityId); startAfterActivity(String activityId, String ancestorActivityInstanceId);启动一个过渡通过 startTransition() 方法,在一个指定的序列流上开始执行,当有多个流出的序列流时,此时可以与 startAfterActivity() 方法一起使用 startTransition(String activityId); startTransition(String activityId, String ancestorActivityInstanceId);取消活动实例通过 cancelActivityInstance() 方法取消指定的活动实例 cancelActivityInstance(String activityInstanceId);取消过渡实例过渡实例表示即将以异步延续的形式进入/离开一个活动的执行流,一个已经创建但尚未执行的异步延续Job被表示为一个过渡实例,可以通过 cancelTransitionInstance() 方法来操作 cancelTransitionInstance(String transitionInstanceId);取消指定活动的所有活动实例通过 cancelAllForActivity() 方法操作 cancelAllForActivity(String activityId);2. 并行的回退流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/13 21:27 * @Description */ @SpringBootTest public class FlowRollbackTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("任务回退-并行的回退") .addClasspathResource("flow/36.任务回退-并行的回退.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_08oudkn:1:61e0cbaf-5a45-11ef-a08c-10ffe00abd05"; runtimeService.startProcessInstanceById(processId); } @Test public void taskRollback() { //例一:从技术总监审批、人事审批回退到组长审批 //String processInstanceId = "765f3a01-5a45-11ef-b89b-10ffe00abd05"; //runtimeService.createProcessInstanceModification(processInstanceId) // .startAfterActivity("StartEvent_1") // .cancelAllForActivity("Activity_04lzlma") // .cancelAllForActivity("Activity_1cy7zrd") // .execute(); //例二:从总经理审批回退到技术总监审批、人事审批 String processInstanceId = "f3d6dd13-5a46-11ef-9eef-10ffe00abd05"; runtimeService.createProcessInstanceModification(processInstanceId) .startAfterActivity("Activity_1u47ggy") .startBeforeActivity("Activity_1cy7zrd") .cancelAllForActivity("Activity_1vpmtcx") .execute(); } } 例一历史流程实例表数据例二历史流程实例表数据3. 排他网关的回退流程图测试此处以项目经理审批回退到排他网关之前,并让流程重新走到人事审批为例package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/13 21:27 * @Description */ @SpringBootTest public class FlowRollbackTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("任务回退-排他网关的回退") .addClasspathResource("flow/37.任务回退-排他网关的回退.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_1we1amp:1:3b817685-5a48-11ef-b838-10ffe00abd05"; runtimeService.startProcessInstanceById(processId); } @Test public void taskRollback() { String processInstanceId = "4b4fc9b1-5a48-11ef-90d7-10ffe00abd05"; runtimeService.createProcessInstanceModification(processInstanceId) .startBeforeActivity("Gateway_0v6gm4b") .setVariable("day", 5) .cancelAllForActivity("Activity_13amaw8") .execute(); } } 历史流程实例表数据4. 子流程的回退流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/13 21:27 * @Description */ @SpringBootTest public class FlowRollbackTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("任务回退-子流程的回退") .addClasspathResource("flow/38.任务回退-子流程的回退.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_0unlfrp:1:ff5ff077-5b0b-11ef-9419-10ffe00abd05"; runtimeService.startProcessInstanceById(processId); } @Test public void taskRollback() { //例一:子任务-项目经理审批回退至组长审批 //String processInstanceId = "31f21b1b-5b0c-11ef-990e-10ffe00abd05"; //runtimeService.createProcessInstanceModification(processInstanceId) // .startBeforeActivity("Activity_0jscehr") // .cancelAllForActivity("Activity_0uodo09") // .execute(); //例二:人事审批回退至子任务-项目经理审批 String processInstanceId = "31f21b1b-5b0c-11ef-990e-10ffe00abd05"; runtimeService.createProcessInstanceModification(processInstanceId) .startBeforeActivity("Activity_093vft3") .cancelAllForActivity("Activity_1bf56np") .execute(); } } 5. 重启/恢复实例流程实例终止后,其历史数据仍然存在,并且可以访问,且可以重启该历史流程实例(前提是历史级别设置为 FULL)。例:当执行中的流程实例没有以期望的方式结束时,此时可以使用重启流程实例的方法恢复被错误地取消的流程实例到最后的状态由于错误路由导致流程实例被终止后重启重启流程实例API runtimeService.restartProcessInstances()流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/13 21:27 * @Description */ @SpringBootTest public class FlowRollbackTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("任务回退-重启、恢复流程实例") .addClasspathResource("flow/39.任务回退-重启、恢复流程实例.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_0f17ijs:1:30fc859e-5b0e-11ef-97d6-10ffe00abd05"; runtimeService.startProcessInstanceById(processId); } @Test public void deleteProcessInstance() { //流程启动后,执行到组长审批、项目经理审批时,删除该流程实例,模拟流程执行过程中的异常中断 String processInstanceId = "400eb4ef-5b0e-11ef-8abb-10ffe00abd05"; runtimeService.deleteProcessInstance(processInstanceId, "deleted"); } @Test public void recoveryProcessInstance() { //恢复流程实例至组长审批、项目经理审批 String processDefinitionId = "Process_0f17ijs:1:30fc859e-5b0e-11ef-97d6-10ffe00abd05"; runtimeService.restartProcessInstances(processDefinitionId) .startBeforeActivity("Activity_1590vkg") .startBeforeActivity("Activity_14mdtr0") .processInstanceIds("400eb4ef-5b0e-11ef-8abb-10ffe00abd05") .execute(); } } 注:恢复后的流程实例从用户角度来说中断前是什么样,恢复后也是什么样;但从系统层面来说,恢复后的流程实例是一个全新的数据(流程实例id已经不同)此处可以参考历史流程实例表数据
2024年08月15日
83 阅读
0 评论
0 点赞
2024-08-13
多人会签
1. 概念多实例活动是为业务流程中的某个步骤定义重复的一种方式,在编程概念中,多实例与 foreach 结构相匹配:它允许对给定集合中的每个项目按顺序或并行地执行某个步骤或一个完整的子流程多实例是一个有额外属性的常规活动,它将导致该活动在运行时被多次执行,以下活动可成为多实例活动:Service Task 服务任务Send Task 发送任务User Task 用户任务Business Rule Task 业务规则任务Script Task 脚本任务Receive Task 接收任务Manual Task 手动任务(Embedded)Sub-Process (嵌入)子流程Call Activity 发起活动Transaction Subprocess 事务子流程注:网关或事件不能用于多实例中如果一个活动是多实例的,这将由活动底部的三条短线表示:三条垂直线 - 并行,三条竖线 - 顺序执行按照规范,每个实例所创建的执行的每个父执行将有以下变量:nrOfInstances:实例总数量nrOfActiveInstances:当前活动的(且未完成)的实例数量,在顺序执行中这个数量恒为1nrOfCompletedInstances:已完成的实例数量这些值可以通过 execution.getVariables() 方法获取此外,每个创建的执行将有一个执行本地变量(即对其他执行不可见,且不存储在流程实例级别)loopCounter:表示该特定实例的 foreach 循环中的索引为了使一个活动实例成为多实例,活动 xml 元素必须有一个 multiInstanceLoopCharacteristics 子元素<multiInstanceLoopCharacteristics isSequential="false|true"> ...... </multiInstanceLoopCharacteristics>2. 并行会签-案例一流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author Suaxi * @Date 2024/8/8 22:25 * @Description */ @SpringBootTest public class FlowMultiInstanceTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("多人会签-并行会签-案例一") .addClasspathResource("flow/32.多人会签-并行会签-案例一.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_0riwap9:1:302f5906-5592-11ef-a63f-10ffe00abd05"; Map<String, Object> variables = new HashMap<>(); variables.put("persons", Arrays.asList("admin", "zhangsan", "lisi")); runtimeService.startProcessInstanceById(processId, variables); } } 启动流程后,可看到有三个待审批的并行执行任务3. 并行会签-案例二流程图MultiInstanceCompleteTaskListenerpackage com.sw.camundademo.listener; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; /** * @Author Suaxi * @Date 2024/8/9 23:03 * @Description */ @Component("multiInstanceCompleteTaskListener") public class MultiInstanceCompleteTaskListener { public Boolean completeTask(DelegateExecution execution) { System.out.println("会签总数:" + execution.getVariable("nrOfInstances")); System.out.println("当前获取的会签数量:" + execution.getVariable("nrOfActiveInstances")); System.out.println("已经完成的会签数量:" + execution.getVariable("nrOfCompletedInstances")); Boolean flag = (Boolean) execution.getVariable("flag"); System.out.println("当前审批意见:" + flag); return flag; } } 测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * @Author Suaxi * @Date 2024/8/8 22:25 * @Description */ @SpringBootTest public class FlowMultiInstanceTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("多人会签-并行会签-案例二") .addClasspathResource("flow/33.多人会签-并行会签-案例二.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_1whtv0v:1:c256cf1b-5661-11ef-b3fe-10ffe00abd05"; Map<String, Object> variables = new HashMap<>(); variables.put("persons", Arrays.asList("admin", "zhangsan", "lisi")); runtimeService.startProcessInstanceById(processId, variables); } @Test public void completeTask() { String taskId = "ce5aac4c-5661-11ef-accb-10ffe00abd05"; Map<String, Object> variables = new HashMap<>(); variables.put("flag", true); taskService.complete(taskId, variables); } } 根据设置的并行会签完成条件,当其中一人审批通过时即通过4. 串行会签流程图测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * @Author Suaxi * @Date 2024/8/8 22:25 * @Description */ @SpringBootTest public class FlowMultiInstanceTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("多人会签-串行会签") .addClasspathResource("flow/34.多人会签-串行会签.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processId = "Process_0sgnfjk:1:c8ba7ba3-57e0-11ef-b282-10ffe00abd05"; Map<String, Object> variables = new HashMap<>(); variables.put("persons", Arrays.asList("admin", "zhangsan", "lisi")); runtimeService.startProcessInstanceById(processId, variables); } } 注:串行会签流程中,审批完一个,才出现下一个待审批任务,如果设置审批完成条件的话,也可以像并行会签流程中的例子一样,一人审批通过,则全部通过,流程进行到下一个节点
2024年08月13日
100 阅读
0 评论
0 点赞
2024-08-05
事件
事件(event)通常用于为流程生命周期中发生的事情建模,事件总是图形化为圆圈。在BPMN2.0中,主要分为:捕获(catching)与抛出(throwing)事件。捕获:当流程执行到达这个事件时,会等待直到触发器执行,触发器类型由XML中的类型声明定义抛出:当流程执行到达这个事件时,会触发对应的触发器1. 定时器事件定时触发相关的事件:定时器启动事件、定时器捕获中间事件、定时器边界事件(1)定时器启动事件定时器启动事件(timer start event)在指定的时间创建流程实例,可用于流程只需要启动一次,或流程需要在特定的时间间隔重复启动等场景。其中需要注意:子流程不能有定时器启动事件在流程部署时就开始计时,不需要单独调用 startProcessInstanceByxxx() 方法来启动,当调用该方法时,会在定时启动的基础上再额外启动一个对应的流程当部署带有定时器启动事件的流程更新版本时,上一个版本的定时器作业会被清除,即Camunda流程引擎不希望旧版本的流程仍然自动启动更新之后的新版本流程实例a. Date 固定时间点触发ISO8601相关内容:https://zh.wikipedia.org/wiki/ISO_8601当该流程部署后,在任务表中能看到对应的固定时间点启动事件任务b. Duration 间隔时间触发同理,流程部署后可在任务表看到对应的任务记录c. Cycle重复多次触发注:timeCycle 表达式包含可选属性 EndDate ,即 R3/PT1M/${EndDate} 表示执行过程中到达 EndDate 指定的时间时应用停止运行,并为该任务执行其他作业(2)定时器中间事件当组长审批完成之后,流程引擎会在任务记录表中创建对应的中间捕获事件对应的任务记录(3)定时器边界事件流程启动后等待一分钟不进行任何操作,等待边界事件触发如果在流程启动后正常进行组长审批,则边界事件不会触发,流程正常走向“项目经理1”审批2. 消息事件(1)启动事件在接收到某些消息后来启动对应的流程实例,消息类型包括不限于邮件、短信等等测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/7/24 21:53 * @Description */ @SpringBootTest public class FlowEventMessageTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-消息事件-启动事件") .addClasspathResource("flow/18.事件-消息事件-启动事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startMessageFlow() { runtimeService.startProcessInstanceByMessage("MsgStartEventMsg"); } } 注:启动流程时hi,可以通过常用的方式来启动,也可以通过对应的 startProcessInstanceByMessage() 方法启动(2)中间事件中间捕获事件即在流程运行过程中需要消息来触发的场景测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/7/24 21:53 * @Description */ @SpringBootTest public class FlowEventMessageTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-消息事件-中间捕获事件") .addClasspathResource("flow/19.事件-消息事件-中间捕获事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startMessageFlow() { String processInstanceId = "Process_14g0sj6:1:2f885ce8-49c7-11ef-9019-a8a1592cf182"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { String taskId = "612049bf-49c7-11ef-b518-a8a1592cf182"; taskService.complete(taskId); } @Test public void sendMessageTest() { runtimeService.messageEventReceived("MsgMiddleCatchEventMsg", "fcbae170-49c7-11ef-8c1d-a8a1592cf182"); } } 注:当组长正常审批完成后,需要发送对应的消息来触发流程图中所画的中间事件,流程才会继续往后走(3)边界事件同理定时器中的边界事件,当流程启动后,在组长审批前发送消息,即可触发对应的消息边界事件,走向新的流程方向(项目经理2审批)测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/7/24 21:53 * @Description */ @SpringBootTest public class FlowEventMessageTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-消息事件-边界事件") .addClasspathResource("flow/20.事件-消息事件-边界事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startMessageFlow() { String processInstanceId = "Process_0ub5i8b:1:b4e5124e-49c9-11ef-9973-a8a1592cf182"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void sendMessageTest() { runtimeService.messageEventReceived("MsgBoundaryEventMsg", "c910f373-49c9-11ef-b0ae-a8a1592cf182"); } } 3. 错误事件(1)开始事件错误启动事件(error start event),可用于触发事件子流程(Event Sub-Process),需注意错误启动事件不能用于启动流程实例流程图JavaDelegatepackage com.sw.camundademo.delegate; import lombok.extern.slf4j.Slf4j; import org.camunda.bpm.engine.delegate.BpmnError; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; /** * @Author Suaxi * @Date 2024/7/31 21:42 * @Description */ @Slf4j public class ErrorEventStartDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { log.info("ErrorEventStartDelegate执行了..."); //抛出的信息必须与设置的error code对应 throw new BpmnError("ErrorEventStartMsg"); } } 测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/7/31 21:49 * @Description */ @SpringBootTest public class FlowEventErrorTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-错误事件-开始事件") .addClasspathResource("flow/21.事件-错误事件-开始事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startErrorFlow() { String processInstanceId = "Process_1jtpd2d:1:26709f49-4f44-11ef-a77c-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } }当启动流程,服务任务绑定的 JavaDelegate 抛出错误后,会启动对应的错误启动事件子流程(2)边界事件当子流程执行过程中对外抛出了相关的异常,在流程中设置的错误边界事件就能捕获到相关的事件,然后做对应的处理流程图,此处以服务任务绑定 JavaDelegate 为例JavaDelegatepackage com.sw.camundademo.delegate; import lombok.extern.slf4j.Slf4j; import org.camunda.bpm.engine.delegate.BpmnError; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; /** * @Author Suaxi * @Date 2024/8/4 20:43 * @Description */ @Slf4j public class ErrorEventBoundaryDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { log.info("ErrorEventBoundaryDelegate执行了..."); //抛出的信息必须与设置的error code对应 throw new BpmnError("ErrorEventBoundaryMsg"); } } 当流程启动,对应的服务任务绑定的 JavaDelegate 执行时,抛出了对应的错误及 error code,则会触发对应的错误边界事件触发后,流程进入对应的节点4. 信号事件(1)开始事件通过信号来启动流程实例测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/5 21:23 * @Description */ @SpringBootTest public class FlowEventSignalTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-信号事件-开始事件") .addClasspathResource("flow/23.事件-信号事件-开始事件.bpmn") .deploy(); System.out.println(deploy.getId()); } /** * 通过信号触发启动流程实例 */ @Test public void signalReceive() { runtimeService.signalEventReceived("signalStartEvent"); } } (2)中间捕获事件当流程实例启动后,会阻塞在信号中间捕获事件处,等待信号触发后才会执行后续的流程测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/5 21:23 * @Description */ @SpringBootTest public class FlowEventSignalTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-信号事件-中间捕获事件") .addClasspathResource("flow/24.事件-信号事件-中间捕获事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_1x6a9fh:1:5eb47e10-532f-11ef-ba7f-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } /** * 通过信号触发中间捕获事件 */ @Test public void signalReceive() { runtimeService.signalEventReceived("signalMiddleCatchEvent"); } } 当执行完组长审批后,流程会阻塞在中间捕获事件处,直到信号 signalMiddleCatchEvent 触发,才会执行后续的流程(3)中间抛出事件在流程执行的过程中,某个节点抛出了对应的信号,触发了对应的信号捕获事件测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/5 21:23 * @Description */ @SpringBootTest public class FlowEventSignalTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-信号事件-中间抛出事件") .addClasspathResource("flow/25.事件-信号事件-中间抛出事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_1tpyp0e:1:fab9fb72-5331-11ef-8386-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { taskService.complete("2b789f00-5332-11ef-98d2-10ffe00abd05"); } } 注:当流程实例启动后,应先执行组长2审批,让对应的中间捕获事件流程处于阻塞的状态,在组长1审批完成后,且抛出信号 signalMiddleThrowEvent 时,才会进入项目经理审批流程,反之只会进入到人事审批流程(4)边界事件测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/5 21:23 * @Description */ @SpringBootTest public class FlowEventSignalTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-信号事件-边界事件") .addClasspathResource("flow/26.事件-信号事件-边界事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_12diz27:1:5e6bea56-5334-11ef-8213-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { taskService.complete("9328e474-5334-11ef-8f89-10ffe00abd05"); } /** * 通过信号触发边界事件 */ @Test public void signalReceive() { runtimeService.signalEventReceived("signalBoundaryEvent"); } } 注:启动流程后,如果在组长审批的过程中没有发送信号 signalBoundaryEvent ,则流程会进入到项目经理审批节点,反之,如果发送了信号,则会被组长审批节点中阻塞等待的信号边界事件捕获,进入到人事审批节点中5. 结束事件(1)错误结束事件当流程执行到达错误结束事件(error end event)时,当前分支结束执行,并抛出错误,这个错误可以由错误边界、中间事件捕获,如果未匹配到对应的错误边界事件,将会抛出异常测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/6 21:10 * @Description */ @SpringBootTest public class FlowEventEndTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-结束事件-错误结束事件") .addClasspathResource("flow/27.事件-结束事件-错误结束事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_00xytj8:1:e8902c02-53f5-11ef-9c4a-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { taskService.complete("9328e474-5334-11ef-8f89-10ffe00abd05"); } } 当流程执行到人事审批时,此时设置流程变量 flag = true,流程走向为:设置 flag = false,流程走向为:(2)中断结束事件中断结束事件也称为终止结束事件,主要用于对流程的终止。当在一个流程实例的执行过程中,需要提前或因为其他原因中断这个运行中的流程,可以使用这个事件来处理。当在流程实例的层面处理,则整个流程都会被中断;当在子流程中处理,则当前作用和作用域内的所有内部流程都会被中断案例一:没有子流程的中断结束事件案例测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/8/6 21:10 * @Description */ @SpringBootTest public class FlowEventEndTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-结束事件-中断结束事件") .addClasspathResource("flow/28.事件-结束事件-中断结束事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_1g4qego:1:9f795b0c-53f8-11ef-a302-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } } 启动流程后,在执行组长3审批时,如果设置的流程变量flag = true,则按照正常的顺序走,反之如果设置的flag = false,则流程直接中断,可在历史流程实例表中查询到相关的数据案例二:有子流程的情况下测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; 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.Map; /** * @Author Suaxi * @Date 2024/8/6 21:10 * @Description */ @SpringBootTest public class FlowEventEndTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-结束事件-中断结束事件(有子流程)") .addClasspathResource("flow/29.事件-结束事件-中断结束事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_1xxaxsj:1:8315add5-53fa-11ef-8ee5-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { Map<String, Object> variables = new HashMap<>(); variables.put("flag", false); taskService.complete("213ce445-53fb-11ef-b9de-10ffe00abd05", variables); } } 启动流程后,在执行组长3审批时,如果设置的流程变量flag = true,则按照正常的顺序走,反之如果设置的flag = false,则当前子流程直接中断,但不会影响组长1审批、组长2审批的执行(3)取消结束事件取消结束事件(cancel end event)只能与BPMN事务子流程一起使用,当流程执行到达取消结束事件时,会抛出取消事件,且必须有取消边界事件(cancel boundary event)捕获,取消边界事件将取消事务,同时触发补偿测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; 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.Map; /** * @Author Suaxi * @Date 2024/8/6 21:10 * @Description */ @SpringBootTest public class FlowEventEndTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-结束事件-取消结束事件") .addClasspathResource("flow/30.事件-结束事件-取消结束事件.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startFlow() { String processInstanceId = "Process_16jqg12:1:74f44003-53fd-11ef-8cb6-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } @Test public void complete() { Map<String, Object> variables = new HashMap<>(); variables.put("flag", false); taskService.complete("88a91c26-53fd-11ef-9b2f-10ffe00abd05", variables); } } 启动流程后,在执行组长审批时,如果设置的流程变量flag = true,则按照正常的顺序(组长审批-项目经理审批-人事审批)走,反之设置的falg = false 时,流程会执行到开发经理审批补偿边界事件中当开发经理审批完成时,触发取消边界事件总经理审批(4)补偿事件通过补偿达到控制业务流程的目的,此处以购票支付失败为例OrderTicketDelegatepackage com.sw.camundademo.delegate; import lombok.extern.slf4j.Slf4j; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; /** * @Author Suaxi * @Date 2024/8/6 22:26 * @Description */ @Slf4j public class OrderTicketDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { log.info("执行OrderTicketDelegate,车票预定成功..."); } } CompensationMiddleThrowEventDelegatepackage com.sw.camundademo.delegate; import lombok.extern.slf4j.Slf4j; import org.camunda.bpm.engine.delegate.BpmnError; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; /** * @Author Suaxi * @Date 2024/8/6 22:28 * @Description */ @Slf4j public class CompensationMiddleThrowEventDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { log.info("执行CompensationMiddleThrowEventDelegate,支付失败..."); throw new BpmnError("compensationMiddleThrowEvent"); } } 测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; 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.Map; /** * @Author Suaxi * @Date 2024/8/6 21:10 * @Description */ @SpringBootTest public class FlowEventEndTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("事件-结束事件-补偿事件") .addClasspathResource("flow/31.事件-结束事件-补偿事件.bpmn") .deploy(); System.out.println(deploy.getId()); repositoryService.deleteDeployment("d8790e22-5400-11ef-a7c9-10ffe00abd05"); } @Test public void startFlow() { String processInstanceId = "Process_0up7x7t:2:954f574f-5401-11ef-a09c-10ffe00abd05"; runtimeService.startProcessInstanceById(processInstanceId); } } 启动流程后,预定车票和支付绑定的 javaDelegate 同步执行流程进入到对应的取消订单补偿节点
2024年08月05日
290 阅读
0 评论
0 点赞
1
2
3
4
...
49