当前位置: 首页 > news >正文

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.前言 此框架为真实项目实战&#xff0c;所以有些数据不便展示&#xff0c;只展示架构和思想 工具&#xff1a;pythonseleniumddtunittest 1.架构说明 2.代码封装 Commom层 base_page.py #__author__19044168 #date2021/8/26 import logging import datetime from sele…...

什么性格的人适合报考机械类专业?(高考志愿填报选专业)

机械类专业 是指涉及机械设计、制造、加工、维护等方面的专业&#xff0c;是工程类专业中的一类。机械类专业的学生主要学习机械工程的基础知识&#xff0c;包括机械设计、力学、材料力学、热力学、流体力学等&#xff0c;同时也会学习机械制造、机电一体化、机器人技术等实践性…...

进程概念详解

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

C语言基础——指针

文章目录一、指针1.指针的意义2.指针类型表示3.一些操作3.1打印1个变量地址3.2通过地址查看改地址的内容以及修改改地址的内容3.3操作某个空间 -- 4个字节,给他赋值为100&#xff0c;只知道该空间的地址0x8000 00004.指针变量的定义5.指针类型的大小6.指针变量的使用6.1 指针变…...

反序列化渗透与攻防(二)之Java反序列化漏洞

Java反序列化漏洞 反序列化漏洞 JAVA反序列化漏洞到底是如何产生的? 1、由于很多站点或者RMI仓库等接口处存在java的反序列化功能,于是攻击者可以通过构造特定的恶意对象序列化后的流,让目标反序列化,从而达到自己的恶意预期行为,包括命令执行,甚至 getshell 等等。 …...

优先级队列的模拟实现(仿函数)

目录&#xff1a; 1.priority_queue接口的实现&#xff08;先建大堆&#xff09; 1.push 加 向上调整的实现 2.pop 3.迭代器区间的构造 2.仿函数 3.仿函数优化我们的优先级队列 -------------------------------------------------------------------------------------------…...

Python pandas和numpy用法参考(转)

以下是转载&#xff1a;Python pandas用法 - 简书介绍 在Python中&#xff0c;pandas是基于NumPy数组构建的&#xff0c;使数据预处理、清洗、分析工作变得更快更简单。pandas是专门为处理表格和混杂数据设计的&#xff0c;而NumPy更适合处...https://www.jianshu.com/p/840ba1…...

mysql数据库的在线数据备份与数据恢复

MySQL是一种常用的关系型数据库管理系统&#xff0c;它支持在线备份和恢复数据。在线备份指的是在MySQL数据库运行时备份数据&#xff0c;而不会中断或影响现有的数据库服务。在本文中&#xff0c;我们将介绍MySQL数据库的在线数据备份和恢复的原理和操作步骤。 一、备份原理 …...

Vue3自定义指令之前端水印功能实现

一、前置知识 — Vue 中的自定义指令 先来说说 vue2和vue3中自定义全局指令的区别 相同点&#xff1a;指令的应用场景&#xff0c;原理是一致的&#xff1b; 不同点&#xff1a;生命周期钩子函数名&#xff0c;指令定义的格式不一样。 vue2中自定义全局指令&#xff1a; 定义…...

文章生成器写出来的原创文章

文章生成机器人 文章生成机器人是一种基于人工智能技术和自然语言处理算法的程序&#xff0c;可以自动地生成高质量、原创的文章。 文章生成机器人的优点如下&#xff1a; 提高工作效率&#xff1a;文章生成机器人能够在较短的时间内自动帮助用户生成大量的文章&#xff0c;提…...

2023年全国最新高校辅导员精选真题及答案49

百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 76.气质就是我们平常所说的脾气秉性。 答案&#xff1a;正确 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编写服务器端代码&#xff0c;而不仅仅是浏览器端的代码。Node.js的出现使得JavaScript可以在…...

比GPT-4 Office还炸裂,阿里版GPT全家桶来袭

疯狂3月的那一天&#xff0c;一切还历历在目。 微软突然在发布会上放出大招&#xff0c;用Microsoft 365 Copilot掀起了办公软件革命。 而今天&#xff0c;阿里也放出一枚重磅炸弹——阿里版的Copilot也要来了&#xff01; 并且比微软更彻底的是&#xff0c;阿里全系产品也都…...

mysql 建表约束

主键约束 -- 主键约束 -- 使某个字段不重复且不得为空&#xff0c;确保表内所有数据的唯一性。 CREATE TABLE user (id INT PRIMARY KEY,name VARCHAR(20) );-- 联合主键 -- 联合主键中的每个字段都不能为空&#xff0c;并且加起来不能和已设置的联合主键重复。 CREATE TABLE …...

在Vue项目中使用tinymce富文本编辑器

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

GPT-4 和ChatGPT API的定价分析

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

基于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角点 检测原理 检测思想&#xff1a;使用一个固定窗口在图像上进行任意方向的滑动&#xff0c;对比滑动前后的窗口中的像素灰度变化程度&#xff0c;如果存在任意方向上的滑动&#xff0c;都有较大灰度变化&#xf…...

【C语言】初阶指针(指针及其类型以及野指针)

简单不先于复杂&#xff0c;而是在复杂之后。 目录 1. 指针是什么&#xff1f; 2. 指针和指针类型 2.1 指针-整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 1. 指针是什么&#xff1f; 指针理解的两个要点&#xff1a; 1. 指针是内存中最小…...

UDS统一诊断服务【六】访问时序参数0X83服务

文章目录前言一、访问时序参数服务介绍二、数据格式2.1 请求报文2.2 子功能2.3 响应三、举例前言 本文介绍UDS统一诊断服务的访问时序参数0X83服务&#xff0c;希望能对你有所帮助 一、访问时序参数服务介绍 这个服务我目前在项目中没怎么用到过&#xff0c;先来看看ISO14229…...

Linux应用编程(文件属性与目录)

本章将会讨论如下主题内容。 ⚫ Linux 系统的文件类型&#xff1b; ⚫ stat 系统调用&#xff1b; ⚫ 文件各种属性介绍&#xff1a;文件属主、访问权限、时间戳&#xff1b; ⚫ 符号链接与硬链接&#xff1b; ⚫ 目录&#xff1b; ⚫ 删除文件与文件重命名。 一、Linux 系统中…...

第十四届蓝桥杯嵌入式详解

目录 第一部分 客观试题&#xff08;15 分&#xff09; 不定项选择&#xff08;1.5 分/题&#xff09; 第二部分 程序设计试题&#xff08;85 分&#xff09; 2.1 STM32CubeMX初始化配置 2.1.1 配置GPIO 2.1.2 配置ADC 2.1.3 配置RCC 2.1.4 配置定时器TIM 2.1.5 配置ADC1、AD…...

新建论文三线表模板,一键格式刷

论文三线表模板写在最前面①表设计&#xff0c;新建表格样式②三线表上下线③三线表标题线④设置表格居中⑤设置表头格式容易出错的步骤写在最前面 论文写完啦&#xff0c;准备调整格式 之前建模也是三线表&#xff0c;但只能基于该文档模板&#xff0c;所以重新设置一下。 如…...

攻防世界-web2(逆向加密算法)

打开链接是PHP源码 给了一串密文&#xff0c;并对这串密文进行了一系列操作加密&#xff0c;注释里说解密$miwen就是flag 在此我们先介绍一些PHP内置函数&#xff1a; strrev(string): 反转字符串 strlen(string): 返回字符串的长度 substr(string, start, length): 返回字符…...

C语言学习1--------Visual Studio集成开发环境的搭建

C语言学习1--------Visual Studio集成开发环境的搭建适合初学者适用集成开发环境下载 Visual Studio 2019安装 Visual Studio 2019安装工作负载为C自定义安装位置激活 Visual Studio适合初学者适用集成开发环境 建议初学者适用最新的——Visual Studio 2019为集成开发环境。 部…...

腾讯云轻量应用服务器搭建网站教程(WordPress为例)

腾讯云轻量应用服务器搭建WordPress网站教程&#xff0c;先安装WordPress应用镜像&#xff0c;然后远程连接轻量应用服务器获取WP用户名和密码&#xff0c;域名DNS解析到轻量服务器IP地址&#xff0c;登陆WordPress后台管理全过程&#xff0c;腾讯云百科来详细说下腾讯云轻量服…...

mac上的PCB设计软件现状

Altium Designer是一款商业化的电路板设计软件&#xff0c;目前没有Mac版本。但是&#xff0c;MacOS上有一些类似Altium Designer的电路板设计软件&#xff0c;以下是一些常用的软件&#xff1a; Eagle&#xff1a;Eagle是一款商业化的电路板设计软件&#xff0c;具有强大的功能…...

【面试题】JavaScript 你常用的 函数有哪些呢? (12个)

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 本文收集了 12 个在日常开发中非常常用的函数&#xff0c;有些可能很复杂&#xff0c;有些可…...

Java集合——Set接口学习总结

一、HashSet实现类 1.常用方法 增加&#xff1a;add(E e)删除&#xff1a;remove(Object o)、clear()修改&#xff1a;查看&#xff1a;iterator()判断&#xff1a;contains(Object o)、isEmpty()常用遍历方式&#xff1a;Set<String> set new HashSet<String>()…...