首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,604 阅读
2
Mac打印机设置黑白打印
4,933 阅读
3
修改elementUI中el-table树形结构图标
4,893 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,671 阅读
5
intelliJ Idea 2022.2.X破解
4,353 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Spring Cloud
Mac
MyBatis
WordPress
MacOS
asp.net
Element UI
Nacos
.Net
Spring Cloud Alibaba
MySQL
Mybatis-Plus
Typecho
jQuery
Java Script
微信小程序
Oracle
Laughing
累计撰写
626
篇文章
累计收到
1,421
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
626
篇与
的结果
2022-09-21
docsify一个神奇的文档网站生成工具
之前一直使用的觅思文档作为内部在线知识库。公司内部最近在进行服务器漏洞扫描,觅思文档使用的Python+Django的形式(我用的Docker一键部署的那个,看Python的版本好像是3.7.3吧),由于Python注入漏洞影响3.10.4及以下版本,所以我尝试将Python升级到3.10.7,但是由于Django与Python版本对应关系存在问题,所以升级以失败告终。也是出于无奈,只能另寻其他替代产品。 经过对比,选择了一款小巧的文档网站生成工具-docsify。一、docsify的优缺点1.1、优点简洁,没有乱七八糟的功能,也不需要复杂的配置部署简单,两三条命令即可完成部署,不需要数据库结构化展示,直接展示本地markdown文件1.2、缺点没有用户管理功能,不方便多人协作因为是本地化部署,所以不方便使用七牛等图床,导致markdown文件中粘贴图片不是很方便。(当然,我们可以通过typora配置图片上传路径解决此问题)二、docsify部署首先确保已安装node.js。2.1、安装docsify-cli推荐全局安装docsify-cli工具,可以方便地创建及在本地预览生成的文档。打开终端,执行以下命令npm i docsify-cli -g2.2、初始化项目新建文件夹,文件夹名称随意起(我创建了docsify),然后在终端进入文件夹在终端输入docsify init然后查看文件夹index.html:入口文件README.md:会做为主页内容渲染.nojekyll:用于阻止 GitHub Pages 忽略掉下划线开头的文件运行直接输入docsify serve即可运行项目默认端口是3000此时网站就搭建成功了。如果我们需要编辑网站的内容,可以直接修改README.md文件。如果需要修改端口,直接运行socsify server -p 端口号关于docsify的一些其他配置,比如更换主题、设置封面、安装插件等,我们稍后在进行介绍。
2022年09月21日
869 阅读
0 评论
0 点赞
2022-09-14
maven编译项目的时候出现 Malformed \uxxxx encoding
在./m2/文件夹下,找到path-to-the-library,然后删掉(若无此文件,可直接忽略此步骤);在./m2/repository文件夹下全局搜索:resolver-status.properties文件,将搜索到的所有此文件全部删除,然后重新编译即可。
2022年09月14日
1,597 阅读
0 评论
0 点赞
2022-09-11
纯js实现html添加水印
有时候出于保密等需要,我们可能需要在前端展示页面添加一些水印信息。window.onload = function () { const element = document.body; watermark(element); } // window.onresize = function () { // const element = document.body; // watermark(element); // } function watermark(element, config) { let chArr = document.body.getElementsByClassName("watermark-item"); for (i = 0; i < chArr.length; i++) { //删除元素 元素.parentNode.removeChild(元素); if (chArr[i] != null) chArr[i].parentNode.removeChild(chArr[i]); } // 获取元素的坐标 function getOffset(el) { if (el.offsetParent) { return { x: el.offsetLeft + getOffset(el.offsetParent).x, y: el.offsetTop + getOffset(el.offsetParent).y, }; } return { x: el.offsetLeft, y: el.offsetTop, }; } if (!element) return; // 默认配置 const _config = { text1: '内部文档', //文本1 text2: '注意保密', // 文本2 start_x: 0, // x轴起始位置 start_y: 0, // y轴起始位置 space_x: 100, // x轴间距 space_y: 50, // y轴间距 width: 210, // 宽度 height: 80, // 长度 fontSize: 20, // 字体 color: '#aaa', // 字色 alpha: 0.4, // 透明度 rotate: 15, // 倾斜度 }; // 替换默认配置 if (arguments.length === 2 && typeof arguments[1] === "object") { const src = arguments[1] || {}; for (let key in src) { if (src[key] && _config[key] && src[key] === _config[key]) { continue; } else if (src[key]) { _config[key] = src[key]; } } } // 节点的总宽度 const total_width = element.scrollWidth; // 节点的总高度 const total_height = element.scrollHeight; // 创建文本碎片,用于包含所有的插入节点 const mark = document.createDocumentFragment(); // 水印节点的起始坐标 const position = getOffset(element); let x = position.x + _config.start_x, y = position.y + _config.start_y; // 先循环y轴插入水印 do { // 再循环x轴插入水印 do { // 创建单个水印节点 const item = document.createElement('div'); item.className = 'watermark-item'; // 设置节点的样式 item.style.position = "absolute"; item.style.zIndex = 99999; item.style.left = `${x}px`; item.style.top = `${y}px`; item.style.width = `${_config.width}px`; item.style.height = `${_config.height}px`; item.style.fontSize = `${_config.fontSize}px`; item.style.color = _config.color; item.style.textAlign = 'center'; item.style.opacity = _config.alpha; item.style.filter = `alpha(opacity=${_config.alpha * 100})`; // item.style.filter = `opacity(${_config.alpha * 100}%)`; item.style.webkitTransform = `rotate(-${_config.rotate}deg)`; item.style.MozTransform = `rotate(-${_config.rotate}deg)`; item.style.msTransform = `rotate(-${_config.rotate}deg)`; item.style.OTransform = `rotate(-${_config.rotate}deg)`; item.style.transform = `rotate(-${_config.rotate}deg)`; item.style.pointerEvents = 'none'; //让水印不遮挡页面的点击事件 // 创建text1水印节点 const text1 = document.createElement('div'); text1.appendChild(document.createTextNode(_config.text1)); item.append(text1); // 创建text2水印节点 const text2 = document.createElement('div'); text2.appendChild(document.createTextNode(_config.text2)); item.append(text2); // 添加水印节点到文本碎片 mark.append(item); // x坐标递增 x = x + _config.width + _config.space_x; // 超出文本右侧坐标停止插入 } while (total_width + position.x > x + _config.width); // 重置x初始坐标 x = position.x + _config.start_x; // y坐标递增 y = y + _config.height + _config.space_y; // 超出文本底部坐标停止插入 } while (total_height + position.y > y + _config.height); // 插入文档碎片 element.append(mark); }
2022年09月11日
1,133 阅读
0 评论
0 点赞
2022-09-04
树莓派免费配置内网穿透
{message type="info" content="没有做内网穿透的树莓派是没有灵魂的。"/} 本文介绍使用Sakura Frp实现树莓派的内网穿透。因为树莓派上我有设置的宝塔面板,我们就实现在外网也能访问宝塔。一、Sakura Frp介绍Sakura有免费的,也有收费的,具体区别请看下图个人使用别搭建网盘的话也差不多够了,并且每天签到还能领流量。{anote icon="" href="https://www.natfrp.com/" type="secondary" content="官方网站"/} 首先需要注册一个Sakura账号并完成认证。这里不过多介绍,我们默认你已经有了账号。二、软件下载打开https://www.natfrp.com/tunnel/download找到arm64,下载软件后,保存到树莓派某个路径下,我这里放到/opt/sakurafrp/三、创建隧道点【穿透】,选择【隧道列表】。{message type="info" content="免费用户能创建两个隧道"/}{message type="warn" content="国内节点域名需要备案"/}服务没开,默认是灰色的四、配置服务我们要实现的目标就是每次开机时,能够自动连上我们的服务,避免每次开机自己设置。4.1、创建服务vi /lib/systemd/system/frpc@.service将以下内容复制进去[Unit] Description=SakuraFrp Service After=network.target [Service] Type=idle User=nobody Restart=on-failure RestartSec=60s ExecStart= /opt/frpc_linux_arm64 -f %i [Install] WantedBy=multi-user.target{message type="warn" content="/opt/sakurafrp/frpc_linux_arm使我们上面步骤下载的软件位置,注意替换"/}下载配置文件,并重命名为frpc.ini,并上传到frpc_linux_arm64同级目录。4.2、查看隧道信息点击隧道,选择【操作】,【配置文件】复制上面的内容,就是-f的那块4.3、打开控制台,开启服务systemctl start frpc@XXX:XXXXXXXXXX对应替换成隧道信息此时再查看隧道列表,可以看到我们隧道前面的灰色原点已经变成绿色了说明我们隧道开启成功了此时执行以下命令,设置开机启动systemctl enable frpc@XXX:XXXXXXX支持,服务已经配置完成,可以重启一下,验证一下隧道列表原点是否依然是绿色,如果是绿色,说明我们开机自启动是没问题的。五、域名解析此时,还剩最后一步,就是我们需要把我们自己的域名解析到Sakura上还是找到隧道配置文件,我们可以在下面看到server_addr我们需要将域名cname指向此地址。输入自己域名可以验证一下
2022年09月04日
1,781 阅读
0 评论
2 点赞
2022-09-04
树莓派4B离线安装JDK1.8
一、确定系统版本我用的是Raspberry PI OS(64-bit),因此需要下载ARM 64 Compressed Archive的压缩包。{message type="info" content="如果使用的是Raspberry PI OS(32-bit),需要下载对应的压缩包。"/}二、JDK下载路径我是在Oracle官网下载的,速度也很快。https://www.oracle.com/back/technologies/downloads/#java8三、安装3.1、将压缩包上传到树莓派任意位置当然,如果你是在树莓派直接下载的,可以调到这步,我这里放到/root文件夹下3.2、解压登录ssh,切换到/root目录,执行tar -zxvf jdk-8u341-linux-aarch64.tar.gz3.3、移动位置将解压后的文件夹剪切到/usr/local/jdk1.8 目录下。切换到/usr/local目录cd /usr/local创建目录mkdir jdk1.8移动mv /root/jdk1.8.0_341 /usr/local/jdk1.8四、配置环境变量执行vim /etc/profile在底部追加JAVA_HOME=/usr/local/jdk1.8/jdk1.8.0_341 JRE_HOME=/usr/local/jdk1.8/jdk1.8.0_341/jre PATH=$JAVA_HOME/bin:$CATALINA_HOME/bin:$JRE_HOME:$PATH CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export JAVA_HOME export JRE_HOME export PATH export CLASSPATH刷新配置文件source /etc/profile五、验证输入java- version如果输出版本信息,代表安装成功
2022年09月04日
1,217 阅读
0 评论
2 点赞
2022-09-04
树莓派如何不用网络、显示器、键鼠安装系统
树莓派镜像烧录器目前已经支持在烧录镜像时同步配置SSH、网络等信息,这样我们无需借助显示器或者外置键鼠在在安装系统时进行配置。 在烧录镜像的时候,点击下面设置 里面有各种设置信息,包括ssh账号、密码、WIFI等 这样烧录完镜像之后,便会自动连接WiFi,通过路由器查看树莓派的IP,便可以通过SSH直接登录使用了。
2022年09月04日
922 阅读
0 评论
1 点赞
2022-09-04
树莓派4B安装宝塔面板直接断网问题
今天又把家里树莓派拿出来玩了玩,重新安装了树莓派32位桌面版系统。本来想安装个宝塔面板,结果已安装就直接断网。 最后查资料才知道{message type="danger" content="宝塔不支持树莓派32位系统,要安装宝塔,必须用64位的才行"/}
2022年09月04日
886 阅读
0 评论
0 点赞
2022-09-01
java同步锁Lock
在Java中Synchronized的用法中,我们介绍了通过Synchronized实现线程同步的机制。除了通过Synchronized实现线程同步之外,我们还可以通过同步锁(java.util.concurrent.locks.Lock)实现线程同步。看下下面代码package com.company.threadpackage; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Apple implements Runnable { private int num = 50; private final Lock lock = new ReentrantLock(); @Override public void run() { while (num > 0) { lock.lock(); try { if (num > 0) { System.out.println(Thread.currentThread().getName() + " 吃了编号为 " + num-- + " 的苹果"); } }finally { lock.unlock(); } } } }调用 Apple apple = new Apple(); for(int i=0;i<1000;i++){ new Thread(apple,"apple"+i).start(); } 查看控制台,可以看到,num始终是在顺序减少。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁。常用的实现类ReentrantLock(可重入锁):java.util.concurrent.locks 包中,通常建议使用 finally 块来确保在必要时释放锁ReentrantLock 是可重入锁:当前持有该锁的线程能够多次获取该锁,无需等待(可以在递归算法中使用锁){mtitle title="Lock 和 synchronized选择"/}Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock 去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会直等待下去,不能够响应中断通过Lock可以知道有没有成功获取锁,而synchronized却无法办到Lock可以提高多个线程进行读操作的效率在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竟争),此时 Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择
2022年09月01日
959 阅读
0 评论
0 点赞
2022-08-27
Java基础知识之内部类
Java四种内部类。实例内部类:没有static修饰的内部类。静态内部类:使用static修饰的内部类。局部内部类:在方法中定义的内部类。匿名内部类:没有名称的局部内部类。package com.company.innerclasspackage; public class Outer { private String classDesc = "实例内部类访问"; private static String staticClassDesc = "静态内部类访问"; /** * 实例内部类 */ public class Inner1 { public void desc() { System.out.println(classDesc); } } /** * 静态内部类 */ public static class Inner2 { public void Desc() { System.out.println(staticClassDesc); } } public void desc() { String localClassDesc = "局部内部类"; class Inner3{ public void desc(){ System.out.println(localClassDesc); } } } }
2022年08月27日
727 阅读
0 评论
1 点赞
2022-07-31
Effective Java (高效 Java) 第三版-单例模式
Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。一些管理器和控制器常被设计成单例模式。单例模式有很多好处,它能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间;能够避免由于操作多个实例导致的逻辑错误。如果一个对象有可能贯穿整个应用程序,而且起到了全局统一管理控制的作用,那么单例模式也许是一个值得考虑的选择。饿汉模式public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton newInstance(){ return instance; } }类的构造函数定义为private的,保证其他类不能实例化此类,然后提供了一个静态实例并返回给调用者。饿汉模式是最简单的一种实现方式,饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。这种实现方式适合单例占用内存比较小,在初始化时就会被用到的情况。但是,如果单例占用的内存比较大,或单例只是在某个特定场景下才会用到,使用饿汉模式就不合适了,这时候就需要用到懒汉模式进行延迟加载。懒汉模式public class Singleton{ private static Singleton instance = null; private Singleton(){} public static Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }懒汉模式中单例是在需要的时候才去创建的,如果单例已经创建,再次调用获取接口将不会重新创建新的对象,而是直接返回之前创建的对象。如果某个单例使用的次数少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,这个时候使用懒汉模式就是一个不错的选择。但是这里的懒汉模式并没有考虑线程安全问题,在多个线程可能会并发调用它的getInstance()方法,导致创建多个实例,因此需要加锁解决线程同步问题,实现如下。public class Singleton{ private static Singleton instance = null; private Singleton(){} public static synchronized Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }synchronized修饰静态方法,可以锁定这个类的所有对象。双重校验锁加锁的懒汉模式看起来即解决了线程并发问题,又实现了延迟加载,然而它存在着性能问题,依然不够完美。synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),累积的性能损耗就比较大了。因此就有了双重校验锁,先看下它的实现代码。public class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) {//2 instance = new Singleton(); } } } return instance; } }可以看到上面在同步代码块外多了一层instance为空的判断。由于单例对象只需要创建一次,如果后面再次调用getInstance()只需要直接返回单例对象。因此,大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高了程序性能。不过还需要考虑一种情况,假如两个线程A、B,A执行了if (instance == null)语句,它会认为单例对象没有创建,此时线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。为了解决这个问题,还需要在同步代码块中增加if (instance == null)语句,也就是上面看到的代码2。我们看到双重校验锁即实现了延迟加载,又解决了线程并发问题,同时还解决了执行效率问题,是否真的就万无一失了呢?这里要提到Java中的指令重排优化。所谓指令重排优化是指在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快。JVM中并没有规定编译器优化相关的内容,也就是说JVM可以自由的进行指令重排序的优化。这个问题的关键就在于由于指令重排优化的存在,导致初始化Singleton和将对象地址赋给instance字段的顺序是不确定的。在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错。以上就是双重校验锁会失效的原因,不过还好在JDK1.5及之后版本增加了volatile关键字。volatile的一个语义是禁止指令重排序优化,也就保证了instance变量被赋值的时候对象已经是初始化过的,从而避免了上面说到的问题。代码如下:public class Singleton { private static volatile Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }静态内部类除了上面的三种方式,还有另外一种实现单例的方式,通过静态内部类来实现。首先看一下它的实现代码:public class Singleton{ private static class SingletonHolder{ public static Singleton instance = new Singleton(); } private Singleton(){} public static Singleton newInstance(){ return SingletonHolder.instance; } }这种方式同样利用了类加载机制来保证只创建一个instance实例。它与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题。不一样的是,它是在内部类里面去创建对象实例。这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。枚举public enum Singleton{ instance; public void whateverMethod(){} }上面提到的四种实现单例的方式都有共同的缺点:1)需要额外的工作来实现序列化,否则每次反序列化一个序列化的对象时都会创建一个新的实例。2)可以使用反射强行调用私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛异常)。而枚举类很好的解决了这两个问题,使用枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。因此,《Effective Java》作者推荐使用的方法。不过,在实际工作中,很少看见有人这么写。
2022年07月31日
734 阅读
0 评论
0 点赞
2022-07-31
Effective Java (高效 Java) 第三版-构造方法参数过多时使用 builder 模式
静态工厂和构造方法都有一个限制:它们不能很好地扩展到很多可选参数的情景。考虑我们有一个人员的类,如果只有姓名是必填的,年龄可选的,也许我们可以提供两个构造函数,但是试想一下,如果有两个类型一样的参数,是不是就没法重载了。或者可选的参数比较多,就比较麻烦了。这个时候,我们就可以考虑builder模式了。 public class Person { private String name; private int age; public static class Builder { private String name; private int age; public Builder(String name) { this.name = name; } public Builder withName(String name) { this.name = name; return this; } public Builder withAge(int age) { this.age = age; return this; } public Person build() { return new Person(this); } } public Person(Builder builder) { this.name = builder.name; this.age = builder.age; } public void desc() { System.out.println("姓名:" + name + ",年龄:" + age); } }调用Person person = new Person.Builder("张三").withAge(30).build(); person.desc();
2022年07月31日
805 阅读
0 评论
1 点赞
2022-07-31
Effective Java (高效 Java) 第三版-考虑使用静态工厂方法替代构造方法
public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }静态工厂方法的优点构造方法没有名字,但是静态工厂方法是有名字的如果构造方法的参数本身并不描述被返回的对象,则具有精心选择名称的静态工厂更易于使用,并且生成的客户端代码更易于阅读。不需要每次调用时都创建一个新对象可以返回其返回类型的任何子类型的对象这种灵活性的一个应用是 API 可以返回对象而不需要公开它的类。 以这种方式隐藏实现类会使 API 非常紧凑。返回对象的类可以根据输入参数的不同而不同声明的返回类型的任何子类都是允许的。 返回对象的类也可以随每次发布而不同。在编写包含该方法的类时,返回的对象的类不需要存在这种灵活的静态工厂方法构成了服务提供者框架的基础,比如 Java 数据库连接 AP(JDBC)。服务提供者框架是提供者实现服务的系统,并且系统使得实现对客户端可用,从而将客户端从实现中分离出来。静态工厂方法的缺点没有公共或受保护构造方法的类不能被子类化要想将Collections框架中任何遍历的实现类进行子类化,是不可能的。程序员很难找到它们它们不像构造方法那样在 API 文档中明确的标注出来。因此,对于提供了静态方法而不是构造器的类来说,想要查明如何实例化一个类是十分困难的。
2022年07月31日
1,045 阅读
0 评论
0 点赞
1
...
14
15
16
...
53