shouldOverrideUrlLoading(下文简称拦截)执行在onPageStarted(下文简称加载)前面,如果拦截成功则不执行加载,有部分机型是不支持拦截的比如某米,有部分HTML代码是不支持拦截的,比如HTML里面有js写计时器。
首先示范正常的拦截(比如拦截http开头的网址):
webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { String url = request.toString(); if (url.indexOf("http") != -1) { Toast.makeText(this, "成功拦截http开头的网址", Toast.LENGTH_SHORT).show(); } return true; } }; 但是如果拦截装逼失败,比如某米的手机拦截不了 那么只能想办法在加载中拦截了,因为加载在拦截后面之后执行,如果拦截失败,加载就启动,如果拦截成功,就没加载什么事了。
下面是加载的代码:
webView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { String urls = url; if (url.indexOf("http") != -1) { Toast.makeText(this, "再次成功拦截http开头的网址,装逼成功", Toast.LENGTH_SHORT).show(); view.stopLoading();//这句的意思是让WebView 停止加载 } super.onPageStarted(view, url, favicon); } }; 注意:要想真正的拦截WebView 中的点击网址,那么上面的两种装逼方式都要加在new WebViewClient() {}里面。
题目 格式:flag:{xxx} 解题链接: http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php 打开连接 查看源码 通过post方式给password变量传值 md5加密后拼接sql查询语句到后台执行 后面的判断就是要求sql语句要成功执行
MD5函数 参考链接:http://www.w3school.com.cn/php/func_string_md5.asp
md5绕过 php在线执行工具:https://tool.lu/coderunner/ 根据链接名,合理猜测字符:ffifdyop
源码: 执行: 提交字符
<div>
<span>适用平台:</span>
<span>{(() => {
switch (currentItems.usePlatform) {
case 0:
return '全平台可用'
case 1:
return '淘宝'
case 2:
return '美团'
case 3:
return '爱奇艺'
case 4:
return '腾讯'
default:
return null
}
}
)()}</span>
</div> 转载于:https://www.cnblogs.com/Fanzifeng/p/9488271.html
Apache ab 下载解压即可:
-n
即requests,用于指定压力测试总共的执行次数。
-c
即concurrency,用于指定的并发数。
-t
即timelimit,等待响应的最大时间(单位:秒)。
-b
即windowsize,TCP发送/接收的缓冲大小(单位:字节)。
-p
即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数。
-u
即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数。
-T
即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain。
-v
即verbosity,指定打印帮助信息的冗余级别。
-w
以HTML表格形式打印结果。
-i
使用HEAD请求代替GET请求。
-x
插入字符串作为table标签的属性。
-y
插入字符串作为tr标签的属性。
-z
插入字符串作为td标签的属性。
-C
添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个)。
-H
添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。
-A
添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开。
-P
添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开。
-X
指定使用的和端口号,例如:"126.10.10.3:88"。
-V
打印版本号并退出。
-k
使用HTTP的KeepAlive特性。
-d
不显示百分比。
-S
不显示预估和警告信息。
-g
输出结果信息到gnuplot格式的文件中。
-e
输出结果信息到CSV格式的文件中。
-r
指定接收到错误信息时不退出程序。
-h
显示用法信息,其实就是ab -help。
常用命令:
ab【命令】 -c【并发数】 100 -n【请求数】 100 -s【不显示警告】 URL
=====================================================================================
/compare
{
"id": deviceId, 设备id
转载 插板法就是在n个元素间的(n-1)个空中插入若干个(b)个板,可以把n个元素分成(b+1)组的方法。 应用插板法必须满足三个条件: (1)这n个元素必须互不相异 (2)所分成的每一组至少分得一个元素 (3)分成的组别彼此相异 把10个相同的小球放入3个不同的箱子,每个箱子至少一个,问有几种情况? 问题的题干满足 条件(1)(2),适用插板法,c92=36 下面通过几道题目介绍下插板法的应用 a凑元素插板法(有些题目满足条件(1),不满足条件(2),此时可适用此方法) 例1:把10个相同的小球放入3个不同的箱子,问有几种情况? 3个箱子都可能取到空球,条件(2)不满足,此时如果在3个箱子种各预先放入 1个小球,则问题就等价于把13个相同小球放入3个不同箱子,每个箱子至少一个,有几种情况? 显然就是c12 2=66 例2:把10个相同小球放入3个不同箱子,第一个箱子至少1个,第二个箱子至少3个,第三个箱子可以放空球,有几种情况? 我们可以在第二个箱子先放入10个小球中的2个,小球剩8个放3个箱子,然后在第三个箱子放入8个小球之外的1个小球,则问题转化为 把9个相同小球放3不同箱子,每箱至少1个,几种方法?c8 2=28 HDU3037 Saving Beans Lucas 定理+逆元
b添板插板法 例3:把10个相同小球放入3个不同的箱子,问有几种情况? -o - o - o - o - o - o - o - o - o - o -o表示10个小球,-表示空位 11个空位中取2个加入2块板,第一组和第三组可以取到空的情况,第2组始终不能取空 此时 若在 第11个空位后加入第12块板,设取到该板时,第二组取球为空 则每一组都可能取球为空c12 2=66 例4:有一类自然数,从第三个数字开始,每个数字都恰好是它前面两个数字之和,直至不能再写为止,如257,1459等等,这类数共有几个? 因为前2位数字唯一对应了符合要求的一个数,只要求出前2位有几种情况即可,设前两位为ab 显然a+b<=9 ,且a不为0 1 -1- 1 -1 -1 -1 -1 -1 -1 --1代表9个1,-代表10个空位 我们可以在这9个空位中插入2个板,分成3组,第一组取到a个1,第二组取到b个1,但此时第二组始终不能取空,若多添加第10个空时,设取到该板时第二组取空,即b=0,所以一共有 c10 2=45 例5:有一类自然数,从第四个数字开始,每个数字都恰好是它前面三个数字之和,直至不能再写为止,如2349,1427等等,这类数共有几个? 类似的,某数的前三位为abc,a+b+c<=9,a不为0 1 -1- 1 -1 -1 -1 -1 -1 -1 - - - 在9个空位种插如3板,分成4组,第一组取a个1,第二组取b个1,第三组取c个1,由于第二,第三组都不能取到空,所以添加2块板 设取到第10个板时,第二组取空,即b=0;取到第11个板时,第三组取空,即c=0。所以一共有c11 3=165 c选板法 例6:有10粒糖,如果每天至少吃一粒(多不限),吃完为止,求有多少种不同吃法? o - o - o - o - o - o - o - o - o - o o代表10个糖,-代表9块板 10块糖,9个空,插入9块板,每个板都可以选择放或是不放,相邻两个板间的糖一天吃掉 这样一共就是 2^9= 512啦 d分类插板 例7:小梅有15块糖,如果每天至少吃3块,吃完为止,那么共有多少种不同的吃法? 此问题不能用插板法的原因在于没有规定一定要吃几天,因此我们需要对吃的天数进行分类讨论 最多吃5天,最少吃1天 1: 吃1天或是5天,各一种吃法 一共2种情况 2:吃2天,每天预先吃2块,即问11块糖,每天至少吃1块,吃2天,几种情况?c10 1=10 3:吃3天,每天预先吃2块,即问9块糖,每天至少1块,吃3天?
介绍 折半查找,又称作二分查找。这个查找的算法的特点,就是,要求数据要是有序的。
1 ,存储结构一定是顺序存储
2 ,关键字大小必须有序排列
算法思想:折半查找只能在有序数列中进行,将待查找的数据与有序数列(递增)中间的元素进行比较,如果相等,则找到;如果待查找的数据大于中间的元素的值,那么再从数组的后一半元素中进行查找,否则,从前一半元素中进行查找;若折半后都找不到,则输出“没找着”等提示信息。 代码实现: #include <stdio.h> void main() { int a[10],num,low,high,mid,i,flag=0; printf("input the array:"); for(i=0;i<=9;i++) { scanf("%d",&a[i]); } printf("input finding number:"); scanf("%d",&num); low=0; high=9; while(low<=high) { mid=(low+high)/2; printf("low=%d,mid=%d,high=%d\n",low,mid,high); if(a[mid]>num) { high=mid-1; } if(a[mid]<num) { low=mid+1; } if(a[mid]==num) { flag=1; break; } } if(flag) { printf("found!\n"); } else { printf("not found!\n"); } } 运行结果
QGridLayout 前言 QGridLayout(网格布局)是将窗口分割成行和列的网格来进行排列,通常可以使用函数addWidget()将被管理的控件(Widget)添加到窗口中,或者使用addLayout()函数将布局(layout)添加到窗口中,也可以通过addWIdget()函数对所添加的控件设置行数与列数的跨越,最后实现网格占据多个窗格
QGridLayout类中常用的方法 方法描述addWidget(QWidget Widget,int row,int col,int alignment=0)给网格布局添加部件,设置指定的行和列,起始位置的默认值为(0,0)widget:所添加的控件row:控件的行数,默认从0开始column:控件的列数,默认从0开始alignment:对齐方式addWidget(QWidget widget,int fromRow,int fromColulmn,int rowSpan,int columnSpan,Qt.Alignment alignment=0)所添加的的控件跨越很多行或者列的时候,使用这个函数widget:所添加的控件fromRow:控件的起始行数fronColumn:控件的起始列数rowSpan:控件跨越的行数column:控件跨越的列数alignment:对齐方式setSpacing(int spacing)设置软件在水平和垂直方向的间隔 实例一:单一的网格单元格 import sys from PyQt5.QtWidgets import QApplication ,QWidget , QGridLayout, QPushButton class Winform(QWidget): def __init__(self,parent=None): super(Winform,self).__init__(parent) self.initUI() def initUI(self): #1创建QGridLayout的实例,并设置窗口的布局 grid = QGridLayout() self.setLayout(grid) #2创建按钮的标签列表 names = ['Cls', 'Back', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+'] #3 在网格中创建一个位置列表 positions = [(i,j) for i in range(5) for j in range(4)] #4 创建按钮并通过addWIdget()方法添加到布局中 for position, name in zip(positions, names): if name == '': continue button = QPushButton(name) grid.
今天和移动端对接的时候,移动端把一些公共参数放在了 header 了,
然而在 laravel 中使用
\Illuminate\Http\Request; //这个是获取所有header信息 Request::header(); //这个是获取header里面的version参数值 Request::header('version'); 这些是可以满足需求获取到参数的。
但是偏偏这次出问题了。新加的参数怎么都是取不到,还以为是什么缓存问题,或者是哪里去除了,又或者带参数有个数限制。
结果调试了半天发现是移动端传参数的时候是不能在命名参数中带 _ (下划线的),
如 app_version,book_id 这样的是有问题的
需要去除下划线,或换成 - 都是可以的!
遇见这个坑记录一下,希望大家别踩啦!
-------------------------------------------------------------------
ps:今天调试中又发现 header 中是不能带 中文 过来的,如果带 中文 过来后端在 header 头中是拿不到值的。
初步测试是这样,如果有问题请大家指正哈!
-----------------------------------------------------------------
2018年11月1日
后续发现是Nginx中配置限制了这个,还是自己知道的太少了!!!
解决方法:
1:配置中http部分 增加underscores_in_headers on; 配置 2:用减号-替代下划线符号_,避免这种变态问题。nginx默认忽略掉下划线可能有些原因。 引用:http://zhaoshijie.iteye.com/blog/2371440
Hibernate的SQLQuery查询SQL的时候报的异常:ORA-00911: 无效字符;
库是Oracle:
打印sql直接在plsql中执行是没问题的,但是在java代码中执行的时候就会报异常:ORA-00911: 无效字符;
其问题根源在SQL的最后结尾处的一个冒号";",应该去掉SQL最后的";",之后再重启就没问题了;
QStackedWidget 前言 QTackedWidget是一个堆栈窗口控件,可以填充一些小控件,但是同一时间只有一个小控件可以显示,QStackedWidget使用QStackedLayout布局。QSTackedWidget控件与QTabWidget类似,可以有效的显示窗口的控件
实例:QStackedWidget的使用 import sys from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * class StackedExample(QWidget): def __init__(self): super(StackedExample, self).__init__() #设置窗口初始位置和大小 self.setGeometry(300,50,10,10) self.setWindowTitle('StackedWidget 例子') #创建列表窗口,添加条目 self.leftlist=QListWidget() self.leftlist.insertItem(0,'联系方式') self.leftlist.insertItem(1,'个人信息') self.leftlist.insertItem(2,'教育程度') #创建三个小控件 self.stack1=QWidget() self.stack2=QWidget() self.stack3=QWidget() self.stack1UI() self.stack2UI() self.stack3UI() #在QStackedWidget对象中填充了三个子控件 self.stack=QStackedWidget(self) self.stack.addWidget(self.stack1) self.stack.addWidget(self.stack2) self.stack.addWidget(self.stack3) #水平布局,添加部件到布局中 HBox=QHBoxLayout() HBox.addWidget(self.leftlist) HBox.addWidget(self.stack) self.setLayout(HBox) self.leftlist.currentRowChanged.connect(self.display) def stack1UI(self): layout=QFormLayout() layout.addRow('姓名',QLineEdit()) layout.addRow('地址',QLineEdit()) self.stack1.setLayout(layout) def stack2UI(self): # zhu表单布局,次水平布局 layout = QFormLayout() sex = QHBoxLayout() # 水平布局添加单选按钮 sex.
问题描述:最近在上线新版本项目的时候,发现有的用户的操作还是调用的老版本JS里面的内容,这样就造成原来新的JS里面加上的限制不能限制用户的操作,从而导致用户可以重复操作。
问题产生原因:
如果在用户之前已经访问过系统,那么浏览器中会缓存该系统的CSS、JS,这些CSS、JS缓存未过期之前,浏览器只会从缓存中读取CSS和JS,如果在服务器上修改了css和js,那么这些修改在用户的浏览器中是不会有变化的。
解决方式一:
用户按Ctrl + F5强制刷新页面或者手动清空了浏览器的缓存。此时浏览器会重新向服务器获取CSS和JS文件,新的文件便会生效。
解决方式二:
但是用户量过大的时候总不能让每个用户一一清理缓存吧,于是便从代码的角度着手解决这个问题。在js后面添加版本号,让浏览器把这个JS文件当做新的文件重新向服务器获取资源。
加版本号前:
<script type="text/javascript" th:src="@{/js/test/index.js}"></script> 加版本号后:
<script type="text/javascript" th:src="@{/js/test/index.js?v=1.0}"></script> 此时问题解决,CSS与上类似。
问题延伸:
但是JS文件或CSS过多的情况下需要一个一个的去修改版本号,会花费大量的时间,此时就需要版本号是动态获取的了。
更换为从messages.properties中读取 <script type="text/javascript" th:src="@{/js/test/index.js(v=#{js.version})}"></script> 目录结构如下
messages.properties内容如下
js.version=2.0 注意:如果要读取到配置文件内容,配置文件名必须是messages.properties。否则会出现以下错误
下面是正常的
到此动态修改JS文件版本号结束。当然配置文件名也支持自定义,只需在application.yml文件中加入一下内容指定文件名
spring: messages: basename: test 此时可以将messages.properties文件更换为test.properties,指定文件名的时候也可以加上文件目录,不一定放在resources目录下,只是默认在这个目录下。
总结:
通过对JS的改动就可以使浏览器重新从服务器获取JS文件,虽然只是一个小的需求,但是减小了用户操作的麻烦以及JS不同步更新的问题。一个小小的细节,可以给我们带来很大的方便。
如今科学上网大都需要开启ipv6,设置的方法也多种多样,这儿记录配置ipv6的相关指令
相关命令 netsh interface teredo set state enterpriseclient server=default // 第一种:设置 Teredo服务器,默认为:win10.ipv6.microsoft.comnetsh interface teredo set state server=teredo.remlab.net //第二种:修改 Teredo 服务器为teredo.remlab.net
ping -6 ipv6.test-ipv6.com ping -6 [2001:470:1:18::125] //测试 IPv6 连接是否成功,两个命令效果一样
netsh interface ipv6 reset // 重置 IPv6 配置
netsh interface Teredo set state disable netsh interface Teredo set state type=default //卸载当前 Teredo 适配器再重新启用 以上命令中,1和2是平行操作,通常使用第一种就能配置成功;3为测试ipv6服务是否成功开启;如果1,2之后仍然不能成功,再尝试4,5操作重置服务之后再进行1或2。 注:操作4需要管理员权限,且重启后才能生效
参考资料 如何开启ipv6
1. 以前刚开始接触Java的时候发现Java中数组越界的问题真的是好难解决,有时候长一点的程序逻辑复杂一点就找不出错误了,现在时间久了之后发现数组越界中最常见的就是:一开始的时候定义了了数组的长度,由于某种原因导致在输出语句的时候或者赋值的时候超出了数组的最大长度
2. 当发生数组越界之后控制台会有提示的,...outofIndex...的错误,而且最重要的是它会提示出第几行,只要在出现错误的那行仔细分析看看是不是输出语句的时候或者赋值的时候超出了数组的最大长度,修改一下代码就可以了
先找到问题出在哪里
一.排查tomcat本身 停掉eclipse中的tomcat,打开tomcat的本地安装目录,bin文件夹下点击startup(手动直接启动),会跳出cmd窗口。有两种可能:
1.如果可以启动,即cmd窗口显示了完整的加载信息,可以看到最后一行为“信息: Server startup in xxxx ms”,不要关闭这个窗口,访问localhost,可以看到tomcat首页。这就说明环境配置和tomcat 软件本身是没问题的,问题出在eclipse中的配置,参看第二步;
2.若是点击startup出现cmd一闪而过,则说明tomcat本身有问题,(以下内容参考自这位同学:https://blog.csdn.net/stypace/article/details/38083581)
先用记事本打开startup.bat(或者鼠标右键,点编辑),找到最后一句话::end,我们知道end表示结束的意思,:end是一个标记,我们在后面加上一句pause(暂停等待的意思)
再次执行startup.bat,就会看到上图,当我们按任意的键时cmd窗口又是一闪而过了。但是这已经确定了我们的环境变量都是正确的。如果根本不停留,那就是环境配置不对,需要检查环境变量是否异常(具体请另行百度)。
为了更加详细的看到信息,我们再来更改一句:找到call "%EXECUTABLE%" start %CMD_LINE_ARGS% 把里面的start替换为run。
再来看看cmd窗口里面输出错误信息了,具体信息各有不同,像我就是因为之前有个项目部署在tomcat中时修改过server.xml中的host配置,导致每次启动都会去加载那个已经不存在的项目,自然不能正常启动了。也可以直接打开tomcat安装目录下的logs文件夹,查看catalina里面的日志信息,同样能找出异常原因。针对这些原因去修正你的配置(这些信息eclipse控制台一般是不显示的)。再次启动startup.bat会看到已经启动成功了(记得把之前修改的内容run、pause还原回去)。此时在访问localhost就不会报错了。
二.排查eclipse中的配置 关掉cmd,在eclipse中新建一个server,不要添加项目,直接启动,再访问localhost,如果依然是404,stop之后,双击Server窗口中的服务器,打开服务器属性窗口
Server Locations选择第二个选项Use Tomcat Installation
系统默认选择第一个选项;
第一个选项指的是将项目保存在workspace路径下;
第二个选项指的是将项目保存至tomcat安装目录下,我们一般选择这个,这样就不用再手动部署到tomcat文件下了;
第三个选项是自定义项目保存路径。
选择完毕之后,ctrl+s保存。再访问一下localhost就可以正常显示了。至此,tomcat的配置都正常了,添加需要部署的项目,如果negotiations正常访问就对了,如果还是不行,那就是项目本身配置有问题,需要检查项目本身了。
————————————————————————2020分割线—————————————————— 补充 最近因为项目原因更新了jdk,使用了jdk1.8,开发时用的一个专用IDE,它集成了web容器,所以很长时间没用tomacat。今天在tomcat下部署一个war包,启动时又是华丽丽的一闪而过……而且这次更坑,连错都不报了,startup.bat加pause也看不到情况,后来在call "%EXECUTABLE%" start %CMD_LINE_ARGS%这一行,改start为run,终于看到一点端倪:Error occurred during initialization of VM java/lang/NoClassDefFoundError: java/lang/Object——类的老祖宗找不到了!!! 这就是jdk环境问题了,先检查环境变量,cmd运行java -version,没问题;运行javac,不行,错误就是上面那些。看看路径配置是否正确(具体参考:https://blog.csdn.net/yzliang2016/article/details/77680601),我的路径配置是正确的,打开jdk下jre下bin,发现没有rt.jar。基础类库都在这个包里,没它自然不行,要补上。jdk1.8安装时有两个文件夹,C:\Program Files\Java下分为jdk与jre(jdk里面也有一个jre,与外面这个不一样),从jre中找到rt.jar,直接复制过来,cmd运行javac,不报错,但是一堆乱码(中文解释乱码)。这时启动tomcat,还是不行的。于是先将jdk/bin/jre下的bin重命名bin_old(保险),再将外面那个jre的整个bin复制过来,cmd运行javac,可以了。启动tomacat,也可以了。
应该还有一种解决方法,即修改环境变量中jre的路径为与jdk同级的那个jre,但是没有试过。
一、API php 接口开发 每个Controller需要继承BaseControllerBaseController里面包含了可使用的工具函数等 传入参数获取 使用$_REQUEST($user_id)获取user_id参数值 传入参数判断 是否为空: check_param_empty()检测API传入参数是否为空,传入有三种情况:(用empty()函数进行判断) 空【直接返回错误】字符串【用逗号分割字符串,然后逐个判断】数组【对数组的key进行判断是否为空(key为传入参数的名字,当然也可以直接判断数组每个key对应的value是否为空,但是对key进行获取$_REQUEST($key)的话会更有保证一些)】
-是否为set: check_param_isset(),检测API传入参数是否为集合:(用isset()函数进行判断)情况同“是否为空” 增删改查 where语句 统一使用数组形式,即:$where=array();然后添加每个条件;注意:如果sql语句中有alias设置别称,在\(where中一定也要加上,eg: ``\)where[‘u.id’] = “1”``;M函数
1.实例化一个没有模型文件的Model
2.项目中已经将DB_PREFIX参数设置为vc_,因此表名不需要加前缀,即:M('xm_farm_user_vegetable_link')alias: 可根据需要增加别名join: 连接其他表的话用join,一般都是使用left join,eg: join('left join vc_xm_farm_vegetable v on l.vegetable_id = v.id') field: 查找时一定要设定需要返回那些字段,一次返回所有字段是个坏的选择,同时要注意有alias的情况getField: getField一般用于查询一个字段的一条记录的情况;如果设置多个字段,返回的数组的下标会根据表的id设置,不会是数组默认下标0,1,2,… 分页 分页使用\Think\Page的构造函数完成注意:使用分页时,也需要将查询语句设定limit,即: limit($Page->firstRow.','.$Page->listRows)`` 步骤:
先获取总记录数,之后如果有left join没有关系,因为是根据左表来设置的,如果会有right join或者其他会改变总记录数的情况就需要视情况而定;创建Page对象: $Page = new \Think\Page($count,$_REQUEST['pagenum']); // 实例化分页类 传入总记录数 【tp框架的分页参数默认为20】 分页数据查询小程序可能会主动去获取分页结果显示【这个不清楚!!!】 返回值 构造合适的返回格式
最简单:直接将查出来的一个list返回,也就是一个一维数组:{[0]=>Array{} [1]=>Array{} …},每个元素的内容为一个数组;需要将每个list和同级返回其他字段,则使用foreach($list as $key=>$item){} 然后通过设定$result[$key][‘ziduan’] = $value; $result[$key][‘list’] = $item进行数组构建;其他的就是数组内部需要加入一些其他内容的情况,视情况而定即可。 其他 返回值规范化: return_format()展示trace信息、返回内容、返回内容json格式等开发时根据小程序的效果图以及小程序开发人员的沟通确定传入参数和返回数据内容以及数据格式开发完毕后需要添加或修改API Doc将返回的json在线规范格式copy进来即可 二、后台管理 php web开发 每个Controller直接继承Controller即可 开发步骤: 进入后台管理系统=>开发人员选项=>后台菜单列表=>添加菜单:设置上级、名称、url商户管理员=>角色设置=>编辑对应角色=>勾选对应功能代码=>Admin=>View里找到相似的功能页面复制创建新的Controller和View下的新文件夹,如果功能在某个Controller下面就不需要了新的Controller和View的html文件根据之前相似的功能进行复制更改然后登陆后台进行测试首先需要初始化工作:protected function _initialize()
1.Linux输出重定向
>: 会重写文件,如果文件里面有内容会覆盖。 >>这个是将输出内容追加到目标文件中。如果文件不存在,就创建文件。 >>:追加文件,也就是如果文件里面有内容会把新内容追加到文件 是定向输出到文件,如果文件不存在,就创建文件;如果文件存在,就将其清空。
2.exec命令 用于调用并行执行指令
3.tee命令 tee命令用于将数据重定向到文件,另一方面还可以提供一份重定向数据的副本作为后续命令的stdin。简单的说就是把数据重定向到给定文件和屏幕上。
-a:向文件中重定向时使用追加模式; -i:忽略中断(interrupt)信号。 4.set指令 set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。
参数说明:
-a 标示已修改的变量,以供输出至环境变量。 -b 使被中止的后台程序立刻回报执行状态。 -C 转向所产生的文件无法覆盖已存在的文件。 -d Shell预设会用杂凑表记忆使用过的指令,以加速指令的执行。使用-d参数可取消。 -e 若指令传回值不等于0,则立即退出shell。 -f 取消使用通配符。 -h 自动记录函数的所在位置。 -H Shell 可利用"!"加<指令编号>的方式来执行history中记录的指令。 -k 指令所给的参数都会被视为此指令的环境变量。 -l 记录for循环的变量名称。 -m 使用监视模式。 -n 只读取指令,而不实际执行。 -p 启动优先顺序模式。 -P 启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接。 -t 执行完随后的指令,即退出shell。 -u 当执行时使用到未定义过的变量,则显示错误信息。 -v 显示shell所读取的输入值。 -x 执行指令后,会先显示该指令及所下的参数。 +<参数> 取消某个set曾启动的参数。 5.Linux指令中if条件语句 每个if语句都要用fi结束,其应用格式如下:
if 条件 then Command1 [else Command2] #中括号表示else语句可以没有 fi #别忘了这个结尾 if语句忘了结尾fi,在运行时报错如下: test.sh: line xx: syntax error: unexpected end of fi Linux shell if 语法 基本语法: if [ command ]; then 符合该条件执行的语句 fi 2、扩展语法: if [ command ];then 符合该条件执行的语句 elif [ command ];then 符合该条件执行的语句 else 符合该条件执行的语句 fi
https://blog.csdn.net/wu_tongtong/article/details/79115921
1. private(私有) 表示私有,只有自己类能访问
2. default(默认)表示没有修饰符修饰,只有同一个包的类能访问
3. protected(受保护的)表示可以被同一个包的类以及其他包中的子类访问
Public(公共)表示可以被该项目的所有包中的所有类访问 这四个修饰符可以修饰属性和方法。
类的修饰符只有两个:public 和default
private(私有)调用:
例如:public class FengZhuang {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "FengZhuang [数字"+age+"]";
}
}
get set的使用先写出一对,然后自定义生成。还需要定义生成toString(创建完对象后,然后Syetem.out.println(创建的对象名);
输入时Set 输出是Get
例如: Book book2 = new Book();
book2.setBookName("大话西游");
System.out.println(book.getBookName());
1、权限不足 打开cmd时,应右键选择以管理员身份运行,如下图:
2、未切换到指定目录下【C:\Program Files\Python36\Scripts】 输入:
cd C:\Program Files\Python36\Scripts 然后再输入对应命令即可。
3、pip未更新 出现类似提示时:
输入下方命令进行更新即可
python -m install --upgrade pip
为什么需要适配 目前市面上设备屏幕属性十分多样化(宽度和DPR并不一致),而作为设计和前端开发,无法为每个尺寸的设备单独设计一套UI并将其转为前端代码,这不现实。所以我们需要一套方案来将一套设计稿完美呈现在不同尺寸的设备上。
设备的多样性不止体现在设备屏幕尺寸上,还有屏幕的DPR也不同,有1,有2,有3等等。不同DPR的设备展示的视图清晰度也不同,所以这套方案要考虑屏幕尺寸和屏幕清晰度这两个因素。
一些基本概念 一个屏幕的DPR是根据屏幕的物理像素除以屏幕的设备独立像素(也叫密度无关像素)得来的(DPR = 物理像素 / 设备独立像素)。iphone6宽度的设备独立像素是375,宽度的物理像素是750,那么就意味着DPR是2。这就意味着需要四个物理像素来描绘一个设备独立像素,就像一个田(请忽略边框)的形状。
设备独立像素又叫做密度无关像素,可以认为是系统中一个点,这个点可以是可以由程序使用的虚拟像素(如CSS的px),然后系统会将这个像素转换为物理像素,在屏幕的DPR为2的设备上CSS的1px就会转为4个物理像素。
屏幕密度(PPI),通常是计算每英寸有多少个像素(设备独立像素),计算公式是:屏幕斜对角的像素数除以屏幕的英寸得出PPI的值。
对一开始适配问题做出一定程度的解释 根据上面DPR解释可以知道在DPR为2的屏幕上会使用四个设备像素来描述一个CSS像素。在这种情况下一张100*100的图片在页面上的尺寸也是100*100那么其实是200*200个物理像素来描绘这张图片,很明显图片的像素是不够的,这时候系统就会让剩下的像素就近取色,这样就造成了图片的模糊,想要图片不模糊要么提供一个200*200的图片,要么将页面上100*100的容器缩小到50*50。
在DPR为2的屏幕上高度的1px其实是由2个物理像素描绘的,所以该屏幕可以描绘的最小像素应该是0.5px,所以这个1px应该是0.5px才对。
怎么做适配 既然提出了问题那么就需要解决,解决方案主要来自手淘的flexibleJS,其原理就是适配不同屏幕尺寸主要用到了rem,而适配不同的DPR主要用到了<meta name="viewport" content="initial-scale=1/dpr"/>
不同屏幕尺寸 在CSS中单位使用rem,那么只要修改html的font-size那么这个页面的尺寸都会随之等比例改变。例如:
首先我们知道设计稿宽度例如750px,其中有个100px的正方形
其次我们也知道当前运行代码的设备的屏幕宽度document.documentElement.clientWidth,这样就可以算出来在当前设备下这个正方形的宽高
通过观察上面设备下元素尺寸的计算公式 100px * document.documentElement.clientWidth / 750。可以简化成 设计稿元素尺寸 * 某个系数,可以联想到rem。这个单位后面的系数就是rem对应的font-size值。
所以在375屏幕尺寸下rem对应的font-size就是 375 / 750 等于 0.5px,0.5px * 100px 等于 50px。所以750下100单位在375设备下为50单位。
到这里我们得到公式 x = 元素在设计稿上的尺寸 * (设备宽度 / 设计稿宽度),其中 设备宽度 / 设计稿宽度是html的font-size值,也就是1rem。
但问题是浏览器有最小font-size的限制,目前算出来的1rem对于的font-size是0.5px,显然小于最小font-size的限制。
所以我们要将1rem对应的font-size搞大点,修改下公式:
x = (元素在设计稿上的尺寸 / 100) * ((设备宽度 / 设计稿宽度) * 100)
将1rem对应的font-size变大之后,要将其调整回来,需要对设计稿上的尺寸再缩小对应倍数。
到这里我们就完成了一份设计稿适配不同尺寸设备的方案。
<div class='container'> </div> <style> .
http://pan.baidu.com/s/1geVx2r5
47pe
今天打开eclipse突然发现有部分快捷键失效了,比如shift + enter , ctrl + d, ctrl +1 … 。但是还有部分的快捷键可以使用。很不方便,就从网上搜索解决办法,但是针对我自己的问题,好多办法都用不了,所以就自己摸索着最终把这个问题解决了。
记录一下自己整理的解决办法,以便以后再出问题可以使用。 从网上搜索大概有两到三种办法,再把我自己摸索的办法整理出来:(由简易到复杂排序)
解决办法 第一种 :很简单的一种方法,我的问题就是这么解决的,把eclipse 当前窗口打开的所以文件窗口全部关闭,重新打开一下就可以使用了,有时候问题解决就这么简单,就不需要再去使用第二种第三种了。
第二种:快捷键只有在Java 编辑模式下才可用,看一下自己的编辑模式是不是没有选Java , Window->Perspective->Open Perspective->Java 如果没有Java,选择Other,选择Java
第三种:前两种没有奏效的情况下,可以尝试重置一下快捷键: eclipse–> window –> preferences –> general –>keys –>Restore Defaults –> Apply and Close
第四种:前三种都不可以的话,那就要检查一下当前运行的软件是不是有快捷键冲突,冲突的话修改一下或者屏蔽掉。
第五种:这是从网上查到的一种方法,我自己也没有尝试,一般不要轻易尝试这种办法,因为这相当于是把eclipse重置了,还要很麻烦的重新去设置,最后真的没有办法了再去尝试。把 eclipse 的工作空间的.metadata文件夹删掉,然后需要自己重新配置。
如果大家出现了类似的问题,希望这篇博客能够帮助大家解决。
1、概述 Fork/Join Pool采用优良的设计、代码实现和硬件原子操作机制等多种思路保证其执行性能。其中包括(但不限于):计算资源共享、高性能队列、避免伪共享、工作窃取机制等。本文(以及后续文章)试图和读者一起分析JDK1.8中Fork/Join Pool的源代码实现,去理解Fork/Join Pool是怎样工作的。当然这里要说明一下,起初本人在决定阅读Fork/Join归并计算相关类的源代码时(ForkJoinPool、WorkQueue、ForkJoinTask、RecursiveTask、ForkJoinWorkerThread等),并不觉得这部分代码比起LinkedList这样的类来说有多少难度, 但其中大量使用位运算和位运算技巧,有大量Unsafe原子操作。博主能力有限,确实不能在短时间内将所有代码一一详细解读,所以也希望各位读者能帮助笔者一同完善。
2、要点 2-1. Fork/Join Pool实例化 实际上在之前文章中给出的Fork/Join Pool使用实例中,我们使用的new ForkJoinPool()或者new ForkJoinPool(N)这些方式来进行操作,这并不是ForkJoinPool作者Doug Lea推荐的使用方式。在ForkJoinPool主类的注释说明中,有这样一句话:
A static commonPool() is available and appropriate for most applications. The common pool is used by any ForkJoinTask that is not explicitly submitted to a specified pool.
Using the common pool normally reduces resource usage (its threads are slowly reclaimed during periods of non-use, and reinstated upon subsequent use).
以上描述大致的中文解释是:ForkJoinPools类有一个静态方法commonPool(),这个静态方法所获得的ForkJoinPools实例是由整个应用进程共享的,并且它适合绝大多数的应用系统场景。使用commonPool通常可以帮助应用程序中多种需要进行归并计算的任务共享计算资源,从而使后者发挥最大作用(ForkJoinPools中的工作线程在闲置时会被缓慢回收,并在随后需要使用时被恢复),而这种获取ForkJoinPools实例的方式,才是Doug Lea推荐的使用方式。代码如下:
...... ForkJoinPool commonPool = ForkJoinPool.
#include<stdio.h>
void main()
{
int i,j,k,a;
printf("请输入几行菱形:");
scanf("%d",&k); a=(k+1)/2; for(i=1;i<=a;i++)
{
for(j=1;j<=a-i;j++)
{
printf(" ");
}
for(j=1;j<=2*i-1;j++)
{
printf("*");
}
printf("\n"); }
for(i=k-a;i>=1;i--)
{
for(j=1;j<=a-i;j++)
{
printf(" ");
}
for(j=1;j<=2*i-1;j++)
{
printf("*");
}
printf("\n"); } }
我们在使用电脑时,系统经常会产生许多垃圾文件,占用磁盘存储空间。在Win10系统中,我们可以通过清理系统盘的临时文件来释放一些存储空间。下面好系统U盘启动就来告诉你具体的方法步骤。 Win10系统C盘清理临时文件的方法 1、在开始菜单中打开Windows设置,选择点击“系统”项。 2、在左侧栏中选择点击“存储”,在右侧栏中就可以看到电脑磁盘的存储情况了,我们选择点击C盘。 3、点击进入后,电脑会扫描该磁盘中的文件存储情况并进行分类,分类过后,我们选择点击“临时文件”。 4、在“临时文件”的设置中,系统会将其分类,我们可以根据每种文件的描述选择是否删除。选择勾选需要删除的文件后,点击上方的“删除文件”按钮即可进行删除,以此来释放磁盘空间。 以上就是Win10系统C盘存储空间不足清理临时文件的方法了,如果你的电脑C盘存储空间也不太够,不妨按照上面的方法来清理一下多余文件,释放一些存储空间。 文章转自好系统U盘启动: https://www.vkebao.com/jiaocheng/fCqtE1.html 来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31536622/viewspace-2199355/,如需转载,请注明出处,否则将追究法律责任。 转载于:http://blog.itpub.net/31536622/viewspace-2199355/
vim /app/tomcat/conf/server.xml #appBase 定义站点目录 #docBase 定义首页目录 ... <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="/app/tomcat/webapps/test" debug="0" reloadable="false" crossContext="true"/> ... </Host>
1.使用字符串切片 >>> def reverse1():
... s = input("please input a string: ")
... return s[::-1]
... >>> reverse1()
please input a string: yangyue!
'!euygnay'
2.使用递归 >>> def reverse2(s):
... if s == "":
... return s
... else:
... return reverse2(s[1:]) + s[0]
... >>> s = 'yangxinyue'
>>> reverse2(s)
'euynixgnay'
3.使用列表的reverse >>> def reverse3(s):
... l = list(s)
... l.reverse()
... print("".join(l))
... >>> reverse3('yangxinyue')
euynixgnay
今天下午用mfc对话框程序调用另一个mfc dll,这是问题出现了,程序正常运行,但是点击对话框上的按钮并不能调用DLL里面的资源,尝试了各种办法也无法解决,吃完晚饭后,沉下心来重头看代码,发现了这样一段MFC自动生成的注释:
//TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的, // 则从此 DLL 导出的任何调入 // MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到 // 该函数的最前面。 // // 例如: // // extern "C" BOOL PASCAL EXPORT ExportedFunction() // { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // 此处为普通函数体 // } // // 此宏先于任何 MFC 调用 // 出现在每个函数中十分重要。 这意味着 // 它必须作为函数中的第一个语句 // 出现,甚至先于所有对象变量声明, // 这是因为它们的构造函数可能生成 MFC // DLL 调用。 // // 有关其他详细信息, // 请参阅 MFC 技术说明 33 和 58。 于是在调用DLL的函数之前加上 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 之后,问题迎刃而解。
C语言中的输入、输出函数,在C++中一直使用cin、cout,对scanf和printf的使用不太熟悉,现做以下整理。
scanf()函数详解 函数名:scanf 功能:执行格式化输入 用法:int scanf(char *format,[argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘)读取输入的信息。可以读入任何固有类型的数据并自动把数值变换成适当的机内格式。 其调用格式为:scanf(“<格式化字符串>”,<地址表>); scanf()函数返回成功赋值的数据项数,出错时则返回EOF; 其控制串由三类字符构成: 1、格式化说明符 2、空白符 3、非空白符
格式化说明符 格式化字符说明%a读入一个浮点值(仅C99有效)%A同上%c读入一个字符%d读入十进制整数%i读入十进制,八进制,十六进制整数%o读入八进制整数%x读入十六进制整数%X同上%c读入一个字符%s读入一个字符串%f读入一个浮点数%F同上%e同上%E同上%g同上%G同上%p读入一个指针%u读入一个无符号十进制整数%n至此已读入值的等价字符数%[]扫描字符集合%%读%符号 附加格式说明字符表
修饰符说明L/l长度修饰符输入“长”数据h长度修饰符输入“短”数据W整型常数指定输入数据所占宽度*星号空读一个数据hh,ll同上h、l,但仅对C99有效 空白字符 空白字符会使scanf()函数在读操作中略去输入中的一个或多个空白字符,空白符可以是space,tab,newline等等,直到第一个非空白符出现为止。
非空白字符 一个非空白字符会使scanf()函数在读入时剔除掉与这个非空白字符相同的字符。
实例详解 问题一 例1:
#include "stdio.h" int main(void) { int a,b,c; scanf("%d,%d,%d",&a,&b,&c); printf("%d,%d,%d/n",a,b,c); return 0; } 运行时按如下方式输入三个值: 3□4□5 ↙(输入a,b,c的值) 3,4,5 (printf输出的a,b,c的值) (1) &a、&b、&c中的&是地址运算符,分别获得这三个变量的内存地址。 (2) “%d%d%d”是按十进值格式输入三个数值。输入时,在两个数据之间可以用一个或多个空格、tab键、回车键分隔。 以下是合法输入方式: ① 3□□4□□□□5↙ ② 3↙ 4□5↙ ③ 3(tab键)4↙ 5↙
例2
#include "stdio.h" int main(void) { int a,b,c; scanf("%d,%d,%d",&a,&b,&c); printf("%d,%d,%d/n",a,b,c); return 0; } 运行时按如下方式输入三个值: 3,4,5 ↙(输入a,b,c的值) 或者 3,□4,□5 ↙(输入a,b,c的值) 3,□□□4,□5 ↙(输入a,b,c的值) …… 都是合法的,但是”,”一定要跟在数字后面,如: 3□,4,□5 ↙就非法了,程序出错。(解决方法与原因后面讲) 再如: 1、sacnf()中的变量必须使用地址 int a, b; scanf("
前言: 为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。
1.简述 对于按键,常见的是通过MCU不断检测按键连接 GPIO 的状态变化(高–>低或低—>高),来确认是否有按键输入,这样的缺点很明显,MCU 一直在循环检测,对资源是一种浪费,不够高效。对于STM32,GPIO 是可以配置成中断的,有这个优势,我们就可以通过中断的方式来检测 GPIO 上电平的变化,进一步的得到按键的状态。
2.硬件电路 按键无上拉电阻,需要在 GPIO 上设为上拉状态,提供一个确定电平。
3.驱动实现 //按键初始化做了三件事 ///1.按键连接的GPIO初始化;2.中断配置初始化;3.中断优先级配置 void Key_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //GPIOA时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //复用功能时钟打开 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); //配置GPIO为中断引脚 EXTI_InitStructure.EXTI_Line = EXTI_Line15; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } //中断服务函数 void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line15) !
Y·S 2018年8月5日15:00:32
点击链接https://tug.org/texlive/ 注:Latex不止TeX这一种,这里只给出了TeX的安装,如果想尝试别的软件的同学可以自行寻找其他教程。
并执行如下操作:
第一步
第二步
第三步
第四步
第五步
装载下载好了的Tex Live安装包:
分以下几种情况:
1.win10系统:右键下载好的ISO文件,点击打开方式—>windows资源管理器 即可。
2.其他windows系统:自行安装虚拟光驱软件并装载。
3.Ubuntu等linux系统:
sudo mkdir /media/iso
sudo mount your-iso-file.iso /media/iso/ -t iso9660 -o loop
4.Mac系统:自行安装Disk Utility。
5.其他系统:不知道。
第六步
耐心等待他的配置,中途可能会跳出一个警告,点击continue无视就好。
第七步
安装路径按照自己喜好设置。
安装内容,有许多不必要的语言包,自行选择处理,数学专业的论文大都只要英语和中文即可(大神除外),德语法语等语言大可不必(你一定要装也行)。
第八步
静静地看着它装完。
第九步
检查一下安装是否成功,验证方式如下:
同时按下键盘上的win+R两个键(不知道什么是win键的去百度查一下)
随后出现“运行”窗口
输入“cmd”,然后按下回车。
在弹出来的命令提示符中,输入“tex -v”,然后按下回车。
这里会显示已安装的tex的版本号等信息
同理,如果输入”latex -v”,则会输出latex的版本信息:
类似的,还有“xelatex -v”:
如果这些版本信息正常输出,说明TeX Live的安装完全正常。
第十步
点击http://texstudio.sourceforge.net/ ,下载图形化界面。
下载完成之后,就是一路傻瓜式安装。
最后,打开安装好的TeXstudio。
至此,安装过程完毕。
问题描述: 在公司项目中,采用了双机部署,负载均衡方式采用iphash
upstream xxxx { ip_hash; server 192.168.241.1:8080; #服务器A server 192.168.241.1:8010; #服务器B } 在测试阶段,有一定几率产生,正常操作确存在退出登录界面的问题。 最开始分析是,网络问题,登录请求刚开始转发到服务器A,服务器A有session,其他的请求转发到服务器B,服务器B没有session导致退出系统。分析nginx日志,确没有发现这样的问题,我很是疑惑。。
但是却发现nginx日志中有这样的情况
192.168.241.1:8080, 192.168.241.1:8010 | 0.202, 0.302 | 500, 500 || "GET /client-web/pages/stbManager/initStb.do HTTP/1.1" 500 请求client-web/pages/stbManager/initStb.do,同时转发到两个服务器,这就很奇怪。。而且这种情况大部分是发生500 404 等错误才会发生的,而且紧接着就会有这样的日志
192.168.241.1:8010 | 0.014 | 200 || "GET /client-web/pages/manage/login/sysOut.do HTTP/1.1" 200 也就是服务器B(8010)会退出系统,这很好理解,用户在服务器A登录,请求转发到B上,B系统没有session发生退出,很正常。但是服务器A上的那个用户为什么会退出?还有为什么会发生一个请求转发到两个地址?
一个请求转发到两个地址 进过分析公司的nginx日志发现有这样的配置
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404; 意思就是如果发生超时,500 503 404 等错误会转到其他的服务器上。这个也就是nginx的重试机制。
服务器A的用户退出的原因 通过调试程序发现,用户A的请求中有sessionid,当这个请求转发到服务器B上,服务器将这个请求跳转到登录界面,所以用户A会跳转到登录界面的原因。
解决问题 谨慎使用重试机制,这回造成很多问题。将重试机制注销掉。
Redis 脚本功能可以自定义新的命令,并且也是原子执行。 本篇和上一篇是相对应的。
一、简单介绍下脚本: redis2.6推出脚本功能,允许开发者使用 Lua语言编写脚本传到Redis中执行,在Lua脚本中可以调用大部分redis命令。
使用脚本优点: 减少网络开销:执行一次脚本只需要发送一次请求,减少网络往返时延。如果不使用脚本,可能多个命令要发送多个请求,还会出现竞态情况。原子操作:Redis会将脚本作为一个整体执行,中间不会被其他事务插入。编写脚本过程中无须考虑竞态条件,也无须使用事务。事务可以完成的所有功能都可以通过脚本实现。复用:客户端发送的脚本会永久存储在Redis 中,意味着其他客户端可以复用这段脚本。 二、使用脚本实现访问频率限制, 方案一: Lua代码如下: -- Lua 使用 redis.call()调用redis命令 local times = redis.call('incr', KEYS[1]) if times == 1 then -- KEYS[1] 键刚刚创建,所以为其设置生存时间 redis.call('expire', KEYS[1], ARGV[1]) end if times > tonumber(ARGV[2]) then -- ARGV[2]为字符串,需要转为number return 0 end return 1 执行脚本: $ redis-cli –eval /path/to/ratelimiting.lua rate.limiting:127.0.0.1 , 10 3
参数说明: –eval:告诉redis-cli 读取并运行后面的Lua脚本。 /path/to/ratelimiting.lua : 文件位置 rate.limiting:userId 要操作的key,在脚本中用 KEYS[1]获取 10 3 :两个参数,在脚本中用 ARGV[1]和ARGV[2] 获取 注意:”,” 两边的空格不能省。
在网上搜了半天也没介绍flask-security汉化方法,于是查看源代码,发现里面是支持Babellex翻译,于是Git源代码,自己增加了中文简体的翻译文件,并提交到作者,不过还没审核通过,详见如何参与Github上的开源项目Flask-security语言翻译
由于需要在项目中使用,等到作者合并到项目中并发布,不知道什么时候,于是就自己编译之后放到项目中,记录一下方法给小伙伴参考。
编译好的语言包:https://download.csdn.net/download/gh254172840/10582647
接上面文章,将项目编译,生成mo文件,此时注意编译的文件如果是messages.po,messages.mo,请将他们改为flask_security.po,flask_security.mo,不然flask_security会检测不到
pybabel compile -d flask_security/translations/ 现在需要把zh_Hans_CN整个文件夹复制到flask_security/translations/,即可。
注意不要更改文件名,不然会检测不到
接着请安装Flask-BabelEx
pip install Flask-BabelEx 配置BabelEx,这个在官方教程没写,可以参考flask-admin如何汉化。
# 初始化flask_babelex from flask import app from flask_babelex import Babel app = Flask(__name__) babel = Babel(app) # 创建一个本地选择器: @babel.localeselector def get_locale(): if request.args.get('lang'): session['lang'] = request.args.get('lang') return session.get('lang', 'zh_CN') 重启服务,你就可以看到汉化效果了
效果如下:
Good Lucky!
Detailed Description QOpenGLWidget类是用于渲染OpenGL图形。
除了可以选择使用QPainter和标准的OpenGL渲染图形,QOpenGLWidget类提供了在Qt应用程序中显示OpenGL图形的功能。它使用起来非常简单:新建类继承于QOpenGLWidget,使用方法就像继承于QWidget类子类一样。
QOpenGLWidget类提供了三个方便的虚函数,可以在新建的子类中重新实现以完成OpenGL的任务: paintGL()—渲染OpenGL场景,需要更新Widget时就会调用。resizeGL()—设置OpenGL视口,投影等。每当调整Widget的大小时(第一次显示窗口Widget时会调用它,因为所有新创建Widget都会自动获得调整大小的事件)。initializeGL()—建立OpenGL的资源和状态。在第一次调用resizeGL()或paintGL()之前调用一次。 如果需要从paintGL()以外的地方触发重绘(一个典型的例子是使用定时器为场景设置动画),应该调用widget的update()函数来进行更新。
当调用paintGL(),resizeGL()或initializeGL()时,Widget的OpenGL渲染环境需要设为当前。如果需要从其他位置调用标准OpenGL API函数(例如,Widget的构造函数或自己的绘图函数中),则必须首先调用makeCurrent()。
所有渲染都发生在OpenGL帧缓冲对象中,makeCurrent()确保它在渲染环境中,在paintGL()中的渲染代码中创建和绑定其他帧缓冲对象时,不要使用ID 0重新绑定帧缓冲区,而是调用defaultFramebufferObject()来获取应该绑定的ID。
QOpenGLWidget允许在平台支持时使用不同的OpenGL版本和配置文件。只需通过setFormat()设置请求的格式。但在同一窗口中有多个QOpenGLWidget,要求它们都使用相同的格式,或者至少不是环境共享的格式。要解决此问题,使用QSurfaceFormat :: setDefaultFormat(),而不是setFormat()。
注意:在请求OpenGL核心配置文件上下文时,在构造QApplication实例之前调用QSurfaceFormat :: setDefaultFormat()在某些平台(例如,macOS)上是必需的。这是为了确保上下文之间的资源共享保持功能,因为所有内部上下文都是使用正确的版本和配置文件创建的。
OpenGL Function Calls, Headers and QOpenGLFunctions 在进行OpenGL函数调用时,强烈建议避免直接调用函数。相反,更喜欢使用QOpenGLFunctions(在制作可移植应用程序时)或版本化变体(例如,QOpenGLFunctions_3_2_Core等,当针对现代的,仅限桌面的OpenGL时)。这样,应用程序将在所有Qt构建配置中正常工作,包括执行动态OpenGL实现加载的应用程序,这意味着应用程序不直接链接到GL实现,因此直接函数调用是不可行的。
在paintGL()中,当前场景(context)始终可以通过调用QOpenGLContext :: currentContext()来访问。从这个context中,可以通过调用QOpenGLContext :: functions()来检索已经初始化的,准备好使用的QOpenGLFunctions实例。为每个GL调用添加前缀的替代方法是从QOpenGLFunctions继承并在initializeGL()中调用QOpenGLFunctions :: initializeOpenGLFunctions()。
至于OpenGL标题,请注意,在大多数情况下,不需要直接包含任何标题,如GL.h.与OpenGL相关的Qt头文件将包含qopengl.h,后者将包含适用于系统的标头。这可能是OpenGL ES 3.x或2.0标头,可用的最高版本,或系统提供的gl.h.此外,作为OpenGL和OpenGL ES的Qt的一部分,提供了扩展头的副本(在某些系统上称为glext.h)。这些将在可行的情况下自动包含在平台上。这意味着来自ARB,EXT,OES扩展的常量和函数指针typedef自动可用。
Code Examples 最简单的例子
class MyGLWidget : public QOpenGLWidget { public: MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } protected: void initializeGL() { // Set up the rendering context, load shaders and other resources, etc.: QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.
关于代码块 代码块有两种,静态代码块,和普通代码块。
静态代码块属于类级别的,加载的时候执行,普通代码块属于对象级别,创建对象的时候执行。而且普通代码块优先于构造函数执行。
package mytest.Proxy.reflect;
public class Main {
public static void main(String[] args) throws InterruptedException {
//System.out.println(ZYP.name+":");
for(int i=0;i<2;i++){
Thread.currentThread().sleep(100);
System.out.println("\t第"+i+"次睡眠。");
}
ZYP zyp = new ZYP();
ZYP zyp1 = new ZYP();
ZYP zyp2 = new ZYP();
}
}
class ZYP {
static String name="zsc";
static{
System.out.println("静态代码块");
}
{
System.out.println("普通代码块");
}
public ZYP(){
System.out.println("构造方法");
}
}
解释:静态代码块属于类级别的,普通代码块数据属于对象级别的。在程序运行的过程中说明了一下几点。
程序启动时并不加载全部文件,在用到时就会去加载文件。加载完数据就会形成类的类对象存入内存。因为静态代码属于类级别,所以在加载的时候会执行静态代码块的代码。(新体会:Java程序之所以封装在函数里面就是要触发或着调用这个方法,然后这个触发的代码。而在代码块中的代码无需触发,就会在动执行。)在新创建实例的时候并不会再次加载文件,而是通过已经存在的类的类对象创建对象。(反射思考:在通过反射实现对象的时候,会根据类的路径先去找这个类的类对象,如果找到就通过类的类对象直接实例化一个对象,找不带就去加载文件,先有类的类对象,再通过这个类类对象创建类实例返回)。 资料: 要想理解反射的原理,首先要了解什么是类型信息。Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。
理解RTTI在Java中的工作原理,首先需要知道类型信息在运行时是如何表示的,这是由Class对象来完成的,它包含了与类有关的信息。Class对象就是用来创建所有“常规”对象的,Java使用Class对象来执行RTTI,即使你正在执行的是类似类型转换这样的操作。
每个类都会产生一个对应的Class对象,也就是保存在.class文件。所有类都是在对其第一次使用时,动态加载到JVM的,当程序创建一个对类的静态成员的引用时,就会加载这个类。Class对象(类的class文件)仅在需要的时候才会加载,static初始化是在类加载时进行的。
创建对象的过程:
类加载器首先会检查这个类的Class对象是否已被加载过,如果尚未加载,默认的类加载器就会根据类名查找对应的.class文件。
想在运行时使用类型信息(使用类信息干什么?创建对象,调用静态方法,参数等),必须获取对象(比如类Base对象)的Class对象的引用,使用功能Class.forName(“ZYP”)可以实现该目的,或者使用ZYP.class。注意,有一点很有趣,使用功能”.class”来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象。(初始化class对象是指,目前我知道的是执行静态代码块这种东西)。
为了使用类而做的准备工作一般有以下3个步骤:
加载:由类加载器完成,找到对应的字节码,创建一个Class对象链接:验证类中的字节码,为静态域分配空间初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块 Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员。这样的话就可以使用Contructor创建新的对象,用get()和set()方法获取和修改类中与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFields()、getMethods()和getConstructors()等许多便利的方法,以返回表示字段、方法、以及构造器对象的数组,这样,对象信息可以在运行时被完全确定下来,而在编译时不需要知道关于类的任何事情。
title:{ //1.标题居中 //left的值为'left', 'center', 'right' left:'center', //默认为10 //2.主副标题之间的间距 itemGap:20, 3.标题文本样式 text:'标题文本', textStyle:{ //文字颜色 color:'#ccc', //字体风格,'normal','italic','oblique' fontStyle:'normal', //字体粗细 'normal','bold','bolder','lighter',100 | 200 | 300 | 400... fontWeight:'bold', //字体系列 fontFamily:'sans-serif', //字体大小 fontSize:18 } //4.副标题 subtext:'副标题', //副标题文本样式 subtextStyle:{}, //5.grid组件离容器左侧的距离。 // left 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比,也 可以是 'left', 'center', 'right'。 //如果 left 的值为'left', 'center', 'right',组件会根据相应的位置自动对齐。 left:'center' }
旧版本的Qt中,模块OpenGL提供了QGL开头类,不提倡使用,只是为了兼容低版本的Qt。新版本的Qt中,有两种方式: 1、Qt的GUI模块中的QOpenGL开头的类。 2、Qt的Widget模块中的QOpenGLWidget类。
每次项目同步到git码云之后,都会好长一段时间不再新上传项目,长时间不使用导致每次项目在新上传时都会记不住使用步骤。在此记下,以作笔记。
Android studio 与 webstorm 等的操作步骤相同
在此以react native 项目为例。
首先在命令行进入项目的目录 执行 react-native init Test 生成项目Test
webstorm打开项目
登陆到码云 新建项目Test
在webstorm的TEST项目中添加版本管理
选中需要上传的项目
ADD操作
在webstorm中右击项目 选中 git —> add
添加成功之后,项目中的字体颜色变成绿色
commit 操作
右击项目 git —> commit directory 提交添加的文件
填写commit message 然后点击commit 提交
pull操作
提交之后 右击项目 选中 git —> repository —> push 将项目push上去
登陆码云 选择新建的Test项目 克隆/下载 选项 复制git地址
点击上图的 define remote 在弹框中填入复制的连接
点击ok
push提交代码。
按照正常的情况一般都是push失败的
不用问为什么,我也不知道,反正先不管它了,失败就失败吧!后面有办法解决
提交之后 右击项目 选中 git —> repository —> pull将服务器上的文件更新到本地
其实也不算坑,只是自己没注意看官网api,定义module另外命名时,需要在module中加一个命名空间namespaced: true
属性,否则命名无法暴露出来,导致报[vuex] module namespace not found in mapState()等错误。
是否有多维子材质:多维子材质材质测试,三个子材质,50个物体,使用多维自材质12帧,330个dc,343面。拆开之后20帧,154dc,134面。多维子材质Unity无法动态合并。叠加模式贴图,可以不用Alpha通道特效粒子贴图是否合并是否有些粒子能使用序列帧,不过和视角有关,去掉alpha贴图合并动画boneweight,没有特殊需求的情况下受两根骨骼影响就够了。 资源不需要animation的在Rig里选择none而不是默认的legacy否则会自动生成animator 动画的更新可以设置Culling
Mode:剔除模式:Always Animate表示即使摄像机看不见也要进行动画播放的更新,Cull Update
Transform表示摄像机看不见时停止动画播放但是位置会继续更新,Cull Completely表示摄像机看不见时停止动画的所有更新。 模型,贴图和动画不要勾选Read/Write这样会在内存中再开辟一份做更新。 贴图不需要Lightmap的例如角色不能勾生成Lightmap的UV。 模型文件通常是勾压缩的而且是high,如果满足不了再降低或者关闭【实际测试高会有些问题,中还不错,看情况】。 材质是游戏内添加的所以这个勾不需要勾。 这个选项是做表情动画的一般也不需要勾。 不需要mipmap的贴图不能勾生成Mipmap。Mipmap旨在有效降低渲染带宽的压力,提升游戏的渲染效率。但是,开启Mipmap会将纹理内存提升1.33倍。对于具有较大纵深感的3D游戏来说,3D场景模型和角色我们一般是建议开启Mipmap功能的,但是UI或者俯视角的游戏开启Mipmap并不会提升渲染效率,反倒会增加无谓的内存占用。 法线的计算方式,不需要Normal的时候选none。如果不使用发现勾了发现本身就会浪费不必要的内存,更严重的是如果项目对Mesh进行Draw
Call Batching操作的话,合并后的大mesh将也带Normal信息造成极大浪费,特别如果合并的Mesh中只要有一个带了Normal那么合并所有的顶点都会带Normal,Color,Tangent。 如果动作不使用挂点可以勾Optimize【挂点这种判断不出是否有用的点可能会被优化掉】。 美术场景等不需要动画的Rig的AnimationType应该是none 美术资源,贴图格式最好设置成ETC2美术资源,部分Generic和Humanoid可以Optimize Game
Objects 界面拾取问题:去掉接受按键消息的勾美术资源,字体文件设置成Dynamic,字体贴图在用的时候才会渲染。这部分内存没被Unity统计,所以设置成静态的也看不到。 美术资源,静态资源都勾上Static。美术资源,GraphicSetting里如果不用系统的Shader,把这些Shader设置成no,减小一点包大小。 Shader可以设置预加载防止游戏内卡顿【实际遇到过】。 关闭不使用的Shader,减少包体大小。美术资源,如果一些贴图的Alpha通道压缩效果不好,增加一些白噪声。美术资源:面数控制在5w面以内,才能保证低配安卓设备流畅
vs2010中,有些项目上的功能是要生产库文件给其他项目调用的,以下是一些设置库文件(x.dll和x.lib)输出路径的方法.
设置x.dll 输出路径方法是在右键项目的"属性"->连接器->常规, 然后在常规属性界面中的 "输出文件" 中填入自己想要x.dll文件的输出路径.
设置x.lib 输出路径方法是在右键项目的"属性"->连接器->高级, 然后在高级属性界面中的 "导入库" 项中填入自己想要x.dll文件的输出路径.
但是在设置x.lib的输出路径时,发现如果你输入的路径中有某个文件夹不存在,那么文件会生成失败,并且提示无法链接到导入库项路径中的lib库.
解决这个问题的方法是保证你设置的路径上每个文件夹都是存在的。如果不存在,就手动创建。
经过测试发现设置x.dll的路径时,如果输入的路径中即使有某个文件夹不存在,编译器会自动给我们生成,并不会出现x.lib设置的情况。
顺便记录一下项目需要我们自己设置的其他路径:
包含头文件路径设置:属性->C++->常规界面 中的 “附加包含目录”
有些项目需要包含一些其他x.dll和x.lib库的路径设置:
包含x.dll库路径设置: 未实际尝试,尝试有用后会添加上来。 另外x.dll文件放到编译好的新工程的 debug 目录下, 新程序就可以调用.dll文件
包含x.lib库路径设置: 属性-》连接器 -》常规 -》 附加库目录 选项中填入包含x.lib库的路径.
包含指定要添加到链接行的附加项lib库: 属性-》连接器 -》输入 -》 附加依赖项 选项中填入需要包含的x.dll完整文件路径.
相对路径的起点为xxx.vcxproj 文件所在的目录
在一个客户项目中,对客户来说一些没必要的字段,需要隐藏。
而使用flask-admin构建后台时,它的CRUD模型的编辑和创建都是根据Model设置的。
于是我使用form_create_rules和form_edit_rules来进行选择编辑,但是Debug命令行会总是发出警告:UserWarning: Fields missing from ruleset................,于是上网搜了一下,发现大家都是选择忽略警告,不满意。终于在flask-admin的api文档中找个一个字段可以通用完成这个功能,又不需要涉及Field rules,显示效果是一样的,完美。。
代码如下:
class PostView(AdminModelView): """View function of Flask-Admin for Post create/edit Page includedin Models page""" # show columns in edit or create page form_columns = ('title', 'text',) 看一下效果:
没设置之前:
设置之后
由于有些字段都是用来做过滤用的,客户编辑并不需要,这样看起来清爽很多,而且不会出现csrf_token的警告。
自己备注一下,发现一个小功能:可以设置字段为只读模式,这个也不错
# If you want to make them not editable in form view: use this piece: form_widget_args = { 'title': { 'readonly': True }, } Good Lucky~
Java垃圾回收机制 为什么要进行垃圾回收? 随着程序的运行,内存中存在的实例对象、变量等信息占据的内存越来越多,如果不及时进行垃圾回收,必然会带来程序性能的下降,甚至会因为可用内存不足造成一些不必要的系统异常。
哪些“垃圾”需要回收? 如果某个对象已经不存在任何引用,那么它可以被回收。
什么时候进行垃圾回收? 引用计数算法 每个对象添加一个引用计数器,每被引用一次,计数器加1,失去引用,计数器减1,当计数器在一段时间内保持为0时,该对象就认为是可以被回收得了。(在JDK1.2之前,使用的是该算法)
缺点:当两个对象A、B相互引用的时候,当其他所有的引用都消失之后,A和B还有一个相互引用,此时计数器各为1,而实际上这两个对象都已经没有额外的引用了,已经是垃圾了。但是却不会被回收
可达性分析算法 该算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点
目前java 中可作为GC Root 的对象有:
虚拟机栈中引用的对象(本地变量表)方法区中静态属性引用的对象方法区中常量引用的对象本地方法栈中引用的对象(Native Object) 引用的分类 JDK 1.2之后,对引用进行了扩充,引入了强、软、若、虚四种引用,被标记为这四种引用的对象,在GC时分别有不同的意义:
强引用(Strong Reference) 就是为刚被new出来的对象所加的引用,它的特点就是,永远不会被GC,除非显示的设置null,才会GC。代码如下:
Object ojb = new Object();
软引用(Soft Reference) 非必须引用,内存溢出之前进行回收。如果JVM内存并不紧张,这类对象可以不被回收,如果内存紧张,则会被回收。此处有一个问题,既然被引用为软引用的对象可以回收,为什么不去回收呢?其实我们知道,Java中是存在缓存机制的,就拿字面量缓存来说,有些时候,缓存的对象就是当前可有可无的,只是留在内存中如果还有需要,则不需要重新分配内存即可使用,因此,这些对象即可被引用为软引用,方便使用,提高程序性能。代码如下:
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj =null;
sf.get();//有时候会返回null
这时候sf是对obj的一个软引用,通过sf.get()方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回null;
弱引用(Weak Reference) 第二次垃圾回收时回收。代码如下:
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj =null;
wf.get();//有时候会返回null
wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾
弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。
弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器
虚引用(Phantom Reference) 垃圾回收时回收,无法通过引用取到对象值。代码如下
1. 我在使用xshell6连接到服务器上面发生了连接失败的问题
2. 仔细分析了一下,可能存在的原因有:
① 在虚拟机上没有连上网
所以首先要保证要连接上网
② 没有开启SSHD服务可以通过系统->服务来查看是否启动了该服务,可以在命令行中输入service sshd status命令来查看该服务的状态
③在网上搜索了一下,可能是防火墙的问题(要关闭掉防火墙)
可以使用命令设置防火墙:
a. 永久性生效
开启:chkconfig iptables on
关闭:chkconfig iptables off
b. 即时生效,重启后失效
开启:service iptables start
关闭:service iptables stop
3. 保证在前面三项都设置好的话,我先在xshell6上尝试连接上服务器,但是连接还是失败,在从网上查找了资料,在xshell6上看看能不能ping通虚拟机的ip地址,发现ping不通,打开控制面板发现在自己虚拟机上设置的NAT模式的网卡的ip地址所在的网段与虚拟机上的不一致
而且没有开启DHCP功能,所以进入虚拟机进行设置,回想起来是因为自己在修改DHCP的网段的时候没有确定,导致没有开启DHCP的服务,连接就失败了,重修修改确定之后再次进入控制面板可以发现Vmware8网卡已经开启了DHCP服务,ip地址与主机的ip地址也在同一个网段
4. 在xshell6上连接Linux服务器就可以连接上了
1.进入火狐配置页进行设置 2.点击”我了解此风险”后进入页面 3.搜索”security.fileuri.strict_origin_policy”,并设置该项为false 4.重启浏览器,可以跨域访问
intellij idea 使用Tomcat部署javaweb项目后到Tomcat的webapps目录下找不到项目.
首先看下部署项目后webapps的目录
首先说明怎么找到已经部署好的项目,再来解释原因.
2.1 首先点击项目,右键点击Show in Explorer.
2.2 这里的项目没有使用maven,所以输出目录是out,如果是maven则是target目录中,还有可能是idea版本的问题,所以名称不同,但是都是属于输出目录.18年的文章…
2.3
2.4
此时部署的web项目已经找到.intellij idea使用Tomcat部署项目后并不会把编译后的项目复制到tomcat的webapps目录下,但是它会把编译好的项目路径告诉Tomcat,让Tomcat来找到这个项目,其它的项目比如Tomcat的主页项目ROOT是打不开的,因为intellij idea 只让Tomcat运行了一个项目.
接下来看一下war包的目录结构,也就是整个web项目编译后的目录结构
4.tomcat有4中部署方式,eclipse的部署方式与IntelliJ idea的部署方式不同. tomcat部署方式分别是:
(1)利用Tomcat自动部署
项目放到webapps目录下,启动tomcat,就回自动部署
(2)利用控制台进行部署
控制台不是说cmd,而是tomcat启动后进入root页面,有个manager管理部署项目.
进入tomcat的manager控制台的deploy区域进行设置就可以部署
上面这两种都是自己用的,就是平时别人发包过来,然后丢进去,启动tomcat就部署,但是开发工具没有用上面两种.
platform-zwml-admin这个是我的项目名称
下面的在IntelliJ idea中使用
(3)增加自定义的Web部署文件(%Tomcat_Home%\conf\Catalina\localhost\platform-zwml-admin.xml)
下面一种都在eclipse中使用
(4)修改%Tomcat_Home%\conf\server.xml文件来部署web应用
所以web项目不是必须放在webapps文件夹里面才能部署的,放在其它位置为也可以部署,
eclipse默认放在工作空间的.metadata文件夹,可以修改到其它地方,一般配置在webapps文件夹.
而idea是配置到out文件夹,就是输出目录.
如下使用ip命令创建一个bond接口不指定参数:
/ # ip link add bond1 type bond
指定bond接口的mode:
/ # ip link add bond2 type bond mode balance-xor
查看新创建的bond接口,bond1未指定mode,其默认为balance-rr模式:
/ # ip -detail link show type bond
24: bond1: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 8a:88:46:0f:8c:61 brd ff:ff:ff:ff:ff:ff promiscuity 0
bond mode balance-rr miimon 0 updelay 0 downdelay 0 use_carrier 1 arp_interval 0 arp_validate none arp_all_targets any primary_reselect always fail_over_mac none xmit_hash_policy layer2 resend_igmp 1 num_grat_arp 1 all_slaves_active 0 min_links 0 lp_interval 1 packets_per_slave 1 lacp_rate slow ad_select stable tlb_dynamic_lb 1 addrgenmode eui64 numtxqueues 16 numrxqueues 16
一、ARM体系结构概述 内容概述: 必须要get到的ARM知识
Cortex-M0处理器介绍
认识STM32
STM32F0硬件平台介绍
必须要get到的ARM知识: STM32的核心部件CPU是Cortex-M 系列处理器
ARM处理器家族:
早先经典处理器 包括ARM7、ARM9、ARM11家族。 Cortex-M 系列 为单片机驱动的系统提供的低成本优化方案,应用于传统 的微控制器市场,智能传感器,汽车周边部件等。
Cortex-A 系列 针对开放式操作系统的高性能处理器; 应用于智能手机,数字电视,智能等高端运用。 Cortex-R 系列 针对实时系统、满足实时性的控制需求; 应于汽车制动系统,动力系统等。
ARM处理器架构:
概念:体系结构定义指令集和基于这一体系结构下处理器的 编程模型(基本数据类型、工作模型、寄存器组)。基于同种体系结构可以有多种处理器、每个处理器的性能不同,面向的应用领域也不同。
ARM体系结构发展:
目前ARM体系架构共定义了8个版本V1-V8
V1-V3 最早的版本,目前已废弃
V4-V6 经典处理器中运用的比较多
V7 目前Cortex系列处理器主要是这种架构、支持Thumb-2的32位指令集
V8 兼容ARMv7架构的特性,并支持64位数据处理
ARM指令集:
指令集的概念:处理器能够识别并执行的指令集合;每一条指令可处理一个简单或复杂操作(加、加乘…);每一条指令对应一条或几条汇编指令。
指令集常见分类:
复杂指令集(CISC):包含处理复杂操作的特定指令,指令长度不固定,执行需要多个周期。
精简指令集(RISC):指令简单而有效,格式和长度通常是固定的,大多数指令在一个周期内可以执行完毕,ARM的内核是基于RISC体系结构的
SOC的概念:
SOC(片上系统)指的是在单个芯片上集成一个完整的计算机系统,所谓完整的系统一般包括中央处理器(CPU)、存储器、以及外围电路等。
Cortex-M0处理器介绍 主要内容:
Cortex-M0处理器简介
Cortex-M0体系结构
Cortex-M0异常和中断
Cortex-M0指令集
Cortex-M0处理器简介:
Cortex-M 系列产品主要包括 Cortex-M0、Cortex-M1、Cortex-M3、Cortex-M4、Cortex-M7 等,其中 Cortex-M0 主打低功耗和混合信号的处理,M3 主要用来替代 ARM7,重点侧重能耗与性能的平衡,而 M7 则重点放在高性能控制运算领域。
注:STM32F051微控制器内核就是ARM Cortex-M0
Cortex-M0结构框图:
Cortex-M0 微处理器主要包括处理器内核、嵌套向量中断控制器(NVIC)、调试子系统、内部总线系统构成。Cortex-M0 微处理器通过精简的高性能总线(AHB-LITE)与外部进行通信。
Cortex-M0特性:
Thumb 指令集,高效、高代码密度;
后台运行命令 如何后台运行python程序。
关键的命令:nohup
只需要输入下面的命令就可以在后台一直执行python程序啦
nohup python -u test.py > test.log 2>&1 & 这条命令的意思是,执行test.py程序,并把程序中执行的情况记录到test.log文件中,包括程序异常、程序中打印的信息等。 -u选项表示每多一条信息就实时输出到log.out中,而不是全部输出完毕再输出 &符号表示在后台执行,运行时可以查看日志或者运行 PS: 也可以把上述命令写成nohup python -u test.py > nohup.out 2>&1 &唯一的区别就是把日志信息写到nohup.out文件中去了,两种做法都行。
输入后,回车。会打印出一个进程号。 查看进程 通过
ps -A 命令查看当前运行的所有进程。你就会发现刚才生成的进程号在列出的进程里面。
也可通过
ps -ef |grep python 查看所有后台Python运行程序
关闭后台运行 方法一:
通过
jobs 命令查看job号(假设为num),然后执行
kill %num 方法二:
通过
ps 命令查看job的进程号(PID,假设为pid),然后执行
kill pid 例子 在远程服务器端后台运行scrapy爬虫程序:
我们都知道,在本地运行scrapy程序只需要命令 scrapy crawal myspider,那么在服务器端,如何运用上述后台运行python文件的方法来运行scrapy程序呢?
简单!再写一个python文件,如run.py,内容如下:
import os if __name__ == '__main__': os.system("scrapy crawl myspider") 然后执行:
nohup python -u run.