【测试报告】思绪网(Java+Selenium+Jmeter自动化测试)

一、项目简介

       思绪网作为一种在线交流平台,支持用户在平台下发布文章,并进行讨论。主要由登录页面,论坛页面,帖子编辑页,帖子详情页等页面组成。

二、项目功能

1.登录页面:输入正确的账号密码进行登录,跳转博客列表页。

2.博客列表页:加载出全部博客,左边显示用户信息与博客信息,右上角可发布新博客、页等按钮,选择一个博客可以进入查看博客详细信息。

3.博客详情页:能查看博客完整内容,当前登录用户查看自己博客有编辑与删除按钮,其余用户仅有查看博客权限。

4.博客编辑页:输入标题、正文选择提交按钮发布博客。

5.更新博客页:现当前需要修改的博客信息(标题,正文),修改完成点击提交按钮。

6.删除博客:在详情页中点击删除博客,可以正确删除,不在出现在列表页。

三、测试计划

(一)功能测试

        1.测试用例设计

2.测试内容
(1)登陆页面

测试用例:

测试用例编号操作账号密码预期结果
1输入正常的账号密码zhangsan123456登录成功
2输入错误的账号和密码tt333登录失败,提示错误
3输入正确的账号和错误的密码zhangsan332登录失败,提示错误
4输入错误的账号和正确的密码tt123456登录失败,提示错误
5不填写账号和密码  登录失败,提示错误
6填写账号不填写密码zhangsan 登录失败,提示错误
7不填写账号填写密码 123456登录失败,提示错误

测试结果:

①测试用例1:

结论:登录成功,跳转至论坛页面,与预期结果一致。

②测试用例2:

结论:显示用户名或密码错误,与预期结果不一致,没有提示账号/密码错误

③测试用例3:

结论:显示密码错误,与预期结果一致

④测试用例4:

结论:显示用户名不存在,与预期结果一致

⑤测试用例5:

结论:显示用户名小于4位,与预期结果一致。

 ⑥测试用例6:

结论:显示密码错误,与预期结果一致。

⑦测试用例7:

结论:显示用户名小于4位,与预期结果一致。

(2)博客列表页面
测试用例编号操作预期结果
1点击Gitee地址可跳转跳转到相应Git地址
2点击查看全文查看博客详情
3点击右上角写博客进入编写博客
4点击右上角注销用户退出
5点击右上角主页回到列表页
6点击右上角发布新博客进入编写博客

①测试用例1:

结论:正常跳转与预期一样

②测试用例2:

结论:与预期结果一样

③测试用例3:

结论:与预期一致

④测试用例4:

结论:与预期一致

⑤测试用例5:

结论:与预期结果一致

⑥测试用例6:

结论:与预期结果一致

(3)博客详情页
测试用例编号操作预期结果
1点击Gitee地址可跳转跳转到相应Git地址
2点击编辑按钮进行更新界面
3点击删除按钮可以删除
4点击右上角注销用户退出
5点击右上角主页回到列表页
6点击右上角发布新博客进入编写博客

①测试用例1:

结论:正常跳转与预期一样

②测试用例2:

结论:正常跳转与预期一样

③测试用例3:

结论:正常跳转与预期一样

④测试用例4:

结论:与预期一致

⑤测试用例5:

结论:与预期结果一致

⑥测试用例6:

结论:与预期结果一致

(4)更新博客
测试用例编号操作预期结果
1只编辑标题点击发布正常发布
2只编辑内容点击发布正常发布
3编辑标题与内容点击发布正常发布
4不编辑标题与内容点击发布正常发布

①测试用例1:

结论:与期望结果一致

②测试用例2:

结论:与期望结果一致

③测试用例3: 

结论:与期望结果一致

④测试用例4: 

结论:与期望结果一致

(5)发布博客
测试用例编号操作预期结果
1只编辑标题点击发布发布失败
2只编辑内容点击发布发布失败
3编辑标题与内容点击发布正常发布
4不编辑标题与内容点击发布发布失败

①测试用例1: 

结论:发布失败,与期望结果一致。

正文内容是系统默认的,需要正文内容不为空和不是默认的才可以进行发布

②测试用例2: 

结论:与期望结果一致

③测试用例3: 

结论:与期望结果一致

④测试用例4: 

结论:发布失败,与期望结果一致。

正文内容是系统默认的,需要正文内容不为空和不是默认的才可以进行发布

(二)自动化测试(Java)

1.测试环境

系统:windows11

浏览器:Chrome137.0.7151.119

测试工具:IntelliJ IDEA 2025.1.2

2.测试内容
(1)项目结构

(2)工具类Utils
public class Utils {public static WebDriver driver = null;public static WebDriverWait wait = null;public static String blogDetailUrl = "http://1.94.188.69:9090/blog_detail.html?blogId=3";public Utils(String url) {driver = createDriver();driver.get(url);wait = new WebDriverWait(driver, Duration.ofSeconds(3));}public static WebDriver createDriver() {if (driver == null) {WebDriverManager.chromedriver().setup();ChromeOptions options = new ChromeOptions();Map<String, Object> prefs = new HashMap<>();prefs.put("credentials_enable_service", false);prefs.put("profile.password_manager_enabled", false);prefs.put("password_manager_leak_detection", false);prefs.put("profile.default_content_settings.popups", 0);options.setExperimentalOption("prefs", prefs);options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));}return driver;}public void screenShot(String str) {try {SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");String dirTime = sim1.format(System.currentTimeMillis());String fileTime = sim2.format(System.currentTimeMillis());String fileName = "./src/test/java/images/" + dirTime + "/" + str + "_" + fileTime + ".png";File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);FileUtils.copyFile(srcFile, new File(fileName));} catch (IOException e) {e.getMessage();}}public String createTime() {SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SS");String curTime = sim.format(System.currentTimeMillis());return curTime;}public static void quit() {if (driver != null) {driver.quit();driver = null; // 重置引用}}}
(3)登录界面类BlogLoginPage
public class BlogLoginPage extends Utils {public static String url = "http://1.94.188.69:9090/blog_login.html";public BlogLoginPage() {super(url);}public void checkPageRight() {driver.findElement(By.cssSelector("body > nav > div > div.flex.items-center.space-x-3"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(1)"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(2)"));driver.findElement(By.cssSelector("#username"));driver.findElement(By.cssSelector("#password"));driver.findElement(By.cssSelector("#submit"));driver.findElement(By.cssSelector("body > div"));screenShot("BlogLoginPage_checkPageRight");}public void checkPublishButton() {driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(2)")).click();driver.findElement(By.cssSelector("#submit"));screenShot("BlogLoginPage_checkPublishButton");driver.navigate().back();}public void checkErrorLogin() {driver.findElement(By.cssSelector("#username")).sendKeys("ssssss");driver.findElement(By.cssSelector("#password")).sendKeys("gssaf");driver.findElement(By.cssSelector("#submit"));screenShot("BlogLoginPage_checkErrorLogin");}public void checkCorrectLogin() {driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");driver.findElement(By.cssSelector("#password")).sendKeys("123456");screenShot("BlogLoginPage_checkCorrectLogin");driver.findElement(By.cssSelector("#submit")).click();driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.mb-8.flex.justify-between.items-center > a"));screenShot("BlogLoginPage_checkCorrectLogin");}}
(4)博客列表页界面类BlogListPage
public class BlogListPage extends Utils {public static String url = "http://1.94.188.69:9090/blog_list.html";public BlogListPage() {super(url);}public void CheckPageRight() {String title = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > div.title.text-xl.font-bold.text-slate-800.hover\\:text-primary.transition-custom.mb-2")).getText();String createTiem = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > div.date.text-slate-500.text-sm.flex.items-center.mb-4")).getText();String content = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > div.desc.text-slate-600.line-clamp-3.mb-4")).getText();String button = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > a")).getText();String text = driver.findElement(By.cssSelector("body > div > div > div.left.md\\:w-1\\/4.lg\\:w-1\\/5 > div > div.px-6.pb-6.-mt-12 > h3")).getText();String git = driver.findElement(By.cssSelector("body > div > div > div.left.md\\:w-1\\/4.lg\\:w-1\\/5 > div > div.px-6.pb-6.-mt-12 > a")).getText();driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a.nav-span.text-primary.font-medium.flex.items-center.gap-1\\.5"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a.nav-span.text-slate-600.hover\\:text-primary.transition-custom.flex.items-center.gap-1\\.5"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a.nav-span.text-slate-600.hover\\:text-red-500.transition-custom.flex.items-center.gap-1\\.5"));assert !title.isEmpty();assert !createTiem.isEmpty();assert !content.isEmpty();assert !text.isEmpty();assert !git.isEmpty();assert button.equals("查看全文");screenShot("BlogListPage_" + "CheckPageRight");}public void CheckPageGitAndPush() {//检查git按钮String beforHandle = driver.getWindowHandle();driver.findElement(By.cssSelector("body > div > div > div.left.md\\:w-1\\/4.lg\\:w-1\\/5 > div > div.px-6.pb-6.-mt-12 > a")).click();String lastHandle = driver.getWindowHandle();List<String> list = driver.getWindowHandles().stream().toList();for (String handle : list) {if (!list.equals(beforHandle)) {driver.switchTo().window(handle);}}screenShot("BlogListPage_" + "CheckPageGitAndPush");driver.switchTo();driver.close();driver.switchTo().window(beforHandle);driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(2)")).click();String title = driver.findElement(By.cssSelector("body > div > div > div.mb-6.animate-fade-in > h1")).getText();assert title.equals("编辑博客");driver.navigate().back();}public void CheackDteail() {String beforTitle = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > div.title.text-xl.font-bold.text-slate-800.hover\\:text-primary.transition-custom.mb-2")).getText();driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > a")).click();String lastTitle = driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-b.border-slate-100 > h1")).getText();assert beforTitle.equals(lastTitle);blogDetailUrl = driver.getCurrentUrl();driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(1)")).click();}
}
(5)详情页界面类BlogDetailPage
public class BlogDetailPage extends Utils {public static String url = blogDetailUrl;public BlogDetailPage() {super(url);}public void checkDetailRight() {String buttonEdit = driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-t.border-slate-100.bg-slate-50\\/50 > div.operating.flex.flex-wrap.gap-4 > button.bg-primary.hover\\:bg-primary\\/90.text-white.px-5.py-2\\.5.rounded-lg.transition-custom.flex.items-center.gap-1\\.5.shadow-sm.btn-hover")).getText();String title = driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-b.border-slate-100 > h1")).getText();String text = driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.detail-content")).getText();String buttonDelete = driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-t.border-slate-100.bg-slate-50\\/50 > div.operating.flex.flex-wrap.gap-4 > button.bg-red-500.hover\\:bg-red-600.text-white.px-5.py-2\\.5.rounded-lg.transition-custom.flex.items-center.gap-1\\.5.shadow-sm.btn-hover")).getText();driver.findElement(By.cssSelector("body > div > div > div.left.md\\:w-1\\/4.lg\\:w-1\\/5 > div > div.px-6.pb-6.-mt-12"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(1)"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a:nth-child(2)"));driver.findElement(By.cssSelector("body > nav > div > div.hidden.md\\:flex.items-center.space-x-6 > a.nav-span.text-slate-600.hover\\:text-red-500.transition-custom.flex.items-center.gap-1\\.5"));assert buttonEdit.equals("编辑");assert buttonDelete.equals("删除");assert !title.isEmpty();assert !text.isEmpty();driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-t.border-slate-100.bg-slate-50\\/50 > div.operating.flex.flex-wrap.gap-4 > button.bg-primary.hover\\:bg-primary\\/90.text-white.px-5.py-2\\.5.rounded-lg.transition-custom.flex.items-center.gap-1\\.5.shadow-sm.btn-hover")).click();String upPageTitle = driver.findElement(By.cssSelector("#title")).getText();assert title.equals(upPageTitle);}public void DetalUpdatepage() {String beforeTitle=driver.findElement(By.cssSelector("#title")).getText();//更新driver.findElement(By.cssSelector("#title")).clear();driver.findElement(By.cssSelector("#title")).sendKeys("自动化更新标题:" + createTime());driver.findElement(By.cssSelector("#submit")).click();String lastTitle = driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > div.title.text-xl.font-bold.text-slate-800.hover\\:text-primary.transition-custom.mb-2")).getText();assert !beforeTitle.equals(lastTitle);}public void DetalDetelepage() {driver.findElement(By.cssSelector("body > div > div > div.right.flex-1 > div.space-y-6.blog-list > div:nth-child(1) > a")).click();//删除driver.findElement(By.cssSelector("#blog-content > div.p-6.md\\:p-8.border-t.border-slate-100.bg-slate-50\\/50 > div.operating.flex.flex-wrap.gap-4 > button.bg-red-500.hover\\:bg-red-600.text-white.px-5.py-2\\.5.rounded-lg.transition-custom.flex.items-center.gap-1\\.5.shadow-sm.btn-hover")).click();wait.until(ExpectedConditions.alertIsPresent());Alert alert = driver.switchTo().alert();alert.accept();wait.until(ExpectedConditions.alertIsPresent());alert = driver.switchTo().alert();alert.accept();}
}
(6)博客编辑类BlogEditPage
public class BlogEditPage extends Utils {public static String url = "http://1.94.188.69:9090/blog_edit.html";public BlogEditPage() {super(url);}public void checkEditPage() {String editNoun = driver.findElement(By.cssSelector("body > div > div > div.mb-6.animate-fade-in > h1")).getText();driver.findElement(By.cssSelector("#submit"));driver.findElement(By.cssSelector("body > nav > div"));driver.findElement(By.cssSelector("body > div > div > div.mb-6.animate-fade-in > p"));driver.findElement(By.cssSelector("#title"));driver.findElement(By.cssSelector("#editor > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div"));assert editNoun.equals("编辑博客");//driver.findElement(By.cssSelector("#title")).clear();}public void EditText() {driver.findElement(By.cssSelector("#title")).sendKeys("自动化创建博客标题:" + createTime());// 定位 CodeMirror 编辑器元素WebElement element = driver.findElement(By.cssSelector("#editor > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div"));// 构建输入内容String content = "自动化内容生成:" + createTime() + "\n" +"自动化内容生成:" + createTime() + "\n" +"自动化内容生成:" + createTime() + "\n" +"自动化内容生成:" + createTime();// 清除现有内容并输入新内容new Actions(driver)// 移动到编辑器并点击获取焦点.moveToElement(element).click()// 全选内容(兼容多平台).keyDown(System.getProperty("os.name").contains("Mac") ? Keys.COMMAND : Keys.CONTROL).sendKeys("a").keyUp(System.getProperty("os.name").contains("Mac") ? Keys.COMMAND : Keys.CONTROL)// 删除选定内容.sendKeys(Keys.DELETE)// 添加短暂等待确保删除完成.pause(Duration.ofMillis(200))// 输入新内容.sendKeys(content)// 确保输入完成后按回车结束.sendKeys(Keys.ENTER).perform();driver.findElement(By.cssSelector("#submit")).click();wait.until(ExpectedConditions.alertIsPresent());Alert alert = driver.switchTo().alert();alert.accept();}
}
(7)Main函数
public class RunTests {public static void main(String[] args) throws InterruptedException {//登录界面BlogLoginPage blogLoginPage = new BlogLoginPage();blogLoginPage.checkPageRight();         //检查界面元素是否加载正常blogLoginPage.checkPublishButton();     //检查博客按钮是否正常blogLoginPage.checkErrorLogin();        //账号与密码错误时blogLoginPage.checkCorrectLogin();      //账号与密码正确时//博客列表界面BlogListPage blogListPage = new BlogListPage();blogListPage.CheckPageRight();  //检查界面元素是否加载正常blogListPage.CheckPageGitAndPush();//检查git与发布按钮是否可以跳转blogListPage.CheackDteail();     //进入详情页//博客更新/删除BlogDetailPage blogDetailPage = new BlogDetailPage();blogDetailPage.checkDetailRight();blogDetailPage.DetalUpdatepage();blogDetailPage.DetalDetelepage();//编辑博客BlogEditPage blogEditPage = new BlogEditPage();blogEditPage.checkEditPage();blogEditPage.EditText();Utils.quit();}
}

(三)性能测试 

使用JMeter工具对论坛系统的接口进行简单的性能测试:

1.添加HTTP相关接口信息添加以及HTTP头文件管理器

   (1)登录接口测试

以JSON格式发送

添加CSV文件,可以保证多个用户轮流登录

(2)博客列表接口测试

添加基本接口信息

写的token进行请求接口

配置JSON提取器,方便其他接口访问当前信息

(3)博客详情页接口测试

(4)更新博客接口测试

(5)发布博客接口

(6)删除接口测试

2.添加同步定时器

3.压力性能测试报告

一、核心指标概览

        1、测试基础信息

测试脚本:test.jmx

持续时间:仅1分钟(11:54 PM → 11:55 PM),时长过短可能导致数据偶然性。

总请求量:1974次(平均并发≈33请求/秒)

        2、成功率与失败率

通过率:99.8%(1970次成功)

失败率:0.2%(4次失败)

二、深度问题诊断

        1. 错误分析(致命问题)

错误类型

次数

影响接口

根本原因

java.net.SocketException

3

登录接口

​​TCP连接超时​​

HttpHostConnectException

1

登录接口

目标服务器无响应

错误细节:

Connect to 1.94.188.69:9090 failed: Connection timed out

问题定位:

目标服务器 1.94.188.69:9090 的网络连通性故障或端口阻塞

服务器过载未及时响应(登录接口响应中位数达 18.4秒!)

        2. 登录接口性能瓶颈

指标

登录接口

其他接口(对比)

请求次数

343

≈325次/接口

错误次数

​​3​​

≤1

响应中位数

​​18415ms​​

约2ms~5ms

P95响应时间

​​3388ms​​

<10ms

结论:

登录接口存在严重性能缺陷(响应延迟高达18秒)

错误率0.87%(远超其他接口0%~0.31%),是系统瓶颈点

        3. Apdex指数分析

全局Apdex:0.879(尚可接受,但局部异常)

登录接口Apdex:0.542(远低于均值)

用户对登录接口的体验满意度显著劣化(500ms容忍阈值下)

以上为本次报告全部内容,感谢观看。

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

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

相关文章

Nestjs框架: 基于Mongodb的多租户功能集成和优化

概述 基于前文&#xff0c;我们知道如何集成多租户的相关功能了, 现在我们继续集成Monodb的多租户形式需要注意的是&#xff0c;MongoDB 在 NestJS 中的使用过程中存在一些“坑点”如果按照默认方式集成&#xff0c;会发现连接数在不断增长&#xff0c;即使我们请求的是相同的数…

如何利用机器学习分析筛选生物标记物

在生物信息学中&#xff0c;Lasso回归、随机森林&#xff08;Random Forest&#xff09;和XGBoost因其各自的特性和优势&#xff0c;被广泛应用于基因组学、蛋白质组学、药物发现和疾病机制研究等领域。 Lasso回归 癌症亚型分类&#xff1a;从TCGA数据中筛选驱动基因&#xf…

计算机网络(基础篇)

TCP/IP 网络模型 应用层&#xff08;Application Layer&#xff09; 应用层只需要专注于为用户提供应用功能&#xff0c;比如 HTTP、FTP、Telnet、DNS、SMTP等。应用层是工作在操作系统中的用户态&#xff0c;传输层及以下则工作在内核态。传输层&#xff08;Transport Layer&a…

全面解析 CSS Flex 布局:从入门到精通的所有属性详解

1. Flex 容器属性 通过 display: flex 或 display: inline-flex 将元素设置为 Flex 容器。以下是所有容器属性。 1.1 display: flex | inline-flex 作用&#xff1a;定义一个 Flex 容器。可选值&#xff1a; flex&#xff1a;块级容器&#xff0c;占据整行。inline-flex&#x…

数据结构:对角矩阵(Diagonal Matrix)

目录 矩阵的传统表示&#xff1a;二维数组 &#x1f50d; 真正有用的数据是哪些&#xff1f; 从二维数组转为一维数组 用 C 类实现对角矩阵 1. 对角矩阵真正需要存什么&#xff1f; 2. 对角矩阵允许哪些行为&#xff1f; 3. 为什么要动态分配数组&#xff1f; 接下来推…

Leetcode_349.两个数组的交集

这道题的意思很明确&#xff0c;就是让寻找两个数组中的共同元素&#xff0c;并去重&#xff0c;由此可以联想到哈希表的特性&#xff0c;注意到题目给的数据范围&#xff0c;在1000以内&#xff0c;所以本题可以使用 STL 的库函数&#xff0c;也可以使用数组进行模拟。 本题要…

STM32——寄存器映射

总 &#xff1a;STM32——HAL库总结-CSDN博客 芯片资料&#xff1a; STM32F1系列参考手册-V10&#xff08;中&#xff09; STM32F103ZET6(English) 一、寄存器基础 1.1 简介 单片机内部的控制机构。 像空气开关控制电路一样的原理&#xff0c;打开关闭某个开关&#xff0…

Java响应式编程

Java 响应式编程是一种基于异步数据流处理的编程范式&#xff0c;它强调数据流的声明式构建和传播变化的自动响应。Java 9 引入的Flow API为响应式编程提供了标准接口&#xff0c;而 Reactor 和 RxJava 等第三方库则提供了更丰富的操作符和工具。核心概念Publisher&#xff08;…

【重学数据结构】二叉搜索树 Binary Search Tree

目录 二叉搜索树的数据结构 手写实现二叉搜索树 树节点定义 插入节点 源码 流程图 二叉树插入步骤图解 第一步: 插入 20 第二步: 插入 10 第三步: 插入 30 第四步: 插入 5 查找节点 源码 场景一: 查找成功 (search for 25) 第一步: 从根节点开始 第二步:…

四、计算机组成原理——第1章:计算机系统概述

目录 1.1计算机发展历程 1.1.1计算机硬件的发展 1.计算机的四代变化 2.计算机元件的更新换代 1.1.2计算机软件的发展 1.2计算机系统层次结构 1.2.1计算机系统的组成 1.2.2计算机硬件 1.冯诺依曼机基本思想 2.计算机的功能部件 (1)输入设备 (2)输出设备 (3)存储器 (4)运算器 (5)…

flutter TextField 失去焦点事件

在 Flutter 中&#xff0c;处理 TextField 的失去焦点事件&#xff08;即失去焦点时触发的操作&#xff09;通常有两种常用方式&#xff1a;使用 FocusNode 或 onEditingComplete 回调。以下是具体实现&#xff1a; import package:flutter/material.dart;class MyTextField e…

Moonlight for ChromeOS 常见问题解决方案

Moonlight for ChromeOS 常见问题解决方案 项目基础介绍 Moonlight for ChromeOS 是一个开源的 NVIDIA GameStream 客户端&#xff0c;允许用户将他们的游戏从高性能的桌面电脑流式传输到运行 ChromeOS 的设备上。该项目还支持 Android 和 iOS/tvOS 平台。Moonlight for Chrome…

SQL语句:读操作、写操作、视图

文章目录读操作分类基础查询语句示例高级查询--分组查询、子查询、表连接、联合查询分组查询&#xff1a;子查询&#xff08;嵌套查询&#xff09;表连接联合查询写操作视图SQL&#xff1a;结构化查询语言读操作 重点是where查询&#xff0c;即高级查询部分 分类 DML &#…

Python 机器学习实战:基于 Scikit-learn

本文围绕《Python 机器学习实战&#xff1a;基于 Scikit-learn 的项目开发》展开&#xff0c;先介绍 Scikit-learn 库的基础特性与优势&#xff0c;再阐述机器学习项目开发的完整流程&#xff0c;包括数据收集与预处理、模型选择与训练、评估与优化等。通过具体实战案例&#x…

java里List链式编程

java里对list的操作&#xff0c;我们一遍使用for遍历&#xff0c;输出或改变里面的内容。单经常在代码里面我们发现&#xff0c;也可以使用这样的代码结构daPaymentActionVo.setApnolist(paymentActionVo.getApnolist().stream().map(PaymentActionVo.Voucher::getApno).collec…

【esp32s3】7 - VSCode + PlatformIO + Arduino + 构建项目

一、PlatformIO 1.1. 概述 官方文档&#xff1a;What is PlatformIO? PlatformIO 是一个跨平台的物联网开发生态系统&#xff0c;专门为嵌入式系统开发设计&#xff0c;支持多种开发板和框架。 1.1.1. 主要特点 跨平台&#xff1a;支持 Windows、macOS 和 Linux多框架支持&…

LE AUDIO CIS/BIS音频传输时延的计算

LE AUDIO音频总时延计算方法 按照BAP的规范,LE AUDIO音频总延时包括三个部分:Audio Processing Time,Transport Latency,Presentation Delay。如下图所示是播放音乐的示例图: 这里还有一个麦克风录音的总时延示例图: Audio Processing Time:这个就是音频DSP获取音频数…

git 修改 更新

git 修改 更新先更新&#xff0c;后修改# 暂存当前修改 git add . git stash# 获取最新的 main 分支 git checkout main git pull# 新建开发分支 git checkout -b lbg_0727# ⚠️ 先把 main 的最新代码合并/变基到当前分支&#xff08;用于消除冲突&#xff09; # 方法1&#x…

飞鹤困局:增长神话的裂痕

增长天花板已然逼近&#xff0c;飞鹤需要探寻新方向。作者|安德鲁编辑|文昌龙“飞鹤&#xff0c;更适合中国宝宝体质”——这句曾让无数妈妈点头的广告语&#xff0c;帮飞鹤坐上了中国奶粉市场的头把交椅。可多年后&#xff0c;时代红利退潮&#xff0c;故事不好讲了。飞鹤的利…

Java设计模式之<建造者模式>

目录 1、建造者模式 2、建造者模式结构 3、实现 4、工厂模式对比 5、适用场景差异 前言 建造者模式是一种创建型设计模式。用于封装复杂对象的构建过程&#xff0c;通过步骤构建产品类。它包括产品类、抽象建造者、具体建造者和指挥者角色。 优点在于灵活性、解耦和易扩展…