十八、动画与canvas

1.RequestAnimationFrame
早期定时动画
setTimeout和setInterval不能保证时间精度,第二个参数只能保证何时将代码添加到浏览器的任务队列
requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用
function updateProgress(){const div = document.getElementById('div');div.style.width = (parseInt(div.style.width, 10) + 5) + '%';if (div.style.width !== '100%'){requestAnimationFrame(updateProgress);}
}
requestAnimationFrame(updateProgress);
requestAnimationFrame()的函数实际上可以接受一个参数,该参数为DOMHighResTimeStamp的实例,表示下次重绘的时间点。
cancelAnimationFrame(id); // 对应clearTimeout clearInterval
requestAnimationFrame()可以用作节流
let enabled = true;
function expensiveOperation(){console.log('scroll', Date.now());
}
window.addEventListener('scroll', () => {if (enabled) {enabled = false;window.requestAnimationFrame(expensiveOperation);setTimeout(() => enabled = true, 50)}
}
2.基本的画布功能
<canvas>元素必须要指定width和height两个属性,标签之间的内容是在浏览器不支持的情况下展示的内容
getContext();// 获取绘制上下文,参数为‘2d’或者‘webgl’
toDataURL(); // 导出canvas元素上的图像,接受一个MIME类型参数
3、2D绘图上下文
原点(0,0)在左上角,width和height分别为x轴和y轴的最大值
填充和描边
fillStyle和strokeStyle两个属性,属性值可以是字符串、渐变对象和图案对象
const myCanvas = document.getElementById('myCanvas');
const ctx = myCanvas.getContext('2d');
ctx.strokeStyle = 'red';
ctx.fillStyle = '#0000ff';
绘制矩形
fillRect(x,y, width, height);
strokeRect(x, y, width, height);
clearRect(x, y, width, height);
绘制路径
必须beginPath()开始绘制新路径,closePath()绘制一条返回起点的路径。而后可以指定fillStyle属性后,使用fill()填充区域,或者指定strokeStyle属性后,使用stroke()填充路径,或者使用clip()创建一个新的剪切区域。
| 方法 | 说明 |
|---|---|
| arc(x, y, startAngle, endAngle, counterclockwise) | 以(x,y)为圆心,从起始角度到结束角度绘制弧线,最后一个参数为是否顺时针,默认为true |
| arcTo(x1, y1, x2, y2, radius) | 给定半径,经过(x1, y1)从上一个点绘制到(x2,y2)的弧线 |
| bezierCurveTo(c1x, c1y, c2x, c2y, x, y) | 以(c1x, c1y)(c2x, c2y)为控制点,绘制从上一点到(x,y)的三次贝塞尔曲线 |
| lineTo(x,y) | 上一点到(x,y)的直线 |
| moveTo(x,y) | 移动光标到(x,y) |
| quadraticCurveTo(cx, cy) | 以(cx, cy)为控制点,绘制从上一点到(x,y)的二次贝塞尔曲线 |
| rect(x, y, width, height) | 绘制一个矩形路径,而非图形 |
| isPointInPath(x, y) | 判断(x, y)是否在当前路径 |
绘制文本
fillText(contentStr, x, y, maxWidth);
strokeText(contentStr, x, y, maxWidth);
// 相关设置属性
ctx.font; // 以css样式指定字体样式、大小、字体簇
ctx.textAlign; // 文本对齐方式 start/end/left/right/center
ctx.textBaseLine; // 文本基线, top/hanging/middle/alphabetic/ideographic/bottom
辅助确定文本大小的方法measureText(str),返回一个TextMetrics对象
变换
| 方法 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| rotate(angle) | 围绕原点将图像旋转angle | |||||||||
| scale(scaleX, scaleY) | 在x轴和y轴上分别缩放相应倍数 | |||||||||
| translate(x, y) | 将坐标原点移动到(x, y) | |||||||||
| transform(m1_1, m1_2, m2_1, m2_2, dx, dy) | 通过矩阵乘法直接修改上下文矩阵
| |||||||||
| setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) | 先将上下文变换矩阵重置,然后以传入的参数调用transform |
save()可以将所有设置放入一个暂存栈,需要恢复时调用restore()
绘制图像
drawImage()可以接受三组不同的参数
//1.传入一个HTML的<img>元素
let img = document.images[0];
ctx.drawImage(img, x, y);
ctx.drawImage(img, x, y, width, height); // width和height默认为<img>的宽高
// 2.将图像的部分绘制到指定区域
ctx.drawImage(img, srcX, srcY, srcWidth, srcHeight, targetX, targetY, targetWidth, targetHeight);
// 3.第一个参数可以是另外一个canvas元素
// 操作的结果可以通过toDataURL() 获取
阴影
属性值设置
| 属性 | 说明 |
|---|---|
| shadowColor | CSS颜色值,默认黑色 |
| shadowOffsetX | x坐标偏移量 |
| shadowOffsetY | y坐标偏移量 |
| shadowBlur | 阴影模糊量 |
渐变
线性渐变通过CanvasGradient的实例表示,createLinearGradient()创建一个CanvasGradient实例,接受起点和终点的坐标作为参数;
addColorStop()方法为gradient对象添加色标,接受两个参数(位置0-1,颜色)
const gradient = ctx.createLinearGradient(30,30,70,70);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'black');
// 绘制红色矩形
ctx.fillStyle = '#FF0000';
ctx.fillRect(10,10,50,50);
// 绘制渐变矩形
ctx.fillStyle = gradient;
ctx.fillRect(30,30,50,50);
径向渐变通过createRadialGradient()创建,接受六个参数,分别为起点和终点的圆心坐标、半径、
ctx.createRadialGradient(startX, startY, startR, endX, endY, endR);
图案
用于填充和描画重复图案,调用createPattern(),接受两个参数,第一个参数为<img>或者<video> 和<canvas>,第二个参数为重复模式(repeat-x, repeat-y, repeat, no-repeat)
图像数据
getImageData(startX, startY, width, height)返回一个ImageData对象,每个ImageData包含三个属性width, height, data,其中data中每四个值分别表示第i个像素点的红、绿、蓝和透明度值,取值范围为0-255
合成
| 属性值 | 说明 | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| globalAlpha | 全局透明度,0-1, 用于指定绘制内容的透明度 | ||||||||||||||||||||||
| globalCompositionOperation | 新绘制的形状如何与已有的上下文形状融合
|
4.WebGL
webgl上下文
getContext(‘webgl’);
webgl基础
可以在调用getContext()时传入配置项,指定创建的上下文的一些选项
| 配置项 | 说明 | 默认值 |
|---|---|---|
| alpha | 是否为上下文创建透明通道缓冲区 | true |
| depth | 是否使用16位深缓冲区 | true |
| stencil | 是否使用8位模板缓冲区 | false |
| antialias | 是否使用默认机制执行抗锯齿操作 | true |
| premultipliedAlpha | 绘图缓冲区是否预乘透明度 | true |
| preserveDrawingBuffer | 绘图完成后是否保留绘图缓冲区 | false |
let drawing = document.getElementById("drawing");
// 确保浏览器支持<canvas>
if (drawing.getContext) {let gl = drawing.getContext("webgl", { alpha: false });if (gl) {// 使用 WebGL}
}
1.常量
OpenGL中以GL_开头的常量大部分都被webGL支持,但不需要这个前缀
gl.COLOR_BUFFER_BIT // GL_COLOR_BUFFER_BIT
2.方法命名
参数数量(1-4)+数据类型(‘f’, ‘i’)如, gl.uniform4f()
3.准备绘图
绘图之前,需要使用clearColor(r, g, b, a) 使用一种颜色清除<canvas>元素, rgba参数值都在0-1;
也可以使用gl.clear(gl.COLOR_BUFFER_BIT)使用之前定义的颜色填充画图
4.视口与坐标
默认情况下,视口为整个canvas区域,也可以使用viewport()方法改变视口
gl.viewport(x, y, width, height)
定义视口的坐标系统是canvas像素坐标系统,而视口中,中心点是原点(0,0),左下角是(-1,-1),右上角是(1,1)。
5.缓冲区
const buffer = gl.createBuffer(); // 创建缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); // 将缓冲区绑定到上下文中,此处是将buffer与ARRAY_BUFFER绑定,将buffer设置为当前上下文的缓冲区
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0.5,1]), gl.STATIC_DRAW); // 将数据写入缓冲区第三个参数可以有3个选择
/**
gl.STATIC_DRAW 数据加载一次,可以在多次绘制中使用
gl.STREAM_DRAW 数据加载一次,只能在几次绘制中使用
gl.DYNAMIC_DRAW 数据可以重复修改,在多次绘制中使用
**/
// 不再需要缓冲区
gl.deleteBuffer(buffer);
6.错误
webGL操作中通常不会抛出错误,gl.getError()方法会返回一个常量,表示发生的错误类型
| gl.NO_ERROR | 没有发生错误 |
| gl.INVALID_ENUM | 上一次操作没有传入webgl预定的常量 |
| gl.INVALID_VALUE | 上一次操作需要无符号数值,但是传入了负数 |
| gl.INVALID_OPERATION | 上一次操作在当前状态下无法完成 |
| gl.OUT_OF_MEMORY | 上次操作因内存不足无法完成 |
| gl.CONTEXT_LOST_WEBGL | 上次操作因外部事件而丢失了上下文 |
7.着色器
定点着色器将3D顶点绘制为2D的点;
片元着色器将计算每个像素的颜色值;
使用GLSL编程
编写着色器
每个着色器有一个main()方法,绘制期间反复执行,
给着色器传递数据的方式有两种attribute和uniform
attribute将定点传入定点着色器,uniform将任意常量值传入任意着色器
创建着色器程序
gl.createShader(shaderType); // shaderType: gl.VERTEX_SHADER, gl.FRAGMENT_SHADER 创建着色器
gl.shaderSource(shader, shaderSource);// 将glsl代码应用于着色器
gl.compileShader(shader); // 编译着色器const program = gl.createProgram(); // 创建着色器程序
gl.attachShader(program, shader); // 将着色器添加到着色器程序,需要调用两次分别传入定点着色器和片元着色器
gl.linkProgram(program); // 将两个着色器链接到变量program
gl.useProgram(program); // 让webgl上下文使用该程序
给着色器传值
// 1.找到接受值的变量位置
let uColorLocation = gl.getUniformLocation(program, 'uColor'); // 针对uniform变量uColor
let aVertextPosLocation = gl.getAttribLocation(program, 'aVertextPosition'); // 针对attribute变量aVertexPosition
// 2.传值
// 针对uniform变量
gl.uniform4fv(uColorLocation, [0,0,0,1]);
// 针对attribte变量
gl.enableVertexAttribArray(aVertexPosLocation);
gl.vertexAttribPointer(aVertexPosLocation, itemSize, gl.FLOAT, false, 0, 0) ; // 创建一个指向bindBuffer()指定的缓冲区指针,并保存在aVertexPosLocation中,
8.绘图
webGL只能绘制3中基本图形:点、线、三角形
绘图方法有两种:
drawArrays()使用数组缓冲区
drawElements()操作元素数组缓冲区
drawArrays()接受三个参数,第一个参数表示形状,第二个参数是数组缓冲区的起点索引,第三个参数是数组缓冲区顶点集合的数量
形状参数列表:
| 参数 | 意义 |
|---|---|
| gl.POINTS | 将每个顶点当做一个点 |
| gl.LINES | 将数组作为一系列点,每两个点依次绘制直线,顶点数必须是偶数 |
| gl.LINE_LOOP | 将数组作为一系列顶点,依次依次绘制直线连接成封闭形状 |
| gl.LINE_STRIP | 类似于gl.LINE_LOOP,区别在于最后不会连接终点和起点 |
| gl.TRIANGLES | 将数组作为一系列顶点,在这些顶点间绘制三角形,每个三角形都不会共享顶点 |
| gl.TRIANGLES_STRIP | 类似于gl.TRIANGLES,区别在于共享点,如果有ABCD四个点,则会绘制两个三角形ABC和BCD |
| gl.TRIANGLES_FAN | 如果有ABCD四个点,则会绘制ABC, ACD三角形 |
/****** 绘制一个三角形 ******/const canvas = document.querySelector('#canvas');const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');const vSource = `attribute vec4 a_position;void main(){gl_Position = a_position;}`;const fSource = `precision highp float;uniform vec4 uColor;void main(){gl_FragColor = uColor;}`;const program = gl.createProgram();const vShader = gl.createShader(gl.VERTEX_SHADER);gl.shaderSource(vShader, vSource);gl.compileShader(vShader);const fShader = gl.createShader(gl.FRAGMENT_SHADER);gl.shaderSource(fShader, fSource);gl.compileShader(fShader);gl.attachShader(program, vShader);gl.attachShader(program, fShader);gl.linkProgram(program);gl.useProgram(program);const uColorLocation = gl.getUniformLocation(program, 'uColor');gl.uniform4f(uColorLocation, 1, 0, 0, 0.5);const positionData = [0.5, 0, 0, 0, 0.5, 0, -0.5, -0.5, 0.5];const positionBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positionData), gl.STATIC_DRAW);const positionLocation = gl.getAttribLocation(program, 'a_position');gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(positionLocation);gl.clearColor(0,1,1,1);gl.clear(gl.COLOR_BUFFER_BIT)gl.drawArrays(gl.TRIANGLES, 0, 3);
纹理
纹理的来源可以是图片、<video>或者<canvas>
let image = new Image(),texture;
image.src = "smile.gif";
image.onload = function() {texture = gl.createTexture(); // 创建纹理gl.bindTexture(gl.TEXTURE_2D, texture); // 绑定缓冲区gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); // 设置存储格式gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);// 除当前纹理gl.bindTexture(gl.TEXTURE_2D, null);
}
读取像素
// 读取(0,0)到(25,25)区域的像素,并写入pixels数组,rgba四值,0-255
let pixels = new Uint8Array(25*25);
gl.readPixels(0, 0, 25, 25, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
相关文章:
十八、动画与canvas
1.RequestAnimationFrame 早期定时动画 setTimeout和setInterval不能保证时间精度,第二个参数只能保证何时将代码添加到浏览器的任务队列 requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用 function updateProgress(){const div document.getElementById(d…...
自动化测试学习-Day4-selenium的安装和8种定位方法
哈喽,大家好! 本人21年毕业,软件工程专业,毕业后一直从事金融行业的软件测试。 希望大家一起见证一名卑微测试的成长之路。 目录 一、环境准备 1.浏览器下载 2.浏览器驱动下载 3.下载selenium 二、Selenium定位元素的8种方法…...
【Kubernetes】第二十五篇 - 布署 nodejs 后端项目(下)
一,前言 上一篇,介绍了部署后端项目之前,需要的准备的相关配置信息; 本篇,创建 Deployment、Service 完成后端项目布署; 二,解决 jenkins 安全问题 构建 docker 镜像之后,登录 do…...
贪心算法之区间问题总结
一、跳跃游戏跳跃游戏类的问题,不关心每一步怎么跳,只需要关心最大覆盖范围这里注意i是在当前最大可覆盖范围内遍历,如{2,1,0,1},就是在0~2范围内遍历,千万不能0~numsSize-1范围内遍历!!&#x…...
无线WiFi安全渗透与攻防(七)之WIFI07-WEP-wifite自动化渗透WEP加密
WIFI07-WEP-wifite自动化渗透WEP加密 1.wifite介绍 wifite是一款自动化wep、wpa以及wps破解工具,不支持windows和osx。wifite的特点是可以同时攻击多个采用wep和wpa加密的网络。wifite只需简单的配置即可自动化运行,期间无需人工干预。 目前支持任何li…...
震撼,支持多模态模型的ChatGPT 4.0发布了
最近几个月,互联网和科技圈几乎ChatGPT刷屏了,各种关于ChatGPT的概念和应用的帖子也是围绕在周围。当去年年底ChatGPT发布的那几天,ChatGPT确实震撼到了所有人,原来AI还可以这么玩,并且对国内的那些所谓的人工智能公司…...
IDEA常用插件列表
一 背景 IDEA常用插件列表,用来提供工作效率。你都安装了吗 IntelliJ IDEA 默认安装并提供了非常多的工具,比如 Maven Integration、Markdown support、SSH Remote Run 等。其中有很多好用,但是不为人知的工具。 二 插件列表 阿里代码规约…...
比df更好用的命令!
大家好,我是良许。 对于分析磁盘使用情况,有两个非常好用的命令:du 和 df 。简单来说,这两个命令的作用是这样的: du 命令:它是英文单词 disk usage 的简写,主要用于查看文件与目录占用多少磁…...
【Git使用学习】记录学习过程(1)
安装就省略了,安装结果如下。 Git Bash:这是一个模拟Linux环境的命令行工具,可以使用Git的所有功能。Git GUI:这是一个图形化界面的工具,可以方便地执行Git的常用操作。Git CMD:这是一个Windows命令行工具&…...
K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示
K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCMQ2传感参模块1.2、STM32F103C8T6MQ2传感参模块五、基础知识学习与相关…...
【云原生·Docker】常用命令
目录 🍁1、管理命令 🍁2、帮助命令 🍁3、镜像命令 🍁4、容器命令 🍂4.1.查看容器 🍂4.2.创建容器 🍂4.3.删除容器 🍂4.4.拷贝文件 🍂4.5.查看容器IP 🍁5、部署…...
户外露营储能电源芯片CSU3AF10
户外露营的项目有很多,随着户外储能电源的发展,越来越多的电子产品可以在户外使用,也不用担心因为在户外时间过长而手机或者其他电子产品电量耗尽。户外储能电源可保证人们随时随地的用电需求,同时也可以满足家电炊具的供电需求&a…...
无线WiFi安全渗透与攻防(八)之WEP-Hirte渗透WEP加密
WEP-渗透WEP新思路–Hirte 1.Hirte介绍 Hirte是破解无线网络WEP Key的一种攻击类型 只要客户端设备(笔记本电脑,手机等)连接过的无线网络,那些WIFI即使是不在攻击者范围内也都能被破解,因为该wifi的WEP密钥和配置文…...
前端常考面试题整理
display:none与visibility:hidden的区别 这两个属性都是让元素隐藏,不可见。两者区别如下: (1)在渲染树中 display:none会让元素完全从渲染树中消失,渲染时不会占据任何空间;visibility:hidden不会让元素…...
二十二、身份验证与权限
一、 准备工作 为了讲清楚身份验证与权限,我们再创建一个应用projects,设计模型如下: class Project(models.Model):name models.CharField(项目名称, max_length20, help_text项目名称)desc models.CharField(项目描述, max_length200, help_text项目…...
k8s pod 升级与回滚
当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有pod,然后下载新版本镜像并创建新的pod。如果集群规模比较大,则这个工作变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。kubernet…...
【Go】Go语言开发环境安装
【Go】Go语言开发环境安装 导入 安装环境:Winowds 我现在是win7安装的,与win10整体步骤是一样的,只是部分显示的时候有点差异不影响; 【名词】 编译器:先将代码编译成可执行文件,再执行; —…...
el-switch使用
效果图: 1.表格代码,给el-waitch加上change事件 <el-table-column prop"status" label"状态" align"center" width"150"> <template slot-sc…...
【算法入门】字符串基础
目录 一.字符串引言1.字符串基础二.洛谷P5734详解1.字符串相关库函数💫(1) strcpy函数 💫💫(2) strcat函数 💫💫(3)strstr函数 💫2.题…...
前端面试题 —— 浏览器原理(二)
目录 一、有哪些可能引起前端安全的问题? 二、网络劫持有哪几种,如何防范? 三、浏览器渲染进程的线程有哪些 四、僵尸进程和孤儿进程是什么? 五、为什么需要浏览器缓存? 六、对浏览器的理解 七、CSS 如何阻塞文档解析&…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
未授权访问事件频发,我们应当如何应对?
在当下,数据已成为企业和组织的核心资产,是推动业务发展、决策制定以及创新的关键驱动力。然而,未授权访问这一隐匿的安全威胁,正如同高悬的达摩克利斯之剑,时刻威胁着数据的安全,一旦触发,便可…...
