关键词优化排名平台/博客网站seo
项目背景
个人博客系统采用了 SSM 框架与 Redis 缓存技术的组合 ,为用户提供了一个功能丰富、性能优越的博客平台。
在技术架构上 ,SSM 框架确保了系统的稳定性和可扩展性。Spring 负责管理项目的各种组件 ,Spring MVC 实现了清晰的请求处理 和视图渲染 , MyBatis 则高效地处理数据库操作。功能方面 ,用户可以轻松撰写、编辑和发布博客文章。
前端主要有 登录/注册、个人中心、操作博客的相关界面构成。
后端主要有 登录/注册、用户信息操作、博客等相关操作。
项目功能
- 注册功能:新用户需要填写用户名和密码,验证通过后需要把用户名和加密的密码存入数据库。
- 个人中心:注册/登录之后跳转到该页面,这个页面可以添加邮箱/Gitee/修改头像。同时还可以跳转到个人博客列表,或者博客广场。
- 添加邮箱:填入绑定的邮箱号之后,会收到一条验证码。当验证码通过后,就会绑定邮箱。同时把绑定的邮箱信息存入数据库。
- 修改邮箱:同添加邮箱。
- 添加Gitee:选择自己的Gitee链接,提交完成后会存入数据库。点击Gitee会跳转到个人首页。
- 修改Gitee:同添加Gitee。
- 我的博客:点击会跳到个人博客列表页。
- 博客广场:点击会跳到博客广场。
- 我的博客:只会显示自己写的博客。博客按照发布时间升序排列。只显示每篇博客的标题,发布时间,文章的前一部分的内容。可以通过查看全文查看整篇文章。可以通过修改来修改文章的内容。通过删除来删除选中的文章。
- 博客广场:与我的博客列表相似,只不过这里是全部人的博客。另外只有查看全文的显示。
- 写博客:当登录之后,就可以点击写博客进行博客的书写和发布。
- 注销:当登陆后可以点击注销进行退出。
测试
功能测试
用户
注册
登录
注销
头像
邮箱
Gitee
博客
个人广场
博客广场
查看博客
增加博客
修改博客
删除博客
自动化测试
引入依赖
<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><!-- 添加junit5依赖--><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>
创建公共类
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() {// 无头模式ChromeOptions options = new ChromeOptions();options.addArguments("-headless");// 判断驱动对象是否已经创建if(driver == null) {// 无头模式driver = new ChromeDriver(options);// 默认的有头模式
// driver = new ChromeDriver();// 创建隐式等待,确保页面渲染出来driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));}return driver;}/** 保存现场<截图>* 把所有用例的执行结果进行保存* 注意:保存的屏幕截图的名字应该是动态生成的,否则会进行图片的覆盖*/// 获取动态文件名public List<String> getTime() {SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");String fileName = sim1.format(System.currentTimeMillis());// 希望文件按天的维度进行文件夹的分类保存SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd");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();// 文件保存路径:dirName+fileName// ./指的是当前路径,这里来说就是BlogAutoTest目录下// 如果目前期望的路径:./src/test/java/com/blogWebAutoTest/dirName/fileName// 注意图片保存的路径以及名称!String fileName = "./src/test/java/com/blogWebAutoTest/"+ list.get(0) + "/" + str + "_" + list.get(1) + ".png"; // 保存的路径+名称File scrFile = driver.getScreenshotAs(OutputType.FILE); // 获取到的屏幕截图// 把屏幕截图生成的文件放到指定路径下FileUtils.copyFile(scrFile,new File(fileName));}
}
具体测试
测试详情页
import com.blogWebAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.IOException;
import java.time.Duration;// 博客详情页测试
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogDetailTest extends AutoTestUtils {public static ChromeDriver driver = createDriver();@BeforeAllstatic void baseControl() {driver.get("http://127.0.0.1:8370/myblog_list.html");}/** 详情页打开正确,但是因为没有blogId会出现Undefined*/@Test@Order(1)void undefindedTest() throws IOException {driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));String expect = "";String fact = driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[1]")).getText();getScreenShot(getClass().getName());Assertions.assertEquals(expect,fact);}/** 测试详情页正确打开[有blogId]* 测试标题以及时间(必定有)* 这里其实还有一种情况:不存在blogId*/@Test@Order(2)void blogDetailPageRight() throws IOException {driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));driver.get("http://127.0.0.1:8370/blog_content.html?id=9");driver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3"));driver.findElement(By.cssSelector("body > div.container > div.container-right > div > div.date"));driver.findElement(By.xpath("//*[@id=\"content\"]/p"));getScreenShot(getClass().getName());driver.findElement(By.xpath("/html/body/div[1]/a[1]")).click(); // 回到列表页}/** 测试“删除”按钮* 删除后会跳回到列表页,然后与最上面的时间进行比对即可【不比较标题,因为标题可能为空】* 这里是要删除第一篇博客*/@Test@Order(3)void deleteTest() throws IOException {driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));getScreenShot(getClass().getName());driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();String before = driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[1]")).getText();driver.findElement(By.cssSelector("#delete_button")).click();String after = driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.date")).getText();getScreenShot(getClass().getName());Assertions.assertNotEquals(before,after); // 比对不同}// 注意更改驱动释放位置(在最后一个类/测试用例之后)@AfterAllstatic void driverQuite() {driver.quit();}
}
其他界面也是类似。
最后一起跑一下。
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;// 测试套件运行
@Suite
@SelectClasses({BlogLoginTest.class, BlogListTest.class,BlogEditTest.class,BlogDetailTest.class,DriverQuiteTest.class})
public class runSuite {
}
相关文章:

【测试】博客系统的测试报告
项目背景 个人博客系统采用了 SSM 框架与 Redis 缓存技术的组合 ,为用户提供了一个功能丰富、性能优越的博客平台。 在技术架构上 ,SSM 框架确保了系统的稳定性和可扩展性。Spring 负责管理项目的各种组件 ,Spring MVC 实现了清晰的请求处理…...

PointCLIP: Point Cloud Understanding by CLIP
Abstract 近年来,基于对比视觉语言预训练(CLIP)的零镜头和少镜头学习在二维视觉识别中表现出了令人鼓舞的效果,该方法在开放词汇设置下学习图像与相应文本的匹配。然而,通过大规模二维图像-文本对预训练的CLIP是否可以推广到三维识别&#x…...

搜索(剪枝)
定义: 剪枝,就是减少搜索树的规模、尽早排除搜索树中不必要分支的一种手段。 在深度优先搜索中,有以下几类常见的剪枝方法: 优化搜索顺序排除等效冗余可行性剪枝最优性剪枝记忆化剪枝 例题1:AcWing 167.木棒 题目:…...

python基础知识点
最近系统温习了一遍python基础语法,把自己不熟知的知识点罗列一遍,便于查阅~~ python教程 Python 基础教程 | 菜鸟教程 1、python标识符 以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 f…...

Android SurfaceFlinger——GraphicBuffer获取内存信息(三十一)
上一篇文章介绍了 GraphicBuffer 初始化的 initWithSize() 函数中的申请内存流程,这里我们看一下另一个比较重要的函数,GraphicBufferMapper. getTransportSize 获取内存信息。该函数通常在需要了解缓冲区的实际内存占用情况时调用,例如在调试内存使用情况或优化性能时。 一…...

基于 SASL/SCRAM 让 Kafka 实现动态授权认证
一、说明 在大数据处理和分析中 Apache Kafka 已经成为了一个核心组件。然而在生产环境中部署 Kafka 时,安全性是一个必须要考虑的重要因素。SASL(简单认证与安全层)和 SCRAM(基于密码的认证机制的盐化挑战响应认证机制ÿ…...

通用多级缓件组件
背景 业界第三方缓存框架一般为redis,本地缓地ehcache或guava,一般通过spring提供的restTemplate操作缓存 然而这样会存在以下问题: 与缓存中间件强耦合需手动整合多级缓存不支持注解数据更新时无法自动刷新缓存存在缓存穿透、缓存击穿、缓…...

MindIE Service服务化集成部署通义千问Qwen模型
一、昇腾开发者平台申请镜像 登录Ascend官网昇腾社区-官网丨昇腾万里 让智能无所不及 二、登录并下载mindie镜像 #登录docker login -u XXX#密码XXX#下载镜像docker pull XXX 三、下载Qwen的镜像 使用wget命令下载Qwen1.5-0.5B-Chat镜像,放在/mnt/Qwen/Qwen1.5-…...

chrome 接口请求等待时间(installed 已停止)过长问题定位
参考: 解决实际项目中stalled时间过久的问题 背景: 测试反馈系统开 6 个标签页后, 反应变的很慢 定位: 看接口请求瀑布流, 已停止时间很长, 后端返回速度很快, 确定是前端的问题 推测是并发请求窗口数量的问题, 屏蔽部分一直 pending 的接口, 发现速度正常了, 搜到上面的参…...

HDialog特殊动画效果
基于HDialog的特殊动画效果实现 业务场景 在开发过程中直接使用HDialog所展现的效果很快,同时不能够与用户所点击位置进行交互,会造成用户的体验观感不够好。因此需要实现一种能够从用户点击按钮位置以可变动画效果所展现的Dialog效果。 工作原理及实…...

基因组挖掘指导天然药物分子的发现-文献精读34
基因组挖掘指导天然药物分子的发现 摘要 天然产物是临床药物的主要来源,也是新药研发过程中先导化合物结构设计和优化的灵感源泉。但传统策略天然药源分子的发现却遭遇了瓶颈,新颖天然产物的数量逐渐无法满足现代药物开发的需求和应对全球多药耐药的威胁…...

hcip学习 DHCP中继
DHCP 中继 在可能收到 DHCP Discover 报文的接口配置 DHCP 中继, 指明 DHCP 服务器的地址,然后将 DHCP 发现报文以单播的形式送到 DHCP 服务器上 DHCP 中继报文的源地址和目标地址怎么确定 1、源地址:收到 Discover 报文的接口地址 2、目…...

[Mysql-函数、索引]
目录 函数: 日期函数 字符串函数 数学函数 聚合函数 索引: 索引分类 慢查询 创建索引 函数: MySQL函数,是一种控制流程函数,属于数据库用语言。 MySQL常见的函数有: 数学函数 用作常规的数学运…...

org.eclipse.jgit 简单总结
org.eclipse.jgit 是一个用于处理 Git 版本控制系统的纯 Java 库。它允许你读取和写入 Git 仓库,执行如克隆、拉取、推送、提交等操作。下面我将通过几个例子来展示如何使用 org.eclipse.jgit 进行一些常见的 Git 操作。 1. 克隆仓库 克隆一个远程 Git 仓库到本地目…...

Fork软件笔记:一键拉取仓库所有模块
Fork是一个好用的git工具,只是没有中文而已(不过不用翻译也能看使用)。 工具下载地址:https://fork.dev/ 界面展示: 当项目中仓库模块比较多时,可以看到每个模块都是一个分页,每一个都要手动切换…...

常见的锂电保护芯片 单节锂电保护/双节锂电保护芯片
目前外出贸易的要求不断增多,出口的产品基本上都需要带上锂电保护芯片 以下是常见的单节锂电保护芯片的选型 包括了市面上大部分的可用型号。 锂电保护芯片的脚位上面基本都是通用,可以直接替代 双节的锂电保护使用情况较少,需要外置MOS管调节…...

初识Java(六)
一、String类 1、类中有操作字符串的方法 查找:找到某个字符是字符串内的第几个:charAt;找到某个字符在字符串内第一次出现的下标:index 替换:替换所有:replaceAll;替换首个:repla…...

Spring-原理篇-DispatcherServlet 初始化 怎么和IOC进行了打通?
委托模式的体现,在初始化醒目的时候Spring MVC为我们提供了一个DispatcherServlet,映射了所有的路径,所有的请求都会先到达这里然后被转发到具体的Controller 进行处理,此文来探索一下,DispatcherServlet 初始化的时候…...

关于swift- OC混编使用Pod遇到的2个错误
错误1 Cannot find interface declaration for UITableViewCell, superclass of "DEFUITalbleViewCell" Cannot find interface declaration for UIView, superclass of "DefUIView" Cannot find interface declaration for 系统类, superclass of "自…...

Golang | Leetcode Golang题解之第290题单词规律
题目: 题解: func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…...

【Django5】模型定义与使用
系列文章目录 第一章 Django使用的基础知识 第二章 setting.py文件的配置 第三章 路由的定义与使用 第四章 视图的定义与使用 第五章 二进制文件下载响应 第六章 Http请求&HttpRequest请求类 第七章 会话管理(Cookies&Session) 第八章 文件上传…...

HTML--JavaScript操作DOM对象
目录 本章目标 一.DOM对象概念 编辑 二.节点访问方法 常用方法: 层次关系访问节点 三.节点信息 四.节点的操作方法 操作节点的属性 创建节点 删除替换节点 五.节点操作样式 style属性 class-name属性 六.获取元素位置 总结 本章目标 了解DOM的分类和节…...

Redis 缓存
安装 安装 Redis 下载: Releases tporadowski/redis (github.com) winr ----services.msc-----将redis 设置为手动(只是学习,如果经常用可以设置为自动) 安装 redis-py 库 pip install redis-py Redis 和 StrictRedis redis-py 提供 Redis 和 Str…...

Prozyme糖样本检测平台--GlykoPrep® Rapid N-Glycan Preparation with APTS
单克隆抗体已成为生物制药行业具有潜力的新兴蛋白候选药物。其药物研发流程包括一系列精细的控制和评估步骤,需要仔细、严格地监测目标化合物的治疗稳定性及有效性。因此,在商业化前的每个阶段对单克隆抗体进行全面表征是极其有益的。在大量研究成熟的蛋…...

力扣面试题(一)
1、给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 char * mergeAlternately(char * word1, char * word2){int len1 strlen(word1);i…...

Python 输入输出
重点内容: 1、梳理掌握输入和输出函数的应用。 2、熟练使用int() float() str()等函数进行数据转换 3、常用转义字符在数据输入、输出中的应用 4、熟练使用ljust()、center()、rjust()等方法对字符位置进行控制。 5、灵活应用ASCII码、字母、数字及特殊字符解决…...

国服最强文字转音频?Fish Speech
官网文档与示例 Fish Speech V1.2 是一款领先的文本到语音 (TTS) 模型,使用 30 万小时的英语、中文和日语音频数据进行训练。我尝试用1066运行,但是质量不尽如人意,建议使用RTX系列的显卡进行推理。 使用结果展示 text """20…...

数据结构(6):图
1 图的基本概念 1.1 基本概念 1.1.1 定义【多对多的关系】 一个图不可能是空图!!!一个图的顶点集一定是非空集,但是边集可以为空集! 1.1.2 应用 1.2 无向图和有向图 弧头是有箭头的那一边,弧尾是没有箭头…...

kaggle使用api下载数据集
背景 kaggle通过api并配置代理下载数据集datasets 步骤 获取api key 登录kaggle,点个人资料,获取到自己的api key 创建好的key会自动下载 将key放至家目录下的kaggle.json文件中 我这里是windows的administrator用户。 装包 我用了虚拟环境 pip …...

前缀表达式(波兰式)和后缀表达式(逆波兰式)的计算方式
缀是指操作符。 1. 前缀表达式(波兰式) (1)不需用括号; (2)不用考虑运算符的优先级; (3)操作符置于操作数的前面。(如 3 2 ) 1.1 中…...