文章目录 如何计算维吉尼亚密码?Java实现加密算法Java实现解密算法参考博客 如何计算维吉尼亚密码? 计算维吉尼亚密码有2种方式,一种是根据密码表查找,另一种是手动计算方法。
1.密码表查找法
第一行是密钥,第一列是明文,某明文对应密钥加密产生的密文即为该行该列处的字母。
比如:明文是I LOVE YOU,密钥是KEY
那么对应的查询关系就是
2.手动计算方法
用数字0-25代替字母A-Z,需要特别注意的是第一个字母是从0开始编号的。要是从1开始计算,得到的结果肯定是错误的。还有就是·编号相加之后数值大于等于26,我们都要将这个数据对26做模运算才行。
则可以有以下计算过程
Java实现加密算法 package encryption; import java.util.Scanner; public class encryption { public static void main(String[] args){ //读取键盘输入值 Scanner sc1 = new Scanner(System.in); System.out.println("请输入明文"); Scanner sc2= new Scanner(System.in); System.out.println("请输入密钥"); //将读取的明文的赋给m,将读取的密钥赋给k String m=sc1.nextLine(); String k=sc1.nextLine(); char[] result=new char[50]; // 测试使用 // String m="iloveyou"; // String k="key"; // System.out.println(m.charAt(0)); // 运行结果是i // System.out.println(m.charAt(0)-'a'); // 运行结果是8,也就是字符i与a之间差的位数 // System.out.println((char)(m.charAt(0)-'a'+97)); // 如果不加97强制转换成char类型会产生乱码 // System.out.println((char)(((m.charAt(1)-'a'+k.charAt(1)-'a')%26)+97)); //加密算法 //java.
#5.1 函数控件介绍
函数控件在node-red中是重点,也是难点。由于其功能强大,能做的事情很多,所以它重要;事实上,函数控件中的“函数”一词,翻译为中文“功能”也是可以的。但是,函数是需要直接编写代码的,所以说也是难点。
节点帮助
一个JavaScr
本文内容已迁移,新的阅读地址 node-red教程 5 函数节点 更新更全的Node-RED教程,请访问 Node-RED系列教程
@Configuration 对比以前原生spring添加组件的区别
如果是以前的原生spring,想要将组件添加到容器中
1.需要在resources目录下创建一个xml配置文件
2.创建bean标签
现在的Spring Boot已经不需要向以前一样了,有一个注解@Configuration(翻译:配置)可以供使用
1.创建一个类。
2.使用注解@Configuration,告诉Spring Boot这是一个配置类。
这个时候在类里边不能写bean标签了需要使用@bean注解,想要构建出user和pet对象需要自己将它创造出来。
@bean :给容器中添加组件,以方法名作为组件的id。返回类型为组件类型,返回的值,就是组件在容器中的实例
在Spring Boot 5.2之后的@Configuration注解多了一个属性proxyBeanMethods,默认为true(翻译:代理bean的方法)
proxyBeanMethods:代理bean的方法
有两种模式:
1.Full:(proxyBeanMethods = true) //全模式
使用代理模式,保证组件的单实例,启动不如false快,但是重复利用率高,适用于会重复使用组件的场景。
2.lite:(proxyBeanMethods = false) //轻量级
不是用代理模式,不用保证组件的单实例,启动最快。单每次调用组件都会重新创建一个新的组件,组件可重复使用率低。适用于需要组件但不会重复使用的场景
总结:用于解决组件依赖
@MapperScan @Mapper 注解的使用
作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类。添加位置:接口类上面
2、@MapperScan注解的使用
作用:指定要变成实现类的接口所在的包,包下面的所有接口在编译之后都会生成相应的实现类。添加位置:是在Springboot启动类上面添加
区别:
添加@MapperScan(“cn.mybatis.mappers”)注解以后,cn.mybatis.mappers包下面所有的接口类,在编译之后都会生成相应的实现类;
在不使用@MapperScan前,我们需要直接在Mapper类上面添加注解@Mapper,这种方式要求每一个Mapper类都需要添加此注解,非常麻烦,属于重复劳动。通过使用@MapperScan注解,可以让我们不用为每个Mapper类都添加@Mapper注解。
@RestController @RestController的作用等同于@Controller + @ResponseBody
@Controller 在一个类上添加@Controller注解,表明了这个类是一个控制器类。
@ResponseBody表示方法的返回值直接以指定的格式写入Http response body中,而不是解析为跳转路径。
格式的转换是通过HttpMessageConverter中的方法实现的,因为它是一个接口,因此由其实现类完成转换。
如果要求方法返回的是json格式数据,而不是跳转页面,可以直接在类上标注@RestController,而不用在每个方法中标注@ResponseBody,简化了开发过程。
@Controller和@RestController的区别:
@Controller:在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解
@RestController:相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
@RequestMapping 作用:将请求和处理请求的控制器方法关联起来,建立映射关系。
位置:
1、标识类:设置映射请求的请求路径的初始信息
2、表示方法:设置映射请求的请求路径的具体信息
value属性: @RequestMapping(“/hello”) == @RequestMapping(value = “/hello”)
value属性是一个字符串类型的数组,表示请求映射能够匹配多个请求地址所对应的请求。
method属性: method属性通过请求的请求方式(get或post)匹配请求映射。他也是一个数组,但是是RequestMethod类的数组,表示请求映射能够匹配多种请求方式的请求。
直接打开网页的请求方式是GET
务必添加app.app_context().push()
不然报错
Flask 2.2.2
Flask-SQLAlchemy 3.0.0
user 为一
articles 为多
# app.py from flask import Flask, render_template, flash, request, session, redirect, url_for, abort, jsonify from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # MySQL所在的主机名 HOSTNAME = "127.0.0.1" # MySQL监听的端口号,默认3306 PORT = 3306 # 连接MySQL的用户名,读者用自己设置的 USERNAME = "root" # 连接MySQL的密码,读者用自己的 PASSWORD = "root" # MySQL上创建的数据库名称 DATABASE = "database_learn" app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4" db = SQLAlchemy(app) app.app_context().push() # with db.engine.connect() as conn: # rs = conn.
要求:
FileWriter:文件字符输出流
利用 FileWriter在本项目路径下创建一个文本文件,并写入内容"abca我爱敲代码";
方式一:创建FileWriter流对象,调用方法自带的write()方法,在括号中传入想写的内容。
方式二:创建char数组,char[] chars = "我是java小白".toCharArray();(为了不冗余内容,在下一篇详述)
Test99.java测试类
import java.io.FileWriter; import java.io.IOException; public class Test99 { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("fw.txt"); fw.write("abc"); fw.write(97); fw.write("我爱敲代码"); } catch (IOException e) { e.printStackTrace(); }finally { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } 运行结果:
总结:FileWriter和FileOutputStream都可以创建文件,区别在于:FileOutputStream向文件写入的是字节,FileWriter写入的是字符,包括数字、字母、字节、文字,后者比较能满足我们写文字的需求。
mac iterm2 使用rz报一串 $ rz ?**B0100000023be50ive.**B0100000023be50 第一步,安装brew,如果安装过,就省略
cd /usr/local/Homebrew/Library/Taps/homebrew/
rm -rf homebrew-core
git clone https://github.com/Homebrew/homebrew-core.git
第二步,安装 rz sz命令
brew install lrzsz
第三步,进入/usr/local/bin目录编辑iterm2-recv-zmodem.sh和iterm2-send-zmodem.sh 脚本
$ cd /usr/local/bin $ wget https://raw.github.com/mmastrac/iterm2-zmodem/master/iterm2-send-zmodem.sh # $ brew install wget $ wget https://raw.github.com/mmastrac/iterm2-zmodem/master/iterm2-recv-zmodem.sh $ chmod 777 /usr/local/bin/iterm2-* 如果上面命令下载文件失败,就手动vim编辑这两个文件,内容如下
iterm2-recv-zmodem.sh脚本内容如下
#!/bin/bash # Author: Matt Mastracci (matthew@mastracci.com) # AppleScript from http://stackoverflow.com/questions/4309087/cancel-button-on-osascript-in-a-bash-script # licensed under cc-wiki with attribution required # Remainder of script public domain osascript -e 'tell application "
引言 最近做T级互动,需要使用到3D模型。相信大家和我一样,在开始着手的时候,一定会有这么些问题:
1.如何选择3D模型的导出格式2.如何对模型文件进行优化3.在大流量的项目中兼容性怎么样 让我们通过这篇文章,进行细致的探索、调研与沉淀。
一、什么是 glTF 文件 glTF 全称 Graphics Language Transmission Format,是三维场景和模型的标准文件格式。
glTF 核心是 JSON 文件,描述了 3D 场景的整个内容。它由场景结构本身的描述组成,其由定义场景图的节点的层次提供。
场景中出现的 3D 对象是使用连接到节点的 meshes(网格)定义的。Materials(材料)定义对象的外观。Animations(动画)描述 3D 对象如何随着时间的推移转换 3D 对象,并且 Skins(蒙皮)定义了对物体的几何形状的方式基于骨架姿势变形。Cameras(相机)描述了渲染器的视图配置。
除此以外,它还包括了带有二进制数据和图像文件的链接,如下图所示。
二、.gltf 与.glb 从 blender 文件导出中可以看出:
glTF 文件有两种拓展形式,.gltf(JSON / ASCII)或.glb(二进制)。.gltf 文件可能是自包含的,也可能引用外部二进制和纹理资源,而 .glb 文件则是完全自包含的(但使用外部工具可以将其缓冲区/纹理保存为嵌入或单独的文件,后面会提到)。
2.1 .glb文件产生原因 glTF 提供了两个也可以一起使用的交付选项:
glTF JSON 指向外部二进制数据(几何、关键帧、皮肤)和图像。glTF JSON 嵌入 base64 编码的二进制数据,并使用数据 URI 内联图像。 对于这些资源,由于 base64 编码,glTF 需要单独的请求或额外的空间。Base64 编码需要额外的处理来解码并增加文件大小(编码资源增加约 33%)。虽然 gzip 减轻了文件大小的增加,但解压缩和解码仍然会增加大量的加载时间。
为了解决这个问题,引入了一种容器格式 Binary glTF。在二进制 glTF 中,glTF 资产(JSON、.bin 和图像)可以存储在二进制 blob 中,就是.
1. 不显示 x 坐标轴刻度 set(gca,'xtick',[]); 2. 坐标轴的刻度朝外 set(gca,'TickDir','out') 3. 绘制单个点 x=100; y=100; plot(x, y, '+') 4. Y轴反向(0刻度在上,往下递增) ax = gca; % current axes ax.YDir = 'reverse'; 5. 将X轴的标度显示在上方 ax.XAxisLocation = 'top'; 6. 只在左侧,和上侧显示标度 ax.Box = 'off'; 示例:
clear; close all; v=[3 3 6 6 5 5 7 7]; z=[0 2 2 10 10 12 12 20]; figure; plot(v,z) xlabel('P-VELOCITY KM/SEC'); ylabel('DEPTH IN KM'); ax = gca; % current axes ax.
分数 5
全屏浏览题目
切换布局
作者 张庆
单位 集美大学
本题目要求编写 Insert语句,在stu表中添加一条学生记录:
学号:S012,姓名:周强,性别:1,其它属性为NULL.
表结构: 请在这里写定义表结构的SQL语句。例如:
CREATE TABLE `stu` ( `sno` char(4) NOT NULL, `sname` char(8) NOT NULL, `sex` tinyint(1) DEFAULT NULL, `mno` char(2) DEFAULT NULL, `birdate` datetime DEFAULT NULL, `memo` text, PRIMARY KEY (`sno`) ); 表样例 请在这里给出上述表结构对应的表样例。例如
stu表:
输出样例: 插入一条学生记录后,stu表如下:
insert into stu values('S012','周强','1',null,null,null)a
文章来源:使用Notepad++来开发C程序
本文介绍的是Notepad++(编辑器)与MinGW(工具集,包含gcc)结合使用的一种C语言开发环境。
1、安装Notepad++
(1)双击安装包进行安装,选择语言,然后点击”OK“按钮:
(2)点击”下一步“:
(3)点击”我接受“按钮:
(4)选择安装路径,这里我选择D盘进行安装:
(5)选择组件,保留默认即可,点击”下一步“:
(6)最后打勾“Create Shortcut Desktop”在桌面创建快捷方式,点击”安装“,等待安装完成:
2、安装gcc编译器
(1)解压MinGW到指定路径中(要记住这个路径,后面需要用的到),如我解压到路径“D:\Program Files\”中:
(2)右击“我的电脑”,点击”属性“:
(3)点击“高级系统设置”:
(4)在系统变量中找到Path,然后点击“编辑”按钮:
(5)点击“新建”按钮新建一个“D:\Program Files\MinGW\bin”变量(bin所在的路径就是刚才解压的路径),然后点击“确定”:
(6)在系统变量中新建一个系统变量,变量名为lib,变量值为MinGW中lib文件夹的路径,然后点击“确定”按钮,如图:
(7)同步骤(6)新建一个系统变量include,如图:
(8)点击“确定”:
(9)点击“确定”:
(10)点击组合键“win + r” 打开运行窗口,输入“cmd”进入DOS窗口:
(11)在DOS窗口下输入命令:“gcc -v”,若输出如下所示信息则表明gcc环境变量配置成功,否则配置失败:
3、如何使用Notepad++、gcc进行开发?
(1)先使用Notepad++编辑好代码:
(2)把源码所在的路径复制下来:
(3)点击“win+r”组合键、输入“cmd”进入DOS窗口:
进入DOS黑窗口后:
进入源代码所在的路径。如果源代码路径(假设为:C:\Users\LiZhengNian\Desktop\hello)与当前路径(假设为:C:\Users\LiZhengNian)在同一个盘符,则直接输入“cd C:\Users\LiZhengNian\Desktop\hello”命令即可进入源代码路径;如果源代码路径与当前路径不再同一盘符,则先进入源代码所在盘符(如进入F盘的命令为:“F:”),再进入源代码所在路径。
输入编译命令进行编译。编译命令:gcc 源文件 -o 可执行文件。如:gcc hello.c -o hello.exe,其中”-o“的作用是重命名生成的可执行文件,也可使用:"gcc 源文件"进行编译,此时生成的可执行文件默认为a.exe。(输入命令时”Tab“键具有自动补齐功能)
运行程序。输入可执行文件即可运行,如输入:hello.exe
版权归原作者所有,如有侵权,请联系删除。
链路层提供的服务
使用链路层协议,将IP数据报通过单一通信链路 从一个节点移动到相邻节点。服务包括
1.成帧
在网络层数据报经链路传送之前,都要将其用链路层帧封装起来。一个帧由数据字段和首部字段组成,而网络层数据报就插在数据字段中
2.链路接入
MAC协议规定了帧在链路上的传输规则。当有多点共享一条链路时,MAC用于协调这些节点的帧传输。
3.可靠交付
链路层的可靠交付服务主要提供在易于产生高差错率的链路上,例如无线链路。其目的是本地纠正一个差错,而不是迫使端到端的数据重传。许多有线的链路层协议不提供该服务
4.差错检测与纠正
通过奇偶校验,循环冗余校验,检验和等方法检测或纠正比特错误
链路层在何处实现
链路层是硬件和软件的结合体,主要由硬件实现。链路层的主体部分是在网卡中实现的,位于网卡核心的是一个链路层控制器,该控制器是一个实现了许多链路层服务的芯片。链路层是协议栈中软件与硬件交接的部分。
链路层的差错检验与纠正技术
奇偶校验
在数据后补0或者1,使得数据中1的个数为奇数个或者偶数个。接收方通过查看1的个数是否符合发送方奇偶性来判断数据的准确性。
现实中通常使用二维奇偶校验,将数据分为不同行,针对每一行每一列进行奇偶校验。
检验和方法
在报文的发送端,会根据报文中的首部或数据来计算一个检验和(IP报文的检验和只对首部进行计算,ICMP报文对报文首部和数据都进行计算),然后一旦接收端接受到相应报文,接收端也会对报文的首部或数据进行一次检验和计算,如果接收端算出来的检验和和发送端发送的不一样,那么对不起,接收端认为报文在传输过程中出了错,于是就丢掉该报文。
循环冗余检测
发送端与接收端约定一个r+1比特位的生成多项式,发送方在数据末尾附加r个冗余比特,若接收方接收的数据(带上冗余比特位)用模二算数可以被生成多项式整除,则数据位正确的
多路访问协议
网络链路有两种类型 :点对点链路以及广播链路。
点对点链路由单一发送方和单一接收方组成。
广播链路能让多个发送方和接收节点都连接到相同的、单一的、共享的广播信道上。之所以称之为广播,是因为当任何一个节点传输一个帧的时候,信道会广播该帧,每个节点都会收到一个副本。
如何协调多个发送节点和接收节点对一个共享广播信道的访问,这就是多路访问问题。而解决这一问题的方式就是使用多路访问协议来规范节点在共享广播信道上的传输行为
因为所有的节点都能传输帧,所以多个节点可能会同时传输帧,使得传输的帧发生碰撞。当碰撞发生时,没有一个节点可以成功接受到该帧
多路访问协议总的来说可以分为三类
信道划分协议,随机接入协议以及轮流协议
信道划分协议
顾名思义,该种协议对信道进行划分。那么划分的方式如何呢?
时分多路复用(TDM)
时分多路复用,将时间划分为时间帧,再将每个时间帧划分为多个时隙,时隙的长度应使一个时隙能够传输单个分组。每个节点只可在它对应的时隙传输。
TDM的优点在于消除了碰撞且十分公平,假设信道总速率为R,共有N个节点共享该信道。则一个时间帧内每个节点都得到了R/N的传输速率
TDM的缺点在于,首先,它限制了每个节点的传输速率只能说平均传输速率。其次,当只有一个节点需要传输数据时,节点必须等待它在传输序列中的轮次。
频分多路复用(FDM)
信道的划分依据由时间变为频段。将Rbps的信道划分为不同频段,每个频段具有R/N的带宽,并把每个频率分配给N个节点中的一个。它的优缺点与TDM类似
码分多址(CDMA)
CDMA对每个节点分配一种不同的编码,然后每个节点用它唯一的编码来对他发送的数据进行编码。这样不同的节点能够同时传输。
随机接入协议
一个传输节点总是以信道的全部速率进行发送。当有碰撞发生时,涉及碰撞的每个节点反复的重发分组,直到该分组无碰撞的通过为止。但是当一个节点经历了一次碰撞时,它不可立即重发,而是等待一个随机时延
常见的随机接入协议有ALOHA协议和载波侦听多路访问协议
时隙ALOHA
时间被划分为多个时隙,一个时隙应当可以传输一帧。节点只在时隙起点开始传输数据,如果一个时隙有两个或多个帧碰撞,该节点以概率P在后序的每个时隙重传它的帧,直到帧被无碰撞的传出去。时隙ALOHA要求所有节点同步它们的传输,即在每个节点开始时开始传输。而第一个ALOHA协议实际上并没有划分时隙,而是立即广播,立即重传。当有大量活跃节点时,时隙ALOHA协议的最大效率为1/e,而非时隙为1/2e
载波侦听多路访问和碰撞检测(CSMA)
ALOHA协议的弊端在于,即使有碰撞的发生,也只会在下一次概率重传而不是停止传输。CSMA则在节点传输之前会先检测信道是否有能量。如果检测到信道正在被使用,则不传输。通俗来讲,就是说话之前先听有没有其他人在说。然而,这样依旧会造成碰撞,因为即使现在检测到信道口没有使用,可是一旦开始传输数据,其他传播过来的数据可能刚好到达,这样也会造成碰撞。所有,如果检测到两个节点同时开始传输,则应立即停止传输,在下次传输之前等待一个随机时间
轮流协议
多路访问协议的两个理想特性是:当只有一个节点活跃时,该活跃节点占用全部吞吐量。当有M个节点活跃时,每个活跃节点具有均分的吞吐量。ALOHA和CSMA协议仅具备第一个特性,但并不具备第二个特性。而轮流协议具备这两种特性
轮询协议
指定一个主节点,主节点不断轮询每个节点,向每个节点发送报文,告知该节点可以传输的帧的最多数量。比如,先向节点1发送报文,告诉它可以传输的最大数量,当节点1传输了某部分帧之后,向节点2发送报文,告知它可以传输的数量。
轮询协议消除了碰撞和空时隙,但引入了轮询时延,即通知节点所需要的时间。并且如果主节点发生故障,则整个信道将会变得不可操作。
令牌传递协议
这种协议中没有主节点,而是以令牌的方式,比如节点1总是将令牌发给节点2,节点2总是给节点3,节点N总是给节点1。具有令牌的节点如果有帧需要发送,则它尽可能地将帧发送。否则立刻给下一个节点。它的缺点在于一个节点的故障容易引起整个信道的崩溃。
链路层寻址
主机和路由器的网卡具有链路层地址,具有多个网卡(即网络接口)的主机或路由器将具有与之关联的多个链路层地址,就像他也具有多个与之关联的网络地址一样。而交换机并不具有与它们接口相关联的链路层地址。链路层地址最为流行的称呼为MAC地址。MAC地址有6个字节,48个比特位,每个字节用十六进制表示。网卡的MAC地址被设置为永久的,不会随着位置的改变而发生变化。但用软件改变一块适配器的MAC地址现在是可能的。发送网卡将目的网卡的MAC地址插入到帧中,并将帧发送到局域网上。当其他网卡接收到一个帧时,会检查该帧中的目的MAC地址是否与自己的MAC地址匹配。如果匹配,就提取出数据报并沿协议栈向上传递。
为什么有了网络层IP地址后还要独立出一个MAC地址呢
首先,网络协议栈应是相互独立的,如果链路层用IP地址的话,则网卡将不能很好的支持其他的网络层协议。其次,如果使用IP地址,每次网卡位置移动的时候还需要重新加电配置。最后,如果不使用MAC地址,而是让网卡将他收到的每个帧向上传递,则主机将被局域网上发送的每个帧中断。
为什么有了MAC地址后还要IP地址呢
如果仅仅有MAC地址而没有IP地址,则网卡只能做基于交换机,集线器的低级转发操作,由于全世界存在着各式各样的网络,它们使用不同的MAC地址。要是这些异构网络能够互相通信就必须进行非常复杂的硬件地址转换工作,因此由用户或用户主机来完成这项工作几乎是不可能的事。当网络规模逐渐扩大,会让交换机的交换表变的十分复杂,这时候就需要统一的IP地址来进行子网的划分以及高级转发,即路由选择算法, 来达到在复杂规模的情况下仍能高效转发的目的——连接到因特网的主机只需拥有统一的IP地址,它们之间的通信就像连接在同一个网络(虚拟互连网络或者简称IP网)上那么简单方便
地址解析协议(ARP)
当发送主机确定了目的主机的IP地址后,他还要向他的网卡提供目的主机的MAC地址。那么,发送主机如何得知目的主机的MAC地址呢?它使用ARP。在发送主机中的ARP模块将取在相同局域网的任何IP地址作为输入,然后返回其对应的MAC地址。他与DNS协议类似,不同之处在于DNS可以解析任何地方的主机名,而ARP只为同一局域网的IP地址提供解析服务。
ARP表存在于每台主机或路由器的内存中。并且ARP是即插即用的,即无需手工配置。APR的表项存在一个过期时间,并且有可能并不完全覆盖子网的所有IP地址。当想要查询一个目的IP地址对应的MAC地址,但这一表项并不存在或者已经过期了,这时该怎么办呢?
首先,发送主机会向ARP模块传递一个查询分组,并且指示网卡使用广播MAC地址(FF-FF-FF-FF-FF-FF)来发送这一分组。在这一局域网的每一块网卡都会收到该帧,并将其向上传递给ARP模块,ARP模块检查该帧的目的IP地址是否与自己的IP地址相同,相同的话就会发回一个带有所希望映射的响应ARP分组,然后发送主机会更新ARP表,并发送IP数据报。查询ARP报文是在广播帧,而响应ARP报文是在标准帧。
ARP协议是一个位于链路层之上,网络层之下的边界协议。因为它既使用到了IP地址,也使用到了MAC地址。
上面我们介绍了,ARP协议只用于局域网之内。那么,如何将数据发送到子网之外呢?其实很简单,只需将数据先发送到这一子网的边界路由器,边界路由器同时具有两边子网的接口,再由边界路由器发送到其他子网即可。
以太网帧结构
1.数据字段
项目场景: 项目使用前后端分离开发,前后端都部署在k8s中。
前端 前端项目通过nginx代理到后端服务器。
nginx中配置了如下Header:
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; 后端 后端项目使用了SpringBoot并使用了Undertow作为Servlet容器
问题描述 现在有两个服务 A 服务使用了springboot 2.3.4,B 服务使用了springboot 2.0.8。这两个服务的配置相同。
A服务可以通过HttpServletRequest 获取 https 及实际请求的域名
B服务通过HttpServletRequest 获取不到请求的协议和实际请求的域名
原因分析: 通过查看springboot项目源码发现,在处理这些Forward的时候Spring提供了两种方式去处理。
1.使用Spring提供的Filter ForwardedHeaderFilter 在这个Filter中使用ForwardedHeaderExtractingRequest包裹了请求对象,并且在初始化时使用UriComponentsBuilder的adaptFromForwardedHeaders 方法处理了Forward请求头信息
处理方法如下:
UriComponentsBuilder adaptFromForwardedHeaders(HttpHeaders headers) { try { String forwardedHeader = headers.getFirst("Forwarded"); if (StringUtils.hasText(forwardedHeader)) { String forwardedToUse = StringUtils.tokenizeToStringArray(forwardedHeader, ",")[0]; Matcher matcher = FORWARDED_PROTO_PATTERN.matcher(forwardedToUse); if (matcher.find()) { scheme(matcher.group(1).trim()); port(null); } matcher = FORWARDED_HOST_PATTERN.
场景: 复制百度文库上的文字,一般是收费的
解决方案: 按“F12”,点击设置,禁用JavaScript,即可复制
出问题前效果,就是滚动不了
给包裹这个盒子css加下面的样式就可以了
height: 800rpx; overflow: auto; 改后的效果
使用scroll()方法
https://www.w3school.com.cn/jquery/event_scroll.asp
当页面滚动条变化时,执行的函数:
$(window).scroll(function () {....}); 或
$(selector).scroll(function)//function非必须 案例
旧版本 旧版本可以使用bind/unbind方法
// 页面渲染完之中执行的代码
$(function(){ // 绑定事件,监听滚动条下拉的动作 bindScrollEvent(); }); function bindScrollEvent(){ // 添加滚动监听事件 $(window).scroll( function() { var docHeight = $(document).height(); // 获取整个页面的高度(不只是窗口,还包括为显示的页面) var winHeight = $(window).height(); // 获取当前窗体的高度(显示的高度) var winScrollHeight = $(window).scrollTop(); // 获取滚动条滚动的距离(移动距离) //还有30像素的时候,就查询 if(docHeight == winHeight + winScrollHeight){ //到底(一般是离到底还有一段距离就查询的) } }); } //移除监听
$(window).unbind("scroll"); 新版本 function doSth () { // do something } // 绑定scroll事件
$(window).on('scroll', doSth); // 解绑scroll事件
js 刷新页面window.location.reload();
Javascript刷新页面的几种方法:
复制代码
1 history.go(0)
2 window.location.reload()
window.location.reload(true)
3 location=location
4 location.assign(location)
5 document.execCommand(‘‘Refresh’’)
6 window.navigate(location)
7 location.replace(location)
8 document.URL=location.href
复制代码
Frame框架:
复制代码
1 frame.html:
2
3 4 5 6 复制代码
七种语句:
复制代码
语句1. window.parent.frames[1].location.reload(); 语句2. window.parent.frames.bottom.location.reload(); 语句3. window.parent.frames["bottom"].location.reload(); 语句4. window.parent.frames.item(1).location.reload(); 语句5. window.parent.frames.item(''bottom'').location.reload(); 语句6. window.parent.bottom.location.reload(); 语句7. window.parent[''bottom''].location.reload(); 复制代码
top.html 页面的代码如下:
1 bottom.html页面:
1 2 This is the content in bottom.html. 3 1.window指代的是当前页面,例如对于此例它指的是top.html页面。 2.parent指的是当前页面的父页面,也就是包含它的框架页面。例如对于此例它指的是frame.html。 3.frames是window对象,是一个数组。代表着该框架内所有子页面。 4.item是方法。返回数组里面的元素。 5.如果子页面也是个框架页面,里面还是其它的子页面,那么上面的有些方法可能不行。 如果想关闭窗口时刷新或者想开窗时刷新的话,在中调用以下语句即可。
开窗时刷新 关闭时刷新 //子窗口刷新父窗口
发现html中引入调用另一个html的方法有很多种,我都尝试了一下,就把他们都列出来吧:
其中推荐第一种和第六种,因为代码太长就写在最后了。其他的方法,可以自己尝试,看是不是适合你当前项目。
一、需要借助 jquery div+$(“#page1”).load(“b.html”) 。
参考代码:
<body> <div id="page1"></div> <div id="page2"></div> <script> $("#page1").load("page/Page_1.html"); $("#page2").load("page/Page_2.html"); </script> </body> 二、iframe 会生成一个边框,需要重新设置一下样式,相当于在页面内嵌入了一个页面。
参考代码:
<head> </head> <body> <div id="page1"> <iframe align="center" width="100%" height="170" src="page/Page_1.html" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> </div> <div id="page2"> <iframe align="center" width="100%" height="170" src="page/Page_2.html" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> </div> </body> 三、object引入 同样会生成一个边框,需要重新设置一下样式。
参考代码:
<head> <object style="border:0px" type="text/x-scriptlet" data="page/Page_1.html" width=100% height=150> </object> </head> 四、import引入 这个我并没有试验成功,可能是我打开方式不对。
参考代码:
<head> <link rel="import" href="page/Page_1.html" id="
方式一:Blob和FileReader 对象
实现原理:
使用xhr请求图片,并设置返回的文件类型为Blob对象[xhr.responseType = “blob”]
使用FileReader 对象接收blob
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>js 图片转base64方式</title> </head> <body> <p id="container1"></p> <script> getBase64("https://z649319834.github.io/Learn_Example/video_track/webvtt.jpg") function getBase64(imgUrl) { window.URL = window.URL || window.webkitURL; var xhr = new XMLHttpRequest(); xhr.open("get", imgUrl, true); // 至关重要 xhr.responseType = "blob"; xhr.onload = function () { if (this.status == 200) { //得到一个blob对象 var blob = this.response; console.log("blob", blob) // 至关重要 let oFileReader = new FileReader(); oFileReader.
转自:山高我为峰 https://www.cnblogs.com/liaojie970/p/7376682.html
在研究react和webpack的时候,经常看到在js文件中出现require,还有import,这两个都是为了JS模块化编程使用。CSS的是@import
1.ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。 Require是CommonJS的语法,CommonJS的模块是对象,输入时必须查找对象属性。
// CommonJS模块 let { stat, exists, readFile } = require('fs'); // 等同于 let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile; above:整体加载fs模块(即加载fs所有方法),生成一个对象"_fs",然后再从这个对象上读取三个方法,这叫“运行时加载”,因为只有运行时才能得到这个对象,不能在编译时做到静态化。
ES6模块不是对象,而是通过export命令显示指定输出代码,再通过import输入。
import { stat, exists, readFile } from 'fs'; above:从fs加载“stat, exists, readFile” 三个方法,其他方法不加载,
2.ES6模块默认使用严格模式,无论是否声明“use strict” ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
Module 主要由两个命令组成,import和export,export用于规定模块的对外接口,import命令用于输入其他模块提供的功能
3.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取。如果希望获取某个变量,必须通过export输出,
// profile.js export var firstName = 'Michael'; export var lastName = 'Jackson'; export var year = 1958; 或者用更好的方式:用大括号指定要输出的一组变量
前言
在异步编程中,Promise 扮演了举足轻重的角色,比传统的解决方案(回调函数和事件)更合理和更强大。可能有些小伙伴会有这样的疑问:2020年了,怎么还在谈论Promise?事实上,有些朋友对于这个几乎每天都在打交道的“老朋友”,貌似全懂,但稍加深入就可能疑问百出,本文带大家深入理解这个熟悉的陌生人—— Promise.
基本用法
1.语法
new Promise( function(resolve, reject) {...} /* executor */ ) 构建 Promise 对象时,需要传入一个 executor 函数,主要业务流程都在 executor 函数中执行。
Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor,resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。一旦状态改变,就不会再变,任何时候都可以得到这个结果。
在 executor 函数中调用 resolve 函数后,会触发 promise.then 设置的回调函数;而调用 reject 函数后,会触发 promise.catch 设置的回调函数。
值得注意的是,Promise 是用来管理异步编程的,它本身不是异步的,new Promise的时候会立即把executor函数执行,只不过我们一般会在executor函数中处理一个异步操作。比如下面代码中,一开始是会先打印出2。
let p1 = new Promise(()=>{ setTimeout(()=>{ console.log(1) },1000) console.log(2) }) console.log(3) // 2 3 1 Promise 采用了回调函数延迟绑定技术,在执行 resolve 函数的时候,回调函数还没有绑定,那么只能推迟回调函数的执行。这具体是啥意思呢?我们先来看下面的例子:
let p1 = new Promise((resolve,reject)=>{ console.
import java.util.Date; public class Demo01Date { public static void main(String[] args) { // 创建日期对象,把当前的时间 System.out.println(new Date()); // Tue Jan 16 14:37:35 CST 2022 // 创建日期对象,把当前的毫秒值转成日期对象 System.out.println(new Date(0L)); // Thu Jan 01 08:00:00 CST 1970 } }
说明:单片机芯片为AT89C52,使用普中开发板,用汇编语言编程。
系统实现了对风扇的控制:
(1)控制器面板包括:启/停键、模式选择键、风速键和类型选择键。
(2)模式分为:手动模式和自动温控模式。在温控模式下,风速键和类型选择键无效。
(3)风速分为:强、中、弱3个等级。按风速键,状态由“弱→中→强→弱……”往复循环改变,每按一下键,状态就改变一次。
(4)类型分为:正常、睡眠和自然3种类型。按类型选择键,状态由“正常→睡眠→自然→正常……”往复循环改变。类型选择时,正常:电风扇连续转动;睡眠:电机慢转,产生轻柔的微风,转动4秒,停止8秒。自然:电风扇模拟自然风,电机转动8秒,停止8秒。
系统的初始状态:风扇停止转动,模式为“手动”,风速为“弱”,类型为“正常”。只有按下启/停键,风扇才开始转动。
(5)采用LCD1602液晶显示器显示风扇当前风速、模式、类型和环境温度。
本课程设计的设计说明书如下,里面详细介绍了各功能的实现方法。
【金山文档】 设计说明书002
智能风扇控制器设计说明书
XGBoost的优缺点: 与GBDT相比: 1)GBDT以传统CART作为基分类器,而XGBoost支持线性分类器,相当于引入L1和L2正则化项的逻辑回归(分类问题)和线性回归(回归问题);
2)GBDT在优化时只用到一阶导数,XGBoost对代价函数做了二阶泰勒展开,引入了一阶导数和二阶导数,一方面增加了精度,另一方面支持自定义的损失函数,只要是能满足二阶连续可导的函数均可以作为损失函数;
3)XGBoost在损失函数中引入正则化项,用于控制模型的复杂度。正则化项包含全部叶子节点的个数gammaT,以及每个叶子节点输出的结果score(wj)的L2模的平方和1/2lambda||w||^2。从Bias-variance tradeoff角度考虑,正则项降低了模型的方差,防止模型过拟合,这也是xgboost优于传统GBDT的一个特性。其中gamma与lambda需要进行调参。
4)当样本存在缺失值时,xgBoosting能自动学习分裂方向,即XGBoost对样本缺失值不敏感,该处理源于稀疏感知算法,在初次计算Gain时剔除缺失值,然后将缺失值先后加入不同方向节点,最终取Gain值最优的结果。
5)XGBoost借鉴RF的做法,支持列抽样,这样不仅能防止过拟合,还能降低计算,这也是xgboost异于传统gbdt的一个特性。
6)XGBoost在每次迭代之后,会将叶子节点的权重乘上一个学习率(相当于XGBoost中的eta,论文中的Shrinkage),主要是为了削弱每棵树的影响,让后面有更大的学习空间。实际应用中,一般把eta设置得小一点,然后迭代次数设置得大一点;
7)XGBoost工具支持并行,但并行不是tree粒度的并行,XGBoost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含了前面t-1次迭代的预测值),XGBoost的并行是在特征粒度上的。XGBoost在训练之前,预先对数据进行了排序,然后保存为(block)结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个块结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行;
8)可并行的近似直方图算法,树结点在进行分裂时,需要计算每个节点的增益,若数据量较大,对所有节点的特征进行排序,遍历的得到最优分割点,这种贪心法异常耗时,这时引进近似直方图算法,用于生成高效的分割点,首先根据特征分布的百分位数提出候选分割点,基于候选分割点,将连续特征映射到各个桶里,最后根据聚合后的分割点效果找出最优的分割点,为了限制树的增长,引入阈值,当增益大于阈值时,进行分裂;
9)XGBoost的原生语言为C/C++,这是也是它训练速度快的一个原因。
与LightGBM相比: 1)XGBoost采用预排序,在迭代之前,对结点的特征做预排序(其中预排续的结果会存储到内存中,保存排序的数据及其对应的节点,因此当数据量增大时,其内存占用量大),遍历选择最优分割点,数据量大时,贪心法耗时;LightGBM方法采用histogram算法,占用的内存低,数据分割的复杂度更低,但是不能找到最精确的数据分割点;
2)XGBoost采用level-wise生成决策树策略,同时分裂同一层的叶子,从而进行多线程优化,不容易过拟合,但很多叶子节点的分裂增益较低,没必要进行更进一步的分裂,这就带来了不必要的开销;LightGBM采用leaf-wise生长策略,每次从当前叶子中选择增益最大的叶子进行分裂,如此循环,但会生长出更深的决策树,产生过拟合,因此 LightGBM 在leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合)。另一个比较巧妙的优化是 histogram 做差加速。一个容易观察到的现象:一个叶子的直方图可以由它的父亲节点的直方图与它兄弟的直方图做差得到。
参考文献:
(88条消息) XGBoost的基本原理_Y学习使我快乐V的博客-CSDN博客_xgboost的原理
(88条消息) 集成学习之Xgboost_Aliert的博客-CSDN博客
(88条消息) GBDT算法的升级--XGBoost与LightGBM算法_CquptDJ的博客-CSDN博客_efb算法
1、实现功能
dataGridVie控件绑定List数据,点击按钮更新List数据并重新绑定,dataGridVie控件的数据更新。
2、编程步骤
(1)、定义Person类
public class Person { private string name; private int age; private double weight; public string Name { get { return name; } set { name = value; } } public int Age { get { return age; } set { age = value; } } public double Weight { get { return weight; } set { weight = value; } } public Person(string _name,int _age,double _weight) { name = _name; age = _age; weight = _weight; } } (2)、初始化dataGridVie控件
文章目录 一、Dataset加载数据——获取数据及其label二、tensorboard的使用1. add_image()函数——显示image2. add_scalar()函数——显示函数 三、torchvision中transform.py的使用三、torchvision中数据集的使用四、Dataloader打包压缩——为网络提供不同的数据形式五、神经网络1. 神经网络基本骨架(简单使用)2. 卷积层(convolution layers)3. 最大池化的使用(pooling layers)4. 非线性激活(Non-linear Activations)relusigmoid 5. 线性层(Linear Layers)(全连接层)6. 搭建网络7. 通过 torch.nn.Sequential 使得网络搭建代码更加简洁8. loss function9. 优化器10. 在pytorch提供的网络模型的基础上进行修改10. 网络模型的保存和读取保存方式1保存方式2 六、完整模型的训练套路GPU加速训练 七、完整模型的验证套路 一、Dataset加载数据——获取数据及其label from torch.utils.data import Dataset from PIL import Image import os class MyData(Dataset): def __init__(self,root_dir,label_dir): self.root_dir = root_dir self.label_dir = label_dir self.path = os.path.join(self.root_dir,self.label_dir) #传递的是图片的相对地址 self.img_path_list = os.listdir(self.path) #将相对地址变为列表形式(可按index找指定的图像) def __getitem__(self, idx): img_name = self.img_path_list[idx] #图像名字 img_item = os.path.join(self.root_dir,self.label_dir,img_name) #图像全貌(相对地址要具体到单张图片) img = Image.open(img_item) label = self.
前言 接下来我们就开始Mybatis的源码之旅,首先从宏观上了解Mybatis的整体框架分为三层,分别是基础支持层、核心处理层、接口层,详情看图片
接口层 接口层是开发者使用频率最多的一层,核心对象SqlSession,它是上层应用和Mybatis打交道的桥梁,SqlSession上定义了非常多的对数据库的操作方法。接口层在接收到调用请求的时候,会调用核心处理层的相应模块来完成具体的操作。
核心处理层 跟数据库操作相关的动作都是在这一层完成的,核心处理层主要做了这几件事:
把接口中传入的参数解析并且映射成JDBC类型解析xml文件中的SQL语句,包括插入参数和动态SQL。执行SQL语句。处理结果集、并映射成JAVA对象 插件也属于核心层,这是由它工作方式和拦截的对象决定的。
基础支持层 基础支持层主要是一些抽取出来的通用的功能,实现复用,用来支持核心处理层的功能,比如数据源、缓存、日志、xml解析、反射、IO、事务等等。
核心流程 系统启动至最终SQL的执行过程 Mybatis的主要工作流程其实就是系统启动至最终SQL的执行过程,从构建SqlSessionFactory开始,调用Configuration用来解析全局配置和映射文件,最终生成一个新的DefaultSqlSessionFactory类。当完成SqlSessionFactory构建后,就会继续构建SqlSession,SqlSession是面向应用开发的接口,SqlSession会调用执行器Executor,Executor再调用处理器StatementHandler,StatementHandler又包括输入参数处理器ParameterHanlder以及输出参数ResultSetHandler,最终执行sql语句。
核心对象的生命周期 SqlSessionFactoryBuiler 首先是SqlSessionFactoryBuiler,它是用来构建SqlSessionFactory的,而SqlSessionFactory只需要一个,所以只要构建了这一个SqlSessionFactory,SqlSessionFactoryBuiler的流程就结束了,也没有存在的意义了,所以它的生命周期只存在于方法的局部。
SqlSessionFactory SqlSessionFactory是用来创建SqlSession的,每次应用程序访问数据库,都需要创建一个会话。因为我们一直有创建会话的需要,所以SqlSessionFactory应该存在于应用的整个生命周期中,作用域是应用作用域。创建SqlSession只需要一个实例来做就行了,否则会产生很多的混乱和浪费资源。所以采用单例模式
SqlSession SqlSession是一个会话,因为它是线程不安全的,不能在线程间共享。所以在请求开始的时候创建一个SqlSession对象,在请求结束或者说方法执行完毕的时候要及时关闭它。
Mapper Mapper实际上是一个代理对象,是从SqlSession中获取的。作用是发送SQL来操作数据库的数据。它应该在一个SqlSession事务方法之内。
UserMapper mapper = sqlSession.getMapper(UserMapper.class); SqlSessionFactory 首先我们来看下SqlSessionFactory对象的获取
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); SqlSessionFactoryBuilder 首先我们new一个SqlSessionFactoryBuilder对象,这是建造者模式的运用,建造者模式用来创建复杂对象,而不需要关注内部细节,是一种封装的提现。Mybatis中很多地方用到了建造者模式。
SqlSessionFactoryBuilder用来创建SqlSessionFactory对象的方法是build(),build()方法有9个重载,可以用不同的方式来创建SqlSessionFactory对象。SqlSessionFactory对象默认是单例的。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { // 用于解析 mybatis-config.xml,同时创建了 Configuration 对象 >> XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 解析XML,最终返回一个 DefaultSqlSessionFactory >> return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.
服务器BIOS和BMC等知识详解 服务器BIOS和BMC等知识详解_大余里的博客-CSDN博客_主板bmc
背景:疫情期间,学校要求每天在上午10点之前填报信息。有时容易忘记填报,就会受辅导员惩罚。
我们用“i至诚”填报,所以这里用这个例子来图文演示如何实现自动签到功能。
程序中使用到的Python库有:
selenium:selenium是一个用电脑模拟人操作浏览器网页,可以实现自动化,测试等的库。
time:此模块提供各种时间相关功能。会用到其sleep()方法让程序挂起一会儿。
1、准备工作 这里python使用chrome浏览器来打开网页。就需要安装chrome浏览器的驱动——chromedrive。
首先康康本电脑chrome浏览器的版本。
下载版本对应的浏览器驱动。
下载位置:https://chromedriver.chromium.org/downloads
这里咱们下载96.0.4664.45版本
将驱动解压放到指定文件夹内。
解压后,要将文件放到两个位置
chrome文件位置
python解释器(Scripts文件夹中)
将chrome文件位置添加到环境变量
用户变量–>Path 添加chrome浏览器的文件位置
当驱动配置完成后,试试python是否能自动打开chrome并访问指定url。
上图是python成功打开浏览器并访问指定url。那么此时准备工作全部完成。
2、代码实现 以下代码为示例,但核心功能就是这一小段:
from selenium import webdriver import time def sign_in(): driver = webdriver.Chrome() url = 'https://xxxxxx' driver.get(url) # 载入到这个网页后,挂起5秒,再继续执行。 # 挂起5秒是因为加载网页是需要一定时间的,当网页还没完全加载出来时,程序早就执行到下一句了,而下一句代码是 # 到网页中寻找指定元素。所以,当网页还没加载出来时,程序会因为找不到指定元素而报错。 time.sleep(5) # 用xpath的方式寻找指定元素。 confirmElement = driver.find_element_by_xpath('//*[@id="CHECK"]/div[2]/div[2]/input') # 点击指定元素 confirmElement.click() if __name__ == '__main__': sign_in() 这里提一下如何获取元素的xpath:
3、踩过的坑和建议: 曾经也用过这种方法,当时每次都是失败,就是因为没有 time.sleep() 导致程序总是报错 “找不到该元素”。
这是个大坑。
所以,在每个点击之前,需要加载的地方都加一个 time.sleep() 会更好,确保能够找到所需元素。
现在,这个程序可以帮你完成点击签到的任务。那么,想要每天自动签到的话就只剩让他定时执行了。
但是要让他每天定时自动执行,自动签到的话,最好将该程序部署到网络服务器上。
简介 <keep-alive>是Vue的内置组件,当他包裹组件时,会对组件进行缓存,不去销毁组件。
首次进入页面时,会触发mounted和activated钩子,当页面被缓存下来后,进入页面只会触发activated钩子,离开页面会触发deactivated,不会触发destroyed。
使用 参数 参数值描述include字符串或正则表达式只有name匹配的组件会被缓存exclude字符串或正则表达式name匹配的组件不会被缓存 // 将缓存 name 为 home 的组件 <keep-alive include='home'> <router-view/> </keep-alive> // 使用正则表达式 <keep-alive :include='/home|index/'> <router-view/> </keep-alive> 通过路由中的 meta 属性控制 通过在路由中的meta添加keepAlive属性为true,标识当前页面需要进行缓存。
{ path: '/shop', name: 'shop', component: () => import('./views/shop.vue'), meta: { keepAlive: true //此组件需要被缓存 } }, 结合v-if进行使用
<keep-alive> <router-view v-if="$route.meta.keepAlive" /> </keep-alive> <router-view v-if="!$route.meta.keepAlive" /> 现在我们已经可以缓存页面了,但是在开发过程中,如下场景:
list:商品列表页。shop:商品页(被缓存)。order:购买页。 当从列表页跳到商品页时,商品页不需要缓存,只有从购买页跳到商品页时,才需要缓存。
为了满足这种同一个页面有时需要缓存,有时不需要的场景,需要使用路由守卫beforeRouteLeave来实现,根据将要访问的页面判断是否要清除缓存。
beforeRouteLeave(to, from, next) { // 回到商品列表不缓存 if(to.name === 'list'){ // 清除缓存 this.$destroy(); } next(); }
原文
http://developer.android.com/guide/appendix/api-levels.html
Android API Levels
在本文中
API的级别是什么?
在Android中使用API级别
开发者需要考虑的内容
应用程序的向前兼容性
应用程序的向后兼容性
平台版本和API级别的选择
声明最低API级别
针对高版本的API级别测试
使用临时的API级别
通过API级别进行文档内容过滤
参见
<uses-sdk> manifest element
当你开发你的Android应用程序时,了解该平台API变更管理的基本方法和概念是很有帮助的。同样的,知道API级别标识以及该标识如何保障你的应用与实际硬件设备相兼容对于开发及后续的发布、维护都是有益的。
本节内容告诉你API级别的知识,以及它如何影响你开发和使用的应用。
关于如何使用“以API级别进行过滤”来使用API参考手册,从本文末尾的文档过滤(Filtering the documentation)中可以得到更多信息。
API级别是什么?(What is API Level?)
API级别是一个整数值,它唯一标识了一个具体版本的Android平台,及其框架的API的版本。
Android平台提供了一套框架API,使得应用程序可以与系统底层进行交互。该框架API由以下模块组成:
一组核心的包和类清单(manifest)文件的XML元素和属性声明资源文件的XML元素和属性声明及访问形式各类意图(Intents)应用程序可以请求的各类授权,以及系统中包含的授权执行 每个Android平台的后续版本会包括它提供的更新的Android应用程序框架的API。
该框架的API的更新设计,使高版本的API与早期版本兼容。也就是说,在新版本API中大多数都是新增功能,和引进新的或替代的功能。作为API的部分升级,老的替换的部分已过时,但不会从新版本中删除,使得已有的应用程序仍然可以使用它们。在极少数情况下,旧版本API的部分可能被修改或删除,通常这种变化是为了保障API的稳定性及应用程序或系统的安全。所有其他早期版本的API将不做修改的保留。
一个Android平台提供的框架API,被指定一个整数标识符,称为“API级别”。每一个版本的Android平台只支持有一个API级别,虽然该支持是隐含地包括了所有早期的API级别(一直到API级别1级)。 Android平台的最初版本提供的框架API级别是1级,随后的版本依次递增。
下表说明了具体平台版本和支持的API级别的对应关系。
平台版本
API级别
Android 3.0
11
Android 2.3.3
10
Android 2.3
9
Android 2.2
8
Android 2.1
7
Android 2.0.1
6
Android 2.0
5
Android 1.6
4
Android 1.5
3
Android 1.1
2
转载这篇文章主要是了解python反爬虫策略,帮助自己更好的理解和使用python 爬虫。 1、判断请求头来进行反爬
这是很早期的网站进行的反爬方式
User-Agent 用户代理
referer 请求来自哪里
cookie 也可以用来做访问凭证
解决办法:请求头里面添加对应的参数(复制浏览器里面的数据)
2、根据用户行为来进行反爬
请求频率过高,服务器设置规定时间之内的请求阈值
解决办法:降低请求频率或者使用代理(IP代理)
网页中设置一些陷阱(正常用户访问不到但是爬虫可以访问到)
解决办法:分析网页,避开这些特殊陷阱
请求间隔太短,返回相同的数据
解决办法:增加请求间隔
3、js加密
反爬方式中较为难处理的一类。
js加密的原理:服务器响应给浏览器的js文件,可以动态的生成一些加密参数,浏览器会根据js的计算 得到这些参数,在请求中带入进来,如果请求中没有这些参数,那么服务器就任务请求无效。
4、字体加密
字体反爬,是一种常见的反爬技术,网站采用了自定义的字体文件,在浏览器上正常显示,但是爬虫抓取下来的数据要么就是乱码,要么就是变成其他字符。采用自定义字体文件是CSS3的新特性,熟悉前端的同学可能知道,就是font-face属性。
5、登录验证码
使用Python爬取网页内容时往往会遇到使用验证码登陆才能访问其网站,不同网站的使用的验证码也不同,在最开始使用简单验证码,识别数字,但是随着反爬的不断发展,慢慢设计出了更多复杂的验证码,比如:内容验证码、滑动验证码、图片拼接验证码等等。
网上有很多打码平台,通过注册账号,调用平台接口,进行验证码的验证。
6、md5相关知识
MD5,消息摘要算法,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。MD5的特点:
1.不可逆:不能从密文推导出明文。
2.不管明文长度为多少,密文的长度都固定。
3.密文之间不会重复。
import hashlib
print(hashlib.md5(‘python’.encode()).hexdigest())
字符串python加密后的结果:
23eeeb4347bdd26bfc6b7ee9a3b755dd
7、base64
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
import base64
#python中base64的加密
print(base64.b64encode(‘python’.encode()).decode())
#python中base64的解密
print(base64.b64decode(‘Y2hpbmE=’.encode()).decode())
结果:
cHl0aG9u
china
8、验证码验证
自己动手看验证码(古诗词网)
import requests
url = “gushiwen.org”
session = requests.Session()
text = session.get(url).text
#解析响应,找到验证码图的片地址
#下载验证码图片,保存
with open(‘code.jpg’, ‘wb’)as f:
介绍: 2022最新云存储网盘系统_文件分享系统_文件存储系统
测试环境:Nginx + MySQL5.6 + PHP7.0
安装教程:
1、上传解压
2、配置laravel5伪静态规则
3、配置数据库文件.env 运行目录设置为public
4、导入数据库文件 dkewl.sql
5、安装PHP扩展exif、fileinfo
6、PHP的php.ini文件里面的;always_populate_raw_post_data = -1 删除前面的分号“;” (这一步可
以不设置)
7、从PHP禁用函数中 删除shell_exec、proc_open、putenv这三个PHP函数
程序:https://qumaw.lanzoul.com/iMv1C0djo58f
小猫爪:S32K3学习笔记09-S32K3之Safety简介 1 前言2 Safety相关硬件介绍3 Safety相关软件介绍4 Safety文章目录END 1 前言 接下来,就要开始进学习一下S32K3最。。最。。最搞的一个部份了,那就是Safety部分了。这也是S32K3自称功能安全等级能达到ASIL-B/D级别的芯片最坚实的支撑。
2 Safety相关硬件介绍 下面是S32K3这个系列中各个PN能达到的等级情况:
其实也可以更简单的来看,就是有锁步核的PN才能达到ASIL-D,因为锁步核是ASIL-D的要求。
那么S32K3为了功能安全Safety都准备哪些功能来支撑呢,S32K3系统框图如下所示:
把这幅图用文字的形式总结一下,如下表:
在核上,S32K3的2个Cortex M7内核可以工作在锁步模式,两个内核实时执行相同指令并实时相互校验,如果执行结果不同,就会报告到内部的故障搜集模块。
在访问权限上,S32K3具备完善的访问保护机制,存储器保护单元MPU可以控制内核对所有地址空间的访问权限;资源域控制模块XRDC可以控制每个内核或总线master对外设寄存器和内存地址空间的访问权限;此外,S32K3的外设桥也可以控制每个总线master的访问权限;上述各种保护机制,为访问权限的控制提供了灵活和完善的配置功能;
在程序运行流的监控上,S32K3为每个内核提供了看门狗watchdog,且看门狗具备独立时钟源和窗口模式;S32K3还具有专用于监控启动阶段Power-on watchdog,可以在MCU启动过程或唤醒过程出现不能响应的情况时,让MCU回到安全状态。
在数据完整性上,S32K3具备完善的ECC校验功能,不管是内部Flash,SRAM,ITCM,DTCM,或者是Cache,都具有ECC校验功能。此外S32K3对数据在内部总线上传输过程也做了端到端的校验,这可以更好的保证数据的完整性。
在时钟监测上,S32K3具有完整的时钟监测功能,其内部的时钟监测单元会将MCU内部振荡器和外部时钟的频率进行对比,从而判断关键时钟是否常。
在电源监测上,S32K3的电源监测功能可以检测到电源电压过低或过高的故障,并在发生故障时产生中断或复位。并且还会监控复位时序,如果在一定时间内没有退出复位时序导致超时则会重启复位时序。
在温度监测上,S32K3集成了温度监测功能,用户可以通过ADC采样一个特定通道,应用软件可以将该通道的结果转换成对应的温度值。随时可监控其自身结温。
在自检上,S32K3的自测试单元可以在应用代码执行之前对微控制器做自检。S32K3的自检功能包括内存自检和逻辑自检,他们都是在MCU复位启动的过程中执行,内存自检是针对所有易失性存储器,逻辑自检是针对MCU内部各种数字逻辑进行检测,这能够帮助检查出MCU内部的潜在失效。此外我们有内核自测试软件,可以让内核运行自测试代码来完成内核逻辑的诊断。另外S32K3的EIM模块用于错误注入,ERM模块用于错误报告,这为故障诊断提供了便利。用户可以注入特定故障来检验诊断功能的完整性。
以及等等(细节太多,不好多说)。
以上就是S32K3在针对功能安全做的一些措施,那么接下来这么多功能,最后体现到S32K3的具体外设中又是怎样的呢?如下:
以上就是跟Safety相关的最最最重要的几个模块了。当然除此之外,还有其他功能则是和相关的外设集成在一起的,比如ADC的自测试,Memory的ECC检测,看门狗等等,另外还有其他独立的外设,比如MPU,XRDC,等等等等等这些搞人玩意,共同构成了S32K3的Safety。
接下来就是一个一个的解剖它们,了解它们的工作机制,而又是怎么相互关联的。
3 Safety相关软件介绍 至于NXP针对S32K3的Safety硬件资源所开发或者规划的软件,S32K3的安全手册上大致把K3的所有的安全机制分成4个部分,分别是SM1,SM2,SM3,SM4四个部分,而软件则是可以根据这四种安全机制来划分。
SM1为S32K3的硬件安全机制,比如什么内部看门狗,内存ECC校验等等这些S32K3本身自带的硬件安全机制,NXP针对SM1开发的软件大多包含在标准软件包RTD和SPD(safety peripheral driver)中,这两个软件开发包是免费的,相当于是S32K3的底层Driver。SM2为S32K3的内部软件安全机制,比如软件检测到相关错误,就让K3重启这种需要软件来实现的,只跟S32K3本身相关的安全机制。NXP针对SM2开发的软件叫做SAF(safety software framework)和SCST(core self-test code),它们大多都是通过调用SPD来实现的软件安全机制,这是收费的。当然如果你们足够牛,你也可以自己去实现这些安全机制。其中SPD是SAF的一个子集,SAF涵盖了SPD的所有功能,说白了SAF是一个针对S32K3的功能安全开发的一个比较完整的大软件框架,而SPD只是这个大软件框架里面的一个小模块。SM3为S32K3外部的硬件安全机制,比如外部看门狗,电源监测等。这得客户自己来实现,一般都是在外面整一个SBC啊,比如高大上的FS26。SM4为应用软件机制,指的是跟具体应用相关的软件机制,这可能牵扯到K3的具体硬件外设,也可能会牵扯与K3无关的东西,比如在通讯中需要确认数据完整性合法性等。这则需要用户根据实际应用需求来自己集成。 有人可能想问这些安全机制具体有哪些?我不告诉你,这些安全机制在K3的安全手册中有详细介绍,自己去看(其实下载安全手册是需要权限的,我不能瞎透露)。
总结,所有的安全机制都只是针对S32K3有关的,而不是针对整个系统层面上而言。与S32K3功能安全相关的软件主要有RTD,SPD, SCST, SAF四个,由于SAF和SCST是要收费的,但是在NXP官网提供了免费体验版,可以下载下来爽一段时间也是不错的选择。
4 Safety文章目录 《S32K3学习笔记10-S32K3之EIM和ERM》《S32K3学习笔记11-S32K3之FCCU》《S32K3学习笔记12-S32K3之STCU2》《S32K3学习笔记13-S32K3之CMU》《S32K3学习笔记14-S32K3之REG_PORT,MPU和XRDC》《S32K3学习笔记15-S32K3之SEMA42和INTM》《S32K3学习笔记16-S32K3之PMC和MC_RGM》《S32K3学习笔记17-S32K3之数据完整性的保障和手段》《S32K3学习笔记18-S32K3之Safety外设总结》《S32K3学习笔记19-S32K3之如何集成SPD进自己的工程》《S32K3学习笔记20-S32K3之SCST及其应用》《S32K3学习笔记21-S32K3之SAF及其应用》 END
今天给大家分享一个能通过代码自动生成文档技术,Spring Rest Doc过在单元测试中额外添加 API 信息描述,从而自动生成对应的文档片段。 下面通过一个简单的例子演示下如何快速上手的。在Spring Boot项目中添加maven 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency> 在controller添加接口
@PostMapping("/show/entity") public Dog getDog(@RequestBody Dog dog){ return dog; } 编写测试用例,并且输出文档。
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.MediaType; import org.springframework.restdocs.RestDocumentationContextProvider; import org.springframework.restdocs.RestDocumentationExtension; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @WebMvcTest @ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) class DogControllerTest { private MockMvc mockMvc; @BeforeEach public void init(WebApplicationContext applicationContext, RestDocumentationContextProvider contextProvider){ mockMvc = MockMvcBuilders.
目 录
第一章 绪论 1
1.1 选题背景及意义 1
1.2国内外研究现状 1
1.2.1国际教育信息化现状 1
1.2.2国内教育信息化现状 2
1.3研究主要内容 2
第二章 开发环境和相关技术简介 4
2.1 开发环境 4
2.2 相关技术 4
2.2.1 MVC简介 4
2.2.2 Struts2简介 6
2.2.3 JSP简介 7
2.2.4 CSS简介 8
2.2.5 Spring简介 9
2.2.6 Mybatis简介 12
2.2.7 Javamail简介 12
第三章 系统分析 14
3.1 需求的背景和目标 14
3.2 项目可行性 14
3.2.1 经济可行性 14
3.2.2 技术可行性 14
3.2.3 社会可行性 14
3.3 需求定义 15
3.3.1 功能需求 15
import { nextTick } from 'vue' 在vue3中,首先引入nextTick,
nextTick 是将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它 nextTick(() => { //在这里进行回显赋值操作 }) 这时候再去操作复选框组,发现可以操作了。
vue2中也是同理,
this.$nextTick(() => { //执行回显赋值操作 }) 仅记录个人工作中碰到的一些小问题,网上搜了很多,答案五花八门,没有能帮到我的,无意之间发现了一篇类似的帖子,遇到的情景和我有些相似,我试着改造后引入我的代码中,发现成功解决,以此来写这篇博客,希望能帮到有需要的人
今年遇到的一道密码学线上赛题,感觉挺有意思大概记录一下。
题目大概是给出rsa密文:
c=23129683905221590810931073733257240695491909600600821626110967741991475952367362466435001712032183901737453265086024660692796844392297498997208235843621067335947024294793917437465567235097523891328309930140339168673282959013006525102332444767839426566939309039615858490944730603509080574471734733118066791730903874584695936232044353090855494398794086718463881637739165577843547326511641921822024263267673375341299485422153934060527418515955523844699687688348603999820720218160844840953001023840468960215702467203343095303314120059019184362079713388502293450806476408625709403546751299379519145557188933345613844133126 然后提供数百个公钥文件,其中有一个修改时间较为特殊key.txt:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt0TBlWiuPttokM+14UTq dxwQ/oJO2lqsQ7yuGzXj6twLpqHEmOSlGRvpHVlPYvRKxQeILpfwim829y2dwnMK Ri+V4dIM3kn7lfxWq3k1xaFuj3VTwpSUeWFzzNeRdodooI0Ign6tuafmVC8GU0ZB 5j8io0XuPyzmHgrw8ZGKG8A/24cL4Zh0hboB/NOlWXEgGueKGB4t6GkdQGB9mZGc sJTeZdHMiFyyX6n3yWApIkRl/rvWChpvj3XXdaFc7zewApS1juOmMYSirb0g0QO9 Nba//dzVjkDHr7f0CwlJQRxGSTczLaznFDlCDi+CZ/k7tpWOCEuSbCQNe4f0RFYU fwIDF1+R -----END PUBLIC KEY----- 第一反应先取n和e:
openssl rsa -pubin -text -modulus -in key.txt 结果为:
Modulus: 00:b7:44:c1:95:68:ae:3e:db:68:90:cf:b5:e1:44: ea:77:1c:10:fe:82:4e:da:5a:ac:43:bc:ae:1b:35: e3:ea:dc:0b:a6:a1:c4:98:e4:a5:19:1b:e9:1d:59: 4f:62:f4:4a:c5:07:88:2e:97:f0:8a:6f:36:f7:2d: 9d:c2:73:0a:46:2f:95:e1:d2:0c:de:49:fb:95:fc: 56:ab:79:35:c5:a1:6e:8f:75:53:c2:94:94:79:61: 73:cc:d7:91:76:87:68:a0:8d:08:82:7e:ad:b9:a7: e6:54:2f:06:53:46:41:e6:3f:22:a3:45:ee:3f:2c: e6:1e:0a:f0:f1:91:8a:1b:c0:3f:db:87:0b:e1:98: 74:85:ba:01:fc:d3:a5:59:71:20:1a:e7:8a:18:1e: 2d:e8:69:1d:40:60:7d:99:91:9c:b0:94:de:65:d1: cc:88:5c:b2:5f:a9:f7:c9:60:29:22:44:65:fe:bb: d6:0a:1a:6f:8f:75:d7:75:a1:5c:ef:37:b0:02:94: b5:8e:e3:a6:31:84:a2:ad:bd:20:d1:03:bd:35:b6: bf:fd:dc:d5:8e:40:c7:af:b7:f4:0b:09:49:41:1c: 46:49:37:33:2d:ac:e7:14:39:42:0e:2f:82:67:f9: 3b:b6:95:8e:08:4b:92:6c:24:0d:7b:87:f4:44:56: 14:7f Exponent: 1531793 (0x175f91) Modulus=B744C19568AE3EDB6890CFB5E144EA771C10FE824EDA5AAC43BCAE1B35E3EADC0BA6A1C498E4A5191BE91D594F62F44AC507882E97F08A6F36F72D9DC2730A462F95E1D20CDE49FB95FC56AB7935C5A16E8F7553C29494796173CCD791768768A08D08827EADB9A7E6542F06534641E63F22A345EE3F2CE61E0AF0F1918A1BC03FDB870BE1987485BA01FCD3A55971201AE78A181E2DE8691D40607D99919CB094DE65D1CC885CB25FA9F7C96029224465FEBBD60A1A6F8F75D775A15CEF37B00294B58EE3A63184A2ADBD20D103BD35B6BFFDDCD58E40C7AFB7F40B0949411C464937332DACE71439420E2F8267F93BB6958E084B926C240D7B87F44456147F 固有套路分解一下n得到p和q:
q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793 p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591 本来打算套一下脚本就齐活了:
import gmpy2 import rsa p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793 q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591 n = 23135514747783882716888676812295359006102435689848260501709475114767217528965364658403027664227615593085036290166289063788272776788638764660757735264077730982726873368488789034079040049824603517615442321955626164064763328102556475952363475005967968681746619179641519183612638784244197749344305359692751832455587854243160406582696594311842565272623730709252650625846680194953309748453515876633303858147298846454105907265186127420148343526253775550105897136275826705375222242565865228645214598819541187583028360400160631947584202826991980657718853446368090891391744347723951620641492388205471242788631833531394634945663 e = 1531793 print(gmpy2.
这是我的目录: 回顾c语言我们是如何实现大小写字母转换的实现大小写母的转换用函数实现 回顾c语言我们是如何实现大小写字母转换的 #define _CRT_SECURE_NO_WARNINGS //大小写字母(alphabet)的转换 大->小 #include<stdio.h> int main() { int ch = 0;//初始化ch,因为getchar的返回值是int,所以初始化的类型也是int while ((ch = getchar())!=EOF)//循环输入一个字符ch,这个字符不能读取失败,否则就返回EOF { printf("%c\n", ch+32);//输出一个字符 getchar();//读走‘/n'; } return 0; } 这里很快我就写出了一种简单的方法,利用ascll码值大小写字母的相差值32的规律。如果是实现小写字母转换成大写字母呢?我们试想一下大写字母+32的ascll码值就转换成了我们的小写字母,反过来小写字母-32的ascll码值是不是我们的大小字母,这是一种换位思考,对于初学者来说还是蛮重要的,验证一下吧:
思考:但是这样我们一次只能输入一个字符,如果是一串字符呢?如果我想输入一串大写字母再输入一串小写字母呢?
实现大小写母的转换 方法一:
回到我们思考的问题,一次可能输入的不是一个字符,而是一串字符,我们可以用数组来实现,想要输出大写字母和小写字母,这里我们就可以写一个for循环来判断是转换成大写还是小写问题就迎刃而解了!c语言可以用同样的方法,这里我用的C++的语法:
#include <iostream> using namespace std; int main() { char a[100];//定义存放100个字符的字符串数组 int i = 0; cout << "请输入一串字符:\n"; cin >> a;//输入一串字符(一个字符也行) for (; a[i]; i++) { if (a[i] >= 'a' && a[i] <= 'z') a[i] -= 32; else if (a[i] >= 'A' && a[i] <= 'Z') a[i] += 32; } for (i = 0; a[i]; i++) cout << a[i];//输出打印转换后的字符串 cout << endl;//换行 system("
文章目录 JframeJDialogJPanel和JScrollPane容器文本组件按钮组件1.JCheckBox2.JRadionButton JComboBox组件菜单组件1.下拉式菜单2.弹出式菜单 JTable Swing包中提供了更加丰富、便捷、强大的GUI组件,而且这些组件都是Java语言编写而成的,因此,Swing组件不依赖于本地平台,可以真正做到跨平台运行。通常来讲,把依赖于本地平台的AWT组件称为重量级组件,而把不依赖本地平台的Swing组件称为轻量级组件。
大部分的Swing组件都是JComponent类的直接或者间接子类,而JComponent类是AWT中java.awt.Container的子类,说明Swing组件和AWT组件在继承树上形成了一定的关系。接下来通过一张继承关系图来描述一下AWT和Swing大部分组件的
关联关系,如图所示。
图中,展示了一些常用的Swing组件,不难发现,这些组件的类名和对应的AWT组件类名基本一致,大部分都是在AWT组
件类名的前面添加了“J”,但也有一些例外,比如Swing的JComboBox组件对应的是AWT中的Choice组件(下拉框)。
通过图中还可以看出,Swing中有三个组件是继承了AWT的Window类,而不是继承自JComponent类,它们分别是JWindow、JFrame、和JDialog,这三个组件是Swing中的顶级容器,它们都需要依赖本地平台,因此被称为重量级组件。其中,JWindow和AWT中的Window一样很少被使用,一般都是用JFrame和JDialog。
Jframe 在Swing组件中,最常见的一个就是JFrame,它和Frame一样是一个独立存在的顶级窗口,不能放置在其他容器之中,JFrame支持通用窗口所有的基本功能,例如窗口最小化、设定窗口大小等。
import javax.swing.*; import java.awt.*; public class JFrameEx extends JFrame { public JFrameEx(){ this.setTitle("first swing jframe"); this.setSize(300,300); JButton button=new JButton("按钮"); this.setLayout(new FlowLayout()); this.add(button); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public static void main(String[] args) { new JFrameEx(); } } JDialog JDialog是Swing的另外一个顶级窗口,它和Dialog一样都表示对话框。JDialog对话框可分为两种:模态对话框和非模态对话框。所谓模态对话框是指用户需要等到处理完对话框后才能继续与其他窗口交互的对话框,而非模态对话框是允许用户在处理对话框的同时与其他窗口交互的对话框。
对话框是模态或者非模态,可以在创建JDialog对象时为构造方法传入参数来设置,也可以在创建JDialog对象后调用它的setModal()方法来进行设置。JDialog常见的构造方法如表所示。
表中,列举了JDialog三个常用的构造方法,在这三个构造方法中都需要接收一个Frame类型的对象,表示对话框所有者,如果该对话框没有所有者,参数owner可以传入null。第三个构造方法中,参数modal用来指定JDialog窗口是模态还是非模态,如果modal值设置为true,对话框就是模态对话框,反之则是非模态对话框,如果不设置modal的值,其默认值为false,也就是非模态对话框。
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class JDialogEx { public static void main(String[] args) { JFrame jFrame=new JFrame("
很多GUI程序都需要在组件上绘制图形,比如实现一个五子棋的小游戏,就需要在组件上绘制棋盘和棋子。在java.awt包中专门提供了一个Graphics类,它相当于一个抽象的画笔,其中提供了各种绘制图形的方法,使用Graphics类的方法就可以完成在组件上绘制图形。表中列出了Graphics类中常用的方法。
表中,列出了Graphics的常用方法,为了更好的理解和使用它们,下面对这些方法进行详细的说明。
①setColor()方法
• 用于指定上下文颜色,方法中接收一个Color类型的参数。在AWT中,Color类代表颜色,其中定义了许多代表各种颜色的常量,比如Color.RED,Color.BLUE等,这些常量都是Color类型的,可以直接作为参数传递给setColor()方法。
②setFont()方法
• 用于指定上下文字体,方法中接收一个Font类型的参数。Font类表示字体,可以使用new关键字创建Font对象。Font的构造方法中接收三个参数,第一个是String类型,表示字体名称,如“宋体”、“微软雅黑”等,第二个参数是int类型,表示字体的
样式,参数接收Font类的三个常量Font.PLAINT、Font.ITALIC和Font.BOLD,第三个参数为int类型,表示字体的大小。
③drawRect()方法和drawOval()方法
• 用于绘制矩形和椭圆形的边框
④fillRect()和fillOval()方法
• 用于使用当前的颜色填充绘制完成的矩形和椭圆形。
⑤drawString()方法
• 用于绘制一段文本,第一个参数str表示绘制的文本内容,第二个和第三个参数x、y为绘制文本的左下角坐标。
import java.awt.*; import java.util.Random; public class AwtDraw { public static void main(String[] args) { final Frame frame=new Frame("验证码"); final Panel panel=new MyPanel(); frame.add(panel); frame.setSize(200,200); frame.setLocationRelativeTo(null); frame.setVisible(true); } } class MyPanel extends Panel{ @Override public void paint(Graphics g){ int width=160; int height=40; g.setColor(Color.BLACK); g.drawRect(0,0,width-1,height-1); Random random=new Random(); for(int i=0;i<100;i++){ int x=random.nextInt(width)-2; int y=random.
事件处理机制专门用于响应用户的操作,比如,想要响应用户的单击鼠标、按下键盘等操作,就需要使用AWT的事件处理机制
事件对象(Event):封装了GUI组件上发生的特定事件(通常就是用户的一次操作)。
事件源(组件):事件发生的场所,通常就是产生事件的组件。
监听器(Listener):负责监听事件源上发生的事件,并对各种事件做出相应处理的对象(对象中包含事件处理器)。
事件处理器:监听器对象对接收的事件对象进行相应处理的方法。
事件对象、事件源、监听器、事件处理器在整个事件处理机制中都起着非常重要的作用,它们彼此之间有着非常紧密的联系。接下来用一个图例来描述事件处理的工作流程,如图所示。
在程序中,如果想实现事件的监听机制,首先需要定义一个实现了事件监听器接口的类,例如Window类型的窗口需要实现WindowListener。接着通过addWindowListener()方法为事件源注册事件监听器对象,当事件源上发生事件时,便会触发事件监听器对象,由事件监听器调用相应的方法来处理相应的事件。
import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class AnonyEvent { public static void main(String[] args) { Frame frame=new Frame("我的窗口"); frame.setVisible(true); frame.setSize(300,300); frame.setLocation(300,300); Button btn=new Button("EXIT"); frame.add(btn); btn.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { System.exit(0); } }); } } MyWindowListener类实现WindowListener接口后,需要实现接口中定义的7个方法,然而在程序中需要用到的只有windowClosing()一个方法,其他六个方法都是空实现,没有发挥任何作用,这样代码的编写明显是一种多余但又必
需的工作。针对这样的问题,JDK提供了一些适配器类,它们是监听器接口的默认实现类,这些实现类中实现了接口的所有方法,但方法中没有任何代码,程序可以通过继承适配器类来达到实现监听器接口的目的。
import java.awt.*; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; public class WinEventEx { public static void main(String[] args) { Frame frame=new Frame("我的窗口"); frame.setSize(300,300); frame.
目录
一、主从复制 新建主服务器容器实例3307
进入/mydata/mysql-master/conf新建my.cnf
修改完配置后重启master实例
进入mysql-master容器
master容器实例内创建数据同步用户
新建从服务器容器实例3308
进入/mydata/mysql-slave/conf新建my.cnf
修改完配置后重启slave实例
在主数据库中查看主从同步状态
进入mysql-slave容器
在从数据库中配置主从复制
在从数据库中查看主从同步状态
在从数据库中开启主从同步
再次查看从数据库状态
二、主从复制测试
主数据库
从数据库
三、读写分离
Docker安装MyCat
server.xml schema.xml sequence_conf.properties rule.xml
运行容器
容器中安装JDK
连接测试
使用Docker安装MySQL5.7的详细文章:Linux中使用Docker安装MySQL5.7(CentOS7)_不会调制解调的猫的博客-CSDN博客
一、主从复制 新建主服务器容器实例3307 这里就算没有拉取mysql5.7的镜像也可以直接运行,若发现没有镜像则会直接自动拉取。
这里的-v如果不懂,也可以查看之前的容器数据卷详解:Docker容器数据卷_不会调制解调的猫的博客-CSDN博客
docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7 ps查看一下,确认它起来了
docker ps 进入/mydata/mysql-master/conf新建my.cnf vim /mydata/mysql-master/conf/my.cnf 直接把以下内容全部复制粘贴进去,然后保存退出。 [mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=101 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能 log-bin=mall-mysql-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062 修改完配置后重启master实例 在宿主机上通过容器数据卷来修改配置,传导给docker内部,是需要重启的
text-decoration:none; color:#333;
鉴权 鉴权(Authentication) 在信息安全领域是指对于一个声明者所声明的身份权利,对其所声明的真实性进行鉴别确认的过程。
在it领域:校验session、cookie、token的合法性和有效性。
1、HTTP鉴权 允许客户端在请求时,通过用户名+密码的方式,实现对用户身份的验证。
⚠️注意:几乎所有的网站都不会走该认证方案,看看就好
过程 客户端向服务器请求一个受限的数据服务器返回 HTTP/401 Unauthorized客户端弹窗询问用户客户端携带Base64格式的用户名+密码再次向服务器发送请求服务端进行身份验证校验成功,服务端返回状态码200给客户端(或校验失败,返回状态码403给客户端) 优点 简单,基本的浏览器都支持 缺点 不安全:基于HTTP传输,几乎是裸奔的,而且Base64解码也很容易无法主动注销:HTTP协议没有提供机制清楚浏览器中的Basic认证信息,除非关闭标签页、浏览器、清除历史记录 使用场景 内部网络对安全要求不是很高的网络 2、Session-Cookie鉴权 Session-Cookie 认证是利用服务端的 Session(会话)和 浏览器(客户端) 的 Cookie 来实现的前后端通信认证模式。
何为Cookie? 为了让服务器区分不同的客户端,用Cookie告知服务器前后两个请求是否来自同一浏览器。
特点:
Cookie存储在客户端,可随意修改,不安全最大为4kb有数量限制,对于一个网站不能超过20个Cookie,浏览器一般能存300个CookieCookie是不可跨域的,但是一级域名和二级域名是可以共享的(domain) 何为Session? Session的抽象概念是会话,是无状态协议通信过程中,为了实现中断/继续操作,将用户和服务器之间的交互进行的一种抽象。
过程:
客户端:用户向服务器首次发请求服务器:接受到数据并自动为该用户创建特定的Session/Session ID,来识别用户并跟踪该用户的会话过程客户端:浏览器收到相应获取会话信息,并在下一次请求时带上Session/Session ID服务器:服务器提取后会与本地保存的Session/Session ID进行对比找到该特定用户的会话,然后获取会话状态至此客户端与服务器的通信变成有状态的通信 特点:
Session保存在服务器通过服务器自动的加密协议进行 与Cookie的差异:
Session的安全性优于Cookie:因为Cookie存在客户端可以被篡改,而Session存在服务器,无法伪造大小不同:Cookie的大小不超过4k有效期不同:Cookie可设置为长时间保存,Session一般失效时间较短存取值的类型不同:Cookie只支持字符串数据,Session可以存放任意数据类型 Session-Cookie鉴权过程 客户端:发送登录信息(用户名+密码)至服务器服务器:校验用户名+密码服务器:通过校验后生成Session ID,并保存在Session服务器中服务器:返回数据给客户端,并Set-Cookie:PHPSESSID=sid客户端:携带Cookie,向服务器请求资源服务器:通过Session服务器校验SessionSession服务器:校验成功服务器:接口处理数据服务器:返回正确的数据给客户端 Session-Cookie 的优点 Cookie简单Session存在服务器,相较于JWT方便进行管理只需后端操作,前端无感 Session-Cookie 的缺点 依赖Cookie,一旦浏览器禁用Cookie,就无法后续操作了不安全,Cookie暴露在浏览器中,容易被盗用、CSRF攻击Session存粗在服务器,增大了服务器开销,用户量大的时候会降低性能 3、Token鉴权 Session-Cookie 的一些缺点,以及Session的维护给服务器造成的压力。然后我们又必须找个地方存放它,Token应运而生。
何为Token? Token是一个令牌,客户端访问服务器时,验证通过后服务端会为其签发一张令牌,之后,客户端就可以携带令牌访问服务器,服务端只需言验证令牌的有效性即可。
Token的组成:
uid(用户唯一身份标识)+ time(当前的时间戳)+ sign(签名,token的前几位以hash算法压缩成的一定长度的十六进制字符串)
Token认证过程 客户端发送登录信息(用户名+密码)给服务器服务器校验登录信息,生成一个加密的Token令牌,返回给客户端客户端获取Token后,保存至本地客户端再次请求API数据时,携带Token至服务器服务器拿到Token后,做解密和签名校验校验成功,服务器返回数据给客户端 Token的优点 服务端无状态化、可扩展性好:Token机制在服务器不需要存储Session信息,本身就已包含了用户的相关信息安全性好:避免CSRF支持跨域访问 Token的缺点 配合:需要前后端配合占带宽:正常情况下比sid更大,消耗更多流量,挤占更多带宽性能:需要加密解密Token,所以更耗性能有效期短:为了避免盗用,一般设置的有效期较短 由于Token有效期较短,所以就有了Refresh Token(刷新Token)
何为Refresh Token? Token过期了,让用户重新登录获取Token会很麻烦,这个时候一个专门生成Access Token的Token就诞生了。Refresh Token的有效期可以长一些,通过独立服务和严格的请求方式增加安全性。由于不常验证,也可以如签名的Session一样处理。
目录
一、文件操作
打印当前工作目录: pwd 【print working directory】
更换工作目录: cd
创建目录: mkdir (make directory)
将一个或多个源文件复制到指定的目录: cp
删除目录中的文件或目录: rm (remove)
移动文件或目录:mv (move)
删除目录: rmdir 【remove directory】
二、查看文件
cat : 连接和显示文件,将文件中的内容打印到输出设备
more:分页显示文件内容
三、文件搜索
which:获取指定命令的绝对路径
find:搜索关键字查找文件或目录,不指定路径,默认在当前路径下搜索
locate: 搜索关键字查找文件或目录
grep:在文件中搜索与指定字符串匹配的行并打印到终端
四、权限管理
chmod:变更文件或目录的权限
五、压缩解压
1.打包
2.压缩与解压
一、文件操作 Linux系统中常见的文件分为普通文件和目录文件,文件操作命令一般是指查看路径、切换目录、创建、删除、修改文件名等。
常用的操作命令ls:
打印当前工作目录: pwd 【print working directory】 更换工作目录: cd 【change directory】(通常是 cd 后跟目录,其中 .. 是切换到上一工作目录)
cd ./Public (切换工作目录到当前目录下的Public)
cd .. (切换工作路径到上一目录)
cd /etc/yum (切换目录到 etc 目录下的yum 目录中)
列出参数的属性信息: ls 【list】
theme: channing-cyan 前言 在开发中,我们经常会将一些常用的代码块、功能块进行封装,为的是更好的复用。那么,被抽离出来独立完成功能,通过API或配置项和其他部分交互,便形成了插件。
下面这些是我在工作中积累的一些常用的前端开源插件,这里只是罗列出来,详细的用法各个插件官网或者Gayhub都有介绍。注意:往往一个解决方案会有多个插件,需要读者根据自己的实际业务需求进行甄别选用,欢迎留言交流和补充。^_^
Javascript 工具 Underscore.js 一套完善的函数式编程的接口,更方便地在JavaScript中实现函数式编程 https://underscorejs.org/
Lodash 一致性、模块化、高性能的 JavaScript 实用工具库 https://lodash.com/
Ramda 一款实用的 JavaScript 函数式编程库 https://ramdajs.com/
Classnames 一个简单的JavaScript实用程序,用于有条件地将类名连接在一起 https://github.com/JedWatson/classnames
crypto-js 加密标准的 JavaScript 库 https://github.com/brix/crypto-js
clsx 一个很小的(228B)工具,用于有条件地构造className字符串 https://github.com/lukeed/clsx
zxcvbn JavaScript密码强度估算库 https://github.com/dropbox/zxcvbn
zxcvbn-ts 支持Typescript的密码强度估算库 https://github.com/zxcvbn-ts/zxcvbn
clipboard.js 将文本复制到剪贴板的轻量级JS 库 https://clipboardjs.com/
tesseract.js Javascript的OCR引擎,在浏览器离线识别图片中的文字 https://tesseract.projectnaptha.com/
number-precision 小而快的库,用于精确地进行加法、减法、乘法和除法运算 https://github.com/nefe/number-precision
big.js 一个用于任意精度十进制算术的小型快速 JavaScript 库 https://github.com/MikeMcl/big.js
fingerprintjs 具有高准确度和稳定性的浏览器指纹库 https://fingerprint.com/
ViteShot 基于Vite的快速简单的截图工具。 https://viteshot.com/
Valine 快速、简洁且高效的无后端评论系统 https://valine.js.org/
cnpm 淘宝提供的一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步 https://npmmirror.com/
yarn 快速、可靠和安全的依赖管理 https://yarnpkg.
# 详细请参考: https://juejin.cn/post/6982419819211522079 # 1. 拉取 ubuntu 镜像 docker pull ubuntu # 2.查看是否拉取成功 dokcer images # 3.运行容器 docker run --name 新建容器名称 -ti -d -p 3316:22 ubuntu # --name 指定生成的容器名称 # -i: 交互式模式运行 常与 -t配合使用 # -t: 为容器分配 tty 终端 # -d: 后台运行容器 # -p: 指定端口映射 一个指定端口 只能绑定一个容器 支持格式 # ubuntu 是镜像名称 # 4.查看容器是否运行成功 docker ps -a # 查看所有容器,包含启动和挂起的容器 # 注意 这个容器 是和极其干净的容器 所有的工具必须 自己安装 # 首先 apt-get update 升级系统 安装 apt-get install wget # 正确退出方式 先按,ctrl+p;再按,ctrl+q。绝对不能使用exit或者ctrl+d来退 #出,这样整个系统就退出了。具体到MAC电脑应该使用control代替ctrl键 # 退出后在进入 ubuntu # 1.
数组的定义 数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。 数组的四个基本特点 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
其元素必须是相同类型,不允许出现混合类型。
数组中的元素可以是任何数据类型,包括基本类型和引用类型。
数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
数组的声明与创建 dataType[ ] arrayRefVar = new dataType[ arraySize]; dataType[ ][ ] arrayRefVar = new dataType[ arraySize][ arraySize]; 数组的引用 public class Main { public static void main(String[] args) { int[] a = {1, 2, 3}; a[0] = 0; for(int i : a) { System.out.println(i); //这里会输出什么? } } } public class Main { public static void main(String[] args) { String[] names = {"ABC", "XYZ", "
#pragma once #include<thread> class BaseThread { public: void Start(); void Wait(); void Stop(); bool is_exit(); private: virtual void Run() = 0; private: std::thread thread_; bool is_exit_ = false; }; #include "BaseThread.h" void BaseThread::Start() { thread_ = std::thread(&BaseThread::Run, this); } void BaseThread::Wait() { if (thread_.joinable()) { thread_.join(); } } void BaseThread::Stop() { is_exit_ = true; Wait(); } bool BaseThread::is_exit() { return is_exit_; } #include<iostream> #include"BaseThread.h" class XThread:public BaseThread { public: void Run() { std::cout << "
引用计数 平时用的python是用c写的,所以叫cpython
标记清除 分代回收