目录
2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷5
模块一 私有云(30分)
任务1 私有云服务搭建(5分)
任务2 私有云服务运维(15分)
任务3 私有云运维开发(10分)
模块二 容器云(30分)
任务1 容器云服务搭建(5分)
任务2 容器云服务运维(15分)
任务3 容器云运维开发(10分)
模块三 公有云(40分)
任务1 公有云服务搭建(5分)
任务2 公有云服务运维(10分)
任务3 公有云运维开发(10分)
任务4 边缘计算系统运维(10分)
任务5 边缘计算云应用开发(5分)
2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷5 某企业根据自身业务需求,实施数字化转型,规划和建设数字化平台,平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”,拟采用开源OpenStack搭建企业内部私有云平台,开源Kubernetes搭建云原生服务平台,选择国内主流公有云平台服务,基于数字化平台底座,面向业务开发边缘计算云应用产品。
拟将该任务交给工程师A与B,分工协助完成云平台服务部署、云应用开发、云系统运维等任务,系统架构如图1所示,IP地址规划如表1所示。
图 1 系统架构图
表 1 IP 地址规划
设备名称
主机名
接 口
IP 地址
说明
云服务器 1
controller
eth0
172.129.x.0/24
vlan x
eth1
自定义
自行创建
云服务器 2
compute
eth0
172.129.x.0/24
vlan x
eth1
自定义
自行创建
云服务器 3
版本:Ubuntu20.04 + Matlab R2021a + PSINS170220
运行psinsinit.m时报错如下:
1、注释掉下面代码
2、修改源代码12-14行
原文件
pp = [';',path,';']; kpsins = strfind(pp, 'psins'); ksemicolon = strfind(pp, ';'); 修改后
pp = [':',path,':']; kpsins = strfind(pp, 'psins'); ksemicolon = strfind(pp, ':'); 继续运行psinsinit.m
参考链接:
非常感谢以下链接
https://blog.csdn.net/yys2324826380/article/details/105712907
一、BigDecimal概述 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。
一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。
BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
二、BigDecimal常用构造函数 2.1、常用构造函数
BigDecimal(int)
创建一个具有参数所指定整数值的对象
BigDecimal(double)
创建一个具有参数所指定双精度值的对象
BigDecimal(long)
创建一个具有参数所指定长整数值的对象
BigDecimal(String)
创建一个具有参数所指定以字符串表示的数值的对象
三、BigDecimal常用方法详解 下面是常用的30个BigDecimal API:
add(BigDecimal val):加法操作subtract(BigDecimal val):减法操作multiply(BigDecimal val):乘法操作divide(BigDecimal val):除法操作setScale(int newScale, int roundingMode):设置小数位数和取整方式compareTo(BigDecimal val):比较大小equals(Object obj):判断两个BigDecimal对象是否相等intValue():返回此BigDecimal的整数值longValue():返回此BigDecimal的长整数值floatValue():将此BigDecimal转换为float类型doubleValue():将此BigDecimal转换为double类型toString():将此BigDecimal转换为字符串valueOf(double val):将double类型转换为BigDecimal对象abs():返回此BigDecimal的绝对值negate():返回此BigDecimal的相反数pow(int n):返回此BigDecimal的n次幂remainder(BigDecimal val):返回此BigDecimal除以val的余数round(MathContext mc):使用指定的MathContext将此BigDecimal四舍五入stripTrailingZeros():返回去除尾部零的BigDecimaltoBigInteger():将此BigDecimal转换为BigInteger类型ulp():返回BigDecimal的最小精度值max(BigDecimal val):返回此BigDecimal与val中较大的值min(BigDecimal val):返回此BigDecimal与val中较小的值setScale(int newScale):设置小数位数,使用默认的取整方式intValueExact():返回此BigDecimal的整数值,如果不是整数则抛出异常longValueExact():返回此BigDecimal的长整数值,如果不是长整数则抛出异常movePointLeft(int n):将小数点左移n位movePointRight(int n):将小数点右移n位scale():返回此BigDecimal的小数位数signum():返回此BigDecimal的符号函数,1表示大于0,-1表示小于0,0表示等于0。 BigDecimal的取整方式 BigDecimal可以通过 setScale(int newScale, int roundingMode) 方法设置小数位数和取整方式。第一个参数 newScale 表示设置后的小数位数,第二个参数 roundingMode 表示取整方式。
roundingMode 参数可以选择以下取整方式:
BigDecimal.ROUND_CEILING :向正无穷方向取整,即大于或等于此数的最小整数。BigDecimal.ROUND_DOWN :向零方向取整,即舍弃小数部分。BigDecimal.ROUND_FLOOR :向负无穷方向取整,即小于或等于此数的最大整数。BigDecimal.ROUND_HALF_DOWN :向最近的整数舍弃一半的小数部分,如果舍弃部分大于等于0.5,则向下取整,否则向上取整。BigDecimal.ROUND_HALF_EVEN :向最近的整数舍弃一半的小数部分,如果舍弃部分等于0.5,并且舍弃部分前面的数字为偶数,则向下取整,否则向上取整。BigDecimal.ROUND_HALF_UP :向最近的整数舍弃一半的小数部分,如果舍弃部分大于0.5,则向上取整,否则向下取整。BigDecimal.ROUND_UNNECESSARY :如果存在小数部分,则抛出 ArithmeticException 异常。BigDecimal.ROUND_UP :向远离零的方向取整,即大于或等于此数的最小整数。 例如,以下代码将一个 BigDecimal 对象舍入到小数点后两位,并以 ROUND_HALF_UP 的方式进行取整:
BigDecimal bd = new BigDecimal("
本身在公司中碰到一个需求是点击按钮,在输入框中展示出按钮的文字。
查阅网上资料,发现在这方面给出的答案很少,要么就是和我的需求不同,我是用不了,要么就是写的太过复杂,很难优化,因为我看的也是云里雾里的。
所以通过对网上的其他资料研究,自己弄了个汇总的,帮助自己以后再碰到这种需求能够更快的解决。
这里用到的就是一个选区对象和区域对象。window.getSelection()获取选区对象。
Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。要获取用于检查或修改的 Selection 对象,请调用 window.getSelection()。包括了用户选中的文明范围或光标位置
还有一个区域对象range,window.getSelection().getRangeAt(0),编辑区中的光标位置操作更多还是在这个对象中实现,这是选区中我们选择的范围对象。
如果一上来对这两个对象没有了解的话,还是不建议接着往下看,因为我讲的不是很细,并没有对这两个对象做一个全面的介绍,我的更多细节会在代码中体现。
如果是对这两个对象有了解的话,可以接着往下看,因为我在代码中给了更多的解释,相较于其他的答案更加直观易懂,写的不算很复杂。
<body> <!-- 实现一个功能:div变为可编辑,可向编辑框中插入元素和自定义文本,并且可以指定光标位置 --> <div class="edit" contenteditable="true" oninput="editInput(event)"></div> <!-- 该按钮指定向编辑框中插入元素 --> <button class="nodeButton">向编辑框中插入元素</button> <br> <input type="text" placeholder="请输入文本"> <!-- 该按钮指定向编辑框中插入自定义文本 --> <button class="textButton">向编辑框中输入文本</button> <script> const div = document.getElementsByClassName("edit")[0] const body = document.getElementsByTagName("body")[0] const nodeButton = document.getElementsByClassName("nodeButton")[0] const textButton = document.getElementsByClassName("textButton")[0] const input = document.getElementsByTagName("input")[0] const creDOM = document.createElement("div") creDOM.innerText = `${div.innerText.length}/100` body.appendChild(creDOM) // 这一个方法是记录输入字符数的,不需要关心 function editInput(e) { creDOM.innerText = `${div.
在Java中,printf和println都是用于在控制台输出文本的方法,但是它们之间有一些不同之处。
目录
一:printf
二:println
三:printf与println的区别
一:printf printf是一个格式化输出方法,它以指定的格式输出指定的信息。它类似于C语言中的printf,在Java中,你可以使用“%”转换符指定要在输出中包含的变量值。下面是一个简单的示例:
System.out.printf("My name is %s and my age is %d", "Bob", 25); 输出: My name is Bob and my age is 25
在这个示例中,“%s”和“%d”是转换符,表示字符串和整数变量,他们按顺序插入到字符串中。
当你使用printf时,你可以使用转换符将不同类型的变量插入到输出字符串中。下面是一些常用的转换符:
- %d - 整数类型(十进制)
- %f - 浮点数类型
- %s - 字符串类型
- %c - 字符类型
- %b - 布尔类型
- %t - 日期/时间类型
- %n - 新行符
你可以在一个printf语句中使用多个转换符,如下所示:
int a = 10; double b = 3.14159; String c = "
目录 1 引入情境基本归并排序实现 C++ 2 原地归并排序2-1 死板的解法2-2 原地工作区2-3 链表归并排序 3 自底向上归并排序4 两路自然归并排序4-1 形式化描述4-2 代码实现 1 引入情境 归并思想:假设有两队小孩,都是从矮到高排序,现在通过一扇门后合并为一队。要求:任何孩子,只有所有比它矮的孩子通过后,才能通过。
直接给出归并排序的伪代码: function merge_sort(A): if len(A) > 1 then m = floor(len(A)/2) # 获取中心点 X = copy_array(A,0,m) Y = copy_array(A,m+1,len(A)-1) #拆成差不多的两半 merge_sort(X) merge_sort(Y) # 分别排序 merge(A,X,Y) # 合并 假如我理解了上面归并,但是,在排序之前,怎么得到有序的两个队列呢?注意到,伪代码的出口是 l e n ( A ) ≤ 1 len(A) \leq 1 len(A)≤1 就会返回,即一个数本身有序。当它拆分到自然有序,返回头开始合并,直接上图:
一个更明确的例子,同色表明为一组,且基本是平均分割: 只剩下一个问题,merge(A,X,Y)是怎么做的?简单的理解,每次比较X,Y头部,选一个最小的放到目标有序数组A的队尾即可;若一队为空,另一队还有剩余就直接放到A的队尾。给出伪代码描述:
function Merge(A,X,Y): i=1,j=1,k=1 xlen=|X| ylen=|Y| # 从队伍头部选一个最小的放到目标队伍末尾 while i<= xlen and j <=ylen do if X[i] <= Y[i] then A[k] = X[i] i = i + 1 else A[k] = Y[j] j = j + 1 k = k + 1 # 处理剩余的部分,放到末尾 while i <= xlen do A[k] = X[i] k = k + 1 while j <= ylen do A[k]= Y[j] j = j + 1 关于时间复杂度,设排序用时为 T ( N ) T(N) T(N),则递归开销为:
目录
protobuf是个好东西
遇到问题
顺便研究一下命令行程序如何调试
protobuf是个好东西 protobuf是一个轻量级的数据格式,相比json,它的数据量为json的1/3,且存储方式为2进制,并进行了压缩,序列化和反序列化更快,保密性更好,但易读性差,适用于在客户端与服务器通信消息传递,尤其是巨量信息时,我们需要学习它。
以下来自chatGPT的回答:
Protobuf(Protocol Buffers)是一种轻量级的数据序列化格式,它可以将结构化的数据转换为紧凑的二进制格式,从而实现高效的数据传输和存储。
下面是 Protobuf 数据量小的原因:
1. 二进制编码:与 XML 和 JSON 等其他数据序列化格式相比,Protobuf 使用二进制编码来表示数据。这意味着它不需要像文本格式那样使用大量的空格、换行符和标签来描述数据,从而减少了数据量的大小。
2. 数据压缩:Protobuf 可以将数据压缩成更小的二进制格式,以进一步减少数据传输和存储的大小。这个功能可以通过启用“压缩”选项来实现。
3. 无需额外的元数据:与 XML 和 JSON 不同,Protobuf 中不需要额外的元数据来描述数据。相反,它使用预定义的消息类型和字段来定义数据结构。这意味着 Protobuf 不需要为每个值添加标签和类型信息,从而减少了数据量的大小。
4. 代码生成:Protobuf 可以自动生成编解码器和相关的代码,这使得代码的体积非常小,而且不需要使用反射等机制。这些编解码器使用底层的二进制协议来快速地读取和写入数据。
因此,由于它使用二进制编码、数据压缩、无需额外的元数据和代码生成等技术,Protobuf 可以实现非常小的数据量,并且可以实现高效的数据传输和存储。
遇到问题 protogen.exe是一个Protobuf for .net的库,期中protogen.exe是一个命令行程序,在使用这个命令行程序时总是出错。我使用的是3.2.8版本。和1.x的命令行参数完全不一样了。
我们看上面的命令提示信息,根据这些信息,尝试了很多参数都是报错误,于是将源代码拉下来研究一下。
代码库地址为:
protobuf-net/protobuf-net: Protocol Buffers library for habitmatic .NET (github.com)
使用以下命令实现了将Person.proto转为Person.cs文件,并且Person.cs位于当前目录\cs
protogen Person.proto --csharp_out="cs" 来看看1.x的命令这样用:1.x提示很清楚,3.x的提示让人无从下手
protogen -i:input.proto -o:output.cs 现在来对照之前的提示信息,我觉得正常人都想不到命令行参数要这么写(或许我水平有限),这算是一个坑吗?
顺便研究一下命令行程序如何调试 新建一个【调试参数配置】
args先使用空格分割,再用=分割,左边是参数右边是值
了解了命令行args的用法,以后工作工可能用得到。
文章目录 前言2048小游戏(C语言实现)导入图片批量加载图片设置背景随机生成数字获取用户的按键向上移动代码:向下移动代码:向左移动代码:向右移动代码:总代码:运行结果 前言 本次实验跟随https://www.bilibili.com/video/BV1BC4y1H7jz/?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click做的练习,感兴趣的可以看看
2048小游戏(C语言实现) 在完成2048小游戏之前,我们要先学会导入图片,导入了图片才会变得好看。
导入图片 #include <stdio.h> #include <stdlib.h> // 导入图片资源的头文件是 #include <graphics.h> int main() { // 首先初始化图形窗口,并设置大小 initgraph(800, 400); // 声明图片变量 IMAGE background; // 加载图片资源到loadimage中(注意,一般"./rec.jpg"就可,如果显示重载错误,请在前面加L) loadimage(&background, L"./rec.jpg", 800, 400); // putimage显示图片 putimage(0, 0, &background); // 避免闪屏 getchar(); // 关闭图形窗口 closegraph(); system("pause"); return 0; } ./rec.jpg是自己导入到main.c当前目录下的文件
在加载图片到loadimage中时,如果产生两个重载的错误,请在前面加L(在网上查找了很久)
或者将字符集改成多字节字符集
显示结果如下:
批量加载图片 正如我们所知,2048有很多图片需要加载,我们不可能每次加载图片都重复写一样的函数,于是就批量加载图片减少代码量
// 存放12张图片 IMAGE img[12]; // 定义图片 int imgIndex[12] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 }; // 加载资源 void loadResource() { for (i = 0; i < 12; i++) { //批量加载 //加入名字 char filename[20] = "
所谓“男怕入错行”,其实对女生来说也是一样,不同行业对人生的改变太大,想要找到满意的工作,就要不断去尝试。
西安的学员小文,大学毕业后从事的本专业(物业管理)工作,但不是很喜欢,薪资也偏低。后面转到建筑行业做人力资源管理,需要跟着项目走,考虑到接下来的职业规划,以及自身情况,小文决定转行软件测试。
虽然行业跨度比较大,也涉及到技术性内容,担心自己学不懂。但鉴于朋友学习软件测试且成功找到了合适的工作,于是几经辗转终于开始了自己的转行IT之路。
从很多毕业学员的经历里我们都能知道,在职场中摸爬滚打后,再沉下心来学习真的很难,但继续着之前温水煮青蛙式的工作更痛苦,选择转行自然需要坚定信心。
因为住得远,小文每天在通勤时间上要花四个小时,学习时间很紧促,写完作业基本都到凌晨了。软件测试的知识量大,每天都要复习和巩固所学的内容。为了跟上教学进度,小文把一些碎片化时间都利用起来学习,会在地铁上看书,背笔记。
转行过程中的学习,是为了积蓄力量,以便让自己走得更远。负责的教学老师,优秀的学习伙伴,都是前进道路上的推动力。
“张颖老师教学经验丰富,课堂上能引导大家跟着她的思路走。王濛老师的教学氛围很轻松,能用简练的语言教授知识点和测试方法。张娜老师,非常认真负责任的一位老师,还有班主任孙老师,时刻在关注和督导我们学习。”
在面试求职阶段,小文难免有些紧张,就业老师给予了很多辅导和支持,帮助她顺利拿到了心仪的offer。
谈及新工作,小文说主要是负责信用卡核心的项目,核心支付涉及到的系统比较多,除了本身的业务知识要非常熟悉,数据库、Linux命令都是会用到的。对于后续的职场发展,她也充满期待。
“知识改变命运这句话不是鸡汤,很现实。没有一个好学历或是掌握一项技能,找到满意的工作基本上是不可能的。所以,想要拥有更好的生活,我们只能不断地丰富和提高自己,学习软件测试是目前我认为最低成本的投入。”
转行是非常重要的事,当你想转行的时候,往往说明在原有的行业里很难继续往上走了。很多人犹豫、纠结,然后时间就这样浪费掉了,这个时候,不如试着去接受新的行业知识和技能,脚踏实地积累经验,掌握必要的技术,自然会有相应的回报。
面试时长跟通过概率有关系吗?
一位网友分享了自己的求职感想:
面试过程越长,差不多一个小时或者超过一个小时,问得越详细,通过的可能性越低。因为问得越细,说明这个公司越挑,需要候选人匹配度越高,但凡有一点跟面试官期望不符,就很可能不通过。
反而是面试时长不长,在半小时左右或者半小时以内,通过的概率越高,因为面试官的要求没有那么多,通过短短的面试过程也无法对求职者有太深了解,只能凭简历、第一印象以及面试中的简单了解确认求职者是否合适,这样被录用的可能性更高。
许多网友表示赞同,有人说,自己找了半年工作,面试跨度一个月的都挂了,最后找到的工作一周就完成了所有流程。
有人说,遇到过面试官跟自己聊了很多的,不出意料地挂了。
有人说,真缺人的时候,谁会在那里问半天,都等着人入职干活呢。
有人说,问得细的人都没有决定权。
有人说,问得细的大多是在白嫖方案,套公司信息。
有人说,也可能是招不到人,在给候选人刷印象分和洗脑。
也有人说,不一定,自己跟资深候选人聊,通常都是几个小时。
有人说,有可能许多大厂规定面试要一个小时。
有人说,按照楼主的说法,面试时间长代表公司规格高,公司技术更厉害,入职一家公司要的不仅仅是高薪,也需要有成长和发展空间。
有人说,面试卡得严的公司比面试宽松的公司,坑少一些。
有人说,面试时间短的公司工资低,面试时间长的公司工资相对高一点。
还有人说,面试时间短有没有可能是求职者太差了?
有人说,如果面试官觉得你牛,就会让你过。如果谈了一个小时还没找到牛逼之处,当然会挂你。别人面试时间短,是因为他只用五分钟就震住了面试官。
一位网友说,面试时长要看职位,一般中低端职位半小时左右,高端职位一两个小时,谈得时间长说明企业关注点多,但泛泛而谈的以后可能坑更多。所以,万事没有绝对。
另一位网友说,找工作,缘分是关键,从hr到人资负责人,用人部门负责人,中心负责人,其中一个没有缘分,这份工作都没戏。
面试时长和通过概率有关系吗?
一般情况下,人们会觉得面试时长越长,说明公司想多了解求职者一些,证明公司对该求职者有兴趣,自然面试成功的几率就大一些。如果面试时间短,说明面试官对求职者兴趣不大,那么面试通过的几率就小一些。
但也有像楼主说的这种情况存在:面试时间长,说明公司要求严苛,比较挑剔,通过的概率就不大;面试时间短一点,说明公司不怎么挑人,容易通过。
不过有一点我们要注意,抛开面试提问,只看面试时长下结论太绝对了。在实际面试中,面试官的问题是切合实际还是浮于表面,是句句在点还是泛泛而谈,都代表着公司对面试的态度,也从侧面反映了公司的水平和门槛。毕竟通过面试只是第一道关卡,后续的个人发展、福利待遇和职场环境更加重要。
想跑的例程:圆环转矩形(python opencv)
https://blog.csdn.net/wi162yyxq/article/details/106980593
文章目录 1. 搭环境2. 代码3. 参考 1. 搭环境 conda新虚拟环境(opencv):numpy,opencv,matplotlib包(conda install 前两个包名,pip install matplotlib),版本降级conda install pywin32=302,conda list查看已安装的包
conda新建虚拟环境
用jupyter notebook打开新环境(opencv)
https://blog.csdn.net/weixin_44109827/article/details/127195459
2. 代码 # cell 1 import cv2 %matplotlib inline import numpy as np import math def get_huan_by_circle(img,circle_center,radius,radius_width): black_img = np.zeros((radius_width,int(2*radius*math.pi),3),dtype='uint8') for row in range(0,black_img.shape[0]): for col in range(0,black_img.shape[1]): theta = math.pi*2/black_img.shape[1]*(col+1) rho = radius-row-1 p_x = int(circle_center[0] + rho*math.cos(theta)+0.5) p_y = int(circle_center[1] - rho*math.sin(theta)+0.5) black_img[row,col,:] = img[p_y,p_x,:] #IM.
文章目录 学习链接通过scrollHeight实现通过js获取auto时的高度去实现(效果不好)优化 通过grid实现 学习链接 vue项目列表折叠面板动画效果实现
element-ui之el-collapse-transition(折叠展开动画)源码解析学习
通过scrollHeight实现 以下代码注意两点
trainsition是需要有两个值,才能产生过渡动画的,所以一开始就需要获取到box1的高度(通过scrollHeight去获取它的高度)box1收缩,其实就是把它的height改为0,超出部分隐藏,这样子元素就隐藏了(但是注意,这个时候,仍然可以通过scrollHeight获取到box1的实际高度,尽管它的style的height已经是0了) <template> <div> <el-button plain type="danger" @click="toggleDiv" size="mini" style="margin-bottom: 10px;" >toggleDiv</el-button> <div class="box1" ref="box1" id="box1"> <div class="box1-item"></div> <div class="box1-item"></div> <div class="box1-item"></div> <div class="box1-item"></div> <div class="box1-item"></div> </div> </div> </template> <script> export default { name: 'Collapse', components: { }, data() { return { isCollapse: false, } }, mounted() { // 刚开始的时候, 就必须先获取到这个元素的高度(transition需要有两个数值才能产生过渡), 它必须刚开始就是可见的(不能display:none) console.log('mounted', this.$refs['box1'].scrollHeight); this.$refs['box1'].style.height = this.$refs['box1'].scrollHeight + 'px' }, methods: { toggleDiv() { this.
我看到一段opencv的代码,是在python环境跑的,我的python环境(anaconda - jupyter notebook)是刚装好的空白环境,没有opencv包。怎么用anaconda安装一个opencv包呢?
他使用了import cv2,我不知道import cv2应该安装哪个包
我不太会用anaconda命令行,所以打开anaconda navigator,在base环境搜索opencv,左侧选择all,然后出来3个包:libopencv,opencv,py-opencv。
我觉得opencv看起来比较靠谱,就点了个勾,apply。
然后它一直卡住(二十来分钟),说solving package specification。
我上网找了这个报错信息,尝试找解决方案,但是,所有的csdn方法看起来都不是很靠谱。有一个有二十条评论说有用的文章我不想用,因为那篇文章找到一个很角落里的文件,把查询什么version的代码换成了一个固定version。妈的,我怎么知道我的version是不是他提供的version?肯定不是啊,我的anaconda是刚更新好的,肯定跟他的不一样,按照他的方法操作,万一出错怎么办?我看这么多人用着都没出问题,那我应该也不会出问题,但是这个操作也太角落了吧?anaconda不是以便捷著称吗?为什么会卡在solving package specification这么显眼的步骤?我不是有梯子吗?我相当于外国人,外国人用anaconda会遇到这些B问题吗?操,不会,因为我网上搜不到这些问题的解决方式。我不喜欢这么简单的软件用这么角落的解决方案,而且我还不理解他的原理,这让我怎么接受!
我打开conda的命令行,新建了一个环境叫opencv,在里面测试python的opencv代码。
我输入conda install opencv-python,因为我查了一下百度应该是安装这个包名(python跑opencv的话),但是报错了,我他妈的刚添加了3条清华源啊,我还有梯子,为什么他妈的给我报错,好像说找不到什么来着,让我找找别的源。我操你妈!anaconda会安装不了opencv这么大的库?你妈的B!我选的是python3.9,有问题!?你妈的B
我记得我换成pip install opencv-python也是下到一半下不动了。他妈的B!我用的是shadowsock,不是很好的梯子吗!为什么你妈的下不动!我操你妈!
然后我换成conda install opencv。
他妈的 成功了!操!为什么!你他妈的不是没有opencv这个包名吗(navigator里)!操!这个世界怎么回事!为什么我搜寻不到我需要的信息!
有没有人帮帮我!我也没有朋友!他妈的!
我也不是计算机专业出身!我只是一个电子类的本科生!普通本科!不是一本!
操
联合两位大佬一起对gpt官方的接口做了整合。 https://sheep.fzgo.me 欢迎大家参与内测,提出宝贵的意见。(Fikz–216)
点我立刻体验
有感兴趣的可以一起开发交流,下文有部分代码讲解。感兴趣的可以加入一起测试玩耍(文末有加入方式)~
模型介绍 内测内容包括文字生成图片、图片生成图片、联网模式、模型定制、多角色设定等。 1、联网模式:联网+gpt回答,答案更准确
# Note: you need to be using OpenAI Python v0.27.0 for the code below to work import openai openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Who won the world series in 2020?"}, {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}, {"role": "user", "content": "Where was it played?"} ] ) format { 'id': 'chatcmpl-6p9XYPYSTTRi0xEviKjjilqrWU2Ve', 'object': 'chat.
VueUse 是一个非常实用的 Vue.js 工具库,它提供了许多有用的组件和方法,可以帮助开发者快速构建高性能、可复用的 Vue.js 应用。本文将详细介绍 VueUse 的代码实现和技术细节。
VueUse 简介 VueUse 是一个实用的 Vue.js 实用工具库,它旨在帮助开发者在项目中避免重复的逻辑,提高开发效率。VueUse 提供了许多用于构建可复用、高性能 Vue.js 应用的实用工具方法和 Hooks。
VueUse 的主要组件和方法 2.1 useMouse 和 useMouseCoordinates
useMouse 是一个用于追踪鼠标位置的 Hook,可以帮助开发者在 Vue.js 应用中实现鼠标追踪和交互效果。同时,VueUse 还提供了 useMouseCoordinates,它是 useMouse 的简化版,只追踪鼠标位置,不涉及鼠标事件的处理。
2.2 useKeyboard 和 useKeyboardNavigation
useKeyboard 是一个用于监听键盘事件的 Hook,可以帮助开发者实现基于键盘事件的交互效果。使用 useKeyboardNavigation,开发者可以更方便地监听键盘事件而不涉及键盘事件的处理。
2.3 useWheel 和 useWheelDelta
useWheel 是一个用于监听鼠标滚轮事件的 Hook,可以帮助开发者实现基于鼠标滚轮事件的交互效果。此外,VueUse 还提供了 useWheelDelta,它是 useWheel 的简化版,只监听鼠标滚轮事件,不涉及鼠标滚轮事件的处理。
2.4 useFocus 和 useBlur
useFocus 是一个用于监听和处理焦点事件的 Hook,可以帮助开发者实现焦点的管理和移动。使用 useBlur,可以更方便地监听和处理焦点事件而不涉及焦点的管理和移动。
除了上述组件和方法之外,VueUse 还提供了许多其他有用的 Hooks,例如 useLocalStorage、useSessionStorage、useFullscreen 等,这些 Hooks 可以更方便地实现一些常见的功能。
VueUse 的实现原理 VueUse 的实现主要依赖于 Vue.
摘要:Windows窗体设计程序提供众多控件,其中,工具箱窗口的公共控件栏里包含较为常见的控件。根据功能分类,其中用于显示信息的控件包括标签(Label)和超链接标签(LinkLabel)。Label用于显示不可编辑的信息,LinkLabel除显示不可编辑信息外,还提供执行文件、网址和电子邮件链接功能,两者使用非常广泛。本文利用Visual Studio 2019的Windows窗体设计程序,基于C#编程语言,从控件常用属性和事件,结合具体示例,分别介绍Label和LinkLabel。
目录
Label控件 属性
布局
设计 外观 行为 LinkLabel控件 属性
事件 小结
Label控件 Label控件用于显示不可编辑信息,支持设置显示内容、字体大小、字体颜色和背景色等功能,具体实现由其属性决定。由于Label控件不支持一些额外的互动,没有特殊的事件,对于其事件将不再赘述。
属性 布局 AntoSize:bool类型,指示是否启用根据标签内容字号自动调整大小,初始为true。 当AntoSize属性为true时,不能设置其尺寸(Size),Size属性根据标签内容(Text)的长度和字体字号(Font)自动给出。若要自定义Size,需要将AntoSize属性置为false。经测试,当AntoSize属性为false时,对于水平显示的文本内容,宽度(Width)不够而高度够(Height),文本内容会自动换行;Width和Height都不够,文本内容将显示不全。因此,在编程时发现标签内容显示不全时,考虑Size是否设置足够大。
Location:Point类型,定义控件左上角相对于其容器左上角的像素坐标,初始为所放置的点的像素坐标。Size:Size类型,定义控件的像素尺寸,初始为宽41,高12,即文本“Label1”在小五宋体所占的尺寸大小。 设计 Name:string类型,定义代码中用于标识控件的成员变量名,初始为Label1。 Name属性需要在GenerateMember属性为true才生效,若GenerateMember属性为false,将不会为控件生成成员变量,此时在代码中输入Name会报错。
GenerateMember:bool类型,指示是否为控件生成成员变量,初始为true,上述已经提到。Locked:bool类型,指示是否可以通过鼠标移动控件(Location)或者调整控件尺寸(Size),初始为false。 当Locked属性为true时,在设计界面选中该控件会在左上角显示一把锁,提示不能通过鼠标移动控件和调整尺寸,但可以通过输入Location坐标或者Size尺寸数值来操作它。
Modifiers:枚举类型,定义控件的可访问性级别,枚举值有Private(同类可访问)、Public(公开访问)、Protected(同类及派生类可访问)、Internal(同程序集可访问)、Protected Internal(同程序集及派生程序集可访问),初始为Private。(注:要想在其他类里访问该控件,需要修改这个属性,这个属性无法写代码修改 当需要在其他类里访问该控件时,应设置Modifiers为合适的属性,用Public最方便,访问无限制,若保持Modifiers为Private,在其他类访问该控件时会报错。
外观 BackColor:Color类型,定义控件的背景色,初始为SystemColors.Control(系统灰)。BorderStyle:BorderStyle枚举类型,定义标签的边框,枚举值有None(无边框)、FixedSingle(固定单线边框)、Fixed3D(固定3D边框),初始为None。 BackgroundImage:Image类型,定义控件的背景图像,初始为空,即透明背景。BackgroundImageLayout:ImageLayout枚举类型,定义控件背景图像布局方式,枚举值有None(靠左显示)、Tile(重复显示)、Center(居中显示)、Stretch(拉伸占满显示)、Zoom(按比例缩放显示),初始为Tile。Cursor:Cursor枚举类型,定义鼠标移动到控件上显示的光标,初始为Default。 在Cursor属性的下拉框展示了各种枚举值所对应光标种类供开发者选择。
Font:Font类型,定义控件文本的字体和字号等,初始为宋体,9pt(小五)。 Font属性提供了一个供开发者选择的交互界面,包括多种不同字体选择、四种字形选择、多种不同字号选择、删除线和下划线选择等,类似于Word设置字体的交互界面。
ForeColor:Color类型,定义控件文本的颜色,初始为系统颜色SystemColors.ControlText(文本黑)。Image:Image类型,定义控件上显示的图像,初始为空。 Label虽是标签控件,但也提供了图像显示功能,有时是可以客串PictureBox控件使用的。
ImageAlign:ContentAlignment枚举型,定义控件显示图像的对齐方式,初始为MiddleCenter(水平、竖直居中)。 ImageAlign提供左上、左中、左下、中上、中中、中下、右上、右中、右下九种不同位置,在其下拉框可以形象的直接选择。
Text:string类型,定义控件显示的文本,初始为“label1”。TextAlign:ContentAlignment枚举型,定义控件显示文本的对齐方式,初始为MiddleCenter(水平、竖直居中),其下拉条交互方式与ImageAlign属性相同,见上图。 行为 AutoEllipsis:bool类型,指示是否自动处理溢出宽度以外的文本,初始为false。 所谓自动处理,实际上就是对溢出文本以省略号显示。
ContextMenuStrip:定义用户右击控件时显示的快捷菜单,初始为空。(注:若要创建此菜单,需要写代码创建或先拖入ContextMenuStrip控件后再到此处选择,详见我的另一篇)C#Windows窗体设计之ContextMenuStrip(鼠标右击菜单)的用法_c# contextmenustrip用法_To be better now的博客-CSDN博客Enabled:bool型,指示是否启用该控件,初始为true。 标签控件的Enabled属性为false时,将默认显示灰色文本。
Visible:bool类型,指示是否显示该控件,初始为true,为false则隐藏控件。
LinkLabel控件 同样是显示信息控件,LinkLabel控件额外提供了外部链接交互功能,用于实现超链接。超链接的具体实现依靠LinkClicked事件,在事件方法体里写入要转到的链接地址即可。LinkLabel控件和Label类似,两者相同的属性在此不再赘述,本节主要介绍LinkLabel控件特有的属性和事件。
属性 ActiveLinkColor:Color类型,定义单击超链接控件且未释放鼠标时,超链接显示的颜色,初始为Red(红色)。DisabledLinkColor:Color类型,定义当超链接被禁用时的颜色,初始为RGB(133,133,133)(灰色)。 注意,这个属性是超链接被禁用时触发,而不是超链接控件被禁用时触发。如果在属性框把控件的Enabled属性置为false,将直接显示默认灰色,跟此属性无关。要使这个属性起作用,需要使用以下代码,其中0可以换成其他索引index。
linkLabel1.Links[0].Enabled = false;//linkLabel1控件的第一条超链接置为不可用 LinkColor:Color类型,定义超链接默认显示的颜色,初始为Blue(蓝色)。LinkVisited:bool类型,指示超链接是否按已访问的样式呈现 ,初始为false。VisitedLinkColor:Color类型,定义当LinkVisited属性为true时,超链接显示的颜色,初始为RGB(128,0,128)(看着像是一种紫色)LinkArea:LinkArea类型,定义超链接控件文本中视为超链接的文本范围,初始为文本全覆盖。 LinkArea属性的格式为(x,y),x代表视为超链接文本的起始索引,y代表视为超链接文本的字符数,整体表示视为超链接的文本从第x个字符开始,数y个字符结束。用代码对其赋值时,需要以new运算符新建一个。
linkLabel2.LinkArea = new LinkArea(0, 5); LinkBehavior:LinkBehevior枚举类型,定义超链接下划线的样式,枚举值包括SystemDefault(系统默认)、AlwaysUnderline(始终有下划线)、HoverUnderline(鼠标悬停时有下划线)、NeverUnderline(无下划线),初始为SystemDefault。Links(控件属性框没有,但很重要):LinkCollection类型,定义超链接控件中包含的超链接的集合,初始集合仅有一个元素,即只包含一个超链接。 Links属性的存在意味着一个超链接控件可以包含多个超链接,可以用不同的字符范围代表不同的超链接,然后将其添加到Links集合就可以实现多个超链接,添加超链接语句如下,效果如下。
linkLabel2.Links.Add(7, 2);//linkLabel2添加超链接,文本范围为第七个字符往后两个字符 事件 LinkClicked():超链接单击事件,单击超链接文本时触发,常用来链接到执行文件、网址和电子邮箱。 输入以下代码到LinkClicked事件方法体里,将其链接到CSDN官网首页,测试。
apisdk-starter整体思路 首先定义开发者定义的开放接口声明为原始类,javassist生成的类是增强类。
使用springboot的EnableAutoConfiguration和Import触发Spring扫描组件扫描原始类,得到所有BeanDefinition拓展FactoryBean,构造函数的参数为原始类的Class遍历BeanDefinition,设置beanClass为拓展的FactoryBean的Class,构造参数是原始类的Class,这样FactoryBean会把原始类对象的生命周期交给spring管理,开发者可以通过@Resource完成依赖注入在FactoryBean#getObject实例化原始类的代理对象时,使用javassist复制原始类,在内存中生成增强类,然后在方法参数上追加SdkContext参数声明,这样增强类就满足了apisdk的要求,通过apisdk生成增强类的代理对象,和原始类的代理对象形成映射关系。 有了原始类和增强类的映射关系后,接下来要解决运行时,如何查找增强类的代理对象,如何构建SdkContext请求上下文的问题。要解决这个问题,就要在原始类的代理对象着手。
抽取spring aop的源码,用aop的JdkDynamicAopProxy创建原始类的代理对象,即FactoryBean#getObject方法返回的对象,这样可以做到执行原始类的方法时,查找增强类的代理对象,发起Http请求,同时在这里做了失败重试的机制拓展参数可变的前置通知,用于SdkContext参数的构建,本质是调用了RegionMock、SecretMock和TokenMock服务,然后把SdkContext参数追加到请求参数中 以上就是apisdk-starter的整体思路,其中抽取spring aop源码是为了脱离spring容器,apisdk-starter仍然可以运行。
apisdk-starter思路分解 我把整体思路中的前3点归结为Spriing拓展点,第4点是javassist字节码技术,后面两点是aop拓展。
首先我们先看下成品的apisdk-starter是如何使用的,接下来会按照思路分解进行技术分享。
apisdk-starter的应用 开放接口声明 可以看到,接口声明已经不再需要SdkContext参数声明。
接口调用 调用时不需要再关心如何调用RegionMock、SecretMock、TokenMock等服务,甚至开发者不需要知道有这些服务。
1. 对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 LVS-DR是client向目标lvs发出请求,lvs接收用户的请求,然后根据负载均衡算法选取一台
realserver,将包转发过去,最后由realserver直接回复给用户。realserver必须拥有lvs的ip,因为
数据包发给lvs后,并未处理而是直接转发给realserver,目标ip必须是realserver拥有的ip才会去处
理数据包。处理完后,源ip封装lvs的ip,目标ip是client的ip,直接发给客户端,而不经过lvs。
优势:从real-server直接到客户端,不需要经过负载调度器。
LVS-NAT是client发送请求到lvs上,lvs选择一个realserver,然后修改client的请求的目的IP地址为
realserver的地址,将请求发给realserver,realserver收到request包后,发现目的IP是自己的IP,
于是处理请求,然后发送reply给lvs,lvs收到reply包后,修改reply包的的源地址为lvsip,发送给
client。
优势:不需要要arp抑制
2. 基于 CentOS 7 构建 LVS-DR 群集 1> 配置两台real-server
node1主机上操作: yum install -y httpd echo "the web hostname ip is `hostname -I`." > /var/www/html/index.html systemctl disable firewalld.service setenforce 0 systemctl start httpd curl 192.168.139.135:80 node2主机上操作: yum install -y httpd echo "the web hostname ip is `hostname -I`." > /var/www/html/index.html systemctl disable firewalld.
场景一:密码中必须包含大小写 字母、数字、特称字符,至少8个字符,最多30个字符 var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,30}'); if (!pwdRegex.test('A3b@C2dEF')) { alert("您的密码复杂度太低(密码中必须包含大小写字母、数字、特殊字符),请及时修改密码!"); } 场景二:密码中必须包含字母(不区分大小写)、数字、特称字符,至少8个字符,最多30个字符 var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,30}'); if (!pwdRegex.test('a2b3c$def')) { alert("您的密码复杂度太低(密码中必须包含字母、数字、特殊字符),请及时修改密码!"); } 场景三:密码中必须包含字母(不区分大小写)、数字,至少8个字符,最多30个字符 var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}'); if (!pwdRegex.test('a2b3c4d5')) { alert("您的密码复杂度太低(密码中必须包含字母、数字),请及时修改密码!"); }
前言 在这个竞争激烈的行业中,只有优秀的 Android 工程师才能够生存,需要我们能够为客户提供的最佳技术和资源,需要有优秀的开发工具,保证以最佳质量以及高效时间来构建。
在同一家公司里呆久了,容易不知道外面市场的行情变化,所以通常建议大家定期去了解一下外面的技术栈行情,即使对于大厂的员工也是如此。
当时群里就有一名Android 中级开发因为一些原因去年离职了,今年找工作,结果没有什么面试机会。
就让我帮忙分析,一般而言没有面试机会基本上就是简历有问题需要修饰。
我就直接让他发一份简历过来,看了一眼就明白了。这个兄弟就是在一家公司呆太久了,他这个简历估计还没有现在应届生的看着舒服。
当时就直接和他说了原因,以及一些现在面试的技巧。
前面文章有写简历的修改和面试前的准备
不到半月,就和我说他现在入职了一家大公司,也说了说他面试就经历,我就顺便分享出来给大家涨涨经验。
面试过程 自我介绍
自我介绍看起来很简单,但是需要你在2分钟内把自己的程序员这几年的项目经历清晰的讲出来。听起来不难,确实对于现在一直在面试的人来说很简单,可是如果你很久没有面试了就会结结巴巴,这样一来给人的第一印象就不好。
这位兄弟自己找的朋友进行模拟面试的时候,自我介绍就栽了。不过多说几遍后也是不成问题。
笔试,刷过题的就不是问题。
项目经历
难点基本上是这一关,而且不同以往。如今的面试官都喜欢项目和八股文结合问。
这个项目我看你用到了啥啥之类的,你是怎么运用的,问完就话锋一转问底层。
Android面试躲不过Handler和Binder
在项目中,各模块代码运行在不同的进程(线程)中,想要真正理解安卓的这几大服务,势必要掌握安卓的通信机制,而安卓最主要的两个通信机制就是Handler和Binder。
Binder机制在Android中的地位举足轻重,我们需要掌握的很多原理都和Binder有关:
系统中的各个进程键的通信
Android系统启动过程
AMS、PMS的原理
四大组件的原理(比如Activity的启动)
插件化原理
系统服务的Client端和Server端的通信原理(比如MediaPlayer和MeidaPlayerService)
可以说Binder机制是掌握系统底层原理的基石。Handler的地位也是同样的原理。
现在的业界有一句话是这样说的:技术好的未必弄得懂底层,但是底层基础好的学起技术来很快。所以,大公司在挑选公司人才的时候,更加看重的是应聘者对底层原理的掌握和理解。
项目经验这方面他自己之前做过准备 基本上问题都能回答,技术面也就没有什么难度。
HR面试
有些人可能会认为这一关面试无关紧要,一般来说技术面试过了就基本上稳了。
但是如果你面试的是大厂,那你就要小心了。这些负责招人的有可能就是你们的技术老大或者部门负责人。
他(她)是有一票否则权的,而且也会问你一些技术问题。
没有拿到offer之前都应该持正态度。
面经虽然有参考性,但是最重要的还是你自身的技术水平如何,作为一个 Android 开发者,不仅要打好自身基础,更重要的是要建立起自己的知识体系, 你要知道知识是碎片化的,建立知识体系会让自己对技术的运用更加融会贯通,往“T 型”人才发展;
技术上的成长往往是会花费很多时间的,但是利用这些时间帮你技术上更上一层台阶进入大厂,岂不妙哉?
所以这里也就没有放面试题。
现在的知识点就是那些,基本上,翻来覆去就是那些换汤不换药的问法。但是现在大家上班要写业务代码,下班又是家庭琐碎,要想自己静下心来好好学习根本不可能,仅仅只是有用信息的筛选就足够麻烦。
不如掌握Framework的这些底层原理,这里分享一份Framework的学习资料!
扫码领取完整文档
《Android Framework 开发揭秘》 目录 第一章 系统启动流程分析 ● 第一节 Android启动概览
● 第二节 init.rc解析
● 第三节 Zygote
● 面试题
目录
1.系统介绍
2.项目截图
3.源代码
1.系统介绍 本系统是基于ssm框架+MySQL+jsp的校园共享单车管理系统,实现功能非常全面。
多说无益,直接上图,清晰可见。
2.项目截图 登录界面
(登录账号见数据库中的admin表,密码均为123)
后台主界面
(点击右上角的改变风格,可以改变后台界面主题颜色)
用户管理和服务点管理
单车管理和分类管理
(第二张图表单变蓝色,是因为我在右上角重新选择了一个主题)
学生信息管理
租赁信息管理
(数据库中对应orders表,也就是订单表) 信息统计管理
(此模块统计了站内所有信息的总数,便于直观地查看信息)
修改个人密码
3.源代码 https://download.csdn.net/download/vx1271487114/86796032?spm=1001.2014.3001.5503https://download.csdn.net/download/vx1271487114/86796032?spm=1001.2014.3001.5503
文章目录 1. torch_geometric.data介绍2. 使用Planetoid下载Cora数据集的代码3. 解决程序运行的机器无法联网的问题3.1 尝试运行,查看数据集下载链接3.2 放置到对应文件夹下3.3 重新运行之前写的程序 4. 一点感慨 1. torch_geometric.data介绍 torch_geometric,简称pyg,是基于pytorch实现的图神经网络库。本文暂时不讲图神经网络的搭建,先介绍一下如何基于这个库获取官方已经集成的数据集。
torch_geometric.datasets这个子包下包含这些类,每个类可以用于下载一个或者几个相关的数据集:
datasets.AMiner( datasets.PascalPF( datasets.gemsec datasets.AQSOL( datasets.PascalVOCKeypoints( datasets.geometry datasets.Actor( datasets.Planetoid( datasets.github datasets.AirfRANS( datasets.PolBlogs( datasets.gnn_benchmark_dataset datasets.Airports( datasets.QM7b( datasets.graph_generator datasets.Amazon( datasets.QM9( datasets.heterophilous_graph_dataset datasets.AmazonProducts( datasets.RandomPartitionGraphDataset( datasets.hgb_dataset datasets.AttributedGraphDataset( datasets.Reddit( datasets.hydro_net datasets.BA2MotifDataset( datasets.Reddit2( datasets.icews datasets.BAMultiShapesDataset( datasets.RelLinkPredDataset( datasets.imdb datasets.BAShapes( datasets.S3DIS( datasets.infection_dataset datasets.BitcoinOTC( datasets.SHREC2016( datasets.jodie datasets.CitationFull( datasets.SNAPDataset( datasets.karate datasets.CoMA( datasets.ShapeNet( datasets.last_fm datasets.Coauthor( datasets.StochasticBlockModelDataset( datasets.lastfm_asia datasets.CoraFull( datasets.SuiteSparseMatrixCollection( datasets.linkx_dataset datasets.DBLP( datasets.TOSCA( datasets.lrgb datasets.DBP15K( datasets.TUDataset( datasets.malnet_tiny datasets.DGraphFin( datasets.
java将一个集合的每个对象依次赋值给另一个对象的字段值: 例如:Demo类中有三个字段都是为TImeDTO类型
-
有一个TImeDTO类型集合,需要将集合中的每个对象依次赋值给Demo类的字段
想要的结果就是依次将集合的数据赋值给对象的字段。
废话不多说,直接上代码。
下面展示一些 内联代码片。
//模拟集合数据 List<TimeDTO> list = new ArrayList<>(); list.add(new TimeDTO("2023-05-10", 1)); list.add(new TimeDTO("2023-05-11", 2)); //通过java反射机制拿到类的所有字段集合 Demo demo = new Demo(); Class<?> clazz = Class.forName(demo.getClass().getName()); Field[] fields = clazz.getDeclaredFields(); //循环集合将字段与集合的对象赋值从新绑定 Map<String, Object> map = new HashMap<>(); for (int i = 0; i < fields.length; i++) { if (i == list.size()) { break; } map.put(fields[i].getName(), list.get(i)); } //将赋值过后的map转换成原来的实体类 Demo newDemo = JSONObject.parseObject(JSONObject.toJSONString(map), Demo.class); System.out.println(JSONObject.toJSONString(newDemo)); 提示:这样就可以根据对象字段集合的长度来进行动态赋值,结果如下:
src/store/modules/haha.js
const haha = { state: { count: 100, text: "学习Vue.js 3管理后台开发" }, getters: { getCount: state => { return state.count + 10; }, getText: state => { return "我正在努力" + state.text } }, mutations: { SET_COUNT(state) { state.count = 10; }, SET_TEXT(state, payload) { state.text = payload; } }, actions: {} } export default haha //export default { // namespace: true, // state, // getters, // mutations, // actions, src/store/index.
java中二维数组字符串转换List集合: 我们在开发过程中可能会遇到二维数组字符串需要转换成集合的情况。
1.简单数据类型的二维数组字符串转换List 例如:[[1,2,3],[4,5,6],[6,7]] 为基本数据类型的二维数组字符串。
String data="[[1,2,3],[4,5,6],[6,7]]"; String[][] parse2 = JSON.parseObject(data, String[][].class); List<List<String>> lists2 = JSON.parseObject(JSON.toJSONString(parse2), new TypeReference<List<List<String>>>() { }); System.out.println(lists2); 2.对象数据类型的二维数组字符串转换List 例如:[[{name:‘张三’,age:18},{name:‘李四’,age:20}],[{name:‘小明’,age:10}]]为对象数据类型的二维数组字符串。
提示:创建对应的对象实体类。
String data="[[{name:'张三',age:18},{name:'李四',age:20}],[{name:'小明',age:10}]]"; String[][] parse2 = JSON.parseObject(data, String[][].class); List<List<String>> lists2 = JSON.parseObject(JSON.toJSONString(parse2), new TypeReference<List<List<String>>>() { }); List<List<User>> userList=new ArrayList<>(); for (List<String> list : lists2) { List<User> entityList= JSONObject.parseArray(list.toString(),User.class); userList.add(entityList); } System.out.println(JSON.toJSONString(userList)); 文章到这里就结束了,有帮助的小伙伴记得点赞收藏加关注呦!!!
1.一个输入值匹配多个字段 关键语法如下 :
SELECT * FROM 表名 WHERE CONCAT( IFNULL( 字段1, '' ), IFNULL( 字段2, '' ), IFNULL( 字段3, '' )) LIKE "%关键字%" mybatis中mapper中的写法如下:
SELECT * FROM `test` WHERE 1 = 1 <if test="name1!=null and name1 !=''"> and CONCAT(`name1`,`name2`,`name3`) like "%"#{name1}"%" </if> <if test="name2!=null and name2 !=''"> and CONCAT(`name1`,`name2`,`name3`) like "%"#{name2}"%" </if> <if test="name3!=null and name3 !=''"> and CONCAT(`name1`,`name2`,`name3`) like "%"#{name3}"%" </if> 需要注意的是:当查询多个字段时,每个字段需要加上IFNULL() 函数,这样保证了当各个匹配的字段中其他列有空的情况下,也会返回这个查询的行,从而保证返回正确的结果集。
2.多个输入值匹配一个字段 关键语法如下:
select * from test where name like 'a%' or name like 'b%' or .
第4期:“自动化”聊起来简单,做起来难
在上一期《如何找到现有研发体系的「内耗问题」?》中,我们聊了评估现有研发体系,正确的找到“体系内耗问题”,是改变研发体系的第一步。本期我们继续聊下一个关键点就是研发体系中引入自动化,看看下面两位嘉宾朋友是如何理解”自动化“这件事。
受访者A:某电商平台 架构师 马经理
受访者B:某金融企业 效能工程师 汪工
Q1:
说到“一切自动化”,这确实是研发体系所追求的。我们在最初进行自动化改造时,首先在单个环节上用自动化工具解决效率问题,再根据流程打通工具链,最后实现全流程的自动化平台。
A:
说到“一切自动化”,这确实是研发体系所追求的。我们在最初进行自动化改造时,首先在单个环节上用自动化工具解决效率问题,再根据流程打通工具链,最后实现全流程的自动化平台。
通过自动化工具解决单点效率问题,这个方法前期效能提升非常显著,可以节省很多人。
第一个最关键的,同时也是我们早期进行的单点突破,就是实现自动化构建发布,像是大家都在使用的Jenkins、Travis、Ansible、Docker等。
第二个单点突破就是实现自动化测试,这部分其实是比较难做的部分,不仅是要考虑合适的工具,更重要的是系统性考虑开发流程、产品架构、技术栈等,自动化测试的目的就是快速反馈研发中的安全质量问题。
解决单点的效率问题后,就是打通工具链,看全局其实还有很多环节可以进行自动化升级,包括接入流程管理、代码托管、代码扫描、测试执行、日志监控等等。每个环节需要做多种工具的选型,需要根据自身实际情况灵活选用调整工具链。最终目的是打通各部门之间的壁垒,从产品经理开始串联研发、测试、安全、运维各环节,减少「内耗」。
打通工具链后,进一步提升研发效能的方式就是打造平台,实践DevOps或DevSecOps,这也是很多大企业的必经之路,市面上也有很多“一站式、一体化XX平台”来给中小企业提升效能。通过打造平台,实现研发流程的标准化、自动化和可持续化,提高研发效率和质量,缩短产品上线时间,更快地满足市场需求。所以,除了集成打通工具链外,平台还需要拥有更强大的可视化管理能力、分析能力和有效的度量体系,全流程引导效能的提升。
B:
我们这边一直实践的DevSecOps,开始也是单点优化,然后慢慢升级成平台。开始做自动化的时候,从以下几个方面入手。
首先,需要明确研发自动化的目标和要求,虽然也是从单点开始做,但需要一个整体的目标,如提高研发效率多少、降低多少成本、团队资源配置等,这是考量我们自动化能力的指标。
其次,在团队建设方面,我们这边因为涉及到很多开源工具的开发,并且安全要求也相对较高,虽然自动化可以节省人工成本,但团队增加人员却是必须的。因为业务在不断发展,需要团队拓展自动化工具的能力或改进流程,所以要增加相关人才,这是我们要时刻跟进投入产出的数据。
再次,自动化工具选型很关键,错误的选择不但影响研发的工作量,更会影响未来产品的走势。因此需要根据业务特点来选型,我们在同一类工具上会选择多个产品,来测试每个产品的效果,从而选出最优工具。
因为我们是实践DevSecOps,要满足安全性,产品上线后的安全监控和响应也需要更高效的自动化工具,来满足严格的安全标准。
Q2:
你们认为,做“自动化”过程中,最困难的地方在哪里?
A:对我来说“自动化测试”是个难点,相信大家也是这么认为。对于产品来说,测试是必须做的,同样也是非常耗时的,所以自动化测试的价值不言而喻。很长一段时间,我们想法局限于单点工具的使用和改进,努力节省测试时间,但从全局看研发效能的提升效果没有达到预期,为什么?
其实,我们在要求提升迭代速度的时候,需求和研发速度提升,使得测试任务加剧,测试时间被严重压缩,产品功能越来越多,测试的范围也越来越大。简单的说就是,测试不够用了。如何提升自动化测试效率,成为了我们一个长期的命题。
但自动化测试除了依靠工具外,还需要从全局考虑,抓住“人”和“方法”两个方面。在“人”的方面,要求研发人员提升测试能力,测试团队配置测试架构师和专家,对测试方案、技术选型、平台对接负责。在“方法”上,拆分小的团队,团队支撑的业务集中,尽量保持团队对业务场景保持统一的认识和理解。
在我们现阶段的一个共识是,通过自动化测试实现效能提升,不只是测试团队的工作,而是全研发体系的工作。
B:“自动化测试”在我们这也是难点,刚刚汪工已经说的比较多了,我再讲一下其他难点。在我们这边来说,在构建自动化工具链上,技术选型也是比较大的难点。首先,技术选型需要考虑企业实际情况,包括企业规模、业务要求、研发团队水平、基础资源等方面。
其次,需要考虑技术的成熟度和稳定性。因为我们经常探索一些开源项目,一些新兴的开源技术往往有很高的潜力和创新性,但是可能不够稳定,存在风险。有些我们采购外部厂商成熟的产品,依赖厂商提供的服务能力。
最后,还需考虑工具链的综合效益和可扩展性,包括具体的研发场景、业务规划,未来的扩展方向等,以便在保证交付质量的前提下更好地推动自动化工具链的后续发展。
本期我们围绕“自动化”聊了两个问题,两位嘉宾回答的比较深刻。我们总结几点:
自动化实践的三个步骤:
a. 单点使用自动化工具,提升单点效率。
b. 打通工具链,建立自动化工具链。
c. 向平台化升级,持续改进。自动化实践两大难点:
a. 通过自动化测试实现效能提升,不只是测试团队的工作,而是全研发体系的工作。
b. 在进行技术选型时,需要通过全面的调研、深入的分析和认真的取舍,才能实现自动化工具链的可靠性、高效性、扩展性。 大家对此有何独特的见解?
欢迎在【公众号:开源网安】《谈效风生》专栏中留言。
我们将「精选留言」,为您送上定制礼品。
数据库中出现死锁是很常见的情况,我们需要对其进行解决。在解决死锁问题之前,需要先了解一下什么是死锁。
死锁是指两个或多个事务互相等待对方持有的资源而无法继续执行的情况。比如,事务A和事务B分别占用了资源X和资源Y,当A试图请求Y而B占用了Y的时候,A就会被阻塞;同样的,当B试图请求X而A占用了X的时候,B也会被阻塞,这时,A和B都无法继续执行,形成了死锁。
目录
1. 降低事务的隔离级别
2. 减少事务并发度
3. 优化SQL语句和索引
4. 使用数据库的死锁检测和超时机制
为了解决数据库死锁的问题,可以采取以下方法:
1. 降低事务的隔离级别 降低事务的隔离级别可以减少死锁的发生,因为事务的隔离级别越高,锁的粒度就越大,这会增加死锁的概率。但是,等级太低可能会引起脏读、不可重复读和幻读等问题,需要根据实际情况权衡。
2. 减少事务并发度 减少事务并发度也可以减少死锁的发生。当存在大量并发事务时,会增加死锁的概率。可以通过调整业务流程或者更改代码实现。
3. 优化SQL语句和索引 优化SQL语句和索引可以减少对同一数据行的竞争,从而降低死锁的概率。可以通过合理设计索引、使用批量更新或者延迟加载等方式来优化SQL语句。
4. 使用数据库的死锁检测和超时机制 大多数数据库会提供死锁检测和超时机制,可以使用这些机制来避免或解决死锁问题。当发现死锁时,数据库会自动回滚其中一个事务,释放资源,避免了死锁的进一步扩大。而超时机制则可以在一定时间内主动结束事务,释放资源,避免死锁的长时间持续,从而提高数据库的并发性能。
综上所述,数据库死锁问题是一种常见的性能问题,需要通过各种方法来解决。在具体的应用场景中,应该根据实际情况选择适合的方法,避免应用系统发生死锁问题,提高应用的并发性能。
State生命周期 1、第一次展示到屏幕上时会依次调用当前element的构造函数,initState,didChangeDependencies,build2、如果只是自己发生了更新,则只会回调build。如果当前对象的父节点发生更新,则会调用didUpdateWidget和build。如果依赖的InheritedWidget发生了改变,则还会先回调didChangeDependencies。3、当widget被移除的的时候,会依次调用deactive和dispose initState initState 是 StatefulWidget 创建完后调用的第一个方法,而且只执行一次,类似于 Android 的 onCreate、iOS 的 viewDidLoad(),所以在这里 View 并没有渲染,但是这时 StatefulWidget 已经被加载到渲染树里了,这时 StatefulWidget 的 mounted 的值会变为 true,直到 dispose 调用的时候才会变为 false。可以在 initState 里做一些初始化的操作
initState() 表示当前 State 将和一个 BuildContext 产生关联,但是此时BuildContext 没有完全装载完成,如果你需要在该方法中获取 BuildContext ,可以使用 Future.delayed(const Duration(seconds: 0, (){//context}); didChangeDependencies 在 initState() 之后调用,当 State 对象的依赖的InheritedWidget 关系发生变化时,该方法被调用,初始化时也会调用。可能会被调用多次。
原理参考:Flutter原理篇:didChangeDependencies什么时候被调用
build 在 StatefulWidget 第一次创建的时候,build 方法会在 didChangeDependencies 方法之后立即调用,另外一种会调用 build 方法的场景是,每当 UI 需要重新渲染的时候,build 都会被调用,所以 build 会被多次调用,然后 返回要渲染的 Widget。千万不要在 build 里做除了创建 Widget 之外的操作,因为这个会影响 UI 的渲染效率。
一、ARP协议 ARP(Address Resolution Protocol,地址解析协议)是一种用于通过网络层地址(比如IP地址)获取链路层地址(比如MAC地址)的通信协议。它将网络层的IP地址与数据链路层的MAC地址相互映射,使得在计算机进行网络通信时,能够正确地将数据包发送到对应的目标主机
二、ARP协议工作流程 当计算机需要向某个目的主机发送数据时,首先在本地ARP缓存(ARP Cache)中查找是否有目标IP地址对应的MAC地址。如果本地ARP缓存中没有对应的MAC地址,则计算机会发送一个广播消息,称为ARP请求(ARP Request),请求目标主机回复其MAC地址。当目标主机收到ARP请求后,如果发现自己的IP地址与请求中的IP地址匹配,则会将自己的MAC地址发送回来,称为ARP响应(ARP Reply)。发送ARP请求的计算机接收到ARP响应后,将得到目标主机的MAC地址,并将其保存在本地ARP缓存中,以备将来使用。 三、ARP攻击与欺骗 ARP(地址解析协议)欺骗是一种网络攻击技术,攻击者利用这种技术向网络中发送虚假的ARP响应,从而欺骗其他计算机的网络配置。当攻击成功时,攻击者可以将数据流量重定向到自己的计算机上,同时可以窃取敏感信息。
具体来说,ARP欺骗攻击主要有两种方式:
MAC地址欺骗:攻击者在网络中发送虚假的ARP响应,将自己的MAC地址伪装成目标计算机的MAC地址,使其他设备将数据包发送到攻击者的计算机上。双边ARP欺骗:攻击者在网络中发送虚假的ARP请求和ARP响应,将两台计算机的MAC地址都伪装成对方的MAC地址,从而使它们之间的通信流量经过攻击者的计算机 1. ARP攻击 主机A要和出口路由器通信,向网络中发送ARP请求,攻击主机C伪装成路由器的IP地址,响应一个虚假的网络中不存在MAC地址66-66给主机A,就会造成主机A无法通信。
2、ARP欺骗 欺骗网关
攻击主告诉A主机的是真实存在的MAC地址。
攻击主机C开启IP转发功能 ,接受A主机发送的信息,之后再将信息转发给出口路由器,以实现数据监听功能。
三、对于ARP攻击与欺骗可采取的措施 使用静态ARP缓存记录,从而避免频繁的ARP查询和响应。确认网络中所有计算机的真实MAC地址,并使用网络访问控制列表(ACL)限制不受信任的计算机的访问。启用网络中的端口安全功能,只允许已知的MAC地址访问网络。在网络中使用安全协议(如SSL、SSH等)来加密数据,从而防止被窃取。 四、实施ARP欺骗与攻击 工具:虚拟机、kali、windows7、dsniff工具
1、 kali配置 配置源及工具安装
root权限运行 - vim /etc/apt/sources.list # 在打开的文件里插入下面的镜像源 // 1.按小写o --插入 // 2.按#号把原来的注释掉 // 3.按ESC 取消插入在 按:和 wq ----保存 2.清华大学镜像源 deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free deb-src https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free 3.apt-get update // 更新一下镜像源 4.apt-get install dsniff //安装工具 2.攻击 攻击
arpspoof -i eth0 -t 192.
先简单交代一下吧,沅哥是某不知名211的本硕,18年毕业加入滴滴,之后跳槽到了头条,一直从事测试开发相关的工作。之前没有实习经历,算是四年半的工作经验吧。
这四年半之间他完成了一次晋升,换了一家公司,有过开心满足的时光,也有过迷茫挣扎的日子,不过还算顺利地从一只职场小菜鸟转变为了一名资深划水员。
我结合前辈经历总结出了一些还算实用的划水经验,有些是自己领悟到的,有些是跟别人交流学到的,在这里跟大家分享一下。
学会深入思考,总结沉淀 我想说的第一条就是要学会深入思考,总结沉淀,这是我觉得最重要也是最有意义的一件事。
先来说深入思考。在测试员这个圈子里,常能听到一些言论:我这个工作一点技术含量都没有,这能让我学到什么东西?抛开一部分调侃和戏谑的论调不谈,这可能确实是一部分同学的真实想法,至少曾经的我,就这么认为过。后来随着工作经验的积累,加上和一些高level的同学交流探讨之后,我发现这个想法其实是非常错误的。
之所以出现没什么可学的这样的看法,基本上是思维懒惰的结果。任何一件看起来很不起眼的小事,只要进行深入思考,稍微纵向挖深或者横向拓宽一下,都是足以让人沉溺的知识海洋。
所以说学习和成长是一个自驱的过程,如果觉得没什么可学的,大概率并不是真的没什么可学的,而是因为自己太懒了,不仅是行动上太懒了,思维上也太懒了。
可以多写技术文章,多分享,强迫自己去思考和总结,毕竟如果文章深度不够,大家也不好意思公开分享。
积极学习,保持技术热情 不可否认,互联网行业在有一点上确实不如公务员等体制内职业。但是这个问题里35岁程序员并不是绝对生理意义上的35岁,应该是指那些工作十几年和工作两三年没什么太大区别的程序员。后面的工作基本是在吃老本,没有主动学习与充电,35岁和25岁差不多,而且没有了25岁时对学习成长的渴望,反而添了家庭生活的诸多琐事,薪资要求往往也较高,在企业看来这确实是没什么竞争力。
而如果我们积极学习,保持技术能力、知识储备与工作年限成正比,这到了35岁哪还有什么焦虑呢,这样的大牛我觉得应该也是各大公司抢着要吧?但是学习这件事,其实是一个反人类的过程,这就需要我们强迫自己跳出自己的安逸区,主动学习,保持技术热情。在滴滴时有一句话大概是,主动跳出自己的舒适区,感到挣扎与压力的时候,往往是黎明前的黑暗,那才是成长最快的时候。相反如果感觉自己每天都过得很安逸,工作只是在混时长,那可能真的是温水煮青蛙了。
刚毕业的这段时间,往往空闲时间还比较多,正是努力学习技术的好时候。借助这段时间夯实基础,培养出良好的学习习惯,保持积极的学习态度,应该是受益终身的。至于如何高效率学习,网上有很多大牛写这样的帖子,到了公司后内网也能找到很多这样的分享,我就不多谈了。
可以加入学习小组和技术社区,公司内和公司外的都可以,关注前沿技术。
主动承担,及时交流反馈 前两条还是从个人的角度出发来说的,希望大家可以提升个人能力,保持核心竞争力,但从公司角度来讲,公司招聘员工入职,最重要的是让员工创造出业务价值,为公司服务。
虽然对于校招生一般都会有一定的培养体系,但实际上公司确实没有帮助我们成长的义务。而在能为公司办成事,创造价值这一点上,我觉得最重要的两个字就是主动,主动承担任务,主动沟通交流,主动推动项目进展,主动协调资源,主动向上反馈,主动创造影响力等等。
一定要主动,可以先从强迫自己在各种公开场合发言开始,有问题或想法及时one-one。
除了以上几点,还有一些小点我觉得也是比较重要的,列在下面: 第一件事建立信任 无论是校招还是社招,刚入职的第一件事是非常重要的,直接决定了leader和同事对自己的第一印象。入职后要做的第一件事一定要做好,最起码的要顺利完成而且不能出线上事故。
这件事的目的就是为了建立信任,让团队觉得自己起码是靠谱的。如果这件事做得比较好,后面一路都会比较顺利。如果这件事就搞杂了,可能有的leader还会给第二次机会,再搞不好,后面就很难了,这一条对于社招来说更为重要。
而刚入职,公司技术栈不熟练,业务繁杂很难理清什么头绪,压力确实比较大。这时候一方面需要自己投入更多的精力,另一方面要多跟组内的同学交流,不懂就问。最有效率的学习方式,我觉得不是什么看书啊学习视频啊,而是直接去找对应的人聊,让别人讲一遍自己基本就全懂了,这效率比看文档看代码快多了,不仅省去了过滤无用信息的过程,还了解到了业务的演变历史。当然,这需要一定的沟通技巧,毕竟同事们也都很忙。
脸皮要厚一点,多找人聊,快速融入,最忌讳有问题也不说,自己把自己孤立起来。
拍马屁是真的香 拍马屁这东西入职前我是很反感的,我最初想加入互联网公司的原因就是觉得互联网公司的人情世故没那么多,事实证明,我错了…入职前几天,部门群里大leader发了一条消息,后面几十条带着大拇指的消息立马跟上,学习了,点赞,真不错,优秀,那场面,说是红旗招展锣鼓喧天鞭炮齐鸣一点也不过分。
除了惊叹大家超强的信息接收能力和处理速度外,更进一步我还发现,连拍马屁都是有队形的,一级部门leader发消息,几个二级部门leader跟上,后面各组长跟上,最后是大家的狂欢,让我一度怀疑拍马屁的速度就决定了职业生涯的发展前景(没错,现在我已经不怀疑了)。
坦诚地说,我到现在也没习惯在群里拍马屁,但也不反感了,可以说把这个事当成一乐了。倒不是说我没有那个口才和能力(事实上也不需要什么口才,大家都简单直接),在某些场合,为活跃气氛的需要,我也能小嘴儿抹了蜜,甚至能把古诗文彩虹屁给leader安排上。而是我发现我的直属leader也不怎么在群里拍马屁,所以我表面上不公开拍马屁其实属于暗地里事实上迎合了leader的喜好…
但是拍马屁这个事只要掌握好度,整体来说还是香的,最多是没用,至少不会有什么坏处嘛。大家能力都差不多,每一次在群里拍马屁的机会就是一次露脸的机会,按某个同事的说法,这就叫打造个人技术影响力…
想舔就舔,不想舔也没必要酸别人,Respect Greatness。
不要被画饼蒙蔽了双眼 说实话,我个人是比较反感灌鸡汤、打鸡血、谈梦想、讲奋斗这一类行为的,都3202年了,这一套***治还在大行其道,真不知道是该可笑还是可悲。当然,这些词本身并没有什么问题,但是这些东西应该是自驱的,而不应该成为外界的一种强push。
『我必须努力奋斗』这个句式我觉得是正常的,但是『你必须努力奋斗』这种话多少感觉有点诡异,努力奋斗所以让公司的股东们发家致富?尤其在钱没给够的情况下,这些行为无异于耍流氓。我们需要对leader的这些画饼操作保持清醒的认知,理性分析,作出决策。比如感觉钱没给够(或者职级太低,同理)的时候,可能有以下几种情况:
leader并没有注意到你薪资较低这一事实
leader知道这个事实,但是不知道你有多强烈的涨薪需求
leader知道你有涨薪的需求,但他觉得你能力还不够
leader知道你有涨薪的需求,能力也够,但是他不想给你涨
leader想给你涨,也向上反馈和争取了,但是没有资源
这时候我们需要做的是向上反馈,跟leader沟通确认。如果是1和2,那么通过沟通可以消除信息误差。如果是3,需要分情况讨论。如果是4和5,已经可以考虑撤退了。对于这些事儿,也没必要抱怨,抱怨解决不了任何问题。我们要做的就是努力提升好个人能力,保持个人竞争力,等一个合适的时机,跳槽就完事了。
时刻准备着,技术在手就没什么可怕的,哪天干得不爽了直接跳槽。
选择和努力哪个更重要? 这还用问么,当然是选择。在完美的选择面前,努力显得一文不值,我有个多年没联系的高中同学今年已经在时代广场敲钟了…但是这样的案例太少了,做出完美选择的随机成本太高,不确定性太大。对于大多数刚毕业的同学,对行业的判断力还不够成熟,对自身能力和创业难度把握得也不够精准,此时拉几个人去创业,显得风险太高。我觉得更为稳妥的一条路是,先加入规模稍大一点的公司,找一个好leader,抱好大腿,提升自己的个人能力。好平台加上大腿,再加上个人努力,这个起飞速度已经可以了。等后面积累了一定人脉和资金,深刻理解了市场和需求,对自己有信心了,可以再去考虑创业的事。
如果对自己没太大自信的话,可以文末加群一起抱团取暖,记住找我内推。
本来还想分享一些生活方面的故事,发现已经这么长了,那就先这样叭。上面写的一些总结和建议我自己做的也不是很好,还需要继续加油,和大家共勉。另外,其中某些观点,由于个人视角的局限性也不保证是普适和正确的,可能再工作几年这些观点也会发生改变,欢迎大家跟我交流~(甩锅成功)
最后祝大家都能找到心仪的工作,快乐工作,幸福生活,广阔天地,大有作为。
整理了一波之前发布的软件测试资源【点击文末小卡片免费领取】,无套路领取!
基本涵盖了软件测试 的全部核心技术点:测试理论,Linux 基础,MySQL 基础,Web 测试,接口测试,App 测试,管理工具,Selenium 相关,性能测试,计算机网络,组成原理,数据结构与算法,逻辑题,人力资源,技术脑图等等…质量非常高!!!应对技术面试绰绰有余!
全网首发-涵盖16个技术栈 第一部分:测试理论(测试基础+需求分析+测试模型+测试计划+测试策略+测试案例等等)
第二部分:Linux( Linux基础+Linux练习题)
第三部分:MySQL(基础知识+查询练习+万年学生表经典面试题汇总+数据库企业真题)
第四部分:Web测试
第五部分:API测试
第六部分:App测试
第七部分:管理工具
第八部分:Python基础(Python基础+编程题+集合+函数+Python特性等等)
第九部分:Selenium相关
第十部分:性能测试
第十一部分:LordRunner相关
第十二部分:计算机网络
第十三部分:组成原理
前言 用 vue-cli 构建的项目通常是采用前后端分离的开发模式,也就是前端与后台完全分离,此时就需要将后台接口地址打包进项目中,但是,我们只是改个接口地址也要重新打包那就太麻烦了。怎么解决呢?方法如下,本文推荐俩种方式。
方式1:通过创建 js 文件进行实现 优点: 简单易懂, 方便上手
缺点: 配置文件容易被抓取【其实也不必太过于担心】
1、在 public 文件夹下创建 webconfig.js 文件
window.webConfig = { "webApiBaseUrl": "http://127.0.0.1:8001", "webSystemTitle":"标题" } 2、在 index.html 页面应用 js 文件 3、应用完成之后,就可以在任何地方使用 window.webConfig
4、接口地址变化后直接修改 dist 下对应的 webconfig.js 文件即可,修改完成重新打开项目查看 ip 端口已经改变, 无需重新打包 vue 工程
方式二: 通过创建 json 文件,配合使用 axios 来实现 1、同样在 public 文件夹下创建 webconfig.json 文件
{ "webApiBaseUrl": "http://api.xxxx.com/api", "webSystemTitle":"后台管理系统" } 2、在 base.js 文件中读取【主要是放在 axios 请求处,因为是把后端接口域名提取出来了,所以当道了 base.js 文件】
/** * 接口域名的管理 */ import axios from 'axios' const base = { web: getWebApiBaseUrl(), signalRApiHost: process.
今天配合后台联调数据的时候遇到一种情况
第三条数据为0时候并没有在y轴为0上,而是跟上一条线重合了
ECharts折线图是堆叠的,折线图堆叠的意思就是:第二条线的数值=本身的数值+第一条线的数值,第三条的数值=第二条线图上的数值+本身的数值,以此类推......
设置折线图不堆叠只需要将每一个stack的值设置为不一样的名称或者将stack属性删除即可。
series: [ { name:'2021', type:'line', //stack: '总量', data:[120, 132, 101, 134, 90, 230, 210] }, { name:'2022', type:'line', //stack: '总量', data:[220, 182, 191, 234, 290, 330, 310] }, { name:'2023', type:'line', //stack: '总量', data:[150, 232, 201, 154, 0,0, 0] }, ] 删掉或者注释掉stack属性的时候效果图如下图所示:
文章目录 1 EndNote导入文献出现带有大括号{}乱码的解决办法3 EndNote X9 插入参考文献常见问题总结4 EndNote X9 快速上手教程(毕业论文参考文献管理器) 1 EndNote导入文献出现带有大括号{}乱码的解决办法 ================================================================
原本正常能插入文献时,插入后的结果如下图所示: ================================================================
================================================================
而有时出现带有大括号{}乱码,如下所示
================================================================
================================================================
原因:因为Endnote插入的参考文献在Word中的代码就是以大括号隔开的,当文章中出现了该符号,endnote就会自动比对Library中的书目,而此时endnote出现错误。
================================================================
================================================================
解决方法:
进入word中的Endnote工具栏——Bibliography Preferences(位于Bibliography区块的右下角),就是那个输入杂志名的小三角形,在Temporary citation delimiters处修改变量的默认符号。将默认的大括号{}修改为文章中不回使用到的符号
================================================================
================================================================
有时设置了还是无效:
Endnote选项卡,然后点击一下Update Citations and Bibliography按钮更新一下。
================================================================
参考:
EndNote导入文献出现带有大括号{}乱码的解决办法
Endnote在Word中导入的参考文献忽然变成带有大括号类似{#}的代码的解决办法
3 EndNote X9 插入参考文献常见问题总结 EndNote X9 插入参考文献常见问题总结
4 EndNote X9 快速上手教程(毕业论文参考文献管理器) EndNote X9 快速上手教程(毕业论文参考文献管理器)
Python爬虫代码是一种自动化程序,可以通过向网站发送HTTP请求来获取内容,并对其进行解析、提取和存储。本文中,分享了一份从小说网站获取小说内容的Python爬虫代码。该代码可以自动批量下载小说,将每章节的内容保存到txt文档中。
# - - - - 小说爬虫程序 - - - - # 从biquge获取小说内容,将内容写入txt文档中。 # 打开biquge主页,将对应小说的网址复制到Python中即可 import re import os import requests # biquge小说主页的网址 novel_url = "https://www.biqudu.net/13_13453/" # 读取页面并解码为utf-8格式 novel_page = requests.get(novel_url).content.decode("UTF-8") # 取出biquge网址 url_array = novel_url.split('/') url_array.remove(url_array[3]) base_url = url_array[0] + "//" + url_array[2] + "/" # 获取小说标题 title_regex = re.compile(r'<h1>(.+)</h1>') title = title_regex.findall(novel_page)[0].center(23, '=') print(title) # 文件名称为小说的标题加上.txt后缀 file_name = title_regex.findall(novel_page)[0] + ".txt" # 获取小说目录 chapter_regex = re.compile(r'<a href="/(.+\.html)">(.+)</a>') chapter_raw = chapter_regex.
在全局style.css中引入以下代码
/**修改全局的滚动条*/ /**滚动条的宽度*/ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-thumb { background-color: #eaecf1; border-radius: 3px; } /*表格*/ .el-table__body-wrapper::-webkit-scrollbar { width: 10px; height: 10px; } .el-table__body-wrapper::-webkit-scrollbar-thumb { background-color: #a1a3a9; border-radius: 3px; } 改完后
以上是我从别的文章中找到的可行方法:
element-ui修改浏览器全局的默认滚动条样式_element ui修改浏览器默认滚动条_Neo_LJH的博客-CSDN博客
一、SpingBoot入门案例 SpringBoot是用来简化Spring应用的初始搭建以及开发过程。
先快速搭建一个SpringBoot:
创建一个空project,再创建SpringBoot模块。
点击Create,出现以下页面配置成功
创建一个控制器测试一下:
@RestController @RequestMapping("/books") public class BookController { @GetMapping public String getById(){ System.out.println("springboot is running..."); return "springboot is running..."; } } @RestController和@Controller的异同:
同:都是用来表示Spring某个类是否可以接收HTTP请求
异:@Controller:标识一个Spring类是SpringMVC controller处理器
@RestController:是@Controller和@ResponseBody的结合体
@Controller类中的方法可以直接通过返回String跳转到jsp、ftl、html等模版页面。在方法上加@ResponseBody注解,也可以返回实体对象。
@RestController类中的所有方法只能返回String、Object、Json等实体对象,不能跳转到模版页面。
扩展:
@RequestBody用于接收json数据,后期开发中,发送请求参数超过一个时,以json格式为主,@RequestBody应用较广
@RequestParam用于接收url地址传参或表单传参,发送非json格式数据
@PathVariable用于接收路径参数,使用{参数名称}描述路径参数。用于RESTful进行开发,当参数数量较少时,例如一个,可以采用@PathVariable接收请求路径变量,通常用于传递id值。
按上面配置在启动的时候会报一个错java: 无法访问org.springframework.web.bind.annotation.GetMapping。是jdk版本和springboot的版本不一致,降低springboot的版本或者提高jdk的版本即可。
最终修改后的版本:
直接运行下面的类,就启动了SpringBoot:
不需要Spring的配置文件,也不需要Spring的配置类,也不需要tomcat,web.xml也不用配置,直接运行!
启动成功:
仔细看一下控制台:
在浏览器中访问:
同时控制台打印 :
总结:
这两个文件直接构成了一个SpringBoot
SpringBoot简化操作体现在如下四个方面: 1.parent:用来减少配置的依赖冲突,同时简化了一些配置 使用parent可以帮助开发者进行版本的统一管理
parent定义出来以后,并不是直接使用的,仅仅给了开发者一个说明书,没有直接使用
进入到pom.xml中,进入pom的父依赖(不是知道能不能这么叫…)
进入父依赖:
再进入父的父。。。
可以看到定义了版本号,并且在依赖中引用了。因此在pom.xml中引用依赖的时候,版本号就创建好了。
定义了这么多的版本号是谁在用,是依赖在用。在pom.xml中引用依赖的时候,自动设置了版本。(因为继承)
2.start:简化配置,要用到parent继承过来的版本 start里又定义了若干坐标,一个start对应了一个要使用的技术。
3.引导类:启动,初始化了一个Spring容器 获取bean的四种方式: 通过bean的id获取;
通过bean的类型获取;
通过id和类型获取
通过接口类型来获取bean(这个接口只能有一个实现类)
Spring SpringMVC都需要IOC容器,对象都以bean的形式交给IOC容器进行管理。SpringBoot也需要Spring容器(SpringBoot只是加速Spring配置的,其实还是Spring容器)
接收一下返回值,可以看到是Spring容器:
可以得到bean,注意controller或者其他的class必须交给容器管理。
在搜索网站网址的时候,或是搜公司名称的时候,会出现提示:该页面可能存在违法信息,如下图。 1、网站已经被篡改 这是搜索出现结果,出现此提示,说明网站已经被攻击,或被挂木马,这种情况出现有时网站是可以正常访问的,有的时候是网站直接打不开,我们查看了一下网站源代码,发现网站标题、关键字,描述,全部被更改了,网站表面上看是没什么问题,但是查看网站源代码就能一下看到被篡改的地方,那就要分析网站为什么会出现这个情况了,一般情况下,是因为网站不安全造成的,比如网站有漏洞被人利用,上传了控制网站的后门文件,导致网站被修改,这种情况下,我们要找到漏洞所在,下面请看具体方法。 2、该页面可能存在违法信息的解决方法 上面我们说到,网站被篡改,是因为网站存在不安全因素,比如网站漏洞,那网站漏洞的存在,也有几种情况。 治标方法:网站被修改,那我们把响应的被注入的页面,和被篡改的页面修改成我们的名称,删除相关页面后,到百度去申诉,申诉就是点击网站下面的链接,如图下图 在以上图片中填写网网址,申诉理由,联系邮箱,验证码后提交,前提是已经修改了网页和删除了相关垃圾页面内容,再去提交,提交后,百度一般会一个工作日左右审核,如果审核通过在搜索和进入网站的时候,就不会出现提示了,反之会被驳回。 治本方法:漏洞在网站建设之初就存在,比如用了某些cms系统,本身就有漏洞,解决此情况,需要分析网站是否是cms,如果是到官网下载最新版本或是补丁文件,进行覆盖,修复漏洞,如果是定制网站那么就要分析网站找出漏洞,方法可以去网站日志文件中分析,看看是什么时间,什么文件,这些在日志中都会有记录,通过查看网站日志,找到漏洞文件并且修复,才能达到治标的目的,网站不是做完就不管了,需要定期更新定期维护和备份的。
Linux服务器时间与本地时间不一致(相差8小时)原因与解决方法 原因是机器时间是美国时间,现在调成越南的.步骤如下
安装ntpdate yum -y install ntpdate 执行时间同步 ntpdate vn.pool.ntp.org 在新建文件添加区域时区. [~]# vim /etc/sysconfig/clock ZONE="Asia/Bangkok" UTC=false ARC=false :wq 执行软连接,同步时间. ln -sf /usr/share/zoneinfo/Asia/Bangkok /etc/localtime 检查时间指令 date 查询时区的便捷工具 https://www.zeitverschiebung.net/en/city/1609350
<html> <head> <title>js抽奖</title> <meta charset="utf-8"/> <style type="text/css"> table{ width:900px; /*border:1px solid blue;*/ margin:10px auto; border-collapse:collapse;/*合并相邻单元格之间的边框*/ } td{ font-size:24px; padding:10px; border:1px solid blue; } </style> </head> <body> <!--抽奖的按钮--> <input type="button" value="抽奖" onclick="chouJiang();"/><br/> <input type="button" value="抽奖" id="but1"/><br/> <script type="text/javascript"> function chouJiang(){ //alert("抽奖开始!"); //定义变量记录次数 赢的次数 var ying=0,ciShu=0; while(true){ //随机一个三位数 var num=""; for(var i=1;i<=3;i++){ num+=parseInt(Math.random()*10); } var result=num.indexOf("8")==-1?"输":"赢"; ying+= (result=="赢"?1:0); ciShu++; var gl=parseInt(ying/ciShu*10000)/100; var message=""; message+="结果是:"+num+"\r\n"; message+=result+"\r\n"; message+="总次数:"+ciShu+",赢次数:"+ying+",赢概率:"+gl+"%\r\n"; message+="继续抽奖吗?"; var b=window.confirm(message); if(!b){ break; } } } //文档加载成功时 给动态的给按钮注册事件 window.
2 计算器 <html> <head> <title>计算器</title> <meta charset="gbk"/> <style type="text/css"> div{ border:1px solid; padding:10px; } #div0{ width:1000px; height:600px; position:absolute; top:100px; left:450px; } #divtop{ width:600px; height:150px; position:absolute; top:50px; left:200px; text-align:center; } #divleft,#divright{ height:300px; position:absolute; top:240px; } #divleft{ width:350px; left:150px; } #divright{ right:150px; width:260px; } #span_text{ font-size:70px; letter-spacing:90px; font-weight:bold; color:blue; text-indent:50px; } #text_show,#but_clear{ font-size:40px; } #divleft input,#divright input{ width:55px; height:55px; font-size:30px; font-weight:bold; } #divleft input{ margin:40px 6px; } #divright input{ margin:40px 14px; } </style> </head> <body> <div id="
删除的原理:改变指向地址
#include<stdio.h> #include<stdlib.h> struct Link { int data; struct Link *next; }; void printLink(struct Link *head) { struct Link *p=head; while(p!=NULL) { printf("%d ",p->data); p=p->next; } putchar('\n'); putchar('\n'); } struct Link* deleteNode(struct Link *head,int inputdata) { struct Link *p=head; if(p->data==inputdata) { head=head->next; free(p); puts("delete head success"); return head; } while(p->next != NULL) { if(p->next->data==inputdata) { p->next=p->next->next; puts("delete success"); return head; } p=p->next; } return head; } int main() { //struct Link l1={1,NULL}; struct Link *p=(struct Link*)malloc(sizeof(struct Link)); p->data=1; struct Link l2={2,NULL}; struct Link l3={3,NULL}; struct Link l4={4,NULL}; struct Link l5={5,NULL}; struct Link l10={10,NULL}; struct Link *head=NULL; //head =&l1; //l1.
自己建立库的元器件的引脚编号必须与封装的焊盘编号对应,比如元件的四个引脚编号为1234,那么焊盘的四个编号也要为1234,才能正确显示出对应的连线。
上图TCRT5000L1的焊盘设置的为1234编号而原理图的四个引脚编号为5678,不一致会导致导出的PCB没有连线。
通常我们将元件的引脚按照数字顺序设置1234......(designator),引脚的name按照功能来定义,那么对应的封装的焊盘designator也需对应1234.....,如果命名为对应的name的(VCC/GND/......)同样不能显示连线关系。
如果封装的焊盘designator不添加命名,转PCB也会无线。
Java、SpringBoot 内置工具类 文章目录 Java、SpringBoot 内置工具类Java 工具类Objects对象工具类比较校验空 Collections 集合工具类集合操作同步控制 Calendar日历类Math数学类 SpringBoot 工具类断言对象、数组、集合ObjectUtilsStringUtilsCollectionUtils 文件、资源、IO 流FileCopyUtilsResourceUtilsStreamUtils 反射、AOPReflectionUtilsAopUtilsAopContext Java 工具类 Objects对象工具类 比较 // 两个参数相等,返回true,否则返回false public static boolean equals(Object a, Object b) // 若两个都是null值的字符串或者数组比较,返回true;该方法在数组比较中尤其有用,不清楚对象的具体类型时可以直接使用此方法来解决 public static boolean deepEquals(Object a, Object b) // 判断引用o所指对象是否为null,不为null,则返回o所指对象的hasCode方法执行结果,为null,返回0。 public static int hashCode(Object o) // 若第一个参数不是 null ,则返回在第一个参数上调用 toString的结果,否则返回第二个参数。 public static String toString(Object o, String nullDefault) 校验空 // 检查指定的对象引用是不是null 。若为null,则抛出空指针异常,否则返回对象本身 public static <T> T requireNonNull(T obj) // 当被校验的参数为null时,根据第二个参数message抛出自定义的NullPointerException public static <T> T requireNonNull(T obj, String message) // 判空方法,如果参数为null则返回true,否则返回false。 public static boolean isNull(Object obj) // 判断非空方法,若参数是非空,返回true,否则返回false。 public static boolean nonNull(Object obj) Collections 集合工具类 集合操作 // 反转 void reverse(List list) // 随机排序 void shuffle(List list) // 按自然排序的升序排序 void sort(List list) // 定制排序,由Comparator控制排序逻辑 void sort(List list, Comparator c) // 交换两个索引位置的元素 void swap(List list, int i , int j) // 旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。 void rotate(List list, int distance) 同步控制 Collections提供了三类方法返回一个不可变集合 emptyXXX():返回一个空的只读集合,静态常量
1. 简述静态网页和动态网页区别 静态网页和动态网页的主要区别在于它们 如何生成 和 呈现页面内容。
静态网页: 静态网页是以HTML静态页面为主要形式的网页,包含内容比较简单。网页的内容在服
务器上预先生成好,当用户请求访问该页面时,服务器直接将该页面的HTML文件发送给用户。静
态网页的优点是简单易于制作和快速加载,但缺点是功能限制较大,内容更新不方便。
动态网页: 动态网页是利用服务器端脚本语言动态生成网页内容的网页。当用户请求访问该页面
时,服务器会根据用户请求的数据和交互动作生成相应的页面。动态网页可以根据用户的需要动态
生成内容,功能更强大,也更具交互性。但是它的缺点是相对于静态网页来说,需要更多的服务器
资源,访问速度也比静态网页慢。
2. 简述 Webl.0 和 Web2.0 的区别 Web1.0与Web2.0的区别在于 重点 和 目的。
Web1.0是指互联网早期阶段的一个时代,主要域为网站设计与开发。它的特点是网站的信息发布
和交流是单向的、静态的、被动的,即由网站管理员发布信息,用户只能被动接受。这种网站的交
互性比较少,用户主要是读取和获取信息。
Web2.0是一个全新的阶段,它主要关注者社交、交互和用户体验,用户不再只是被动接受信息,
而是可以更加积极的参与到网站的内容中,从而实现了社会化互动。
Web2.0是具有更高交互性和个性化的互联网时代,其主要特点包括:
1> 用户可以更活跃地参与网络
2> 网站具有更好的社交性,而非只是提供信息
3> 借助云计算、大数据、人工智能等新技术,提高网站的易用性、性能和用户体验。
4> 网站建立起了内容生态系统:用户和开发者可以在这个系统内进行交流、创作、分享和消费,
这种模式是Web1.0所无法实现的。
总之,Web2.0相比Web1.0有更多的交流和互动,而且数据源会更加多元化,人们可以通过它来更
好地实现信息的共享。
3. Tomcat安装 1> 安装Java环境
[root@localhost ~]# yum install jdk-8u261-linux-x64.rpm -y # 检验jdk是否安装成功及版本 [root@localhost ~]# java -version 2> 安装Tomcat解压包(在官网下载apache-tomcat-8.5.20.tar.gz)
[root@localhost ~]# tar xf apache-tomcat-8.5.20.tar.gz -C /usr/local/ # 创建软连接 [root@localhost ~]# ln -sv /usr/local/apache-tomcat-8.
传统AI面试已死,L5级别AIGC面试官已成
传统AI面试存在以下三大问题难以解决:
1. 题目泄漏:由于传统AI面试题目较为固定,一些面试培训机构和已参加AI面试的候选人在网络平台传播题目,导致部分候选人获得不公平的准备机会。
2.无法追问:受算法能力限制,在传统AI面试中,候选人和AI面试官往往采取一问一答,无法互动,这使得AI面试官难以深入了解候选人,而候选人也可能无法充分展现自己的真正实力。 3. 互动交流缺失:从候选人的视角中,传统的AI面试过程就是一个录制视频的过程,无法体验到AI能力。只有HR和面试官才能在AI面试产品的后端查看到AI算法对于候选人的打分和评价。如果候选人想询问AI面试官一些问题,AI面试官是没有能力进行回答的。
以上三个问题,让传统AI面试的应用场景受限于校园招聘,且离真实还原人类之间的面试场景相去甚远,我们不禁感叹,传统AI面试已死。
得益于AI多模态算法大模型为基础的HR近屿超脑的强大能力,AI得贤招聘官的L4级别AI面试已成功迭代演进为得贤L5级别AIGC面试官,以上三大问题迎刃而解。(AI得贤招聘官官网:AI得贤招聘官)
解决方案一:自适应提问能力,杜绝题目泄漏
得贤L5级别AIGC面试官基于自研的AI多模态大模型——近屿超脑进行AI生成式提问,让面试过程更加公平、高效和人性化。
解决方案二:追问能力,深入了解候选人
得贤L5级别AIGC面试官能够根据候选人回答进行有针对性追问,实现全自动深度理解,让候选人有更多机会展现实力。
解决方案三:多轮对话能力,实现真正互动交流
得贤L5级别AIGC面试官已具备多轮对话能力,帮助候选人更好地了解雇主品牌和职位信息,提升面试体验。候选人可以随心所欲地提问AI面试官,AI面试官也能够给予准确的回答。
信息安全保障:严格遵循法规,确保数据安全
在全球化背景下,数据跨境传输泛起关注。得贤L5级别AIGC面试官利用自研的AI多模态算法大模型——HR近屿超脑,严格遵循信息安全规范,并确保产品和服务完全符合PIPL和GDPR的合法合规要求。
得贤L5级别AIGC面试官期待与您共同探索人力资源管理的光明未来。现在,您可以通过搜索AI得贤招聘官官网联系客服,预约得贤L5级别AIGC面试官的Demo和试用账号,体验AI面试的革新之路。
效果图 js
function $(id) { return document.getElementById(id); } function checkUser() { var uname = $("uname").value; uname = uname.trim(); var userp = $("unameWarn"); userp.innerHTML = ""; var reg = /^[a-zA-Z][a-zA-Z0-9]{5}$/; var reg = new RegExp("[a-zA-Z][a-zA-Z0-9]{5}"); if (reg.test(uname) == false) { userp.innerHTML = "错误"; return false; } } function checkPwd() { var psw = $("psw").value; psw = psw.trim(); var pswW = $("pswWarn"); var reg = /^[a-zA-Z0-9]{8,16}$/; pswW.innerHTML = ""; if (reg.test(psw) == false) { pswW.
Python是一种高级编程语言,属于通用编程语言。它是由荷兰人Guido van Rossum在1989年创造的,其语法简单、易读易写,是一种解释型、面向对象、动态数据类型的编程语言,支持多种编程范式,如面向对象、函数式、过程化等。Python在人工智能、数据科学、Web开发、自动化测试等领域广泛应用,拥有丰富的开源库和工具。因为其易学易用的特点,Python已经成为了编程初学者的首选语言之一。
以下是一些Python代码示例:
1、Hello World程序
print("Hello, World!")
2、列表排序
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
sorted_list = sorted(my_list)
print(sorted_list)
3、字符串拼接
name = "John"
age = 23
print("My name is " + name + " and I am " + str(age) + " years old.")
4、文件读取
with open("file.txt", "r") as f:
contents = f.read()
print(contents)
5、数据库连接
import sqlite3
conn = sqlite3.connect('example.db')
c = conn.
原文:canvas绘制“飞机大战”小游戏,真香!,点击链接查看更多技术内容。
canvas是ArkUI开发框架里的画布组件,常用于自定义绘制图形。因为其轻量、灵活、高效等优点,被广泛应用于UI界面开发中。
本期,我们将为大家介绍canvas组件的使用。
目录
一、canvas介绍
二、canvas基础绘制方法
三、飞机大战小游戏绘制实践
一、canvas介绍 1. 什么是canvas?
在Web浏览器中,canvas是一个可自定义width、height的矩形画布,画布左上角为坐标原点,以像素为单位,水平向右为x轴,垂直向下为y轴,画布内所有元素的位置基于原点进行定位。
如图1所示,我们通过<canvas>标签,创建了一个width=1500px,height=900px的空白画布,我们还需要“画笔”才能绘制图形。canvas采用轻量的逐像素渲染机制,以JS为“画笔”直接控制画布像素,从而实现图形绘制。
图1 canvas画布
2. canvas的“画笔”
canvas本身虽不具备绘制能力,但是提供了获取“画笔”的方法。开发者可通过getContext('2d')方法获取CanvasRenderingContext2D对象完成2D图像绘制,或通过getContext('webgl')方法获取WebGLRenderingContext对象完成3D图像绘制。
目前,ArkUI开发框架中的WebGL1.0及WebGL2.0标准3D图形绘制能力正在完善中,所以本文将着重介绍2D图像的绘制。如图2所示,是CanvasRenderingContext2D对象提供的部分2D图像绘制方法,丰富的绘制方法让开发者能高效的绘制出矩形、文本、图片等。
图2 图像绘制方法
另外,开发者还可以获取OffscreenCanvasRenderingContext2D对象进行离屏绘制,绘制方法同上。
当绘制的图形比较复杂时,频繁的删除与重绘会消耗很多性能。开发者可根据自身的需求灵活选取canvas的渲染方式。这时,开发者可以根据自身的需求灵活选取离屏渲染的方式,通过创建OffscreenCanvas对象作为一个缓冲区,然后将需要绘制的内容先绘制在OffscreenCanvas上,最后再将OffscreenCanvas绘制到主画布上,以提高画布性能,确保绘图的质量。
二、canvas基础绘制方法 通过上节对canvas组件的基本介绍,相信大家对canvas组件已经有了一定的认识,下面我们将为大家实际演示canvas组件在ArkUI开发框架中的使用方法。ArkUI开发框架参考Web浏览器中canvas的设计,并在“类Web开发范式”及“声明式开发范式”两种开发范式中进行提供,接下来我们将分别介绍这两种开发范式中canvas的使用。
1. 类Web开发范式中canvas的绘制方法
类Web开发范式,使用HML标签文件进行布局搭建、CSS文件进行样式描述,并通过JS语言进行逻辑处理。目前,JS语言的canvas绘图功能已经基本上完善,下面我们将通过两个示例,展示基于JS语言的canvas组件基础使用方法。
(1)矩形填充
CanvasRenderingContext2D对象提供了fillRect(x, y, width,height)方法,用于绘制一个填充的矩形。如图3所示,在画布内绘制了一个黑色的填充矩形,x与y指定了在canvas画布上所绘制的矩形的左上角(相对于原点)的坐标,width和height则设置了矩形的尺寸。
图3 填充的矩形
示例代码如下:
//创建一个width=1500px,height=900px的画布 <!-- xxx.hml --> <div> <canvas ref="canvas" style="width: 1500px; height: 900px; "></canvas> </div> //xxx.js export default { onShow() { const el =this.$refs.canvas; //获取2D绘制对象 const ctx = el.getContext('2d'); //设置填充为黑色 ctx.fillStyle = '#000000'; //设置填充矩形的坐标及尺寸 ctx.fillRect(200, 200, 300, 300); } } (2)缩放与阴影
先分享下libmodbus-3.1.7.tar.gz安装包,安装包放在linux系统下的home的某个文件夹下,我选择创建一个Modbus文件夹
链接:https://pan.baidu.com/s/17w8q_KRbi7ULLslTVKWVkw 提取码:yp6w cd ~ //打开家目录 mkdir Modbus //创建Modbus目录 1.在linux中解压压缩包 将库压缩包复制到linux下,进行解压
tar -xvf libmodbus-3.1.7.tar.gz //解压命令 解压过程
2.进入源码目录,创建文件夹(存放头文件、库文件) cd libmodbus-3.1.7 //进入源码目录 mkdir install //创建install目录 3.执行脚本configure,进行安装配置(指定安装目录) ./configure --prefix=$PWD/install 4.执行make和make install make//编译 make install//安装 执行完成后会在install文件夹下生产对应的头文件、库文件件夹,install用于存放产生的头文件、库文件等
5.要想编译方便,可以将头文件和库文件放到系统路径下 特别注意:下面的两条命令的要在你创建的文件夹Modbus路径下运行 sudo cp install/include/modbus/*.h /usr/include sudo cp install/lib/* -r /lib -d 后期编译时,可以直接gcc xx.c -lmodbus 6.验证