简朴博客系统测试报告
文章目录
- 一. 项目简介
- 二. 测试概要
- 三. 测试环境
- 四. 测试执行概况及功能测试
- 1. 手工测试
- 1.1 手动测试用例编写
- 1.2 执行的部分测试用例
- 2. 自动化测试Selenium
- 2.1 编写测试用例
- 2.2 自动化测试代码
- 3. 测试结果
- 五. 发现的问题
一. 项目简介
简朴博客系统是采用前后端分离的方式来实现的,是基于 SpringFrameWork 和 MyBatis 框架实现的一个简易的博客发布网站,同时将其部署到了云服务器上。
目前博客系统主要实现了户的注册登录,文章的编写、发布,以及对自己文章的查看、修改、删除操作,个人文章列表及文章数统计这些;还可以分页显示所有作者汇总的文章列表,显示文章阅读量等。
使用 IDEA 开发,项目用到的技术有,SpringBoot, SpringMVC, MyBatis, MySQL, Redis, Lombok,HTML,CSS,JavaScript,jQuery 等。
二. 测试概要
测试对象:基于 SSM 项目的博客系统。
测试目的:校验博客项目功能是否符合自己的预期。
测试点:主要针对常用的主流程功能进行测试,如:注册、登录、汇总博客列表页、博客编辑页、个人博客列表页、导航栏组件等涉及到的功能。
测试方法和工具:主要是黑盒测试,自动化工具使用 Selenium 和 Junit。
三. 测试环境
硬件:Lenovo Yoga 14S 2021(R7-5800H/16GB/512GB/集显)。
浏览器:Google Chrome 版本 119.0.6045.160(正式版本) (64 位)。
操作系统:Windows 11。
测试工具:Selenium3 和 Junit5。
四. 测试执行概况及功能测试
1. 手工测试
1.1 手动测试用例编写
♨️注册页
♨️登录页
♨️个人博客列表页
♨️博客详情页
♨️博客编辑页
1.2 执行的部分测试用例
- 🍂登录页:界面能否正常加载,输入正确 / 错误的账号、密码是否能得到预期的响应。
1️⃣界面能否正常加载。
2️⃣账号正确,密码错误。
预期结果:弹窗提示:“出错了: 登录失败, 请重新操作! 用户名或密码错误! ”。
实际结果如下:
3️⃣账号正确,密码为空。
预期结果:弹窗提示:“请输入密码! ”。
实际结果如下:
4️⃣账号正确,密码正确。
预期结果:页面跳转至个人博客列表页。
实际结果如下:
- 个人博客列表页:检测界面是否符合预期,点击“查看全文”按钮是否能跳转到对应的博客详情页,点击“修改”按钮是否能跳转到博客编辑页并获取到待修改的标题和内容,点击“删除”按钮是否能成功删除文章,点击“注销”是否能退出登录。
1️⃣界面显示符合预期。
2️⃣点击“查看全文”按钮是否能跳转到对应的博客详情页。
预期结果:进入到对应的博客详情页,且能够正确加载文章内容。
实际结果如下:
3️⃣点击“修改”。
预期结果:点击修改后跳转到文章编辑页。
实际结果如下:
4️⃣点击“删除”。
预期结果:点击删除后文章被删除。
实际结果如下:
5️⃣点击“注销”是否能退出登录。
预期结果:点击注销后退出跳转到登录页面。
实际结果如下:
2. 自动化测试Selenium
2.1 编写测试用例
2.2 自动化测试代码
🍂引入依赖:selenium
,commons-io
,junit
,suite
,engine
。
<dependencies><!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.141.59</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.2</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-params</artifactId><version>5.9.2</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite --><dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.9.1</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.9.1</version></dependency>
</dependencies>
🍂初始化工具类InitAndEnd
。
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;public class InitAndEnd {static WebDriver webDriver;@BeforeAllstatic void SetUp() {// 创建 web 驱动webDriver = new ChromeDriver();}@AfterAllstatic void TearDown() {// 关闭 web 驱动webDriver.quit();}// 获取当前时间戳将截图按照时间保存public List<String> getTime() {// 文件夹以当天日期保存// 截图以当天日期-时间保存SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd");SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");String dirname = sim1.format(System.currentTimeMillis());String filename = sim2.format(System.currentTimeMillis());List<String> list = new ArrayList<>();list.add(dirname);list.add(filename);return list;}// 获取屏幕截图,把所有的用例执行的结果保存下来public void getScreenShot(String str) throws IOException {List<String> list = getTime();String filename = "D:\\bit\\software_testing\\software-testing\\test-blog\\src\\main\\java\\com\\blog\\test" + list.get(0) + "\\" + str + "_" + list.get(1) + ".png";File srcfile = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);// 把屏幕截图生成的文件放到指定的路径FileUtils.copyFile(srcfile, new File(filename));}
}
🍂常用功能主流程测试:
🍁LoginSuccess.csv
。
admin, admin, http://47.113.217.156:8080/myblog_list.html
🍁RegCases
。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.By;import java.io.IOException;
import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;public class RegCases extends InitAndEnd {@Order(1)@ParameterizedTest@CsvSource({"zhaoliu, 123, 123, http://47.113.217.156:8080/login.html"})void regSuccess(String username, String password, String againpassword, String login_url) throws InterruptedException, IOException {// 打开登录页webDriver.get(login_url);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 找到注册按钮并点击webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 输入注册的用户名和密码及确认密码webDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.findElement(By.cssSelector("#password2")).sendKeys(againpassword);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 点击注册按钮webDriver.findElement(By.cssSelector("#submit")).click();sleep(3000);// 点击确认弹窗webDriver.switchTo().alert().accept();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 用新注册的账号进行登录// 输入账号 zhaoliuwebDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 输入密码 123webDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 点击登录按钮webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 刚注册的账号登录后没有文章,验证是否有 “创作” 按钮String butt = webDriver.findElement(By.cssSelector("#artListDiv > h3 > a")).getText();String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertEquals("创作", butt);}
}
🍁BlogCases
。
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;import static java.lang.Thread.sleep;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd {/*** 登录页:输入正确的账号,错误的密码,登录失败*/@Order(1)@ParameterizedTest@CsvSource({"admin, 123", "zhangsan, 666"})void LoginAbnormal(String username, String password) throws InterruptedException, IOException {// 打开登录页webDriver.get("http://47.113.217.156:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 输入账号和密码webDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 点击登录按钮webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);sleep(300);//登录失败,出现弹窗//获取验证弹窗内容String text = webDriver.switchTo().alert().getText();String except = "出错了: 登录失败, 请重新操作! 用户名或密码错误!";webDriver.switchTo().alert().accept();String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertEquals(except, text);}/*** 登录页:输入正确的账号,密码,登录成功*/@Order(2)@ParameterizedTest@CsvFileSource(resources = "LoginSuccess.csv")void LoginSuccess(String username, String password, String blog_list_url) throws IOException, InterruptedException {System.out.println(username + " " + " " +password + " " + blog_list_url);// 打开登录页webDriver.get("http://47.113.217.156:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 输入账号 adminwebDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 输入密码 adminwebDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 点击登录按钮webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);sleep(3000);// 登录成功,跳转到个人列表页// 获取到当前页面 urlString methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);String cur_url = webDriver.getCurrentUrl();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 如果 url == http://47.113.217.156:8080/myblog_list.html,测试通过,否则测试不通过Assertions.assertEquals(blog_list_url, cur_url);}/*** 个人博客列表页:admin 账户登录后博客数量不为 0*/@Order(3)@Testvoid BlogList() throws IOException {// 打开个人博客列表页webDriver.get("http://47.113.217.156:8080/myblog_list.html");// 获取页面上所有博客标题对应的元素webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);int title_num = webDriver.findElements(By.cssSelector(".title")).size();// 如果元素数量不为 0,测试通过String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertNotEquals(0 ,title_num);}/*** 个人博客列表页:查看全文* 博客详情页:* url* 博客标题* 页面 title 是 “博客详情”*/public static Stream<Arguments> Generator() {return Stream.of(Arguments.arguments("http://47.113.217.156:8080/blog_content.html","博客详情", "URL到页面: 探索网页加载的神秘过程"));}@Order(4)@ParameterizedTest@MethodSource("Generator")void BlogDetail(String expected_url, String expected_title, String expected_blog_title) throws IOException {// 打开个人博客列表页webDriver.get("http://47.113.217.156:8080/myblog_list.html");// 找到第一篇博客对应的查看全文按钮webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > a:nth-child(4)")).click();// 获取当前页面 urlwebDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);String cur_url = webDriver.getCurrentUrl();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 获取当前页面 titleString cur_title = webDriver.getTitle();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 获取博客标题String cur_blog_title = webDriver.findElement(By.cssSelector("#title")).getText();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertEquals(expected_title, cur_title);Assertions.assertEquals(expected_blog_title, cur_blog_title);Assertions.assertTrue(cur_url.contains(expected_url));}/*** 博客编辑页:发布文章*/@Order(5)@Testvoid EditBlog() throws InterruptedException, IOException {// 打开个人博客列表页webDriver.get("http://47.113.217.156:8080/myblog_list.html");// 找到写博客按钮,点击webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 通过 Js 进行输入((JavascriptExecutor) webDriver).executeScript("document.getElementById(\"title\").value=\"自动化测试\"");sleep(3000);// 点击发布文章按钮webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();sleep(3000);// 验证发布成功后的弹窗内容String cur_text = webDriver.switchTo().alert().getText();String expect_text = "文章添加成功! 是否继续添加文章? ";// 点击取消弹窗webDriver.switchTo().alert().dismiss();String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertEquals(expect_text, cur_text);}/*** 汇总列表页:验证博客成功发布* 校验第一篇博客标题* 校验第一篇博客时间*/@Order(6)@Testvoid BlogInfoChecked() throws IOException {webDriver.get("http://47.113.217.156:8080/blog_list.html");// 获取第一篇博客标题String first_blog_title = webDriver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > div.title")).getText();// 获取第一篇博客发布时间String first_blog_time = webDriver.findElement(By.xpath("//*[@id=\"artListDiv\"]/div[1]/div[2]")).getText();String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);// 校验博客标题是不是自动化测试Assertions.assertEquals("自动化测试", first_blog_title);// 如果时间是 2023-11-18 年发布的,测试通过Assertions.assertTrue(first_blog_time.contains("2023-11-18"));}/*** 个人列表页:删除刚刚发布的博客*/@Order(7)@Testvoid DeleteBlog() throws InterruptedException, IOException {// 打开个人博客列表页面webDriver.get("http://47.113.217.156:8080/myblog_list.html");// 点击删除按钮webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > a:nth-child(6)")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);sleep(3000);webDriver.switchTo().alert().accept();// 删除后博客列表页第一篇博客标题不是 “自动化测试”String first_blog_title = webDriver.findElement(By.xpath("//*[@id=\"artListDiv\"]/div[1]/div[1]")).getText();// 校验当前博客标题不等于 “自动化测试”webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertNotEquals(first_blog_title, "自动化测试");}//注销@Order(8)@Testvoid Logout() throws IOException {// 打开个人博客列表页面//点击注销webDriver.get("http://47.113.217.156:8080/myblog_list.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();webDriver.switchTo().alert().accept();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 校验 url 注销后进入登录页String cur_url = webDriver.getCurrentUrl();String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();getScreenShot(methodName);Assertions.assertEquals("http://47.113.217.156:8080/login.html", cur_url);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);}
}
🍂RunSuite
,通过 class 运行测试用例。
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;@Suite
@SelectClasses({RegCases.class, BlogCases.class,})
public class RunSuite {
}
3. 测试结果
测试通过,整体的主流程业务操作是没有问题的。
测试截图如下:
五. 发现的问题
🎯手工测试过程中发现的问题。
🍂问题描述:
博客汇总页在未登录的情况下,点击“我的”按钮,结果不符合预期。
预期结果:直接跳转到登录页。
实际结果:有时候会出现弹窗提示错误,关闭弹窗后也不能直接跳转到登录页,需要刷新页面才能成功跳转。
🍂原因分析:
问题的根本原因可能在于异步请求的特性和后端拦截器的重定向,异步请求是非阻塞的,即在请求发送的过程中,代码会继续往下执行而不会等待请求完成。
在拦截器中使用response.sendRedirect
进行重定向时,实际上是在响应中设置了一个重定向的状态,但对于异步请求而言,这个重定向的状态可能无法被正确处理,导致浏览器不会直接跳转到登录页,因为异步请求的结果是在JavaScript中处理的,而不是在浏览器地址栏中执行的。
这就导致了在异步请求中执行重定向时,可能会产生不确定的行为,因为重定向的结果可能无法按照预期顺序执行。
🍂造成问题的代码定位:
🍂解决方案:
修改前端代码,通过 JS 在 success 回调中判断返回的 res 中的code,如果是未登录状态,则手动跳转到登录页,以此来规避异步请求中可能产生的问题,确保在未登录时能够及时跳转到登录页。
🎯自动化程序编写过程碰到的问题:
一些自动化操作是不能在弹窗的情况下完成操作的(比如截图),如果在测试程序执行报unexpected alert open: {Alert text : ...}
这种异常,那么就是你没有将弹窗关闭掉,可以使用 accept() 方法确认弹窗或者 dismiss() 取消弹窗后再执行相关操作。
相关文章:

简朴博客系统测试报告
文章目录 一. 项目简介二. 测试概要三. 测试环境四. 测试执行概况及功能测试1. 手工测试1.1 手动测试用例编写1.2 执行的部分测试用例 2. 自动化测试Selenium2.1 编写测试用例2.2 自动化测试代码 3. 测试结果 五. 发现的问题 一. 项目简介 简朴博客系统是采用前后端分离的方式…...

Qt遇到常见问题记录
1.Qt版本选择 Qt4.8.7是Qt4的终结版本,是Qt4系列版本中最稳定最经典的 (很多嵌入式板子还是用Qt4.8),其实该版本是和Qt5.5差不多时间发布的。 参考链接 Qt 5.5 Released Qt5.6.3最最后支持xp系统的长期支持版本,Q…...

pm2在Windows环境中的使用
pm2 进程管理工具可以Windows操作系统上运行,当一台Windows电脑上需要运行多个进程时,或者运维时需要运行多个进程以提供服务时。可以使用pm2,而不再是使用脚本。 1. 使用PM2管理进程 1.1. 启动PM2项目 1.1.1. 直接启动项目 参数说明&…...

使用百度翻译API或腾讯翻译API做一个小翻译工具
前言 书到用时方恨少,只能临时抱佛脚。英文pdf看不懂,压根看不懂。正好有百度翻译API和腾讯翻译API,就利用两个API自己写一个简单的翻译工具,充分利用资源,用的也放心。 前期准备 关键肯定是两大厂的翻译API&#x…...

Flutter笔记:桌面应用 窗口定制库 bitsdojo_window
Flutter笔记 桌面应用窗口管理库 bitsdojo_window 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/13446…...

iOS_折叠展开 FoldTextView
1. 显示效果 Test1:直接使用: Test2:在 cell 里使用: 2. 使用 2.1 直接使用 // 1.1 init view private lazy var mooFoldTextView: MOOFoldTextView {let view MOOFoldTextView(frame: .zero)view.backgroundColor .cyanvie…...

java使用 TCP 的 Socket API 实现客户端服务器通信
一:什么是 Socket(套接字) Socket 套接字是由系统提供于网络通信的技术, 是基于 TCP/IP 协议的网络通信的基本操作,要进行网络通信, 需要有一个 socket 对象, 一个 socket 对象对应着一个 socket 文件, 这个文件在 网卡上而不是硬盘上, 所以有了 sokcet…...

conda从4.12升级到最新版23.9 自动升级失败 手动升级方法
最新版conda有多线程下载,还做了一些其它易用性改动,所以决定从很老的4.12版本升级到最新版。因为版本差别过大,使用自带的conda update conda已经不起作用了。 手动升级最先想到的是把老环境全部导出为yaml文件,在新环境里全部重…...

WPF下实现拖动任意地方都可以拖动窗口
首先在xaml中添加事件 <Window PreviewMouseLeftButtonDown"Window_PreviewMouseLeftButtonDown"PreviewMouseMove"Window_PreviewMouseMove"PreviewMouseLeftButtonUp"Window_PreviewMouseLeftButtonUp"/>然后脚本输入 Point _pressedP…...

Swin Transformer
Swin Transformer 简介 下采样的层级设计,能够逐渐增大感受野。采用window进行注意力计算,极大降低了内存消耗,避免了整张图像尺寸大小的qkv矩阵滑窗操作包括不重叠的 local window,和重叠的 cross-window。不重叠的local window…...

【csapp lab】lab2_bomblab
文章目录 前言实验内容phase_1phase_2phase_3phase_4phase_5phase_6secret_phase 前言 刚做了csapp lab2,记录一下。 我这里用的的系统环境是Ubuntu22.04,是64位系统,与用32位系统可能有所差异。 实验共包括七个阶段,每个阶段考…...

开发者分享 | Ascend C算子开发及单算子调用
本文分享自《AscendC算子开发及单算子调用》,作者:goldpancake。 笔者在阅读Ascend C官方文档的过程中发现,对于初学者来说,尤其是第一次接触异构编程思想的初学者,有部分内容是无需特别关注的,例如算子工…...

如何在 Linux 上部署 RabbitMQ
如何在 Linux 上部署 RabbitMQ 文章目录 如何在 Linux 上部署 RabbitMQ安装 Erlang从预构建的二进制包安装从源代码编译 Erlang RabbitMQ 的安装使用 RabbitMQ Assistant 连接 RabbitMQ Assistant 是一款优秀的RabbitMQ 可视化管理工具,提供丰富的管理功能。下载地址…...

解决更换NodeJs版本后npm -v返回空白
一、问题描述 win11电脑上输入cmd进入控制台,输入 node --version 有正常返回安装的nodejs的版本号 再输入 npm -v 返回空白。正常情况应该是要返回版本号。 二、问题背景 最近准备学习vue,在不久前已经安装了NodeJs和python。运行了好几个开源项…...

【ES常用查询】基于ElasticsearchRestTemplate及NativeSearchQuery的查询
包含当前es所有的查询, 需要什么代码直接照搬,改个参数就行! 用的好请务必给我点赞!!!感谢爱你们!!! (周末更 筒) 为啥写这篇文章呢ÿ…...

全志XR806基于http的无线ota功能实验
XR806不仅硬件功能多,XR806也提供了功能极其丰富的SDK,几天体验下来非常容易上手。常见的功能几乎都有相应的cmd或demo实现,HAL也做得非常全面,非常适合快速开发。这一点超级好评!本文章要实现的无线OTA也基于该SDK。 …...

2023年11月15号期中测验选择题(Java)
本篇续接《2023年11月15号期中测验判断题(Java)》->传送门 2-1 以下程序运行结果是 public class Test extends Father{private String name"test";public static void main(String[] args){Test test new Test();System.out.println(tes…...

C# static关键字详解
在C#中,static关键字有许多重要的用途。以下是关于如何使用static关键字的一些详细信息: 静态类(Static Classes):静态类是不能实例化的类,它的所有成员都是静态的。静态类常常用作工具类或帮助类ÿ…...

开发一款回合制游戏,需要注意什么?
随着游戏行业的蓬勃发展,回合制游戏因其深度的策略性和令人着迷的游戏机制而受到玩家们的热烈欢迎。如果你计划投身回合制游戏的开发领域,本文将为你提供一份详细的指南,从游戏设计到发布,助你成功打造一款引人入胜的游戏。 1. 游…...

java的包装类
目录 1. 包装类 1.1 基本数据类型和对应的包装类 1.2 装箱和拆箱 1.3 自动装箱和自动拆箱 1. 包装类 在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了 一个包装类型。 若想了解…...

【数据结构(一)】线性结构和非线性结构
文章目录 线性结构和非线性结构1. 线性结构2. 非线性结构 线性结构和非线性结构 数据结构包括:线性结构和非线性结构。 1. 线性结构 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系。线性结构有两种不同的存储结构ÿ…...

持续集成指南:GitHubAction 自动构建+部署AspNetCore项目
前言 之前研究了使用 GitHub Action 自动构建和发布 nuget 包:开发现代化的.NetCore控制台程序:(4)使用GithubAction自动构建以及发布nuget包 现在更进一步,使用 GitHub Action 在其提供的 runner 里构建 docker 镜像,之后提交到阿…...

Docker 笔记(三)--容器
Docker 笔记(三)–容器 记录Docker 安装操作记录,便于查询。 参考 链接: Docker 入门到实战教程(三)镜像和容器链接: docker run中的-itd参数正确使用链接: docker官方文档链接: 阿里云Debian 镜像链接: Debian 全球镜像站链接: Debian/Ub…...

gd32关于IO引脚配置的一些问题
一、gd32f103的PA15问题 1、 #define GPIO_SWJ_NONJTRST_REMAP ((uint32_t)0x00300100U) /*!< full SWJ(JTAG-DP SW-DP),but without NJTRST */ #define GPIO_SWJ_SWDPENABLE_REMAP ((uint32_t)0x00300200U) /*!< JTAG-DP disabled and SW-DP enab…...

QT小记:警告Use multi-arg instead
"Use multi-arg instead" 是一个提示,建议使用 QObject::tr() 函数的多参数版本来处理多个占位符,而不是使用单参数版本。 在 Qt 中,tr() 是用于进行文本翻译(国际化)的函数。它允许你在应用程序中使用多种…...

皮肤性病科专家谭巍主任提出HPV转阴后饮食七点建议
HPV转阴是每一位感染者都期盼的,因为转阴所以健康,只有转为阴性才意味着不具备传染性,从此也不必再害怕将病毒传染给家人的风险,也不必再担忧持续感染而引发的健康风险。总之,HPV转阴是预示感染者恢复健康与否的主要标…...

快速弄懂C++中的智能指针
智能指针是C中的一个对象,它的行为类似于指针,但它提供了自动的内存管理功能。当智能指针超出作用域时(比如说在函数中使用智能指针指向了一个对象,当该函数结束时会自动销毁该对象),它会自动删除其所指向的…...

C#调用C++ dll教程
文章目录 一、创建C dll项目二、C#程序员调用C dll三、C与C#数据类型对应基本数据类型对应表C指针类型与C#类型 在使用C#开发客户端时,有时需要调用C dll,本篇博客来介绍C#程序如何调用C dll。 一、创建C dll项目 首先使用VS2022创建C dll项目…...

计算机毕设 深度学习 大数据 股票预测系统 - python lstm
文章目录 0 前言1 课题意义1.1 股票预测主流方法 2 什么是LSTM2.1 循环神经网络2.1 LSTM诞生 2 如何用LSTM做股票预测2.1 算法构建流程2.2 部分代码 3 实现效果3.1 数据3.2 预测结果项目运行展示开发环境数据获取 最后 0 前言 🔥 这两年开始毕业设计和毕业答辩的要…...

97.qt qml-自定义Table之实现ctrl与shift多选
我们之前实现了:93.qt qml-自定义Table优化(新增:水平拖拽/缩放自适应/选择使能/自定义委托)-CSDN博客 实现选择使能的时候,我们只能一行行去点击选中,非常麻烦,所以本章我们实现ctrl多选与shift多选、 所以在Table控件新增两个属性: 1.实现介绍 ctrl多选实现原理:当我…...