个人博客系统项目进行自动化测试

news2024/11/16 10:41:32

目录

一、项目界面

二、博客系统自动化测试用例

 三、自动化测试

1)准备工作

2)登录界面测试

测试正确的登录案例

登录界面测试出现问题

 测试错误的登录案例

3)博客列表界面测试

4)博客详情界面测试

 5)博客编辑界面测试

1、写博客和发布博客进行效验

2、效验发布博客标题

6)删除功能博客测试

7)注销功能测试

四、整体自动化测试

 整体代码


一、项目界面

登录界面

注册界面

 博客列表界面

博客详情界面

博客编辑界面

 博客修改页面

二、博客系统自动化测试用例

 三、自动化测试

接下来就将一一介绍上面测试用例来进行自动化测试,

1)准备工作

1、准备selenium环境搭建:https://blog.csdn.net/qq_73471456/article/details/130836494

2、在IDEA创建Maven项目,导入pom.xml相关依赖

<dependencies>
        <!-- 导入selenium依赖 -->
        <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.6</version>
        </dependency>

        <!-- 导入Junit测试框架 -->
        <!-- 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>
        </dependency>
        <!--  导入junit 参数化依赖-->
        <!-- 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>
    </dependencies>

 注意事项:若导入Junit依赖后,使用@Test注解无法成功时,需要点击@Test注解,选择add Maven选项和即可

3、初始化浏览器驱动,因为在运行每个自动化测试用例之前都需要进行创建驱动,运行所有的测试方法结束之后来需要释放浏览器驱动,于是此时创建一个类来初始化浏览器驱动和释放浏览器

package Blog;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class StartAndEnd {
    // 初始化浏览器驱动
    static   WebDriver webDriver;
    @BeforeAll
    static void Start(){
        // 加载浏览器驱动
        webDriver = new ChromeDriver();
    }
    @AfterAll
    static  void End(){
        // 释放浏览器驱动
        webDriver.quit();
    }

}

2)登录界面测试

测试正确的登录案例

 /**
     * 登录成功界面测试用例
     */
    @Order(2)
    @ParameterizedTest
    @CsvSource("是烟花哈,123")
    void LoginSuccess(String username, String password) throws InterruptedException {
        // 打开博客登录界面
        webDriver.get("http://121.43.190.21:8080/login.html");
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入账号:是烟花哈
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入密码:123
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击提交按钮
        webDriver.findElement(By.cssSelector("#submit")).click();
        // 强制等待3秒钟
        sleep(1000);
        webDriver.switchTo().alert().accept();//跳转到弹窗  点击确认,如果有取消按钮就用dismiss()方法


        // 跳转到博客列表页 (判断当前跳转页面url == http://121.43.190.21:8080/myblog_list.html 测试通过  否则测试不通过)
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/myblog_list.html", url);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 博客列表页展示用户信息为“是烟花哈” (判断当前用户名 == 是烟花哈  测试通过 否则测试不通过)
        String name = webDriver.findElement(By.cssSelector("#username")).getText();
        Assertions.assertEquals("是烟花哈", name);
    }

登录界面测试出现问题

分析原因:隐式等待无法识别非HTML的弹窗,弹窗是无法等待,此时页面还没加载完,弹窗还没出现,程序就开始去寻找弹窗,当程序未找到弹窗时便报异常错误了。此时处理弹窗就不能使用隐式等待,需要使用强制等待或者显示等待。

在上面代码中已经使用了隐式等待,当显示等待与隐式等待同时出现在同一个程序中时,会可能出现错误,因此就只能选择强制等待来代替隐式等待

 测试错误的登录案例

/**
     * 登录失败界面测试用例
     */
    @Order(1)
    @ParameterizedTest
    @CsvSource({"是烟花哈,123456", "小红,123"})
    // 验证用户名或者密码错误情况
    void LoginFail(String username, String password) throws InterruptedException {
        // 打开博客登录界面
        webDriver.get("http://121.43.190.21:8080/login.html");
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入账号:是烟花哈
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入密码:123
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击提交按钮
        webDriver.findElement(By.cssSelector("#submit")).click();
        // 强制等待3秒钟
        sleep(2000);
        // 获取弹窗内容 == 登录失败!用户名或密码错误,请重新输入 登录失败
        String text = webDriver.switchTo().alert().getText();//跳转到弹窗  点击确认,如果有取消按钮就用dismiss()方法
        Assertions.assertEquals("登录失败!用户名或密码错误,请重新输入", text);
        //点击弹窗确定按钮
        webDriver.switchTo().alert().accept();

        // 判断当前跳转页面url == http://121.43.190.21:8080/login.html 测试通过  否则测试不通过)
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/login.html", url);
    }

3)博客列表界面测试

 /**
     * 查看博客列表界面测试
     * 效验博客列表文章数量不为0
     */
    @Order(3)
    @Test
    void BlogList() {
        // 获取博客列表页网址
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 获取博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)

        int num = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();
        System.out.println(num);
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 判断所有文章数量不为0 测试通过
        Assertions.assertNotEquals(0, num);

        // 判断个人信息中的文章数量是否与博客列表文章标题数量是否一致
        String articleNum = webDriver.findElement(By.cssSelector("#artCount")).getText();
        Assertions.assertEquals(articleNum, num + "");
    }

 注意点:获取博客列表页所有博客文章标题数量, 获取多个标题数量 使用findElements ,定位多个具体的div标签 #artDiv > div.blog > div.title

4)博客详情界面测试

 /**
     * 博客详情界面测试
     * 点击查看全文按钮是否能跳转到文章详情页,效验URL
     * 效验文章详情页的博客文章标题是否与博客标题一致,若一致则测试通过
     */
    @Order(4)
    @Test
    void Blog_content() {
        // 获取博客列表页网址
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击第一篇文章的查看全文按钮
        webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(1) > a:nth-child(4)")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 效验跳转页面url == http://121.43.190.21:8080/blog_content.html?id=5
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/blog_content.html?id=5", url);

    }

注意点:当CSS选择器定位不到div元素中的标题时,找到标题在div盒子的具体路径,分别列出div路径

使用这种定位方式:

body > div.container > div.container-right > div.blog-content > h3

 5)博客编辑界面测试

1、写博客和发布博客进行效验

 /**
     * 博客编辑界面测试
     * 写博客和发布博客测试
     */
    @Order(5)
    @Test
    void BlogEdit() throws InterruptedException {
        // 找到写博客按钮并点击
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 找到输入框输入标题
        webDriver.findElement(By.cssSelector("#title")).sendKeys("自动化测试");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 点击发布按钮
        webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
        // 点击发布文章跳出弹窗进行确认
        sleep(2000);
        webDriver.switchTo().alert().accept();
        // 强制等待2秒
        sleep(2000);
        webDriver.switchTo().alert().accept();
        // 强制等待2秒
        sleep(2000);
        webDriver.switchTo().alert().dismiss();

        // 效验发布成功跳转页面url == 博客文章列表页url
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/myblog_list.html", url);
    }

2、效验发布博客标题

 /**
     * 效验已发布博客标题
     * 效验已发布博客时间
     */
    @Order(6)
    @Test
    void BlogInfoCheck(){
        // 回到文章列表页
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 获取发布博客标题
        String text = webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(7) > div.title")).getText();
        // 获取发布博客时间
        String blog_time = webDriver.findElement(By.xpath("//*[@id=\"artDiv\"]/div[7]/div[2]")).getText();
        // 效验发布博客标题是否一致
        Assertions.assertEquals("自动化测试",text);
        // 效验博客列表页发布博客时间是否与发布博客时间一致
        Assertions.assertEquals("2023-07-27",blog_time);
    }

6)删除功能博客测试

 /**
     * 删除已发布的博客文章
     * 效验删除之前文章数量与删除之后文章数量不相同
     */
    @Order(7)
    @Test
    void Delete() throws InterruptedException {
        // 打开博客列表页
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 查询删除之前文章数量
        // 获取删除之前博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)
        int  BeforNum = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();

        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 点击删除按钮
        webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(7) > a:nth-child(6)")).click();
        // 强制等待3秒
       sleep(2000);
        // 进行删除弹窗确认
        webDriver.switchTo().alert().accept();
        // 强制等待3秒
        sleep(2000);
        // 进行删除弹窗二次确认
        webDriver.switchTo().alert().accept();

        // 效验删除之后文章数量与删除之前文章数量是否不一致 ,若不一致则删除测试成功
        // 获取删除之后的博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)

        int AfterNum = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();
        Assertions.assertNotEquals(BeforNum,AfterNum);
    }

7)注销功能测试

 /**
     * 注销功能测试
     * 点击注销按钮,页面跳转到登录界面,判断当前页面是否为登录界面,测试通过
     */
    @Order(8)
    @Test
    void logout() throws InterruptedException {
        // 找到注销按钮并点击
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();
        // 强制等待3秒 等待注销弹窗
        sleep(2000);

        // 定位到弹窗并确认
        webDriver.switchTo().alert().accept();
        sleep(2000);
        // 获取当前跳转页面url
        String url = webDriver.getCurrentUrl();
        // 效验当前页面 == 登录界面url
        Assertions.assertEquals("http://121.43.190.21:8080/login.html",url);
       
    }

四、整体自动化测试

博客系统自动化测试

 整体代码

package Blog;

import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

/**
 * 自动化测试用例
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends StartAndEnd { // 继承初始化浏览器驱动和释放驱动
    /**
     * 登录成功界面测试用例
     */
    @Order(2)
    @ParameterizedTest
    @CsvSource("是烟花哈,123")
    void LoginSuccess(String username, String password) throws InterruptedException {
        // 打开博客登录界面
        webDriver.get("http://121.43.190.21:8080/login.html");
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入账号:是烟花哈
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入密码:123
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击提交按钮
        webDriver.findElement(By.cssSelector("#submit")).click();
        // 强制等待3秒钟
        sleep(1000);
        webDriver.switchTo().alert().accept();//跳转到弹窗  点击确认,如果有取消按钮就用dismiss()方法


        // 跳转到博客列表页 (判断当前跳转页面url == http://121.43.190.21:8080/myblog_list.html 测试通过  否则测试不通过)
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/myblog_list.html", url);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 博客列表页展示用户信息为“是烟花哈” (判断当前用户名 == 是烟花哈  测试通过 否则测试不通过)
        String name = webDriver.findElement(By.cssSelector("#username")).getText();
        Assertions.assertEquals("是烟花哈", name);
    }

    /**
     * 登录失败界面测试用例
     */

    @Order(1)
    @ParameterizedTest
    @CsvSource({"是烟花哈,123456", "小红,123"})
    // 验证用户名或者密码错误情况
    void LoginFail(String username, String password) throws InterruptedException {
        // 打开博客登录界面
        webDriver.get("http://121.43.190.21:8080/login.html");
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入账号:是烟花哈
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 输入密码:123
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        // 隐式等待3秒钟
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击提交按钮
        webDriver.findElement(By.cssSelector("#submit")).click();
        // 强制等待3秒钟
        sleep(2000);
        // 获取弹窗内容 == 登录失败!用户名或密码错误,请重新输入 登录失败
        String text = webDriver.switchTo().alert().getText();//跳转到弹窗  点击确认,如果有取消按钮就用dismiss()方法
        Assertions.assertEquals("登录失败!用户名或密码错误,请重新输入", text);
        //点击弹窗确定按钮
        webDriver.switchTo().alert().accept();

        // 判断当前跳转页面url == http://121.43.190.21:8080/login.html 测试通过  否则测试不通过)
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/login.html", url);
    }

    /**
     * 查看博客列表界面测试
     * 效验博客列表文章数量不为0
     */
    @Order(3)
    @Test
    void BlogList() {
        // 获取博客列表页网址
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 获取博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)

        int num = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();
        System.out.println(num);
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 判断所有文章数量不为0 测试通过
        Assertions.assertNotEquals(0, num);

        // 判断个人信息中的文章数量是否与博客列表文章标题数量是否一致
        String articleNum = webDriver.findElement(By.cssSelector("#artCount")).getText();
        Assertions.assertEquals(articleNum, num + "");
    }

    /**
     * 博客详情界面测试
     * 点击查看全文按钮是否能跳转到文章详情页,效验URL
     * 效验文章详情页的博客文章标题是否与博客标题一致,若一致则测试通过
     */
    @Order(4)
    @Test
    void Blog_content() {
        // 获取博客列表页网址
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 点击第一篇文章的查看全文按钮
        webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(1) > a:nth-child(4)")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 效验跳转页面url == http://121.43.190.21:8080/blog_content.html?id=5
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/blog_content.html?id=5", url);

    }

    /**
     * 博客编辑界面测试
     * 写博客和发布博客测试
     */
    @Order(5)
    @Test
    void BlogEdit() throws InterruptedException {
        // 找到写博客按钮并点击
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 找到输入框输入标题
        webDriver.findElement(By.cssSelector("#title")).sendKeys("自动化测试");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 点击发布按钮
        webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
        // 点击发布文章跳出弹窗进行确认
        sleep(2000);
        webDriver.switchTo().alert().accept();
        // 强制等待2秒
        sleep(2000);
        webDriver.switchTo().alert().accept();
        // 强制等待2秒
        sleep(2000);
        webDriver.switchTo().alert().dismiss();

        // 效验发布成功跳转页面url == 博客文章列表页url
        String url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://121.43.190.21:8080/myblog_list.html", url);
    }
    /**
     * 效验已发布博客标题
     * 效验已发布博客时间
     */
    @Order(6)
    @Test
    void BlogInfoCheck(){
        // 回到文章列表页
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 获取发布博客标题
        String text = webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(7) > div.title")).getText();
        // 获取发布博客时间
        String blog_time = webDriver.findElement(By.xpath("//*[@id=\"artDiv\"]/div[7]/div[2]")).getText();
        // 效验发布博客标题是否一致
        Assertions.assertEquals("自动化测试",text);
        // 效验博客列表页发布博客时间是否与发布博客时间一致
        Assertions.assertEquals("2023-07-27",blog_time);
    }
    /**
     * 删除已发布的博客文章
     * 效验删除之前文章数量与删除之后文章数量不相同
     */
    @Order(7)
    @Test
    void Delete() throws InterruptedException {
        // 打开博客列表页
        webDriver.get("http://121.43.190.21:8080/myblog_list.html");
        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 查询删除之前文章数量
        // 获取删除之前博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)
        int  BeforNum = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();

        // 隐式等待3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 点击删除按钮
        webDriver.findElement(By.cssSelector("#artDiv > div:nth-child(7) > a:nth-child(6)")).click();
        // 强制等待3秒
       sleep(2000);
        // 进行删除弹窗确认
        webDriver.switchTo().alert().accept();
        // 强制等待3秒
        sleep(2000);
        // 进行删除弹窗二次确认
        webDriver.switchTo().alert().accept();

        // 效验删除之后文章数量与删除之前文章数量是否不一致 ,若不一致则删除测试成功
        // 获取删除之后的博客列表页所有博客文章标题数量
        // (注意点:获取多个标题数量 使用findElements ,定位具体的div标签 #artDiv > div.blog > div.title)

        int AfterNum = webDriver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();
        Assertions.assertNotEquals(BeforNum,AfterNum);
    }
    /**
     * 注销功能测试
     * 点击注销按钮,页面跳转到登录界面,判断当前页面是否为登录界面,测试通过
     */
    @Order(8)
    @Test
    void logout() throws InterruptedException {
        // 找到注销按钮并点击
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();
        // 强制等待3秒 等待注销弹窗
        sleep(2000);

        // 定位到弹窗并确认
        webDriver.switchTo().alert().accept();
        sleep(2000);
        // 获取当前跳转页面url
        String url = webDriver.getCurrentUrl();
        // 效验当前页面 == 登录界面url
        Assertions.assertEquals("http://121.43.190.21:8080/login.html",url);

    }
}


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

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

相关文章

DEVICENET转ETHERNET/IP网关devicenet协议

捷米JM-EIP-DNT&#xff0c;你听说过吗&#xff1f;这是一款自主研发的ETHERNET/IP从站功能的通讯网关&#xff0c;它能够连接DEVICENET总线和ETHERNET/IP网络&#xff0c;从而解决生产管理系统中协议不同造成的数据交换互通问题。 这款产品在工业自动化领域可谓是一大利器&…

【QT 网络云盘客户端】——主窗口界面的设计

目录 1.设计主窗口界面 2.设置窗口的背景图片 3. 自定义标题栏 3.1 设置toolbutton按钮的图片 3.2 设置按钮的大小 3.3 将自定义标题栏添加设置到主页面中 3.4 去除窗口的原标题栏 3.5 设置按钮颜色 3.6 切换页面功能实现 4.我的文件页面的设计 4.1 菜单栏的设计 4…

插件使用权限管理软件(三)WebAPI项目IIS部署

前言 前面完成了WebAPI项目的接口服务类编写工作&#xff0c;接下来讲把项目部署到服务器的IIS上&#xff0c;让系统运行起来。 一. 项目发布 右键项目RightsManagementSystems.Web.Entry 选择“发布”选项 弹出发布选项界面&#xff0c;选择“文件夹”&#xff0c;点击下一步…

【Android知识笔记】UI体系(一)

Activity的显示原理 setContentView 首先开发者Activity的onCreate方法中通常调用的setContentView会委托给Window的setContentView方法: 接下来看Window的创建过程: 可见Window的实现类是PhoneWindow,而PhoneWindow是在Activity创建过程中执行attach Context的时候创建的…

SystemServer进程

前言 在systemServer启动文章中我们讲了在SystemServer.java的main方法里面调用new SystemServer().run&#xff08;&#xff09;方法启动System_server进程。那么我们接着看一下SystemServer.java具体做了哪些事情&#xff1f; ##SystemServer的run方法介绍 frameworks\base…

VictoriaMetrics

VictoriaMetrics是一个开源的时序数据库和监控解决方案&#xff0c;专门用于存储和查询大规模时间序列数据。它的设计灵感来自Prometheus&#xff0c;但在某些方面与Prometheus有所区别&#xff0c;主要关注于提供高性能、高可用性和低资源占用的特点。 一、与Prometheus区别和…

Kotlin Multiplatform 创建多平台分发库

目标&#xff1a;通过本教程学习如何使用 Kotlin Multiplatform Library 创建多平台分发库(iOS&#xff0c;安卓)。 创建一个项目 1、本教程使用的是Android Studio创建 2、选择 新建工程&#xff0c;选择 Kotlin Multiplatform Library 3、点击next 输入需要创建的项目名称以…

第2章 逻辑分页、AutoFac注入、工作单元与仓储

1 CoreCms.Net.Model.ViewModels.Basics.IPageList<T> namespace CoreCms.Net.Model.ViewModels.Basics { ///<typeparam name"T">泛型类型实例(1个指定实体的类型实例)。</typeparam> /// <summary> /// 【逻辑分页列表--接口】 /// <…

akka 简单使用

由于AKka的核心是Actor&#xff0c;而Actor是按照Actor模型进行实现的&#xff0c;所以在使用Akka之前&#xff0c;有必要弄清楚什么是Actor模型。 Actor模型最早是1973年Carl Hewitt、Peter Bishop和Richard Seiger的论文中出现的&#xff0c;受物理学中的广义相对论(general…

3ds MAX绘制茶壶

综合一下之前的内容画个茶壶 长方形&#xff0c;然后转化为可编辑多边形&#xff0c;添加节点并设置圆角&#xff0c;如下图 车削生成一个圆环&#xff0c;其实这一步也可以用一个圆柱体和两个圆角圆柱体解决 效果如下&#xff1a; 茶壶的底座绘制好了 接下来是茶壶的上半边 …

牛客网面试必刷:CD12 换钱的最少货币数

牛客网面试必刷&#xff1a;CD12 换钱的最少货币数 前言一、动态规划&#xff08;1&#xff09;需要判断钱币和总金额&#xff08;2&#xff09;不需要判断钱币和总金额 前言 问题链接: CD12 换钱的最少货币数 一、动态规划 参考自&#xff1a;【编程题 动态规划】兑换零钱(…

Coremail敏感配置信息泄露

生活是美好的&#xff0c;生命在其间又是如此短促。既然活着&#xff0c;就应该好好地活。应该更珍惜自己生命的每个时刻&#xff0c;精神上的消沉无异于自杀。像往日一样正常的投入生活吧&#xff0c;即便是痛苦&#xff0c;也应该被看做是人的正常情感&#xff0c;甚至它是组…

【多线程】进程调度的基本过程

进程调度的基本过程 1. 什么是进程/任务&#xff08;Process/Task&#xff09;2. 描述一个进程3. 什么是进程调度&#xff1f;3.1 进程状态3.2 进程的优先级3.3 进程的上下文3.4 进程的记账信息 4. 组织这些进程 1. 什么是进程/任务&#xff08;Process/Task&#xff09; 操作…

【用户体验分析报告】 按需加载组件,导致组件渲染卡顿,影响交互体验?组件拆包预加载方案来了!

首先&#xff0c;我们看一些针对《如何提升应用首屏加载体验》的文章&#xff0c;提到的必不可少的措施&#xff0c;便是减少首屏幕加载资源的大小&#xff0c;而减少资源大小必然会想到按需加载措施。本文提到的便是一个基于webpack 插件与 react 组件实现的一套研发高度自定义…

nginx入门 - 学习笔记

一、初识 1、相关概念 1&#xff09;正向代理 一个位于客户端和原始服务器之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理发送一个请求并指定目标&#xff0c;然后代理向原始服务器转交请求并将获得内容返回给客户端。 2&#xff09;反向代理…

【C++】多态,虚函数表相关问题解决

文章目录 多态概念及其触发条件重写和协变&#xff08;考点1&#xff09;&#xff08;考点2&#xff09; 虚函数表及其位置&#xff08;考点3&#xff09; 多继承中的虚函数表 多态概念及其触发条件 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态。具体点就是去完成…

DSA之图(2):图的存储结构

文章目录 0 图的结构1 邻接矩阵1.1 无向图的邻接矩阵1.2 有向图的邻接矩阵1.3 网&#xff08;有权图&#xff09;的邻接矩阵表示法1.4 邻接矩阵的建立1.4.1 采用邻接矩阵建立无向网1.4.2 采用邻接矩阵建立有向网 1.5 邻接矩阵的优缺点1.5.1 优点1.5.2 缺点 2 邻接表2.1 无向图的…

Java将汉字转拼音以及判断字符是否为汉字

首先是将汉字转换为拼音&#xff1a; 导入依赖&#xff1a; <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency>创建转拼音的静态方法toPinyin&#xf…

掌握 Python RegEx:深入探讨模式匹配

动动发财的小手&#xff0c;点个赞吧&#xff01; 什么是正则表达式&#xff1f; 正则表达式通常缩写为 regex&#xff0c;是处理文本的有效工具。本质上&#xff0c;它们由一系列建立搜索模式的字符组成。该模式可用于广泛的字符串操作&#xff0c;包括匹配模式、替换文本和分…

在线阅读版:《2023中国软件供应链安全分析报告》全文

聚焦源代码安全&#xff0c;网罗国内外最新资讯&#xff01; 专栏供应链安全 数字化时代&#xff0c;软件无处不在。软件如同社会中的“虚拟人”&#xff0c;已经成为支撑社会正常运转的最基本元素之一&#xff0c;软件的安全性问题也正在成为当今社会的根本性、基础性问题。 随…