个人博客系统-自动化测试

news2024/11/25 8:19:09

1、项目背景

1.1技术背景

1)个人博客系统主要是通过前端(HTML+css+js)+后端(SpringBoot)实现的一个博客的基本功能。前端通过jQuery的方式向后端请求数据。后端通过MyBatis从数据库中查询数据响应给前端。

2)项目中,用户的密码使用md5的加盐算法进行加密处理,以保证密码的安全性。

3)数据封装成统一的返回格式,便于前后端交互。

1.2功能背景

1)注册:新用户进行注册,后端会进行校验,如果注册的用户已存在,会弹窗提示用户已存在,如果两次密码不一致,会提示用户重新输入;如果注册成功,会跳转到登录页面。

2)登录:用户输入用户名和密码,登录成功,跳转到个人博客列表页,显示当前用户已发布的博客信息。

3)发布博客:点击发布博客,会跳转到博客添加页,输入博客内容,发布博客,然后跳转到博客列表页,展示刚刚发布的博客。

4)博客详情页:点击查看全文,跳转到博客详情页,展示了博客的标题、内容、发布时间、阅读量、作者信息(作者用户名、作者发布文章数)。

5)博客列表页:显示所有用户发布的博客,会以分页的形式展示,我设置的默认是每页显示两条,会有总页数,当前所在页。

6)修改博客:在个人博客列表中,可以点击修改某一篇文章,进入博客修改页重新进行编辑,然后发布修改。

7)删除博客:在个人博客列表中,可以点击删除某一篇文章。

8)游客登录:如果用户未登录,作为游客可以访问博客列表页(主页),可以查看所有用户发布的博客内容及博客详情,但是不能发布文章。

9)注销:退出当前账号,回到登录页面。

2、测试用例编写

3、自动化测试

3.1、准备工作

1)创建Maven项目,导入相关依赖

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0</version>
        </dependency>
        <!--   保存屏幕截图文件需要用到的包     -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2)准备工具

创建驱动对象,创建获取屏幕截图方法

package com.blogWebAutoTest.common;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public class AutotestUtils {
    public static ChromeDriver driver;

    //创建驱动对象
    public static ChromeDriver createDriver(){
        //驱动对象已经创建好了/没有创建
        if( driver == null){
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--remote-allow-origins=*");
            driver = new ChromeDriver(options);
            //创建隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        }
        return driver;
    }

    public List<String> getTime(){
        //文件能不能按照天的维度按文件夹进行保存
        //文件格式 20230212-123030毫秒
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd");
        String filename = sim1.format(System.currentTimeMillis());
        String dirname = 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();
        //dir+filename
        // ./指的是当前的项目路径下,也就是BlogAutoTest下
        // ./src/test/java/com/blogWebAutoTest/dirname/filename
        // ./src/test/java/com/blogWebAutoTest/20230212/logintest_20230212-123030毫秒.png
        String filename = "./src/test/java/com/blogWebAutoTest/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";
        File srcfile = driver.getScreenshotAs(OutputType.FILE);
        //把屏幕截图生成的文件放到指定的路径
        FileUtils.copyFile(srcfile,new File(filename));
    }
}

3.2、登录界面测试

package com.blogWebAutoTest.Tests;

import com.blogWebAutoTest.common.AutotestUtils;
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.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.IOException;
import java.time.Duration;

/**
 * 博客登录页
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogLoginTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();;
    //如果要测试登录页面,以下所有的用例都有一个共同的步骤
    //1、要有浏览器对象  2、访问登录页面的url
    @BeforeAll
    static void baseControl(){
        driver.get("http://localhost:8080/login.html");
    }
    /**
    检查登录页面打开是否正确
    检查点:主页 写博客 元素是否存在
     */
    @Test
    @Order(1)
    void loginPageLoadRight() throws IOException {
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
        getScreenShot(getClass().getName());
    }

    /**
     * 检查正常登录情况
     */
    @ParameterizedTest
    @CsvSource({"wcx,123456"})
    @Order(3)
    void loginSuc(String name , String passwd) throws InterruptedException, IOException {
        //这三步只是登录的步骤结束了,能不能保证登录是成功的呢??
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#submit")).click();
        //对登录结果进行检测,如果跳转到了博客列表页才算是登录成功了
        driver.findElement(By.cssSelector("#artDiv > div:nth-child(1) > a:nth-child(4)"));
        getScreenShot(getClass().getName());
//        driver.navigate().back();
    }
    /**
    * 检查异常登录情况
    */
    @ParameterizedTest
    @CsvSource({"wcxx,123456","wcx,1234567",})
    @Order(2)
    void loginFail(String name, String passwd) throws IOException, InterruptedException {
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        driver.switchTo().alert().accept();
        driver.findElement(By.cssSelector("#submit"));
//        driver.navigate().back();
    }

}

3.3、个人博客列表页测试

package com.blogWebAutoTest.Tests;

import com.blogWebAutoTest.common.AutotestUtils;
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.chrome.ChromeDriver;

import java.io.IOException;

/**
 * 个人博客列表页
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogListTest extends AutotestUtils {
    public static ChromeDriver  driver = createDriver();
    @BeforeAll
    static void baseControl(){
        driver.get("http://localhost:8080/myblog_list.html");
    }
    /**
     * 博客列表页可以正常显示
     */
    @Test
    void listPageLoadRight() throws IOException {
        driver.findElement(By.cssSelector("#username"));
        int num = driver.findElements(By.cssSelector("#artDiv > div.blog > div.title")).size();
        System.out.println(num);
        String articalNum = driver.findElement(By.cssSelector("#artCount")).getText();
        Assertions.assertEquals(articalNum,num + "");
        getScreenShot(getClass().getName());
    }



}

3.4、编辑博客页测试

package com.blogWebAutoTest.Tests;

import com.blogWebAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.IOException;

/**
 * 博客编辑页
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();
    public static String num = null;
//    @BeforeAll
//    static  void baseControl(){
//        driver.get("http:localhost/blog_system/blog_edit.html");
//    }
    /**
     * 检查博客编辑页可以正常打开
     */
    @Test
    @Order(1)
    void editPageLoadRight() throws IOException {
        num = driver.findElement(By.cssSelector("#artCount")).getText();
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        getScreenShot(getClass().getName());
    }
    @Test
    @Order(2)
    void editAndSubimitBlog() throws IOException, InterruptedException {
        String expect = "java Autotest";
        driver.findElement(By.cssSelector("#title")).sendKeys(expect);
        //因博客系统使用到的编辑是第三方软件,所以不能直接使用sendKeys向编辑模块发送文本
        driver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
//        getScreenShot(getClass().getName());
        Thread.sleep(1000);
        driver.switchTo().alert().accept();
        Thread.sleep(1000);
        driver.switchTo().alert().dismiss();
        String actual = driver.findElement(By.cssSelector("#artCount")).getText();
        System.out.println(num);
        int a = Integer.parseInt(num)+1;
        String numa = String.valueOf(a);
        Assertions.assertEquals(numa,actual);
    }
    @Test
    @Order(3)
    void editNoTitle() throws InterruptedException {
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        driver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
        Thread.sleep(1000);
        driver.switchTo().alert().accept();
        Thread.sleep(1000);
        driver.switchTo().alert().accept();
        driver.navigate().back();
    }
}

3.5、博客详情页测试

package com.blogWebAutoTest.Tests;

import com.blogWebAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.IOException;

/**
 * 博客详情页
 */
public class BlogDetailTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();
    public static String read = null;
    @BeforeAll
    static  void baseControl(){
        driver.get("http://localhost:8080/blog_list.html");
    }
    @Test
    void blogDeailLoadRight() throws IOException{
        driver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > a")).click();
        String read = driver.findElement(By.cssSelector("#rcount")).getText();
        driver.navigate().back();
        driver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > a")).click();
        String readAgain = driver.findElement(By.cssSelector("#rcount")).getText();
        int a = Integer.parseInt(read)+1;
        read=String.valueOf(a);
        Assertions.assertEquals(read,readAgain);
        String url = driver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/blog_content.html?id=1",url);
        getScreenShot(getClass().getName());
        driver.navigate().back();

    }
}

3.6、注册页面测试

package com.blogWebAutoTest.Tests;

import com.blogWebAutoTest.common.AutotestUtils;
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.chrome.ChromeDriver;

/**
 * 博客注册页
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogRegisterTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();
    @BeforeAll
    public static void baseControl(){
        driver.get("http://localhost:8080/reg.html");
    }

    /**
     * 检查正常注册情况
     * @param name
     * @param passwd
     * @param repasswd
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"999,999,999"})
    @Order(1)
    public void regSuc(String name,String passwd,String repasswd) throws InterruptedException {
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#password2")).sendKeys(repasswd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        String text = driver.switchTo().alert().getText();
//        Assertions.assertEquals("恭喜:注册成功!是否要跳转到登录页面?",text);
        driver.switchTo().alert().accept();

    }

    /**
     * 检查异常注册情况(密码与确认密码不符)
     * @param name
     * @param passwd
     * @param repasswd
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"999,999,998"})
    @Order(2)
    public void regFailWrongpassword(String name,String passwd,String repasswd) throws InterruptedException {
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#password2")).sendKeys(repasswd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        String text = driver.switchTo().alert().getText();
//        Assertions.assertEquals("两次密码输入的不一致,请先检查!",text);
        driver.switchTo().alert().accept();

    }

    /**
     * 检查异常注册情况(无用户名)
     * @param passwd
     * @param repasswd
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"999,998"})
    @Order(3)
    public void regFailname(String passwd,String repasswd) throws InterruptedException {
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#password2")).sendKeys(repasswd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        String text = driver.switchTo().alert().getText();
//        Assertions.assertEquals("请先输入用户名!",text);
        driver.switchTo().alert().accept();

    }

    /**
     * 检查异常注册情况(无密码)
     * @param name
     * @param repasswd
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"999,999,998"})
    @Order(4)
    public void regFailpasswd(String name,String repasswd) throws InterruptedException {
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password2")).sendKeys(repasswd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        String text = driver.switchTo().alert().getText();
//        Assertions.assertEquals("请先输入密码!",text);
        driver.switchTo().alert().accept();

    }

    /**
     * 检查异常注册情况(无确认密码)
     * @param name
     * @param passwd
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"999,999,998"})
    @Order(5)
    public void regFailrepasswd(String name,String passwd) throws InterruptedException {
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(name);
        driver.findElement(By.cssSelector("#password")).sendKeys(passwd);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(1000);
        String text = driver.switchTo().alert().getText();
//        Assertions.assertEquals("请先输入确认密码!",text);
        driver.switchTo().alert().accept();

    }

}

运行效果

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

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

相关文章

天通报警呼叫柱助力宜宾——破汛期河心洲岛通信困境,守护人民群众生命安全

随着主汛期的到来&#xff0c;我国多地遭遇频繁降雨&#xff0c;强降雨或连绵不断的降雨&#xff0c;极易引发山洪、滑坡、泥石流等次生灾害。8月18日23时至20日10时&#xff0c;辽宁省西部地区出现暴雨到大暴雨&#xff0c;葫芦岛市部分乡镇出现特大暴雨。受到强降雨影响&…

Qt-QWidget的windowIcon属性(14)

目录 描述 相关API 使用 并不需要在堆上创建 不要带中文路径 运行观察 不要使用绝对路径 描述 这个其实就是你打开窗口的左上角那个图标&#xff0c;这个就是用来设置那个的 相关API 使用 创建一个新的项目&#xff0c;如下&#xff0c;添加一个设置图片的代码 并不需…

uboot中 fastboot udp 协议分析

注&#xff1a; 1. 本文所分析的fastboot源码不是android下的源码&#xff0c;而是恩智浦芯片厂商在IMX6UL芯片的uboot源码中自己实现的源码&#xff0c;二者不同&#xff0c;请读者注意区分。一些图片是网上找到的&#xff0c;出处不好注明&#xff0c;请见谅。 2. 分析fastbo…

VM——轮廓/快速匹配中的多模版匹配

1、轮廓或者快速匹配中支持建立多个模型&#xff0c;按照从上而下的顺序进行匹配&#xff0c;匹配上了即停止后续模版的匹配。 2、如果要多个模版都参与匹配&#xff0c;则需要打开“全部搜索模式”。 3、延拓阈值 “延拓阈值”&#xff0c;看参数名字不知所云&#xff0c;文档…

CR-NeRF 代码eval.py解析

这段代码是一个用于CR-NeRF&#xff08;Neural Radiance Fields&#xff09;模型的推理脚本。它主要用于生成和保存渲染的图像&#xff0c;并计算图像质量的评价指标&#xff08;如PSNR和SSIM&#xff09;。以下是对这段代码的详细解析&#xff1a; &#xff08;1&#xff09;…

【亚马逊云科技】有手就能做到的Amazon Lightsail快速建站

文章目录 前言一、为什么选择Amazon Lightsail二、创建账号与登录注册亚马逊账号登录控制台 三、创建Amazon Lightsail进入控制台创建实例实例配置查看实例查看网站定制页面 总结 前言 不论是个人名片还是官方网站都离不开网站建设工作。计算机技术经历漫长的发展&#xff0c;…

2024年如何将低质量视频变成高质量视频

创建低质量的视频对您没有好处&#xff0c;尤其是当您打算将这些视频上传到社交媒体帐户时。观众不喜欢观看模糊和低质量的视频&#xff0c;而这个东西没有意义&#xff0c;不会为你的内容增加价值。 那么&#xff0c;您应该如何确保您的社交媒体观众喜欢您的视频内容呢&#x…

企业内部知识库意义何在?怎么搭建?

引言 在知识经济时代&#xff0c;企业竞争力的核心日益转向知识的管理与应用能力。随着企业规模的扩大和业务复杂性的增加&#xff0c;如何高效地收集、整理、存储并分享内部知识&#xff0c;成为了企业持续发展和创新的关键。企业内部知识库应运而生&#xff0c;它不仅帮助企…

自定义注解+拦截器实现,对部分敏感字段的加解密

上一篇,我用的自定义注解AOP的方式,实现敏感字段的加解密,这一篇换个方案,这个方案相比一个方案,节省了一部分的性能开销 第一步:新建自定义注解 /*** 敏感信息类注解*/ Inherited Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) public interface EnableSe…

tomcat session共享

1. 日志监控工具 安装 tar xf goaccess-1.4.tar.gz cd goaccess-1.4/ yum install GeoIP-devel-1.5.0-13.el7.x86_64.rpm yum install -y ncurses-devel.x86_64 ./configure --enable-utf8 --enable-geoiplegacy make make install2. 使用 goaccess /usr/local/nginx/logs/a…

java多线程(六)关键字Volatile可见性、有序性以及单个变量的原子性

volatile关键字 作用 volatile 是 Java 虚拟机提供的轻量级的同步机制&#xff0c;主要用来确保变量被线程安全地读取和写入。 当一个变量定义为 volatile 后&#xff0c;它具备以下特性&#xff1a; 可见性&#xff1a;确保不同线程对这个变量操作的可见性&#xff0c;即一…

自存实践本地访问 nginx放前端打包好的项目

nginx 部署前端项目_哔哩哔哩_bilibili 将打包好的dits文件放到 配置nginx.conf文件的location 启动命令 start nginx.exe 输入localhost即可访问打包好的项目 nginx的特点 1.静态资源 2.转发 设置代理转发请求 关闭nginx .\nginx.exe -s quit

Kubernetes-Pod调度基础

一.复制控制器&#xff08;ReplicationController&#xff0c;RC&#xff09; RC用来确保Pod副本数达到预期值&#xff0c;这样可以确保一个或多个同类Pod总是可用的。可以通过扩缩来增加或减少pod。 &#xff08;1&#xff09;示例&#xff1a; vim replicationcontroller-ng…

Codeforces Round 967 (Div. 2)

文章目录 A. Make All Equal题目描述思路代码 B. Generate Permutation题目描述思路代码 C. Guess The Tree题目描述思路代码 A. Make All Equal 题目描述 一个数组&#xff0c;最多实行n-1次&#xff0c;计算最少多少次可以变为同一个数 思路 计算重复次数最多的数&#x…

产业园区数字化转型:面对挑战,我们如何把握机遇加速前行?

在当今数字化的时代浪潮中&#xff0c;产业园区数字化转型已成为推动经济发展和提升竞争力的关键举措。然而&#xff0c;这一进程并非坦途&#xff0c;充满了各种挑战。 产业园区数字化转型面临着技术更新换代快的压力。新技术不断涌现&#xff0c;如物联网、人工智能、大数据…

Mybatis 速通秘籍 节省回顾知识点和学习成本

目录 一、MyBatis简介 1、MyBatis历史 2、MyBatis特性 3、MyBatis下载 4、和其它持久层技术对比 二、搭建MyBatis 1、开发环境 2、创建maven工程 a>打包方式 b>引入依赖 3、创建MyBatis的核心配置文件 4、创建mapper接口 5、创建MyBatis的映射文件 6、通过j…

python学习之路 - python的异常、模块与包

目录 一、python的异常、模块与包1、了解异常2、异常的捕获方法a、捕获基本异常b、捕获指定异常c、捕获多个异常d、捕获异常后的finally 3、异常的传递4、python模块a、定义b、基础语法c、使用方法d、补充 5、python包a、定义b、操作方法c、使用方法 6、安装第三方python包a、命…

MVC和三层架构

&#x1f449;参考文章&#xff1a;mvc简介&#xff0c;mvc与三层架构的区别 一.MVC是什么&#xff1f; Model-View-Controller&#xff08;MVC&#xff09;是一种软件架构模式&#xff0c;是软件设计模式的体现 &#xff0c;用于组织代码并分离关注点&#xff0c;广泛应用于…

GPS和桩号互转

文章目录 前言一、通过bigmap软件生成坐标信息csv二、Java实现1.CSV分隔2.计算2.1 读取gps_data.csv2.2 读取piles.csv2.3 进行线性插值2.4 返回值实体2.5 根据GPS坐标计算距离工具2.6 根据GPS坐标读取桩号2.7 根据桩号读取GPS坐标(根据距离计算&#xff0c;找到最近的桩号) 前…

短视频SDK解决方案,智能技术加持,提升创作效率

随着社交媒体、直播电商、在线教育等领域的蓬勃发展&#xff0c;短视频以其独特的魅力迅速崛起&#xff0c;成为内容创作与传播的新风口。为了助力企业和个人轻松拥抱视频化趋势&#xff0c;美摄科技匠心打造了一套高效、易用的短视频SDK解决方案&#xff0c;以“轻编辑&#x…