WebTest搭建
0.前言
此框架为真实项目实战,所以有些数据不便展示,只展示架构和思想
工具:python+selenium+ddt+unittest
1.架构说明
2.代码封装
Commom层
base_page.py
#__author__=19044168
#date=2021/8/26
import logging
import datetime
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import time
from Common import dir_configfrom Common.logger import GetLogger
logger = GetLogger.get_logger()#1.封装基本函数,执行日志,异常处理,失败截图
#2.所有的页面公共行为,非业务层面的行为
class BasePage:def __init__(self,driver):self.driver = driver#等待元素可见def wait_eleVisible(self,locator,wait_times=30,poll_frequency=0.5,doc=""):""":param locator: 元素定位元组形式(定位类型,定位方式):param times::param poll_frequency::param doc: 模块名_页面名_操作名:return: None"""logger.info("等待元素{0}可见".format(locator))try:#开始等待时间start = datetime.datetime.now().timestamp()#转化为sWebDriverWait(self.driver,wait_times,poll_frequency).until(EC.visibility_of_element_located(locator))# 结束等待时间end = datetime.datetime.now().timestamp()#求一个时间差值写到日志中sub_time = end - startlogger.info("等待时长为:{}".format(sub_time))# self.save_screenshot(doc)except:logger.exception('等待元素可见失败!!!')#截图操作self.save_screenshot(doc)raise#待元素不可见def wait_eleNotVisible(self,locator,wait_times=30,poll_frequency=0.5,doc=""):""":param locator: 元素定位元组形式(定位类型,定位方式):param times::param poll_frequency::param doc: 模块名_页面名_操作名:return: None"""logger.info("{0}等待元素{1}不可见".format(doc,locator))try:# 开始等待时间start = datetime.datetime.now() # 转化为sWebDriverWait(self.driver,wait_times, poll_frequency).until(EC.invisibility_of_element_located(locator))# 结束等待时间end = datetime.datetime.now()# 求一个时间差值,写到日志中wait_time = (end - start).secondslogger.info("{0}:元素{1}已可见,等待起始时间:{2},等待结束时间:{3},等待时长为:{4}".format(doc,locator,start,end,wait_time))# self.save_screenshot(doc)except:logger.exception('等待元素不可见失败!!!')# 截图操作self.save_screenshot(doc)raise#等待元素存在def wait_elePresence(self,locator,wait_times=30,poll_frequency=0.5,doc=""):logger.info("等待元素{0}存在".format(locator))try:# 开始等待时间start = datetime.datetime.now().timestamp() # 转化为sWebDriverWait(self.driver, wait_times, poll_frequency).until(EC.presence_of_element_located(locator))# 结束等待时间end = datetime.datetime.now().timestamp()# 求一个时间差值写到日志中sub_time = end - startlogger.info("等待时长为:{}".format(sub_time))# self.save_screenshot(doc)except:logger.exception('等待元素存在失败!!!')# 截图操作self.save_screenshot(doc)raise#查找元素def get_element(self,locator,doc=""):logger.info('{0}查找元素:{1}'.format(doc,locator))try:return self.driver.find_element(*locator)except:logger.exception("查找元素失败!!!")# 截图操作self.save_screenshot(doc)raise#点击操作def click_elemnet(self,locator,doc=""):#找元素ele = self.get_element(locator,doc)logger.info("{0}点击元素:{1}".format(doc,locator))#元素操作try:ele.click()except:logger.exception("点击元素失败!!!")# 截图操作self.save_screenshot(doc)raise#输入操作def input_text(self,locator,text,doc=""):# 找元素ele = self.get_element(locator,doc)logger.info("{0}输入元素{1}".format(doc,locator))try:ele.send_keys(text)except:logger.exception("输入元素失败!!!")# 截图操作self.save_screenshot(doc)raise#获取元素文本内容def get_text(self,locator,doc=""):ele = self.get_element(locator,doc)logger.info("{0}获取文本内容{1}".format(doc,locator))try:return ele.textexcept:logger.exception("获取文本内容失败!!!")# 截图操作self.save_screenshot(doc)raise#获取元素属性def get_element_attribute(self,locator,attr,doc=""):ele = self.get_element(locator, doc)logger.info("{0}获取元素{1}的{2}属性的值".format(doc,locator,attr))try:return ele.get_attribute(attr)except:logger.exception("获取元素属性失败!!!")# 截图操作self.save_screenshot(doc)raise# 获取所有句柄def get_handles(self,doc):logger.info("获取所有页面句柄")try:return self.driver.window_handlesexcept:logger.exception("获取所有页面句柄失败!!!")# 截图操作self.save_screenshot(doc)raise# 获取当前句柄def get_current_handle(self, doc):logger.info("获取当前{}页面句柄".format(doc))try:return self.driver.current_window_handleexcept:logger.exception("获取获取当前页面句柄失败!!!")# 截图操作self.save_screenshot(doc)raise# 窗口切换def switch_window(self,handle,doc):logger.info("从当前窗口{}切换到指定窗口".format(doc))try:self.driver.switch_to.window(handle)except:logger.exception("切换窗口失败")self.save_screenshot(doc)raise#获取当前urldef get_current_url(self,doc):logger.info("获取当前页面{}url".format(doc))try:return self.driver.current_urlexcept:logger.exception("获取当前页面url失败")self.save_screenshot(doc)raise#移动到元素def move_to_element(self,target,doc):logger.info("{0},移动元素到{1}".format(doc,target))try:ActionChains(self.driver).move_to_element(target).perform()except:logger.exception("移动元素失败")self.save_screenshot(doc)raise#alert处理def alert_action(self,action='accept'):pass#iframe切换def switch_iframe(self,iframe_reference):pass#上传操作def upload_file(self):pass#截图操作def save_screenshot(self,doc):#图片名称:模块名_页面名_操作名_年-月-日-时-分-秒.png# now = datetime.datetime.now()# format_time = now.strftime("%Y-%m-%d-%H-%M-%S")# filename = 'OutPuts/screenshots/' + "{0}_{1}.png".format(name,format_time)# self.driver.save_screenshot(filename)# logging.info('截取网页成功,文件路径为{}'.format(filename))filePath = dir_config.screenshot_dir + '/'+ '{0}_{1}.png'.format(doc,time.strftime("%Y-%m-%d-%H-%M-%S",time.localtime()))try:self.driver.save_screenshot(filePath)logger.info("截屏成功,截屏路径为{0}".format(filePath))except:logger.exception('截屏失败!!')raise#滚动条操作...if __name__ == '__main__':pass
dir_config.py
email_fundation.py
#__author__=19044168
#date=2021/8/13
import smtplib
from email.mime.text import MIMEText#这是发正文
from email.mime.multipart import MIMEMultipart#这是发附件
import osclass Email:def __init__(self):self.send_user = 'xx@xxing.com'self.receive_user = 'yy@yying.com'# global user_listself.user_list = ['xx@xxing.com','ss4@ssing.com']self.server_host = 'smtp.suning.com'self.username = 'dfdds@ddning.com'self.password = 'dfsdfsdfsd'def sendEmail(self,new_file):f = open(new_file,'rb')mail_body = f.read()f.close()msg = MIMEMultipart('mixed')html_file = MIMEText(mail_body,'html','utf-8')# msg = MIMEMultipart(mail_body,'html','utf-8')msg['Subject'] = "Hbase WebAutoTest Report"context = MIMEText('<html><h2>您好,这是Hbase服务化测试报告</h2></html>', 'html', 'utf-8')msg.attach(context)msg.attach(html_file)# 发动邮件server = smtplib.SMTP()server.connect(self.server_host)server.login(self.username, self.password)# server.sendmail(self.send_user, self.receive_user, msg.as_string())server.sendmail(self.send_user, self.user_list, msg.as_string())server.close()def new_report(self,reportpath):lists = os.listdir(reportpath)lists.sort(key=lambda fn:os.path.getmtime((reportpath + '/' + fn)))print(lists)new_file = os.path.join(reportpath,lists[-1])print(new_file)return new_file
e = Email()if __name__ == '__main__':print(os.getcwd())e = Email()test_report = '../OutPuts/reports'new_report = e.new_report(test_report)e.sendEmail(new_report)
logger.py
#__author__=19044168
#date=2021/8/27
import logging.handlers
import time
from Common.dir_config import logs_dirclass GetLogger():logger = None@classmethoddef get_logger(cls):if cls.logger == None:# 日志器实例cls.logger = logging.getLogger()# 设置日志级别cls.logger .setLevel(level=logging.INFO)# 控制台处理器实例ch = logging.StreamHandler()# 以时间切分日志文件处理器filename = logs_dir + '/' + time.strftime('%Y-%m-%d-%H-%M-%S') + '_WebUiTestLog.log'th = logging.handlers.TimedRotatingFileHandler(filename=filename,encoding='utf-8')# 设置日志格式fmt = "%(asctime)s %(levelname)s [%(name)s] [filename: %(filename)s - module: %(module)s - func: %(funcName)s %(lineno)d line] - %(message)s"fm = logging.Formatter(fmt)# 将日志格式添加到处理器ch.setFormatter(fm)th.setFormatter(fm)# 将处理器添加到日志器cls.logger .addHandler(ch)cls.logger .addHandler(th)return cls.loggerif __name__ == '__main__':print(time.strftime())
OutPuts层,不需要封装,代码定义好目录即可
PageLocators层,根据页面层次进行组织
loginpage_locators.py,登录页面
其他页面自行封装
PageObjects层,根据页面层次进行组织
login_page.py,登录页面
#__author__=19044168
#date=2021/8/19
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from PagesObjects.index_page import IndexPage
from PageLocators.loginpage_locators import LoginPageLocator as loc #直接用,不要继承,不然对象可选方法变量太多
from time import sleepfrom Common.logger import GetLogger
logger = GetLogger.get_logger()from Common.base_page import BasePageclass LoginPage(BasePage):# #用户名输入框# username_loc = (By.XPATH,'//input[@id="userId"]')# #密码输入框# password_loc = (By.XPATH,'//input[@id="password"]')# #登录按钮# login_loc = (By.XPATH,'//a[@id="submit_btn"]')# #是否记住密码勾选框# remember_loc = (By.XPATH,'//input[@id="remember"]')# #登录入口链接# enter_loc = (By.XPATH,'//a[@class="btn-login"]')# #用户名格式错误验证文本# errorMsg_from_wrongUser = (By.XPATH,'//div[@class="layui-layer-content"]')# #账号密码错误提示文本# msg_loc = (By.XPATH,'//div[@id ="error"]')# def __init__(self,driver):# self.driver = driver#登录入口def login_enter(self):doc = '登录地址入口页面_登录跳转功能'self.wait_eleVisible(loc.enter_loc,doc=doc)self.click_elemnet(loc.enter_loc,doc=doc)# enter_loc = '//a[@class="btn-login"]'# WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc.enter_loc))# self.driver.find_element_by_xpath(enter_loc).click()# self.driver.find_element(*self.enter_loc).click()#解包元组# self.driver.find_element(*loc.enter_loc).click()#解包元组#登录页面def login(self,username,password,is_remember=False):# 这些元素属性可以定义成类的属性,最好注释说明。但是有弊端,因为定位方式不止一种,修改定位就要修改元素操作方式# 不方便优化# username_loc = '//input[@id="userId"]'# password_loc = '//input[@id="password"]'# login_loc = '//a[@id="submit_btn"]'# remember_loc = '//input[@id="remember"]'# WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc.username_loc))doc = "登录页面_登录功能"self.wait_eleVisible(loc.username_loc,doc=doc)self.input_text(loc.username_loc,username,doc=doc)self.input_text(loc.password_loc,password,doc=doc)# self.driver.find_element(*loc.username_loc).send_keys(username)# self.driver.find_element(*loc.password_loc).send_keys(password)#is_remember来判断是否需要记住账号密码if is_remember:# self.driver.find_element(*loc.remember_loc).click()self.click_elemnet(loc.remember_loc,doc=doc)else:pass# self.driver.find_element(*loc.login_loc).click()self.click_elemnet(loc.login_loc,doc=doc)#获取账号格式错误信息def get_errorMsg_from_wrongUser(self):# ret = self.driver.find_element(*loc.errorMsg_from_wrongUser)doc = "登录页面_账号格式错误信息"ret = self.get_text(loc.errorMsg_from_wrongUser,doc=doc)return ret#获取账号或者密码错误def get_errorMsg_from_pageCenter(self):doc = "登录页面_账号格式错误信息"self.wait_eleVisible(loc.msg_loc,doc=doc)# WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc.msg_loc))ret = self.get_text(loc.msg_loc,doc=doc)return ret#帮助链接页面def help_link(self):current_handle = self.get_current_handle(doc="登录页面句柄")#其实也可以在base_page封装doc = "登录页面_帮助链接功能"self.wait_eleVisible(loc.help_link_loc,doc=doc)self.click_elemnet(loc.help_link_loc,doc=doc)handle = self.get_handles(doc="获取所有页面句柄")[-1]self.switch_window(handle,doc="帮助链接页面")#其实也可以在base_page封装help_url = self.get_current_url(doc='帮助链接页面')self.switch_window(current_handle,doc='登录页面')#其实也可以在base_page封装return help_url# 忘记密码链接页面def forget_pwd_link(self):current_handle = self.get_current_handle(doc="登录页面的句柄")#其实也可以在base_page封装doc = "登录页面_忘记密码链接功能"self.wait_eleVisible(loc.forget_pwd_link_loc,doc=doc)self.click_elemnet(loc.forget_pwd_link_loc,doc=doc)self.switch_window(self.get_handles(doc='获取所有页面句柄')[-1],doc='忘记密码链接页面')#其实也可以在base_page封装forget_pwd_url = self.get_current_url(doc='忘记密码链接url')#其实也可以在base_page封装self.switch_window(current_handle,doc='登录页面')#其实也可以在base_page封装return forget_pwd_urlif __name__ == '__main__':from selenium import webdriverfrom time import sleepfrom selenium.webdriver.common.action_chains import ActionChainsdriver = webdriver.Chrome()driver.maximize_window()driver.get('http://datakingdom.cnsuning.com/')lg = LoginPage(driver)ip = IndexPage(driver)lg.login_enter()# print(lg.help_link())# print(lg.forget_pwd_link())# lg.login_redirect()lg.login('19044168','19044168')sleep(1)driver.find_element_by_link_text('控制台').click()sleep(1)driver.find_element_by_xpath('//div[contains(text(),"平台基础服务")]').click()driver.find_element_by_css_selector('ul[role="menubar"] > li:nth-child(4) > ul > li:nth-child(1)').click()sleep(1)driver.find_element_by_xpath('//tr[2]//a').click()driver.find_element_by_xpath('//ul[@x-placement="bottom-end"]/li[contains(text(),"进入雨花prd环境")]').click()sleep(3)# print(lg.get_errorMsg_from_pageCenter())# target = driver.find_element_by_xpath('//div[@class="user-info"]')# ActionChains(driver).move_to_element(target).perform()# a = driver.find_element_by_link_text('退出')# print(a.text)# ip.isExist_logout_ele()driver.quit()
TestCases层
#__author__=19044168
#date=2021/8/20
from selenium import webdriver
import time
from PagesObjects.login_page import LoginPage
from PagesObjects.index_page import IndexPage
import unittest
from TestDatas import Common_Datas as CD
from TestDatas import Login_Datas as LD
import ddtfrom Common.logger import GetLogger
logger = GetLogger.get_logger()@ddt.ddt
class TestLogin(unittest.TestCase):@classmethoddef setUpClass(cls):logger.info("======整个用例前置:打开浏览器,只执行一次=======")#通过excel获取本功能当中所需要的测试数据,但是比较麻烦。建议使用python文件保存测试数据cls.driver = webdriver.Chrome()cls.driver.maximize_window()cls.driver.get(CD.web_login_url)cls.lg = LoginPage(cls.driver)cls.lg.login_enter()#将该步骤提前到初始化步骤中,节省时间# cls.driver.save_screenshot()@classmethoddef tearDownClass(cls):logger.info("=======整个用例后置:关闭浏览器,只执行一次=======")cls.driver.quit()#每个案例执行后进行页面刷新def tearDown(self):logger.info("=======每个用例后置:刷新一次页面======")self.driver.refresh()time.sleep(0.5)def test05_login_success(self):# self.lg.login_enter()#将该步骤提前到初始化步骤中,节省时间logger.info("=======登录用例:正常场景->登陆成功======")self.lg.login(LD.success_data['user'],LD.success_data['passwd'])self.assertTrue(IndexPage(self.driver).isExist_logout_ele(),'退出元素未出现')#异常用例--账号格式不正确(大于8位,小于8位,等于8位且包含非数字)#ddt,步骤断言都一致,只有文本内容不一致@ddt.data(*LD.user_data)def test01_login_wrongUserFormat(self,data):# self.lg.login_enter()#将该步骤提前到初始化步骤中,节省时间logger.info("=======登录用例:异常场景->账号格式错误,登陆失败======")self.lg.login(data['user'], data['passwd'])self.assertEqual(self.lg.get_errorMsg_from_wrongUser(),data['check'], '账号格式错误提示信息不对')# 异常用例--用户名或者密码错误@ddt.data(*LD.user_pwd_data)def test02_login_wrongUserOrPwd(self,data):# self.lg.login_enter()#将该步骤提前到初始化步骤中,节省时间logger.info("=======登录用例:异常场景->用户名或者密码错误,登陆失败======")self.lg.login(data['user'],data['passwd'])self.assertEqual(self.lg.get_errorMsg_from_pageCenter(),data['check'],'非用户名或密码错误')#帮助链接验证用例def test03_help_link(self):logger.info("=======登录帮链接用例:正常场景->帮助链接有效======")self.assertIn(LD.help_url,self.lg.help_link(),'帮助链接地址不包含在内')# 忘记密码链接验证用例def test04_forget_pwd_link(self):logger.info("=======登录忘记密码帮链接用例:正常场景->忘记密码链接有效======")self.assertIn(LD.forget_pwd_url,self.lg.forget_pwd_link(),'忘记密码链接地址不包含在内')if __name__ == '__main__':unittest.main()
TestDatas层
run.py
#__author__=19044168
#date=2021/8/27
import unittest
from HTMLTestRunner import HTMLTestRunner
from Common.dir_config import htmlreport_dir,testcases_dir
import time
from Common.send_mail_file import *
#实例化套件对象
suite= unittest.TestSuite()#TestLoader的用法
#1.实例化Testloader对象
#2.使用discover去找到一个目录下的所有用例
#3.使用suite
loader = unittest.TestLoader()
# suite.addTests(loader.discover(testcases_dir,pattern='log*'))
suite.addTests(loader.discover(testcases_dir,pattern='*test.py'))#运行
# runner = unittest.TextTestRunner()
# runner.run(suite)cur_time = time.strftime("%Y-%m-%d-%H-%M-%S",time.localtime())
fp = open(htmlreport_dir + '/' + cur_time + '-AutoTest_report.html','wb')
runner = HTMLTestRunner(stream=fp,title='web测试报告',description="这是hbase的web测试报告",tester='小猪')
runner.run(suite)e.sendEmail(e.new_report(htmlreport_dir))
运行run.py文件即可
收工!!!
相关文章:

WebTest搭建
0.前言 此框架为真实项目实战,所以有些数据不便展示,只展示架构和思想 工具:pythonseleniumddtunittest 1.架构说明 2.代码封装 Commom层 base_page.py #__author__19044168 #date2021/8/26 import logging import datetime from sele…...
什么性格的人适合报考机械类专业?(高考志愿填报选专业)
机械类专业 是指涉及机械设计、制造、加工、维护等方面的专业,是工程类专业中的一类。机械类专业的学生主要学习机械工程的基础知识,包括机械设计、力学、材料力学、热力学、流体力学等,同时也会学习机械制造、机电一体化、机器人技术等实践性…...

进程概念详解
目录 进程是什么? 描述进程:进程控制块-PCB task_struct task_struct 是什么? task_struct内容分类 组织进程 查看进程 fork创建子进程 进程状态 僵尸进程 孤儿进程 进程优先级 其他概念 进程是什么? 一般书上…...

C语言基础——指针
文章目录一、指针1.指针的意义2.指针类型表示3.一些操作3.1打印1个变量地址3.2通过地址查看改地址的内容以及修改改地址的内容3.3操作某个空间 -- 4个字节,给他赋值为100,只知道该空间的地址0x8000 00004.指针变量的定义5.指针类型的大小6.指针变量的使用6.1 指针变…...
反序列化渗透与攻防(二)之Java反序列化漏洞
Java反序列化漏洞 反序列化漏洞 JAVA反序列化漏洞到底是如何产生的? 1、由于很多站点或者RMI仓库等接口处存在java的反序列化功能,于是攻击者可以通过构造特定的恶意对象序列化后的流,让目标反序列化,从而达到自己的恶意预期行为,包括命令执行,甚至 getshell 等等。 …...

优先级队列的模拟实现(仿函数)
目录: 1.priority_queue接口的实现(先建大堆) 1.push 加 向上调整的实现 2.pop 3.迭代器区间的构造 2.仿函数 3.仿函数优化我们的优先级队列 -------------------------------------------------------------------------------------------…...

Python pandas和numpy用法参考(转)
以下是转载:Python pandas用法 - 简书介绍 在Python中,pandas是基于NumPy数组构建的,使数据预处理、清洗、分析工作变得更快更简单。pandas是专门为处理表格和混杂数据设计的,而NumPy更适合处...https://www.jianshu.com/p/840ba1…...
mysql数据库的在线数据备份与数据恢复
MySQL是一种常用的关系型数据库管理系统,它支持在线备份和恢复数据。在线备份指的是在MySQL数据库运行时备份数据,而不会中断或影响现有的数据库服务。在本文中,我们将介绍MySQL数据库的在线数据备份和恢复的原理和操作步骤。 一、备份原理 …...

Vue3自定义指令之前端水印功能实现
一、前置知识 — Vue 中的自定义指令 先来说说 vue2和vue3中自定义全局指令的区别 相同点:指令的应用场景,原理是一致的; 不同点:生命周期钩子函数名,指令定义的格式不一样。 vue2中自定义全局指令: 定义…...

文章生成器写出来的原创文章
文章生成机器人 文章生成机器人是一种基于人工智能技术和自然语言处理算法的程序,可以自动地生成高质量、原创的文章。 文章生成机器人的优点如下: 提高工作效率:文章生成机器人能够在较短的时间内自动帮助用户生成大量的文章,提…...
2023年全国最新高校辅导员精选真题及答案49
百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 76.气质就是我们平常所说的脾气秉性。 答案:正确 77.社会心理通常是通过社会…...

【STL十】关联容器——set容器、multiset容器
【STL十】关联容器——set容器、multiset容器一、set简介二、头文件三、模板类四、set的内部结构五、成员函数1、迭代器2、元素访问3、容量4、修改操作~~5、操作~~5、查找6、查看操作六、demo1、查找find2、修改操作insert3、修改操作erase、clear七、multisetset和multiset会根…...

什么是Node.js
文章目录什么是Node.js简介常用命令Node内置模块Node.js和JavaScript的区别什么是Node.js 简介 Node.js是一个基于Chrome V8引擎的JavaScript运行环境。它允许开发者使用JavaScript编写服务器端代码,而不仅仅是浏览器端的代码。Node.js的出现使得JavaScript可以在…...

比GPT-4 Office还炸裂,阿里版GPT全家桶来袭
疯狂3月的那一天,一切还历历在目。 微软突然在发布会上放出大招,用Microsoft 365 Copilot掀起了办公软件革命。 而今天,阿里也放出一枚重磅炸弹——阿里版的Copilot也要来了! 并且比微软更彻底的是,阿里全系产品也都…...
mysql 建表约束
主键约束 -- 主键约束 -- 使某个字段不重复且不得为空,确保表内所有数据的唯一性。 CREATE TABLE user (id INT PRIMARY KEY,name VARCHAR(20) );-- 联合主键 -- 联合主键中的每个字段都不能为空,并且加起来不能和已设置的联合主键重复。 CREATE TABLE …...

在Vue项目中使用tinymce富文本编辑器
TinyMC编辑器简介 TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。跟其他富文本编辑器相比,有着丰富的插件,支持多种语言,能够满足日常的业务需求并且免费。 TinyMCE的优势: 开源可商用,基于LGPL2.1 插…...

GPT-4 和ChatGPT API的定价分析
OpenAI发布了他们的ChatGPT新机器学习模型GPT-4。GPT-4是GPT-3的一大进步,GPT-3是当前ChatGPT免费版本(GPT 3.5 Turbo)所运行的模型的基础,今天我们也来凑个热点,研究一下它们的定价 GPT-4新的功能 GPT-4可以在对话中使用图像,并…...

基于html+css的盒子展示2
准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…...

【持续更新篇】SLAM视觉特征点汇总+ORB特征点+VINS前端
Harris角点 opencv函数 cornerHarris提取输入图像的Harris角点 检测原理 检测思想:使用一个固定窗口在图像上进行任意方向的滑动,对比滑动前后的窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有较大灰度变化…...

【C语言】初阶指针(指针及其类型以及野指针)
简单不先于复杂,而是在复杂之后。 目录 1. 指针是什么? 2. 指针和指针类型 2.1 指针-整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 1. 指针是什么? 指针理解的两个要点: 1. 指针是内存中最小…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...