Dev
S
O
N
G
主页
分类
时间轴
涂鸦
关于
留言
工具箱
Dev
S
O
N
G
Dev
S
O
N
G
一个理想主义者的博客
主页
分类
时间轴
涂鸦
关于
留言
工具箱
TimeClip——一个实用的剪贴板小工具
附带源码,欢迎交流
......
It's
欢迎访问本站,欢迎留言、分享、点赞。愿您阅读愉快!
https://www.devsong.org
1024程序员节快乐
转眼又过了一年,,,感触良多,人生的每个阶段都会有不同的想法,伴随着的是更多的烦恼和顾忌。。额,扯远了。1024程序员节快乐。 祝自己、祝各位猿: bug抗体永存,不加班,不脱发,升职加薪一气呵成
2021-10-24
时光记
expect<<EOF中的interact无效问题
问题描述 使用 expect 进行交互式 shell 编程,当以 expect<<EOF 的形式在 shell 脚本中穿插 expect 语句时,interact 在执行中无效。 搜索了一番,找到如下解释: 问题出在 expect << EOF。对于 expect << EOF,expect 的 stdin 是 here-doc,而不是tty。但是interact命令只有在 expect 的 stdin 是 tty 时才起作用。 解决方法 使用整段 expect 代码包裹为一个字符串参数的形式,以 -c 形式调用 expect 执行 更改前 ... ...shell code... ... /usr/bin/expect << EOF spawn xxxxxxx expect 'xxx' send 'xxxxxx' interact EOF ... ...shell code... ...更改后 ... ...shell code... ... /usr/bin/expect -c "spawn xxxxxxx expect "xxx" send \"xxxxxx\" interact " ... ...shell code... ...
2021-06-07
Linux
linux expect 下载安装
linux expect安装 expect依赖tcl,首先下载tcl和expect源码。 tcl: https://sourceforge.net/projects/expect/files/Expect/ expect: https://core.tcl-lang.org/expect/index?name=Expect#unix1、下载完成后,进行解压。 2、之后进入到tcl文件夹下的unix文件夹,依次执行以下指令(安装路径以/usr/tcl为例) ./configure --prefix=/usr/tcl --enable-shared make make install3、解压expect压缩包,进入expect文件夹,依次执行以下指令(注意tcl版本号根据实际情况调整) ./configure --prefix=/usr/expect --with-tcl=/usr/tcl/lib --with-tclinclude=../tcl8.6.11/generic make make install4、验证,在/usr/bin下面建立expect软链接 ln -s /usr/tcl/bin/expect /usr/bin/expect然后在终端输入expect验证
2021-06-07
Linux
centos7 虚拟机网络配置
没有足够服务器使用的时候,有时候需要在本地搭建linux虚拟机用来进行大数据组件集群开发测试服务。 其中,网络配置是基础一环。 以下以windows下VMWARE workstation 12平台centos7.x为例。 1、首先,虚拟机网络连接改为NAT模式 2、vmware -> 编辑 -> 虚拟网络编辑器 -> 选中NAT条目, 将 "使用本地DHCP服务将ip地址分配给虚拟机" 取消勾选, 然后点击NAT设置按钮,记录下网关IP,后面会用到。点击确定。 3、到windows网络和internet设置,点击更改适配器属性,找到vmware 网络适配器, 右键点击属性,选择'internet 协议版本4(TCP/ipv4)', 点击属性,设置静态IP,IP配置与刚记下的网关ip同一网段,更改最后一段为其他数字 子网掩码配置会自动填充,如果没有自动填充,手动配置255.255.255.0,保存配置 4、开启虚拟机,ipaddr查看网卡名称,以ens33为例:编辑对应配置文件 vi /etc/sysconfig/network-scripts/ifcfg-ens33 修改内容: BOOTPROTO="dhcp" 改为 BOOTPROTO="static" ONBOOT="no" 改为 ONBOOT="yes" #最后添加: DNS1=114.114.114.114 #DNS服务器,默认 IPADDR=192.168.59.4 #设置静态ip,与前面记录的网关同一网段 NETMASK=255.255.255.0 #子网掩码,默认 GATEWAY=192.168.59.2 #网关ip,填写前面记录下的ip 5、保存编辑,重启网络服务 service network restart查看ip是否已更改 ip addr 测试网络连接 ping www.baidu.com
2021-05-22
Linux
ubuntu下截图文件无法在windows下预览、重命名、删除
现象 Ubuntu下保存的截图拷贝到windows下无法预览、更名、删除 原因 Ubuntu截图软件默认保存的文件命名规则为: Screenshot from yyyy-mm-dd HH:mm:ss.png问题就出在文件名中的英文冒号。英文冒号在windows平台是不允许出现在文件名中的。 所以遇到这样的文件,windows就懵了。这是一个违反windows平台文件命名规范的文件,自然无法正常进行预览、删除、重命名。图形界面下还能显示该文件,命令行下甚至显示文件列都不行。 可以上网搜索如何删除这类文件。本篇文章不作说明。 解决办法 在linux环境下重命名我们拷贝的文件,将特殊字符删除,改为符合windows平台命名规则的文件即可。(可以尝试使用win10 wsl环境测试下)
2020-05-11
Windows
Ubuntu14.04安装Intel8265ac无线网卡驱动
由于某种原因需要折腾比较老的东西,为方便,切换回ubuntu14环境。因为年代比较早,搭配现在的新笔记本会出现有些常用硬件驱动没有的情况,这样就需要自己动手安装驱动。只要不需要繁琐的编译就还好,今天设置的这款网卡驱动就正好不需要我们自行下载源码进行编译。他就是今天的主角Intel8265AC无线网卡。 准备 驱动文件可在此下载,其他型号大部分也可以在此找到:https://wireless.wiki.kernel.org/en/users/Drivers/iwlwifi 此处我们只看主角8265AC 注意看内核版本要求4.6+,重点来了,实测内核版本4.6是不行的,因此此处内核版本要求4.6以上,而不是4.6及以上。 ubuntu14.04LTS默认内核是4.4.0,因此需要我们手动升级至4.6以上。内核升级可以参考我另一篇文章。 安装 升级完内核之后,操作就很简单了,把下载的驱动文件解压,里面有一个说明文件,一个许可文件,和一个真正的驱动文件。直接把驱动文件拷贝至 /lib/firmware 下,然后重启即可。 当然,把三个文件都拷贝过去也无妨 sudo cp iwlwifi-*.ucode /lib/firmware 重启机器之后,开心用无线吧。
2020-05-11
Linux
Ubuntu升级内核
linux上面很多驱动和软件都是跟内核版本挂钩的,版本不匹配就会出现无法工作的情况。为了能使某些驱动和程序正常运作,有时候需要升级内核,甚至有时候还需要降级内核。 内核下载 直接访问以下网址下载目标版本的kernel: https://kernel.ubuntu.com/~kernel-ppa/mainline/ 此处我下载的版本是4.10.17 根据自己处理器版本下载对应内核:(此处博主安装的64位系统,故下载amd64版本) 至于generic和lowlatency,我们正常使用选择generic版本即可,两者在调度力度上会有些许区别,lowlatency版本直译过来为低延迟版本,频繁调度能增加响应速率,在一些实时性要求较高的场景可以选用该版本。但有舍有得,在带来快速响应的同时会加大系统开销,系统总体的吞吐量便会降低。 博主升级的目标版本: linux-headers-4.10.17-041017-generic_4.10.17-041017.201705201051_amd64.deb linux-headers-4.10.17-041017_4.10.17-041017.201705201051_all.deb linux-image-4.10.17-041017-generic_4.10.17-041017.201705201051_amd64.deb安装 下载好之后,进行安装: sudo dpkg -i linux-headers* linux-image* 更新引导 sudo update-grub 然后重启计算机。 输入以下命令查看当前启用的内核版本: uname -r 卸载无用的内核 列出已安装的内核: sudo dpkg --get-selections |grep linux 对于博主的电脑,可以看到,4.4.0相关的我都是不需要的 执行以下命令清除相关内容 sudo apt purge linux-headers-4.4.0-142 \ linux-headers-4.4.0-142-generic \ linux-image-4.4.0-142-generic \ linux-image-extra-4.4.0-142-generic \ linux-signed-image-4.4.0-142-generic 保险起见,再次更新下启动引导,然后重启计算机即可。
2020-05-09
Linux
安卓刷机双清recovery报错 Failed to mount '/data' (invalid argument)
由于疫情影响,开学时间一再推迟,上网课就成了学生在家里面必进行的活动。很多网课要求在手机上安装相关的app,做题上课均在手机上,这时候就有个问题,手机屏幕小,做题上课都不方便,加大手机屏幕是不可能了,分频也不实用。于是有了一个折中的方案,用两个手机操作,一个听课,另一个同时做题。 于是有了下面的折腾。不少软件对安卓版本有限制,为了安装上软件进行操作,在抽屉里翻出了一个7年前的手机,想让它发光发热只能升级系统,网上找了一番,下载了一个Android9.0版本的系统。 不得不说,开源是真的好,7年前的手机在开源社区还有人维护系统,最新的版本已经到了Android10。下载好对应rom、第三方recovery。开刷。于是碰到了下面的错误。 错误详情 在格式化 cache、data的时候报错,说无法挂载分区。手动挂载所有分区发现只有 /system 分区能正常挂载,其他都是不行的。所以格式化等操作均无法进行。 Failed to mount '/data' (invalid argument) Failed to mount '/cache' (invalid argument) ... 解决办法 上网找了下,发现不少人遇到了一样的情况。然后发现 fastboot 有个命令,能初始化分区,因为旧手机内没有数据需要备份,于是直接执行了。 fastboot -w 执行结果: PS C:\Users\admin\Downloads> fastboot -w mke2fs 1.44.3 (10-July-2018) Creating filesystem with 3322875 4k blocks and 832320 inodes Filesystem UUID: 8371ac4a-7670-11ea-87a2-950aa878b190 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done mke2fs 1.44.3 (10-July-2018) Creating filesystem with 98304 4k blocks and 98304 inodes Filesystem UUID: 838a3882-7670-11ea-8cae-af4c5004139d Superblock backups stored on blocks: 32768 Allocating group tables: done Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done Erasing 'userdata' OKAY [ 9.484s] Sending 'userdata' (3372 KB) OKAY [ 0.109s] Writing 'userdata' OKAY [ 0.103s] Erasing 'cache' OKAY [ 0.230s] Sending 'cache' (152 KB) OKAY [ 0.009s] Writing 'cache' OKAY [ 0.021s] Finished. Total time: 10.774s 执行完以上指令后就能正常挂载、格式化、更新系统了。
2020-04-16
Android
一个实用的剪贴板小工具——TimeClip
由于工作的特殊性,每天都需要使用电脑。而处理各种文本等数据又是使用电脑最基本的操作。处理文本就涉及剪贴板,多个文本协同的话,文本打开多了就容易乱,有时候复制把复制覆盖了,就要在一堆中找来找去重新复制。 有时候十分抓狂,为此,自己利用闲暇时光写了个小工具,没有很华丽但用起来还挺方便,分享给需要的人。 就这样,TimeClip诞生了,随便取了个这样的名字。 基本功能 保存最近六条剪贴板内容,方便随时获取历史剪贴内容 鼠标滑入展示记录 单击某条记录将该记录复制到系统剪贴板 很简单,却很实用。 工程&可执行文件 本工具实用JavaFx编写,功能很简单,所以工程也很小,并不常用JavaFx,所以代码可能有些混乱,但还是分享出来给有需要的人参考。 至于打包,由于针对windows平台在idea上使用完全打包,把jdk也包含了进去,所以略大。这里没有去好好研究下打包方面的东西,有兴趣的伙伴可以下载源码自己打包,精简下体积。 下载相关 源码 百度云:https://pan.baidu.com/s/1yVpbYpQAV_s2zjbX58vEog - 提取码:3duq 蓝奏云:https://www.lanzous.com/iavx52b 可执行文件 百度云:https://pan.baidu.com/s/1shYsYWLAPXw0I8LmIH60Zg - 提取码:osnj 蓝奏云:https://www.lanzous.com/iavxluf 免责声明 对于敏感数据,保留历史剪贴板内容可能导致隐私数据泄露,建议使用后离开电脑前清空保留的内容。本软件使用带来的后果与作者无关。带来方便的同时请权衡利弊,谨慎使用。
2020-04-01
Java
js选择和复制html中的文本
在开发过程中,有时候为方便用户,需要提供点击选中某部分文本并进行复制的操作。借助JQuery可以方便地实现以上需求。 而本篇所讲的是使用纯js的方式进行实现。大体分为两类。 选中文本 针对文本控件(如文本域、输入框) 针对文本控件,其本身有select()方法可供调用,所以处理起来是很方便的,直接定位到目标元素,然后调用其select()方法即可。 示例元素 <textarea id="testSel"></textarea> 示例代码 document.getElementById('testSel').select(); 针对div等块级元素 对于div等元素,由于其并未提供select()方法,故需要另外实现。以下为博主整理的示例,经供参考。 示例元素 <div id="testSel"></div> 示例代码 /** * 选择函数 */ function selectText(element) { var text = document.getElementById(element); if (document.body.createTextRange) { var range = document.body.createTextRange(); range.moveToElementText(text); range.select(); } else if (window.getSelection) { var selection = window.getSelection(); var range = document.createRange(); range.selectNodeContents(text); selection.removeAllRanges(); selection.addRange(range); } else { console.log('none'); } } //使用示例 selectText('testSel'); 此示例只是简单演示,可以根据需求更改 selectText 函数,使其更完善更强大,比如针对class、id做适配等 复制 以上完成了文本选择操作,接下来就是复制操作了。使用以下代码即可完成复制。 document.execCommand("Copy"); 拓展 了解了以上知识,对于div等元素,实现复制,可以转变一下思路,在用户点击复制交互的时候,使用文本控件呈现,控件内容为div内文本内容(即展示一个正常情况下隐藏的文本控件,原始的div或覆盖或隐藏),这样,就可以使用文本控件的 select() 方法进行文本选择。 目前很多网站都采用这样的处理方式,可以规避很多问题,如兼容性问题。
2020-03-16
JavaScript
Chrome浏览器暗色模式
暗色模式(黑暗模式)在近两年来一直是热门,无论安卓还是IOS,先后都有了暗色模式。windows10 在一些列版本更新后也加入了暗色模式。 一些常用的软件也都纷纷适配了各个系统的暗色模式。今天所说的就是比较常用的chrome浏览器。网页开发少不了它。 如果您目前使用的是windows 10 系统,且正在使用系统的暗色模式,那么只要你的 chrome 版本是较新的版本,就自动会开启暗色模式 如果您的chrome浏览器版本较老,那么就需要更新后使用。 且值得一提的是,目前chrome浏览器设置里面并未直接提供暗色模式的开关,于是有了下面的内容。 另一种场景 如果您的系统支持暗色模式,但你又不喜欢使用暗色模式,只想单独开启chrome的暗色模式,那么此篇文章可以帮助到你。 操作 右键chrome快捷方式,打开属性,在目标一栏末尾加上" --force-dark-mode"即可,后面只需要是通过这个快捷方式启动的,就是暗色模式。 效果 改为暗色模式后,调试模式简直对喜欢暗色主体开发工具的开发人员无限友好。
2020-01-07
实用工具
java获取IP地址归属地(本地查询方式)
java获取ip地址归属地的常见方法有两个: 一种是调用网络上一些服务商提供的api 另一种是将数据存储在本地,然后进行本地查询。 两种方式各有优劣,本篇文章提供了本地查询的实现方式。 准备 要实现本地查询,首先需要准备归属地数据,可以在网络上搜索‘qqwry.dat’,然后下载即可。 此处推荐 github 的开源项目 地址https://github.com/out0fmemory/qqwry.dat,里面的数据更新及时,基本每天都会刷新,直接下载 qqwry_latest.dat 即可 代码实现 以下工具类参考自互联网, 可根据实际需求修改:IpSeekUtils.java import org.apache.log4j.Logger; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class IpSeekUtils { private final Logger logger = Logger.getLogger(this.getClass()); private static final int IP_RECORD_LENGTH = 7; private static final byte AREA_FOLLOWED = 0x01; private static final byte NO_AREA = 0x2; private MappedByteBuffer buffer; // 内存映射文件,提高IO 读取效率 private HashMap<String, IPLocation> cache = new HashMap<String, IPLocation>(); // 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找 private int ipBegin; private int ipEnd; @SuppressWarnings("resource") public IpSeekUtils(File file) throws Exception { buffer = new RandomAccessFile(file, "r").getChannel().map( FileChannel.MapMode.READ_ONLY, 0, file.length()); if (buffer.order().toString().equals(ByteOrder.BIG_ENDIAN.toString())) { buffer.order(ByteOrder.LITTLE_ENDIAN); } ipBegin = readInt(0); ipEnd = readInt(4); if (ipBegin == -1 || ipEnd == -1) { throw new IOException("IP地址信息文件格式有错误,IP显示功能将无法使用"); } logger.debug("使用IP地址库:" + file.getAbsolutePath()); } /** * 给定一个ip 得到一个 ip地址信息 * * @param ip * @return */ public String getAddress(String ip) { return getCountry(ip) + " " + getArea(ip); } /** * 根据IP得到国家名 * * @param ip * IP的字符串形式 * @return 国家名字符串 */ public String getCountry(String ip) { IPLocation cache = getIpLocation(ip); return cache.getCountry(); } /** * 根据IP得到地区名 * * @param ip * IP的字符串形式 * @return 地区名字符串 */ public String getArea(String ip) { IPLocation cache = getIpLocation(ip); return cache.getArea(); } /** * 获得一个IP地址信息 * * @param ip * @return */ public IPLocation getIpLocation(String ip) { IPLocation ipLocation = null; try { if (cache.get(ip) != null) { return cache.get(ip); } ipLocation = getIPLocation(getIpByteArrayFromString(ip)); if (ipLocation != null) { cache.put(ip, ipLocation); } } catch (Exception e) { logger.error(String.valueOf(e)); } if (ipLocation == null) { ipLocation = new IPLocation(); ipLocation.setCountry("未知国家"); ipLocation.setArea("未知地区"); } return ipLocation; } /** * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录 * * @param s * 地点子串 * @return 包含IPEntry类型的List */ public List<IPEntry> getIPEntries(String s) { List<IPEntry> ret = new ArrayList<IPEntry>(); byte[] b4 = new byte[4]; int endOffset = ipEnd + 4; for (int offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) { // 读取结束IP偏移 int temp = readInt3(offset); // 如果temp不等于-1,读取IP的地点信息 if (temp != -1) { IPLocation loc = getIPLocation(temp); // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续 if (loc.country.indexOf(s) != -1 || loc.area.indexOf(s) != -1) { IPEntry entry = new IPEntry(); entry.country = loc.country; entry.area = loc.area; // 得到起始IP readIP(offset - 4, b4); entry.beginIp = getIpStringFromBytes(b4); // 得到结束IP readIP(temp, b4); entry.endIp = getIpStringFromBytes(b4); // 添加该记录 ret.add(entry); } } } return ret; } /** * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到 * * @param ip * 要查询的IP * @return IPLocation结构 */ private IPLocation getIPLocation(byte[] ip) { IPLocation info = null; int offset = locateIP(ip); if (offset != -1) { info = getIPLocation(offset); } return info; } // -----------------以下为内部方法 /** * 读取4个字节 * * @param offset * @return */ private int readInt(int offset) { buffer.position(offset); return buffer.getInt(); } private int readInt3(int offset) { buffer.position(offset); return buffer.getInt() & 0x00FFFFFF; } /** * 从内存映射文件的offset位置得到一个0结尾字符串 * * @param offset * @return */ private String readString(int offset) { try { byte[] buf = new byte[100]; buffer.position(offset); int i; for (i = 0, buf[i] = buffer.get(); buf[i] != 0; buf[++i] = buffer .get()) { } if (i != 0) { return getString(buf, 0, i, "GBK"); } } catch (IllegalArgumentException e) { } return ""; } /** * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是 * 文件中是little-endian形式,将会进行转换 * * @param offset * @param ip */ private void readIP(int offset, byte[] ip) { buffer.position(offset); buffer.get(ip); byte temp = ip[0]; ip[0] = ip[3]; ip[3] = temp; temp = ip[1]; ip[1] = ip[2]; ip[2] = temp; } /** * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的 * * @param ip * 要查询的IP * @param beginIp * 和被查询IP相比较的IP * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。 */ private int compareIP(byte[] ip, byte[] beginIp) { for (int i = 0; i < 4; i++) { int r = compareByte(ip[i], beginIp[i]); if (r != 0) { return r; } } return 0; } /** * 把两个byte当作无符号数进行比较 * * @param b1 * @param b2 * @return 若b1大于b2则返回1,相等返回0,小于返回-1 */ private int compareByte(byte b1, byte b2) { if ((b1 & 0xFF) > (b2 & 0xFF)) // 比较是否大于 { return 1; } else if ((b1 ^ b2) == 0)// 判断是否相等 { return 0; } else { return -1; } } /** * 这个方法将根据ip的内容,定位到包含这个ip国家地区的记录处,返回一个绝对偏移 方法使用二分法查找。 * * @param ip * 要查询的IP * @return 如果找到了,返回结束IP的偏移,如果没有找到,返回-1 */ private int locateIP(byte[] ip) { int m = 0; int r; byte[] b4 = new byte[4]; // 比较第一个ip项 readIP(ipBegin, b4); r = compareIP(ip, b4); if (r == 0) { return ipBegin; } else if (r < 0) { return -1; } // 开始二分搜索 for (int i = ipBegin, j = ipEnd; i < j;) { m = getMiddleOffset(i, j); readIP(m, b4); r = compareIP(ip, b4); // log.debug(Utils.getIpStringFromBytes(b)); if (r > 0) { i = m; } else if (r < 0) { if (m == j) { j -= IP_RECORD_LENGTH; m = j; } else { j = m; } } else { return readInt3(m + 4); } } // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非 // 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移 m = readInt3(m + 4); readIP(m, b4); r = compareIP(ip, b4); if (r <= 0) { return m; } else { return -1; } } /** * 得到begin偏移和end偏移中间位置记录的偏移 * * @param begin * @param end * @return */ private int getMiddleOffset(int begin, int end) { int records = (end - begin) / IP_RECORD_LENGTH; records >>= 1; if (records == 0) { records = 1; } return begin + records * IP_RECORD_LENGTH; } /** * @param offset * @return */ private IPLocation getIPLocation(int offset) { IPLocation loc = new IPLocation(); // 跳过4字节ip buffer.position(offset + 4); // 读取第一个字节判断是否标志字节 byte b = buffer.get(); if (b == AREA_FOLLOWED) { // 读取国家偏移 int countryOffset = readInt3(); // 跳转至偏移处 buffer.position(countryOffset); // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向 b = buffer.get(); if (b == NO_AREA) { loc.country = readString(readInt3()); buffer.position(countryOffset + 4); } else { loc.country = readString(countryOffset); } // 读取地区标志 loc.area = readArea(buffer.position()); } else if (b == NO_AREA) { loc.country = readString(readInt3()); loc.area = readArea(offset + 8); } else { loc.country = readString(buffer.position() - 1); loc.area = readArea(buffer.position()); } return loc; } /** * @param offset * @return */ private String readArea(int offset) { buffer.position(offset); byte b = buffer.get(); if (b == 0x01 || b == 0x02) { int areaOffset = readInt3(); if (areaOffset == 0) { return "未知地区"; } else { return readString(areaOffset); } } else { return readString(offset); } } /** * 从内存映射文件的当前位置开始的3个字节读取一个int * * @return */ private int readInt3() { return buffer.getInt() & 0x00FFFFFF; } /** * 从ip的字符串形式得到字节数组形式 * * @param ip * 字符串形式的ip * @return 字节数组形式的ip */ private static byte[] getIpByteArrayFromString(String ip) throws Exception { byte[] ret = new byte[4]; java.util.StringTokenizer st = new java.util.StringTokenizer(ip, "."); try { ret[0] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF); ret[1] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF); ret[2] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF); ret[3] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF); } catch (Exception e) { throw e; } return ret; } /** * 根据某种编码方式将字节数组转换成字符串 * * @param b * 字节数组 * @param offset * 要转换的起始位置 * @param len * 要转换的长度 * @param encoding * 编码方式 * @return 如果encoding不支持,返回一个缺省编码的字符串 */ private static String getString(byte[] b, int offset, int len, String encoding) { try { return new String(b, offset, len, encoding); } catch (UnsupportedEncodingException e) { return new String(b, offset, len); } } /** * @param ip * ip的字节数组形式 * @return 字符串形式的ip */ private static String getIpStringFromBytes(byte[] ip) { StringBuffer sb = new StringBuffer(); sb.append(ip[0] & 0xFF); sb.append('.'); sb.append(ip[1] & 0xFF); sb.append('.'); sb.append(ip[2] & 0xFF); sb.append('.'); sb.append(ip[3] & 0xFF); return sb.toString(); } public class IPLocation { private String country;// 所在国家 private String area;// 所在地区 public IPLocation() { } public IPLocation(String country, String area) { this.country = country; this.area = area; } public IPLocation getCopy() { return new IPLocation(country, area); } public String getArea() { return " CZ88.NET".equals(area) ? "" : area; } public void setArea(String area) { this.area = area; } public String getCountry() { return " CZ88.NET".equals(country) ? "" : country; } public void setCountry(String country) { this.country = country; } } /** * * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP * * */ public class IPEntry { public String beginIp; public String endIp; public String country; public String area; /** * 构造函数 */ public IPEntry() { } @Override public String toString() { return new StringBuilder(this.area).append(";") .append(this.country).append(";").append("IP范围:") .append(beginIp).append("-").append(endIp).toString(); } } } 使用 简单使用测试,实际使用根据需求进行自行封装。 import java.io.File; public class IpSeekTest { public static void main(String[] args) { try { IpSeekUtils ipSeekUtils = new IpSeekUtils(new File("qqwry.dat文件路径")); System.out.println(ipSeekUtils.getAddress("IP地址")); } catch (Exception e) { e.printStackTrace(); } } }
2020-01-07
Java
JavaFx隐藏任务栏图标
JavaFx 开发时,运行程序,任务栏默认会显示一个当前程序图标,如果配置了自定义图标,那显示的就是自定义的图标,如果没有设置,则默认显示java图标,例如下图中这种情况: 隐藏图标-初步 有时候希望任务栏不显示当前程序的图标,这个在开发某些工具类应用时会有需要。为此,可以使用Stage 的 initStyle 方法并传入参数'StageStyle.UTILITY',这样,系统任务栏就不会显示运行的图标了。代码示例如下: public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); // 初始化样式为 UTILITY primaryStage.initStyle(StageStyle.UTILITY); primaryStage.setTitle("Hello World"); primaryStage.setScene(new Scene(root, 300, 275)); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 但随之而来的问题是,这样设置之后,图标是不显示了,但是标题栏变得很丑,因为不再显示图标,所以最大化最小化按钮也都没了,只有一个关闭的按钮。如图所示: 隐藏图标+个性化定制 以上方法只是解决了图标隐藏的问题,而如果要定制化,还得微调一下代码。思路是:重新初始化一个Stage, 并设置其所属者(owner)为已经初始化为 utilityStyle 的Stage(即父级Stage)。这样再运行就不会显示图标了,并且新初始化的Stage可以自由定制样式。这样修改后效果如下: 可以看到运行会显示两个窗口,要处理也很简单,只需要把父级Stage的透明度设置为0即可。代码示例如下: public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ // 设置风格为 UTILITY primaryStage.initStyle(StageStyle.UTILITY); // 设置父级透明度为0 primaryStage.setOpacity(0); Stage mainStage = new Stage(); // 将 primaryStage 设置为归属对象,即父级窗口 mainStage.initOwner(primaryStage); Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); mainStage.setTitle("Hello World"); mainStage.setScene(new Scene(root, 300, 275)); // 先把 primaryStage 显示,再显示其他内容(顺序必须这样,因为父级必须显示,如果直接显示 mainStage, 则任务栏图标隐藏无效) primaryStage.show(); mainStage.show(); } public static void main(String[] args) { launch(args); } } 博主目前只知道这样的处理方法,不知道JavaFx 13会不会有新的简便的方法提供。 此外,需要注意,由于显示的窗口不是初始的窗口,所以关闭可见的Stage时,即需要退出程序时需要手动调用父级的close方法。否则只是关闭了显示的窗口。 如果您有什么好的方法和简介,欢迎在下方留言交流。
2020-01-02
Java
2019年终总结
转眼间,本命年2019已经悄悄溜走了,过去的这一年,错过高铁、加班通宵、出差奋战、满脸爆痘、减肥无效都经历了。 首先说错过高铁,怪自己拖延症犯了,出发晚,怪自己高估了这城市的交通情况,也怪百度,叫个车40分钟才到,无力吐槽,第一次用也是最后一次用。 其次是加班,2019年的加班还是比较多的,看过了凌晨4点的合肥,也看过了凌晨4点的武汉,过了几周没双休的日子,吃了几周合肥地铁美食城的饭菜,着重夸下朱岗地铁站那家酸菜鱼,店面小,味道却很一流,而且很实惠,老板娘人很好,赞!好想再吃一次那个酸菜鱼,只是按照目前的计划来看,应该是不太可能了。 出差总是和加班一起袭来,对于目前的工作来说,出差=到远方加班。很讨厌,但也没办法。加班熬夜太多,加上饮食不规律,满脸爆痘,记忆中从没长过这么多且大且难受的痘痘。 总的来说,这个本命年工作上挺辛苦的,加班成常态。好在今年的收获很大,学到了很多,关键是生活上收获了一个小傻瓜,是我今年最大的幸运。 2020近在眼前,新的一年,愿一切顺利。 2019,再见。 祝大家:元旦快乐,新的一年心想事成,万事如意。
2019-12-31
时光记
MyBatis XML 文件中注释包含占位符导致参数匹配失败
MyBatis XML 中使用包含占位符的注释,会导致异常:java.sql.SQLException: 序列号无效 具体报错信息 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='id', mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLException: 序列号无效 at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy128.update(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:294) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy185.updateReportInfo(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy186.updateReportInfo(Unknown Source) ... ... 所谓包含占位符的注释 示例如下: <update id="updateUser" parameterType="org.devsong.domain.vo.UserVo"> update t_user set user_name = #{userName}, --age = #{age}, email = #{email} where id = #{id} </update> 其中的注释 -- age = #{age} 在匹配参数解析时依然会当成一个占位符进行匹配,导致以上异常。删除对应的注释即可。
2019-10-25
数据库
1
2
3
...
7
8
9
涂鸦
热门
CSS hover更改其他元素属性
12140
JPEGView--一个好用的图片查看和编辑软件
11157
MySQL 8.0 java.sql.SQLException Unknown system variable 'query_cache_size'
9795
Chrome浏览器暗色模式
8694
intelliJ IDEA Java注释模板配置
8683
Maven 和 Gradle 国内代理配置
8088
android.database.sqlite.SQLiteException:AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY (code 1)
7993
安卓刷机双清recovery报错 Failed to mount '/data' (invalid argument)
6890
Tomcat响应流程及Servlet的执行流程
6392
一个eclipse配置tomcat容易困扰新手的问题
6168
分类
Java
(43)
Android
(9)
C/C++
(11)
嵌入式
(2)
数据库
(8)
PHP
(1)
JavaScript
(7)
HTML/CSS
(7)
随笔
(8)
实用工具
(10)
时光记
(8)
Linux
(11)
Windows
(2)
日常娱乐
(2)
数码
(1)
每日资讯
(0)
最新留言
LuckyX
Aug 18, 2021.
有用!红米note5A 成功,谢谢楼主
嗯
June 23, 2021.
12
极客
Apr 13, 2021.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As range, Cancel As Boolean) Dim min As Double Dim max As Double Dim range As Double max = ActiveSheet.range(Target.Address).Offset(11, -1).Value min = ActiveSheet.range(Target.Address).Offset(12, -1).Value range = ActiveSheet.range(Target.Address).Offset(13, -1).Value For i = 0 To 10 ActiveSheet.range(Target.Address).Offset(i, 0).Value = (max - ActiveSheet.range(Target.Address).Offset(i, -1).Value) / range Next i End Sub
招投标
Jan 06, 2021.
这个确实很刚需了,用的时候比较多
招投标
Jan 06, 2021.
下次拿家里的安卓机试一试,还可以偶尔用下
招投标
Jan 06, 2021.
感谢大佬的分享,支持一下
招投标
Jan 06, 2021.
文章写的不粗哦,赞一个
月雅
Sept 17, 2020.
大佬教我学编程.。。。。。
小曾曾的博客(www.xiaozeng.cc)
June 14, 2020.
抱歉,因为个人原因,本站暂停运营。
小曾曾的博客(www.xiaozeng.cc)
Apr 29, 2020.
小曾曾的博客(www.xiaozeng.cc)已添加贵站链接,希望贵站能添加。
友链
帅大叔的博客
DevSONG
张宇童-前沿技术博客
逆风的小窝