【测试开发】自动化测试 selenium 篇

目录

一. 什么是自动化测试

二. selenium

1. selenium的工作原理 

2. selenium+Java的环境搭建(Chrome浏览器)

 三. selenium中常用的API

1. 定位元素 findElement

1.1 css选择语法 

1.2 xpath

2. 操作测试对象

2.1  sendKeys-在对象上模拟按键输入

2.2 click-点击对象

2.3 clear-清除对象输入的文本内容

2.4 submit-提交 

2.5 getText()-获取元素的文本信息

2.6 getAttribute("对应属性")-获取元素的属性信息 

2.7 场景分析

2.8 sleep-强制等待

2.9 智能等待中的隐式等待

2.10 智能等待中的显式等待 

2.11 显式等待和隐式等待的区别 

2.12 获取页面的 URL 和 title 

3. 浏览器的操作

3.1 浏览器前进后退和刷新

3.2 浏览器滚动条的操作 

3.3 窗口的最大化,满屏,和设置像素大小

3.4 代码演示: 

4. 键盘的操作

5. 鼠标操作

6. 对多选框和单选框进行区分选择 

7. 多层框架定位

8. 下拉框处理

9. 针对 alter 弹窗的一个操作

10. 上传文件

11. 关闭浏览器

12. 切换窗口操作 

13. 截图操作


一. 什么是自动化测试

自动化测试通俗一些来讲,就是相当于将人工测试手段进行转换,让代码去自动执行。
自动化测试主要分为:单元测试,接口测试,UI测试;

本篇文章先对于UI自动化测试中的 web 测试的 selenium 测试框架进行讲解; 

UI自动化测试是可以大大提高测试效率的,例如版本的更新,是需要进行大量的回归测试的,随着版本的更新,功能会越来越多,而每一次版本更新都进行手动测试,显然不太现实,效率也很低下,此时就可以使用自动化来进行回归测试,可以来代替大部分的手动测试,减少重复测试的时间。 

二. selenium

selenium是用来做web自动化测试框架;适用于多种语言,多种浏览器和多种平台,有着丰富的API; 

1. selenium的工作原理 

编写自动化脚本代码,发送请求给 webdrive浏览器驱动,由 webdrive浏览器驱动进行解析后,发送给浏览器进行执行,再将结果依次返回。

2. selenium+Java的环境搭建(Chrome浏览器)

1. 先确定Chrome当前的版本,然后下载对应版本的Chrome浏览器驱动:https://chromedriver.chromium.org/downloads

 2. 解压下载好的驱动压缩包,将下载好的Chromedriver.exe放大Java系统环境变量下 ,也就是jdk所在环境下。

 

 3. 验证环境是否搭建成功,需要在Java项目中引入selenium依赖,进入  Maven Repository: Search/Browse/Explore (mvnrepository.com) 查找 selenium 对应的依赖,然后添加到 pom 文件中。

4. 执行代码,如果打开了浏览器,则说明环境搭建成功,此时就是借助驱动程序来打开浏览器,并执行。

public class Test {public static void main(String[] args) {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("https://www.baidu.com");}
}

如果pom.xml中引入的是selenium3版本或以上的话,可以直接写

WebDriver webDriver = new ChromeDriver();

webDriver.get("https://www.baidu.com"); 

 三. selenium中常用的API

1. 定位元素 findElement

( findElement() 只返回一个WebElement,而 findElements() 返回类型为 List<WebElement> ) 

 主要有两种方式,一种是 css选择语法 ,另一种是 xpath ;

 返回类型都为  WebElement

 1.  WebElement element = webDriver.findElement(By.cssSelector("css选择器"));

 2.  WebElement element = webDriver.findElement(By.xpath("xpath路径"));

1.1 css选择语法 

1. id选择器:#id

2. 类选择器:.class

3. 标签选择:标签名

4. 后代选择器:父级选择器 子级选择器 

1.2 xpath

1. 绝对路径:例如:/html/head/title 但这种方法一般不用 ;

2. 相对路径 :

相对路径  + 索引 ://form/span[1]/input

相对路径 + 属性值 ://input [@class=""]

相对路径 + 通配符://*[@*=""]

相对路径 + 文本匹配://a[text()=""]

绝对路径下: (如果是该路径下同一个标签有多个,可以用[n]进行选择,默认从1开始;后同)

 相对路径1:

 相对路径2:

 相对路径3:

 相对路径4:

 在定位元素的时候,也通常可以直接从后台管理中去复制:

从整体来看,css选择器定位元素效率是要比xpath更高的,所以一般也更推荐css选择器法;因为css选择器是浏览器原生支持的,而Xpath需要引入额外的解析器来解析xpath表达式。

2. 操作测试对象

 2.1  sendKeys-在对象上模拟按键输入

webElement.sendKeys(" "); 

 2.2 click-点击对象

 webElement.click();

2.3 clear-清除对象输入的文本内容

 webElement.clear();

2.4 submit-提交 

 webElement.submit();

如果点击的元素在form标签中,此时submit实现的效果是和click一样的,如果点击的元素放  在非form标签中,此时使用submit会报错,所以一般还是使用 click 更好一些。

2.5 getText()-获取元素的文本信息

webElement.getText(); 

2.6 getAttribute("对应属性")-获取元素的属性信息 

webElement.getAttribute();

getText 只能获取到标签之间的对应值 eg: <a> 111 </a>,而不能获取属性值 eg: <a value = "111"> </a>,所以就有了 getAttribute("对应的属性")获取属性值;

2.7 场景分析

在进行登录自动化测试的时候,验证码无法获取到,要怎么去测试?

答:可以在自动化测试账号加一个白名单,设定一个账号,当使用这个账号登录的时候,此时就不需要要验证码处理; 

2.8 sleep-强制等待

sleep(ms); 

2.9 智能等待中的隐式等待

隐式等待 等待的是所有的元素生成,如果超过设定的时间,还没生成就会报错,一旦生成获取到页面上的元素,就会继续往下执行。

webDrive.manage().timeouts().implicitlyWait( 单位长度 ,  TimeUnit类型(包含秒,分钟,小时...) ); 

例如如下语句表示隐式等待 3小时

webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.HOURS);

2.10 智能等待中的显式等待 

显式等待 等待的是对应的条件,条件满足了则继续往下执行,等待时间到了还没满足条件那么就会报错。

WebDriverWait wait = new WebDriverWait(WebDriver driver, long timeOutInSeconds);

wait.until(Function<? super T, V> isTrue);

eg:如下代码表示的是:在显式等待三秒中 ,如果满足页面中的 title 是"百度一下,你就知道",那么就继续往下执行,如果显式等待三秒后,条件依旧不满足,则报错。

WebDriverWait wait = new WebDriverWait(webDriver,3); wait.until(ExpectedConditions.titleIs("百度一下,你就知道"));

2.11 显式等待和隐式等待的区别 

因此我们也可以得知,智能等待中显式等待和隐式等待的区别:

隐式等待等待的是所有的元素;

显式等待等待的是一定的条件,这个条件也是由程序员自定义的;

2.12 获取页面的 URL 和 title 

webDrive.getCurrentUrl() 和 webDrive.getTitle() ;

3. 浏览器的操作

 3.1 浏览器前进后退和刷新

webDriver.navigate().back();          // 浏览器后退

webDriver.navigate().refresh();          // 浏览器刷新

webDriveer.navigate().forward();            // 浏览器前进

3.2 浏览器滚动条的操作 

浏览器滚动条的操作需要借助转换 JS 来执行;

((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=高度"); 

3.3 窗口的最大化,满屏,和设置像素大小

webDriver.manage().window().maximize();        // 窗口最大化

webDriver.manage().window().fullscreen();        // 窗口满屏

weebDriver.manage().window().setSize(new Dimension(width,height));        // 设置像素大小

3.4 代码演示: 

    private static void test07() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com");webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);// 浏览器后退webDriver.navigate().back();                    // navigate 表示导航sleep(3000);// 刷新webDriver.navigate().refresh();sleep(3000);// 浏览器前进webDriver.navigate().forward();sleep(3000);// 浏览器的滚动条,需要借助转换 JS 来执行((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=10000");// 窗口最大化webDriver.manage().window().maximize();sleep(2000);// 窗口满屏webDriver.manage().window().fullscreen();sleep(3000);// 设置像素点webDriver.manage().window().setSize(new Dimension(1000,1000));}

4. 键盘的操作

在sendKeys的基础上操作:

例如要输入ctrl+A:sendKeys(Keys.CONTROL,"A");

代码演示:

private static void test08() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com");webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");// 键盘操作   Keys.// ctrl + AwebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"A");sleep(1000);// ctrl + XwebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"X");sleep(1000);// ctrl + VwebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"V");sleep(1000);}

5. 鼠标操作

通过 Actions 对象来操作:Actions actions = new Actions(webDriver);

鼠标右击:contextClick();

鼠标双击:doubleClick(); 

鼠标移动:moveToElement(webElement);

执行行为:perform();

场景设计:在百度这个页面中,搜索 "520" ,点击百度进行搜索,然后对页面中的 图片超链接 进行右击;  注意最后要进行  perform() 进行执行!!!

private static void test09() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("http://www.baidu.com");webDriver.findElement(By.cssSelector("#kw")).sendKeys("520");webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);// 找到图片这个按钮WebElement webElement = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-pic"));// 鼠标右击Actions actions = new Actions(webDriver);// 先移动到对应的元素,然后右击,最后执行,注意要加上perform执行sleep(3000);actions.moveToElement(webElement).contextClick().perform();}

6. 对多选框和单选框进行区分选择 

在如下页面中,实现对多选框( type = checkbox )进行选择,单选框( type = radio )不选择。 

代码实现: 

private static void page01() {WebDriver webDriver = new ChromeDriver();webDriver.get("");    // 对应页面// 由于有些页面找的元素有些多,害怕有些元素渲染不出来,可以进行一个隐式等待(智能)webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.DAYS);List<WebElement> webElements = webDriver.findElements(By.cssSelector("input"));for (int i = 0; i < webElements.size(); i++) {// 如果元素type值等于checkbox进行点击// getAttribute 来获取页面上元素的属性值,里面的 type 是当前元素属性,返回值就为对应的属性值if (webElements.get(i).getAttribute("type").equals("checkbox")){webElements.get(i).click();}else {// 否则什么也不操作;}}}

 7. 多层框架定位

对于在 <iframe> 标签下的标签,不可直接通过 findElement 来进行查找并click。 

而应该先通过对应的 id 或者 name 或者iframe自带的其他属性来定位到对应的框架下,此处可以使用 webDriver.switchTo().frame("id属性值");来定位

例如如下页面中,想要对 页面中的 click元素 进行一个点击,通过后台可以看到 click元素 属于<iframe id="f1">,所以此时就应该先定位到对应的框架下,再去 click 。

 代码实现:

   private static void page02() {WebDriver webDriver = new ChromeDriver();webDriver.get("");webDriver.switchTo().frame("f1");     // 参数可以为 要选择的标签 位于的那个<iframe>标签下的 id 属性值(string)webDriver.findElement(By.cssSelector("body > div > div > a")).click();   }

 8. 下拉框处理

对如下页面中的下拉框进行选择,此时需要进行两次定位,先定位到下拉框,对下拉框进行操作,再定位到下拉框中要选择的选项。

首先需要定位到下拉框,然后使用 Select select = new Select(webElement) 对其进行选定,再进行选项的选定。

代码实现: 

private static void page03() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("");WebElement webElement = webDriver.findElement(By.cssSelector("#ShippingMethod"));Select select = new Select(webElement);select.selectByIndex(1);    // 下标从0开始算sleep(3000);select.selectByValue("10.69");  // value属性对应的值}

 9. 针对 alter 弹窗的一个操作

如下页面中,要实现点击 "这是一个弹窗" 后会出现一个弹窗。

实现弹窗取消:webDriver.switchTo().alter().dismiss();

再点击弹窗,进行输入。

最后进行弹窗确认:webDriver.switchTo().alter().accept(); 

 代码实现:

private static void page04() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("");webDriver.findElement(By.cssSelector("button")).click();sleep(3000);// alter弹窗取消webDriver.switchTo().alert().dismiss();sleep(3000);// 点击按钮webDriver.findElement(By.cssSelector("button")).click();// 在 alter 弹窗输入 xxxwebDriver.switchTo().alert().sendKeys("11");// alter弹窗确认sleep(3000);webDriver.switchTo().alert().accept();}

 10. 上传文件

 上传文件的操作较简单,例如下图中实现文件的选择,只需要对 " 选择文件 "进行定位,然后 sendKeys("要选择文件的路径");

 代码实现:

private static void page05() {WebDriver webDriver = new ChromeDriver();webDriver.get("");webDriver.findElement(By.cssSelector("input")).sendKeys("D:\\桌面\\image");}

11. 关闭浏览器

 关闭浏览器,主要有两种方式:

1. webDriver.close(); 这种方式只会关闭一个页面,关闭原始的那个页面,而不会关闭新的页面,也不会清空缓存;

2. webDriver.quit();这种方式会把整个浏览器都关闭,会清空缓存(cookie);

12. 切换窗口操作 

当获取到新的页面后,对于新的页面,无法直接 findElement() 进行定位元素了,因为此时的  findElement() 还是针对第一次 GET 获取到的页面 (首页) 而言的。

所以此时需要对窗口进行定位:通过 webDriver.getWindowHandles() 获取到当前所有的窗口句柄,此时的返回类型为 Set<String> ,里面存放着当前每一个页面的窗口句柄。对这个返回类型进行遍历,所得到的 set 的最后一个元素就是最后一个生成页面的窗口句柄。因此就可以使用 webDriver.switchTo().window(String 对应页面的窗口句柄); 将自动化找元素的操作页面转换为新的页面了,再进行 findElement() 等操作即可;

代码实现: 

private static void test11() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com");webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();sleep(3000);// 直接这样操作是不可行的!!!
//        webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
//        webDriver.findElement(By.cssSelector("#s_btn_wr")).click();// 通过 getWindowHandles 获取所有的窗口句柄// 通过 getWindowHandle 获取的 get 打开的页面窗口句柄System.out.println(webDriver.getWindowHandle());Set<String> handles = webDriver.getWindowHandles();String target_handle = "";for (String handle:handles ) {target_handle = handle;}// 这样遍历到最后 ,对应的 handle 就为对应的页面,也就是最后一个生成的页面webDriver.switchTo().window(target_handle); // 此处的操作就相当于把 自动化找元素的操作的页面转换为新的页面了(target_handle)sleep(3000);// 此时就可以对新生成的页面进行定位操作了webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");webDriver.findElement(By.cssSelector("#s_btn_wr")).click();}

 13. 截图操作

截图操作,需要引入依赖。

可以使用 ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);以文件的形式返回,然后将文件放置对应的路径即可。

<!--        截图--><!-- ht tps://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency>

 代码实现:

private static void test12() throws InterruptedException, IOException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com");webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);// 将文件放到某个位置FileUtils.copyFile(file,new File("D://test_jietu.png"));  // 将file文件放到第二个参数对应的位置}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/752841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

elasticsearch8.12 分词器安装

分词器的主要作用将用户输入的一段文本&#xff0c;按照一定逻辑&#xff0c;分析成多个词语的一种工具 分词器下载地址 analysis-ik Releases infinilabs/analysis-ik GitHub 一个简便 安装方式 安装完成之后 会提示重启&#xff0c;重启es即可 ./bin/elasticsearch-pl…

配置LVS NAT模式

配置LVS NAT模式 环境准备 client1&#xff1a;eth0->192.168.88.10&#xff0c;网关192.168.88.5lvs1: eth0 -> 192.168.88.5&#xff1b;eth1->192.168.99.5web1&#xff1a;eth1->192.168.99.100&#xff1b;网关192.168.99.5web2&#xff1a;eth1->192.168…

基于C语言的“贪吃蛇”游戏设计理念

3.功能描述&#xff1a;本游戏主要实现以下几种功能 图1.游戏功能模块 3.1. 贪吃蛇的控制功能&#xff1a;通过各种条件的判断&#xff0c;实现对游戏蛇的左移、右移、下移、上移、自由移动&#xff0c;贪吃蛇的加长功能。 3.2. 游戏显示更新功能&#xff1a;当贪吃蛇左右移动、…

操作系统笔记之进程调用API中的getpid、fork、wait、exec补充

操作系统笔记之进程调用API中的getpid、fork、wait、exec补充 code review! —— 杭州 2024-03-17 夜 文章目录 操作系统笔记之进程调用API中的getpid、fork、wait、exec补充1.getpid()2.fork()3.wait()4.exec()5.通常&#xff0c;exec() 调用与 fork() 调用一起使用&#xff…

算法笔记p154最大公约数和最小公倍数

目录 最大公约数辗转相除法证明例子代码实现 最小公倍数代码实现 最大公约数 正整数a与b的最大公约数是指a与b的所有公约数中最大的那个公约数&#xff0c;一般用gcd(a, b)表示a和b的最大公约数。 辗转相除法 设a、b均为正整数&#xff0c;则gcd(a, b) gcd(b, a % b)。即被…

【C语言_字符函数和字符串函数_复习篇】

目录 一、字符函数 1.1 字符分类函数 1.2 字符转换函数 二、字符串函数 2.1 strlen函数 2.1.1 strlen函数的使用 2.1.2 strlen函数的模拟实现 2.2 strcpy函数 2.2.1 strcpy函数的使用 2.2.2 strcpy函数的模拟实现 2.3 strcat函数 2.3.1 strcat函数的使用 2.3.2 strcat函数的…

hololens2发布unity设置

生成vs工程再向hololens发布时&#xff0c; Architecture选X64或ARM64都可以成功发布

es索引操作命令

索引操作 index 创建索引 put 方法创建索引 使用 put 创建索引时必须指明文档id&#xff0c;否则报错 # PUT 创建命令 # test1 索引名称 # type1 类型名称&#xff0c;默认为_doc&#xff0c;已经被废弃 # 1 文档id PUT /test1/type1/1 {"name":"zhangsan&…

【leetcode】二叉树的前序遍历➕中序遍历➕后序遍历

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家刷题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1. 二叉树的前序遍历2. 二叉树的中序遍历3. 二叉树的后序遍历 1. 二叉树的前序遍历 点击查看题目 根…

lv17 安防监控项目实战 3

代码目录 框架 our_storage 编译最终生成的目标文件obj 编译生成中间的.o文件 data_global.c 公共资源定义&#xff08;使用在外extern即可&#xff09;定义了锁定义了条件变量消息队列id、共享内存id、信号量id及key值发送短信、接收短信的号码向消息队列发送消息的函数&am…

华为汽车业务迎关键节点,长安深蓝加入HI模式,车BU预计今年扭亏

‍编辑 |HiEV 一年之前&#xff0c;同样是在电动汽车百人会的论坛上&#xff0c;余承东在外界对于华为和AITO的质疑声中&#xff0c;第一次公开阐释了华为选择走智选车模式的逻辑。 一年之后&#xff0c;伴随问界M7改款、问界M9上市&#xff0c;华为智选车模式的面貌已经发生了…

【Maven篇】解锁 Maven 的智慧:依赖冲突纷争下的版本调停者

缘起 软件开发世界是一个充满无限可能的领域&#xff0c;但同时也伴随着诸多挑战。其中之一&#xff0c;就是依赖冲突的问题。在这篇文章中&#xff0c;我们将揭开 Maven 这位“版本调停者”的神秘面纱&#xff0c;深入探讨如何在版本纠纷的盛宴中解决依赖问题。 Maven&#…

RDP爆破

工具&#xff1a;超级弱口令检查工具 第一步&#xff1a;双击打开工具 第二步&#xff1a;导入账号 第三步&#xff1a;导入密码 第三步&#xff1a;线程 线程默认是50&#xff0c;如果担心影响业务可以修改为5 第四步&#xff1a;填写目标 第五步&#xff1a;选择需要检查的…

前端入职配置新电脑!!!

前端岗位入职第一天到底应该做些什么呢&#xff1f;又该怎样高效的认识、融入团队&#xff1f;并快速进入工作状态呢&#xff1f;这篇文章就来分享一下&#xff0c;希望对即将走向或初入前端职场的你&#xff0c;能够有所帮助。内含大量链接&#xff0c;欢迎点赞收藏&#xff0…

jenkins使用公共库问题

Jenkins解决上编译解决引用问题 本地运行 把公共库创建链接到指定项目目录下即可 mklink /d /j D:\codepath\xxxx\yyyyy\tool_base D:\codepath\tool_base

香港公司变更注册地址所需材料及流程全解析

香港公司变更注册地址&#xff1a;所需材料及流程全解析 各位老板好&#xff0c;我是经典世纪胡云帅&#xff0c;随着业务的拓展和发展&#xff0c;香港公司可能需要变更其注册地址。变更注册地址不仅关系到公司的日常运营&#xff0c;还与公司的法律地位和品牌形象息息相关。本…

cesium HeadingPitchRoll HeadingPitchRange

一、HeadingPitchRoll表示Heading、Pitch、Roll&#xff0c;用于orientation属性上的&#xff0c;比如camera的setView&#xff0c;flyTo var heading Cesium.Math.toRadians(0.0);var pitch Cesium.Math.toRadians(-25.0);var roll Cesium.Math.toRadians(0);viewer.camera…

餐饮店引流活动方案与最佳营销方案揭秘

想开实体店或正在创业的朋友们&#xff0c;大家好&#xff01;我是一名资深的实体店创业者&#xff0c;本人经营鲜奶吧5年时间&#xff0c;做的是社区店&#xff0c;今天我将分享一些餐饮店引流活动和营销方案的干货&#xff0c;希望能给大家带来一些启发和帮助。 一、引流活动…

基于多尺度视网膜增强图像去雾算法(MSR,Multi-Scale Retinex),Matalb实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供有偿…

【Flink SQL】Flink SQL 基础概念(四):SQL 的时间属性

《Flink SQL 基础概念》系列&#xff0c;共包含以下 5 篇文章&#xff1a; Flink SQL 基础概念&#xff08;一&#xff09;&#xff1a;SQL & Table 运行环境、基本概念及常用 APIFlink SQL 基础概念&#xff08;二&#xff09;&#xff1a;数据类型Flink SQL 基础概念&am…