首页
留言
友链
关于
Search
1
思源笔记docker私有化部署及使用体验分享
2,627 阅读
2
windows11 远程提示:为安全考虑,已锁定该用户帐户,原因是登录尝试或密码更改尝试过多。
1,170 阅读
3
解决 nginxProxyManager 申请证书时的SSL失败问题
754 阅读
4
Pointer-Focus:一款功能强大的教学、录屏辅助软件
710 阅读
5
使用cspell对项目做拼写规范检查
621 阅读
Web前端
CSS
JavaScript
交互
Vue
小程序
后端
运维
项目
生活
其他
转载
软件
职场
登录
Search
标签搜索
docker
DevOps
magic-boot
Linux
酷壳
frp
RabbitMQ
gitlab
Node
git
工具
MybatisPlus
clickhouse
Syncthing
规范
前端
产品
nginx
markdown
axios
朱治龙
累计撰写
149
篇文章
累计收到
9
条评论
首页
栏目
Web前端
CSS
JavaScript
交互
Vue
小程序
后端
运维
项目
生活
其他
转载
软件
职场
页面
留言
友链
关于
搜索到
149
篇与
朱治龙
的结果
2022-01-21
自动化项目部署系列:③部署宝塔面板
宝塔面板是一款服务器管理软件,支持windows和linux系统,可以通过Web端轻松管理服务器,提升运维效率。例如:创建管理网站、FTP、数据库,拥有可视化文件管理器,可视化软件管理器,可视化CPU、内存、流量监控图表,计划任务等功能。宝塔官网: https://www.bt.cn/选择使用宝塔,主要是为了更方便的在线管理服务器资源。官方有提供 Docker 版本:https://www.bt.cn/bbs/forum.php?mod=viewthread&tid=79499。但为了更好的应用于服务器管理,我将 Docker 直接安装于宿主机上。安装步骤创建宝塔根目录 /wldata/btroot 并为宝塔应用目录 /www 创建软连接[root@VM-16-6-centos wldata]# mkdir /wldata/btroot [root@VM-16-6-centos wldata]# ln -s /wldata/btroot /www [root@VM-16-6-centos wldata]#开始安装根据官网:https://www.bt.cn/bbs/thread-19376-1-1.html 使用如下命令进行安装yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh安装过程记录如下:[root@VM-16-6-centos wldata]# yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile docker-ce-stable | 3.5 kB 00:00:00 epel | 4.7 kB 00:00:00 extras | 2.9 kB 00:00:00 os | 3.6 kB 00:00:00 updates | 2.9 kB 00:00:00 Package wget-1.14-18.el7_6.1.x86_64 already installed and latest version Nothing to do --2022-01-21 16:16:44-- http://download.bt.cn/install/install_6.0.sh Resolving download.bt.cn (download.bt.cn)... 116.10.184.143, 240e:a5:4200:89::143 Connecting to download.bt.cn (download.bt.cn)|116.10.184.143|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 26258 (26K) [application/octet-stream] Saving to: ‘install.sh’ 100%[========================================================================================================>] 26,258 --.-K/s in 0.03s 2022-01-21 16:16:44 (765 KB/s) - ‘install.sh’ saved [26258/26258] install.sh: line 23: [: : integer expression expected +---------------------------------------------------------------------- | Bt-WebPanel FOR CentOS/Ubuntu/Debian +---------------------------------------------------------------------- | Copyright © 2015-2099 BT-SOFT(http://www.bt.cn) All rights reserved. +---------------------------------------------------------------------- | The WebPanel URL will be http://SERVER_IP:8888 when installed. +---------------------------------------------------------------------- Do you want to install Bt-Panel to the /www directory now?(y/n): y --------------------------------------------- Selected download node... Download node: http://dg2.bt.cn --------------------------------------------- Synchronizing system time... Fri Jan 21 16:16:52 CST 2022 Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile docker-ce-stable | 3.5 kB 00:00:00 epel | 4.7 kB 00:00:00 extras | 2.9 kB 00:00:00 os | 3.6 kB 00:00:00 updates | 2.9 kB 00:00:00 Package ntp-4.2.6p5-29.el7.centos.2.x86_64 already installed and latest version Nothing to do 21 Jan 16:16:52 ntpdate[28087]: the NTP socket is in use, exiting setenforce: SELinux is disabled Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Package wget-1.14-18.el7_6.1.x86_64 already installed and latest version Package 2:tar-1.26-35.el7.x86_64 already installed and latest version Package gcc-4.8.5-44.el7.x86_64 already installed and latest version Package 1:make-3.82-24.el7.x86_64 already installed and latest version Package zip-3.0-11.el7.x86_64 already installed and latest version Package gcc-4.8.5-44.el7.x86_64 already installed and latest version Package libxml2-2.9.1-6.el7_9.6.x86_64 already installed and latest version Package zlib-1.2.7-19.el7_9.x86_64 already installed and latest version Package zlib-devel-1.2.7-19.el7_9.x86_64 already installed and latest version Package libwebp-0.3.0-10.el7_9.x86_64 already installed and latest version Package freetype-2.8-14.el7_9.1.x86_64 already installed and latest version Package lsof-4.87-6.el7.x86_64 already installed and latest version Package pcre-8.32-17.el7.x86_64 already installed and latest version Package pcre-devel-8.32-17.el7.x86_64 already installed and latest version No package vixie-cron available. Package crontabs-1.11-6.20121102git.el7.noarch already installed and latest version Package xz-devel-5.2.2-1.el7.x86_64 already installed and latest version Resolving Dependencies --> Running transaction check ---> Package bzip2-devel.x86_64 0:1.0.6-13.el7 will be installed ---> Package c-ares.x86_64 0:1.10.0-3.el7 will be installed ---> Package freetype-devel.x86_64 0:2.8-14.el7_9.1 will be installed ---> Package gdbm-devel.x86_64 0:1.10-8.el7 will be installed ---> Package icu.x86_64 0:50.2-4.el7_7 will be installed ---> Package libcurl-devel.x86_64 0:7.29.0-59.el7_9.1 will be installed epel/7/x86_64/filelists_db | 12 MB 00:00:01 os/7/x86_64/filelists_db | 7.2 MB 00:00:00 updates/7/x86_64/filelists_db | 7.2 MB 00:00:00 ---> Package libdb4-devel.x86_64 0:4.8.30-13.el7 will be installed --> Processing Dependency: libdb4(x86-64) = 4.8.30-13.el7 for package: libdb4-devel-4.8.30-13.el7.x86_64 ---> Package libffi-devel.x86_64 0:3.0.13-19.el7 will be installed ---> Package libicu-devel.x86_64 0:50.2-4.el7_7 will be installed ---> Package libjpeg-turbo-devel.x86_64 0:1.2.90-8.el7 will be installed ---> Package libpcap-devel.x86_64 14:1.5.3-12.el7 will be installed ---> Package libpng-devel.x86_64 2:1.5.13-8.el7 will be installed ---> Package libwebp-devel.x86_64 0:0.3.0-10.el7_9 will be installed ---> Package libxml2-devel.x86_64 0:2.9.1-6.el7_9.6 will be installed ---> Package libxslt.x86_64 0:1.1.28-6.el7 will be installed ---> Package libxslt-devel.x86_64 0:1.1.28-6.el7 will be installed --> Processing Dependency: libgcrypt-devel for package: libxslt-devel-1.1.28-6.el7.x86_64 ---> Package libxslt-python.x86_64 0:1.1.28-6.el7 will be installed ---> Package ncurses-devel.x86_64 0:5.9-14.20130511.el7_4 will be installed ---> Package openssl.x86_64 1:1.0.2k-22.el7_9 will be updated ---> Package openssl.x86_64 1:1.0.2k-24.el7_9 will be an update --> Processing Dependency: openssl-libs(x86-64) = 1:1.0.2k-24.el7_9 for package: 1:openssl-1.0.2k-24.el7_9.x86_64 ---> Package openssl-devel.x86_64 1:1.0.2k-22.el7_9 will be updated ---> Package openssl-devel.x86_64 1:1.0.2k-24.el7_9 will be an update ---> Package readline-devel.x86_64 0:6.2-11.el7 will be installed ---> Package sqlite-devel.x86_64 0:3.7.17-8.el7_7.1 will be installed ---> Package tk-devel.x86_64 1:8.5.13-6.el7 will be installed --> Processing Dependency: tcl-devel = 1:8.5.13 for package: 1:tk-devel-8.5.13-6.el7.x86_64 --> Processing Dependency: libXft-devel for package: 1:tk-devel-8.5.13-6.el7.x86_64 --> Processing Dependency: libX11-devel for package: 1:tk-devel-8.5.13-6.el7.x86_64 ---> Package unzip.x86_64 0:6.0-22.el7_9 will be updated ---> Package unzip.x86_64 0:6.0-24.el7_9 will be an update --> Running transaction check ---> Package libX11-devel.x86_64 0:1.6.7-4.el7_9 will be installed --> Processing Dependency: pkgconfig(xcb) >= 1.11.1 for package: libX11-devel-1.6.7-4.el7_9.x86_64 --> Processing Dependency: pkgconfig(xproto) for package: libX11-devel-1.6.7-4.el7_9.x86_64 --> Processing Dependency: pkgconfig(xcb) for package: libX11-devel-1.6.7-4.el7_9.x86_64 --> Processing Dependency: pkgconfig(kbproto) for package: libX11-devel-1.6.7-4.el7_9.x86_64 ---> Package libXft-devel.x86_64 0:2.3.2-2.el7 will be installed --> Processing Dependency: pkgconfig(xrender) for package: libXft-devel-2.3.2-2.el7.x86_64 --> Processing Dependency: pkgconfig(fontconfig) for package: libXft-devel-2.3.2-2.el7.x86_64 ---> Package libdb4.x86_64 0:4.8.30-13.el7 will be installed ---> Package libgcrypt-devel.x86_64 0:1.5.3-14.el7 will be installed --> Processing Dependency: libgpg-error-devel for package: libgcrypt-devel-1.5.3-14.el7.x86_64 ---> Package openssl-libs.x86_64 1:1.0.2k-22.el7_9 will be updated ---> Package openssl-libs.x86_64 1:1.0.2k-24.el7_9 will be an update ---> Package tcl-devel.x86_64 1:8.5.13-8.el7 will be installed --> Running transaction check ---> Package fontconfig-devel.x86_64 0:2.13.0-4.3.el7 will be installed --> Processing Dependency: pkgconfig(uuid) for package: fontconfig-devel-2.13.0-4.3.el7.x86_64 --> Processing Dependency: pkgconfig(expat) for package: fontconfig-devel-2.13.0-4.3.el7.x86_64 ---> Package libXrender-devel.x86_64 0:0.9.10-1.el7 will be installed ---> Package libgpg-error-devel.x86_64 0:1.12-3.el7 will be installed ---> Package libxcb-devel.x86_64 0:1.13-1.el7 will be installed --> Processing Dependency: pkgconfig(xau) >= 0.99.2 for package: libxcb-devel-1.13-1.el7.x86_64 ---> Package xorg-x11-proto-devel.noarch 0:2018.4-1.el7 will be installed --> Running transaction check ---> Package expat-devel.x86_64 0:2.1.0-12.el7 will be installed ---> Package libXau-devel.x86_64 0:1.0.8-2.1.el7 will be installed ---> Package libuuid-devel.x86_64 0:2.23.2-65.el7_9.1 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================================================================================== Package Arch Version Repository Size ================================================================================================================================================== Installing: bzip2-devel x86_64 1.0.6-13.el7 os 218 k c-ares x86_64 1.10.0-3.el7 os 78 k freetype-devel x86_64 2.8-14.el7_9.1 updates 447 k gdbm-devel x86_64 1.10-8.el7 os 47 k icu x86_64 50.2-4.el7_7 os 187 k libcurl-devel x86_64 7.29.0-59.el7_9.1 updates 303 k libdb4-devel x86_64 4.8.30-13.el7 epel 32 k libffi-devel x86_64 3.0.13-19.el7 os 23 k libicu-devel x86_64 50.2-4.el7_7 os 703 k libjpeg-turbo-devel x86_64 1.2.90-8.el7 os 99 k libpcap-devel x86_64 14:1.5.3-12.el7 os 118 k libpng-devel x86_64 2:1.5.13-8.el7 os 122 k libwebp-devel x86_64 0.3.0-10.el7_9 updates 23 k libxml2-devel x86_64 2.9.1-6.el7_9.6 updates 1.1 M libxslt x86_64 1.1.28-6.el7 os 242 k libxslt-devel x86_64 1.1.28-6.el7 os 309 k libxslt-python x86_64 1.1.28-6.el7 os 59 k ncurses-devel x86_64 5.9-14.20130511.el7_4 os 712 k readline-devel x86_64 6.2-11.el7 os 139 k sqlite-devel x86_64 3.7.17-8.el7_7.1 os 104 k tk-devel x86_64 1:8.5.13-6.el7 os 488 k Updating: openssl x86_64 1:1.0.2k-24.el7_9 updates 494 k openssl-devel x86_64 1:1.0.2k-24.el7_9 updates 1.5 M unzip x86_64 6.0-24.el7_9 updates 172 k Installing for dependencies: expat-devel x86_64 2.1.0-12.el7 os 57 k fontconfig-devel x86_64 2.13.0-4.3.el7 os 138 k libX11-devel x86_64 1.6.7-4.el7_9 updates 981 k libXau-devel x86_64 1.0.8-2.1.el7 os 14 k libXft-devel x86_64 2.3.2-2.el7 os 19 k libXrender-devel x86_64 0.9.10-1.el7 os 17 k libdb4 x86_64 4.8.30-13.el7 epel 607 k libgcrypt-devel x86_64 1.5.3-14.el7 os 129 k libgpg-error-devel x86_64 1.12-3.el7 os 16 k libuuid-devel x86_64 2.23.2-65.el7_9.1 updates 93 k libxcb-devel x86_64 1.13-1.el7 os 1.1 M tcl-devel x86_64 1:8.5.13-8.el7 os 165 k xorg-x11-proto-devel noarch 2018.4-1.el7 os 280 k Updating for dependencies: openssl-libs x86_64 1:1.0.2k-24.el7_9 updates 1.2 M Transaction Summary ================================================================================================================================================== Install 21 Packages (+13 Dependent packages) Upgrade 3 Packages (+ 1 Dependent package) Total download size: 12 M Downloading packages: No Presto metadata available for updates (1/38): c-ares-1.10.0-3.el7.x86_64.rpm | 78 kB 00:00:00 (2/38): bzip2-devel-1.0.6-13.el7.x86_64.rpm | 218 kB 00:00:00 (3/38): expat-devel-2.1.0-12.el7.x86_64.rpm | 57 kB 00:00:00 (4/38): gdbm-devel-1.10-8.el7.x86_64.rpm | 47 kB 00:00:00 (5/38): fontconfig-devel-2.13.0-4.3.el7.x86_64.rpm | 138 kB 00:00:00 (6/38): libXau-devel-1.0.8-2.1.el7.x86_64.rpm | 14 kB 00:00:00 (7/38): libXft-devel-2.3.2-2.el7.x86_64.rpm | 19 kB 00:00:00 (8/38): icu-50.2-4.el7_7.x86_64.rpm | 187 kB 00:00:00 (9/38): freetype-devel-2.8-14.el7_9.1.x86_64.rpm | 447 kB 00:00:00 (10/38): libXrender-devel-0.9.10-1.el7.x86_64.rpm | 17 kB 00:00:00 (11/38): libffi-devel-3.0.13-19.el7.x86_64.rpm | 23 kB 00:00:00 (12/38): libX11-devel-1.6.7-4.el7_9.x86_64.rpm | 981 kB 00:00:00 (13/38): libdb4-devel-4.8.30-13.el7.x86_64.rpm | 32 kB 00:00:00 (14/38): libgpg-error-devel-1.12-3.el7.x86_64.rpm | 16 kB 00:00:00 (15/38): libgcrypt-devel-1.5.3-14.el7.x86_64.rpm | 129 kB 00:00:00 (16/38): libcurl-devel-7.29.0-59.el7_9.1.x86_64.rpm | 303 kB 00:00:00 (17/38): libdb4-4.8.30-13.el7.x86_64.rpm | 607 kB 00:00:00 (18/38): libjpeg-turbo-devel-1.2.90-8.el7.x86_64.rpm | 99 kB 00:00:00 (19/38): libicu-devel-50.2-4.el7_7.x86_64.rpm | 703 kB 00:00:00 (20/38): libpcap-devel-1.5.3-12.el7.x86_64.rpm | 118 kB 00:00:00 (21/38): libwebp-devel-0.3.0-10.el7_9.x86_64.rpm | 23 kB 00:00:00 (22/38): libpng-devel-1.5.13-8.el7.x86_64.rpm | 122 kB 00:00:00 (23/38): libuuid-devel-2.23.2-65.el7_9.1.x86_64.rpm | 93 kB 00:00:00 (24/38): libxslt-1.1.28-6.el7.x86_64.rpm | 242 kB 00:00:00 (25/38): libxcb-devel-1.13-1.el7.x86_64.rpm | 1.1 MB 00:00:00 (26/38): libxml2-devel-2.9.1-6.el7_9.6.x86_64.rpm | 1.1 MB 00:00:00 (27/38): libxslt-python-1.1.28-6.el7.x86_64.rpm | 59 kB 00:00:00 (28/38): libxslt-devel-1.1.28-6.el7.x86_64.rpm | 309 kB 00:00:00 (29/38): openssl-1.0.2k-24.el7_9.x86_64.rpm | 494 kB 00:00:00 (30/38): ncurses-devel-5.9-14.20130511.el7_4.x86_64.rpm | 712 kB 00:00:00 (31/38): openssl-devel-1.0.2k-24.el7_9.x86_64.rpm | 1.5 MB 00:00:00 (32/38): sqlite-devel-3.7.17-8.el7_7.1.x86_64.rpm | 104 kB 00:00:00 (33/38): readline-devel-6.2-11.el7.x86_64.rpm | 139 kB 00:00:00 (34/38): tcl-devel-8.5.13-8.el7.x86_64.rpm | 165 kB 00:00:00 (35/38): openssl-libs-1.0.2k-24.el7_9.x86_64.rpm | 1.2 MB 00:00:00 (36/38): unzip-6.0-24.el7_9.x86_64.rpm | 172 kB 00:00:00 (37/38): xorg-x11-proto-devel-2018.4-1.el7.noarch.rpm | 280 kB 00:00:00 (38/38): tk-devel-8.5.13-6.el7.x86_64.rpm | 488 kB 00:00:00 -------------------------------------------------------------------------------------------------------------------------------------------------- Total 4.3 MB/s | 12 MB 00:00:02 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : xorg-x11-proto-devel-2018.4-1.el7.noarch 1/42 Installing : libxslt-1.1.28-6.el7.x86_64 2/42 Updating : 1:openssl-libs-1.0.2k-24.el7_9.x86_64 3/42 Installing : libXau-devel-1.0.8-2.1.el7.x86_64 4/42 Installing : libxcb-devel-1.13-1.el7.x86_64 5/42 Installing : libX11-devel-1.6.7-4.el7_9.x86_64 6/42 Installing : libXrender-devel-0.9.10-1.el7.x86_64 7/42 Installing : 1:tcl-devel-8.5.13-8.el7.x86_64 8/42 Installing : libdb4-4.8.30-13.el7.x86_64 9/42 Installing : libgpg-error-devel-1.12-3.el7.x86_64 10/42 Installing : libgcrypt-devel-1.5.3-14.el7.x86_64 11/42 Installing : expat-devel-2.1.0-12.el7.x86_64 12/42 Installing : ncurses-devel-5.9-14.20130511.el7_4.x86_64 13/42 Installing : libuuid-devel-2.23.2-65.el7_9.1.x86_64 14/42 Installing : libxml2-devel-2.9.1-6.el7_9.6.x86_64 15/42 Installing : 2:libpng-devel-1.5.13-8.el7.x86_64 16/42 Installing : freetype-devel-2.8-14.el7_9.1.x86_64 17/42 Installing : fontconfig-devel-2.13.0-4.3.el7.x86_64 18/42 Installing : libXft-devel-2.3.2-2.el7.x86_64 19/42 Installing : 1:tk-devel-8.5.13-6.el7.x86_64 20/42 Installing : libxslt-devel-1.1.28-6.el7.x86_64 21/42 Installing : readline-devel-6.2-11.el7.x86_64 22/42 Installing : libdb4-devel-4.8.30-13.el7.x86_64 23/42 Updating : 1:openssl-devel-1.0.2k-24.el7_9.x86_64 24/42 Updating : 1:openssl-1.0.2k-24.el7_9.x86_64 25/42 Installing : libxslt-python-1.1.28-6.el7.x86_64 26/42 Installing : sqlite-devel-3.7.17-8.el7_7.1.x86_64 27/42 Installing : libcurl-devel-7.29.0-59.el7_9.1.x86_64 28/42 Installing : icu-50.2-4.el7_7.x86_64 29/42 Installing : libwebp-devel-0.3.0-10.el7_9.x86_64 30/42 Installing : c-ares-1.10.0-3.el7.x86_64 31/42 Installing : bzip2-devel-1.0.6-13.el7.x86_64 32/42 Installing : gdbm-devel-1.10-8.el7.x86_64 33/42 Installing : 14:libpcap-devel-1.5.3-12.el7.x86_64 34/42 Updating : unzip-6.0-24.el7_9.x86_64 35/42 Installing : libffi-devel-3.0.13-19.el7.x86_64 36/42 Installing : libicu-devel-50.2-4.el7_7.x86_64 37/42 Installing : libjpeg-turbo-devel-1.2.90-8.el7.x86_64 38/42 Cleanup : 1:openssl-devel-1.0.2k-22.el7_9.x86_64 39/42 Cleanup : 1:openssl-1.0.2k-22.el7_9.x86_64 40/42 Cleanup : 1:openssl-libs-1.0.2k-22.el7_9.x86_64 41/42 Cleanup : unzip-6.0-22.el7_9.x86_64 42/42 Verifying : libXft-devel-2.3.2-2.el7.x86_64 1/42 Verifying : 2:libpng-devel-1.5.13-8.el7.x86_64 2/42 Verifying : libxslt-python-1.1.28-6.el7.x86_64 3/42 Verifying : libxml2-devel-2.9.1-6.el7_9.6.x86_64 4/42 Verifying : libjpeg-turbo-devel-1.2.90-8.el7.x86_64 5/42 Verifying : 1:openssl-libs-1.0.2k-24.el7_9.x86_64 6/42 Verifying : libicu-devel-50.2-4.el7_7.x86_64 7/42 Verifying : libffi-devel-3.0.13-19.el7.x86_64 8/42 Verifying : unzip-6.0-24.el7_9.x86_64 9/42 Verifying : libuuid-devel-2.23.2-65.el7_9.1.x86_64 10/42 Verifying : libdb4-devel-4.8.30-13.el7.x86_64 11/42 Verifying : 14:libpcap-devel-1.5.3-12.el7.x86_64 12/42 Verifying : gdbm-devel-1.10-8.el7.x86_64 13/42 Verifying : bzip2-devel-1.0.6-13.el7.x86_64 14/42 Verifying : fontconfig-devel-2.13.0-4.3.el7.x86_64 15/42 Verifying : 1:openssl-devel-1.0.2k-24.el7_9.x86_64 16/42 Verifying : libxslt-devel-1.1.28-6.el7.x86_64 17/42 Verifying : ncurses-devel-5.9-14.20130511.el7_4.x86_64 18/42 Verifying : readline-devel-6.2-11.el7.x86_64 19/42 Verifying : libX11-devel-1.6.7-4.el7_9.x86_64 20/42 Verifying : 1:tk-devel-8.5.13-6.el7.x86_64 21/42 Verifying : c-ares-1.10.0-3.el7.x86_64 22/42 Verifying : 1:openssl-1.0.2k-24.el7_9.x86_64 23/42 Verifying : xorg-x11-proto-devel-2018.4-1.el7.noarch 24/42 Verifying : libXrender-devel-0.9.10-1.el7.x86_64 25/42 Verifying : libwebp-devel-0.3.0-10.el7_9.x86_64 26/42 Verifying : icu-50.2-4.el7_7.x86_64 27/42 Verifying : freetype-devel-2.8-14.el7_9.1.x86_64 28/42 Verifying : libgcrypt-devel-1.5.3-14.el7.x86_64 29/42 Verifying : libcurl-devel-7.29.0-59.el7_9.1.x86_64 30/42 Verifying : expat-devel-2.1.0-12.el7.x86_64 31/42 Verifying : libxcb-devel-1.13-1.el7.x86_64 32/42 Verifying : sqlite-devel-3.7.17-8.el7_7.1.x86_64 33/42 Verifying : libxslt-1.1.28-6.el7.x86_64 34/42 Verifying : libgpg-error-devel-1.12-3.el7.x86_64 35/42 Verifying : libdb4-4.8.30-13.el7.x86_64 36/42 Verifying : 1:tcl-devel-8.5.13-8.el7.x86_64 37/42 Verifying : libXau-devel-1.0.8-2.1.el7.x86_64 38/42 Verifying : 1:openssl-1.0.2k-22.el7_9.x86_64 39/42 Verifying : 1:openssl-devel-1.0.2k-22.el7_9.x86_64 40/42 Verifying : 1:openssl-libs-1.0.2k-22.el7_9.x86_64 41/42 Verifying : unzip-6.0-22.el7_9.x86_64 42/42 Installed: bzip2-devel.x86_64 0:1.0.6-13.el7 c-ares.x86_64 0:1.10.0-3.el7 freetype-devel.x86_64 0:2.8-14.el7_9.1 gdbm-devel.x86_64 0:1.10-8.el7 icu.x86_64 0:50.2-4.el7_7 libcurl-devel.x86_64 0:7.29.0-59.el7_9.1 libdb4-devel.x86_64 0:4.8.30-13.el7 libffi-devel.x86_64 0:3.0.13-19.el7 libicu-devel.x86_64 0:50.2-4.el7_7 libjpeg-turbo-devel.x86_64 0:1.2.90-8.el7 libpcap-devel.x86_64 14:1.5.3-12.el7 libpng-devel.x86_64 2:1.5.13-8.el7 libwebp-devel.x86_64 0:0.3.0-10.el7_9 libxml2-devel.x86_64 0:2.9.1-6.el7_9.6 libxslt.x86_64 0:1.1.28-6.el7 libxslt-devel.x86_64 0:1.1.28-6.el7 libxslt-python.x86_64 0:1.1.28-6.el7 ncurses-devel.x86_64 0:5.9-14.20130511.el7_4 readline-devel.x86_64 0:6.2-11.el7 sqlite-devel.x86_64 0:3.7.17-8.el7_7.1 tk-devel.x86_64 1:8.5.13-6.el7 Dependency Installed: expat-devel.x86_64 0:2.1.0-12.el7 fontconfig-devel.x86_64 0:2.13.0-4.3.el7 libX11-devel.x86_64 0:1.6.7-4.el7_9 libXau-devel.x86_64 0:1.0.8-2.1.el7 libXft-devel.x86_64 0:2.3.2-2.el7 libXrender-devel.x86_64 0:0.9.10-1.el7 libdb4.x86_64 0:4.8.30-13.el7 libgcrypt-devel.x86_64 0:1.5.3-14.el7 libgpg-error-devel.x86_64 0:1.12-3.el7 libuuid-devel.x86_64 0:2.23.2-65.el7_9.1 libxcb-devel.x86_64 0:1.13-1.el7 tcl-devel.x86_64 1:8.5.13-8.el7 xorg-x11-proto-devel.noarch 0:2018.4-1.el7 Updated: openssl.x86_64 1:1.0.2k-24.el7_9 openssl-devel.x86_64 1:1.0.2k-24.el7_9 unzip.x86_64 0:6.0-24.el7_9 Dependency Updated: openssl-libs.x86_64 1:1.0.2k-24.el7_9 Complete! Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Package libxslt-1.1.28-6.el7.x86_64 already installed and latest version Package libxslt-devel-1.1.28-6.el7.x86_64 already installed and latest version Package libxslt-python-1.1.28-6.el7.x86_64 already installed and latest version Nothing to do Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Package libjpeg-turbo-devel-1.2.90-8.el7.x86_64 already installed and latest version Nothing to do Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile No package vixie-cron available. Error: Nothing to do Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Package libdb4-devel-4.8.30-13.el7.x86_64 already installed and latest version Nothing to do Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Resolving Dependencies --> Running transaction check ---> Package epel-release.noarch 0:7-14 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================================================================================== Package Arch Version Repository Size ================================================================================================================================================== Installing: epel-release noarch 7-14 epel 15 k Transaction Summary ================================================================================================================================================== Install 1 Package Total download size: 15 k Installed size: 25 k Downloading packages: epel-release-7-14.noarch.rpm | 15 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : epel-release-7-14.noarch 1/1 Verifying : epel-release-7-14.noarch 1/1 Installed: epel-release.noarch 0:7-14 Complete! https://mirrors.tencent.com/pypi/simple cat: /etc/.productinfo: No such file or directory OS: el - 7 --2022-01-21 16:17:30-- http://dg2.bt.cn/install/pyenv/pyenv-el7-x64.tar.gz Resolving dg2.bt.cn (dg2.bt.cn)... 116.10.184.219, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|116.10.184.219|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 73258911 (70M) [application/octet-stream] Saving to: ‘/www/pyenv.tar.gz’ 100%[========================================================================================================>] 73,258,911 10.0MB/s in 7.2s 2022-01-21 16:17:37 (9.68 MB/s) - ‘/www/pyenv.tar.gz’ saved [73258911/73258911] Install python env... Python 3.7.9 --2022-01-21 16:17:40-- http://dg2.bt.cn/install/src/bt6.init Resolving dg2.bt.cn (dg2.bt.cn)... 116.10.184.219, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|116.10.184.219|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 9873 (9.6K) [application/octet-stream] Saving to: ‘/etc/init.d/bt’ 100%[========================================================================================================>] 9,873 --.-K/s in 0s 2022-01-21 16:17:40 (229 MB/s) - ‘/etc/init.d/bt’ saved [9873/9873] --2022-01-21 16:17:40-- http://dg2.bt.cn/install/public.sh Resolving dg2.bt.cn (dg2.bt.cn)... 42.157.129.47, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|42.157.129.47|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 4267 (4.2K) [application/octet-stream] Saving to: ‘/www/server/panel/install/public.sh’ 100%[========================================================================================================>] 4,267 --.-K/s in 0s 2022-01-21 16:17:40 (419 MB/s) - ‘/www/server/panel/install/public.sh’ saved [4267/4267] --2022-01-21 16:17:40-- http://dg2.bt.cn/install/src/panel6.zip Resolving dg2.bt.cn (dg2.bt.cn)... 42.157.129.47, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|42.157.129.47|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 9230063 (8.8M) [application/zip] Saving to: ‘panel.zip’ 100%[========================================================================================================>] 9,230,063 24.7MB/s in 0.4s 2022-01-21 16:17:40 (24.7 MB/s) - ‘panel.zip’ saved [9230063/9230063] --2022-01-21 16:17:40-- http://dg2.bt.cn/install/src/bt7.init Resolving dg2.bt.cn (dg2.bt.cn)... 42.157.129.47, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|42.157.129.47|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 10438 (10K) [application/octet-stream] Saving to: ‘/etc/init.d/bt’ 100%[========================================================================================================>] 10,438 --.-K/s in 0s 2022-01-21 16:17:41 (238 MB/s) - ‘/etc/init.d/bt’ saved [10438/10438] --2022-01-21 16:17:41-- http://dg2.bt.cn/install/src/bt7.init Resolving dg2.bt.cn (dg2.bt.cn)... 42.157.129.47, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|42.157.129.47|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 10438 (10K) [application/octet-stream] Saving to: ‘/www/server/panel/init.sh’ 100%[========================================================================================================>] 10,438 --.-K/s in 0.006s 2022-01-21 16:17:41 (1.68 MB/s) - ‘/www/server/panel/init.sh’ saved [10438/10438] --2022-01-21 16:17:41-- http://dg2.bt.cn/install/conf/softList.conf Resolving dg2.bt.cn (dg2.bt.cn)... 116.10.184.219, 240e:a5:4200:89::143 Connecting to dg2.bt.cn (dg2.bt.cn)|116.10.184.219|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 3287 (3.2K) [application/octet-stream] Saving to: ‘/www/server/panel/data/softList.conf’ 100%[========================================================================================================>] 3,287 --.-K/s in 0s 2022-01-21 16:17:41 (348 MB/s) - ‘/www/server/panel/data/softList.conf’ saved [3287/3287] Starting Bt-Panel.... done Starting Bt-Tasks... done username: t1c2mbup Stopping Bt-Tasks... done Stopping Bt-Panel... done Starting Bt-Panel.... done Starting Bt-Tasks... done Loaded plugins: fastestmirror, langpacks Repository epel is listed more than once in the configuration Loading mirror speeds from cached hostfile Package firewalld-0.6.3-13.el7_9.noarch already installed and latest version Nothing to do Created symlink from /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service to /usr/lib/systemd/system/firewalld.service. Created symlink from /etc/systemd/system/multi-user.target.wants/firewalld.service to /usr/lib/systemd/system/firewalld.service. success ================================================================== Congratulations! Installed successfully! ================================================================== 外网面板地址: http://110.40.150.131:8888/ac9859fb 内网面板地址: http://172.17.16.6:8888/ac9859fb username: t1c2mbup password: b6abed29 If you cannot access the panel, release the following panel port [8888] in the security group 若无法访问面板,请检查防火墙/安全组是否有放行面板[8888]端口 ================================================================== Time consumed: 1 Minute! [root@VM-16-6-centos wldata]# 根据安装成功的登录信息登录宝塔面板并重置相关登录信息
2022年01月21日
107 阅读
0 评论
0 点赞
2022-01-21
自动化项目部署系列:②部署Docker
容器化部署技术在自动化部署过程中有着举足轻重的位置,本章将讲解docker的安装部署。安装过程主要参考 docker官网的文档:https://docs.docker.com/engine/install/centos/安装相关依赖sudo yum install -y yum-utils显示信息如下:[zhuzl@VM-16-6-centos /]$ sudo yum install -y yum-utils Loaded plugins: fastestmirror, langpacks Determining fastest mirrors epel | 4.7 kB 00:00:00 extras | 2.9 kB 00:00:00 os | 3.6 kB 00:00:00 updates | 2.9 kB 00:00:00 (1/3): epel/7/x86_64/updateinfo | 1.0 MB 00:00:00 (2/3): updates/7/x86_64/primary_db | 13 MB 00:00:00 (3/3): epel/7/x86_64/primary_db | 7.0 MB 00:00:01 Package yum-utils-1.1.31-54.el7_8.noarch already installed and latest version Nothing to do设置yum 仓库sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo显示显示如下:[zhuzl@VM-16-6-centos /]$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo Loaded plugins: fastestmirror, langpacks adding repo from: https://download.docker.com/linux/centos/docker-ce.repo grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo repo saved to /etc/yum.repos.d/docker-ce.repo 安装 Docker[zhuzl@VM-16-6-centos /]$ sudo yum install docker-ce docker-ce-cli containerd.io Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile docker-ce-stable | 3.5 kB 00:00:00 (1/2): docker-ce-stable/7/x86_64/primary_db | 70 kB 00:00:00 (2/2): docker-ce-stable/7/x86_64/updateinfo | 55 B 00:00:01 Resolving Dependencies --> Running transaction check ---> Package containerd.io.x86_64 0:1.4.12-3.1.el7 will be installed --> Processing Dependency: container-selinux >= 2:2.74 for package: containerd.io-1.4.12-3.1.el7.x86_64 ---> Package docker-ce.x86_64 3:20.10.12-3.el7 will be installed --> Processing Dependency: docker-ce-rootless-extras for package: 3:docker-ce-20.10.12-3.el7.x86_64 --> Processing Dependency: libcgroup for package: 3:docker-ce-20.10.12-3.el7.x86_64 ---> Package docker-ce-cli.x86_64 1:20.10.12-3.el7 will be installed --> Processing Dependency: docker-scan-plugin(x86-64) for package: 1:docker-ce-cli-20.10.12-3.el7.x86_64 --> Running transaction check ---> Package container-selinux.noarch 2:2.119.2-1.911c772.el7_8 will be installed --> Processing Dependency: policycoreutils-python for package: 2:container-selinux-2.119.2-1.911c772.el7_8.noarch ---> Package docker-ce-rootless-extras.x86_64 0:20.10.12-3.el7 will be installed --> Processing Dependency: fuse-overlayfs >= 0.7 for package: docker-ce-rootless-extras-20.10.12-3.el7.x86_64 --> Processing Dependency: slirp4netns >= 0.4 for package: docker-ce-rootless-extras-20.10.12-3.el7.x86_64 ---> Package docker-scan-plugin.x86_64 0:0.12.0-3.el7 will be installed ---> Package libcgroup.x86_64 0:0.41-21.el7 will be installed --> Running transaction check ---> Package fuse-overlayfs.x86_64 0:0.7.2-6.el7_8 will be installed --> Processing Dependency: libfuse3.so.3(FUSE_3.2)(64bit) for package: fuse-overlayfs-0.7.2-6.el7_8.x86_64 --> Processing Dependency: libfuse3.so.3(FUSE_3.0)(64bit) for package: fuse-overlayfs-0.7.2-6.el7_8.x86_64 --> Processing Dependency: libfuse3.so.3()(64bit) for package: fuse-overlayfs-0.7.2-6.el7_8.x86_64 ---> Package policycoreutils-python.x86_64 0:2.5-34.el7 will be installed --> Processing Dependency: setools-libs >= 3.3.8-4 for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libsemanage-python >= 2.5-14 for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: audit-libs-python >= 2.1.3-4 for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: python-IPy for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libqpol.so.1(VERS_1.4)(64bit) for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libqpol.so.1(VERS_1.2)(64bit) for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libapol.so.4(VERS_4.0)(64bit) for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: checkpolicy for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libqpol.so.1()(64bit) for package: policycoreutils-python-2.5-34.el7.x86_64 --> Processing Dependency: libapol.so.4()(64bit) for package: policycoreutils-python-2.5-34.el7.x86_64 ---> Package slirp4netns.x86_64 0:0.4.3-4.el7_8 will be installed --> Running transaction check ---> Package audit-libs-python.x86_64 0:2.8.5-4.el7 will be installed ---> Package checkpolicy.x86_64 0:2.5-8.el7 will be installed ---> Package fuse3-libs.x86_64 0:3.6.1-4.el7 will be installed ---> Package libsemanage-python.x86_64 0:2.5-14.el7 will be installed ---> Package python-IPy.noarch 0:0.75-6.el7 will be installed ---> Package setools-libs.x86_64 0:3.3.8-4.el7 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================================================================================== Package Arch Version Repository Size ================================================================================================================================================== Installing: containerd.io x86_64 1.4.12-3.1.el7 docker-ce-stable 28 M docker-ce x86_64 3:20.10.12-3.el7 docker-ce-stable 23 M docker-ce-cli x86_64 1:20.10.12-3.el7 docker-ce-stable 30 M Installing for dependencies: audit-libs-python x86_64 2.8.5-4.el7 os 76 k checkpolicy x86_64 2.5-8.el7 os 295 k container-selinux noarch 2:2.119.2-1.911c772.el7_8 extras 40 k docker-ce-rootless-extras x86_64 20.10.12-3.el7 docker-ce-stable 8.0 M docker-scan-plugin x86_64 0.12.0-3.el7 docker-ce-stable 3.7 M fuse-overlayfs x86_64 0.7.2-6.el7_8 extras 54 k fuse3-libs x86_64 3.6.1-4.el7 extras 82 k libcgroup x86_64 0.41-21.el7 os 66 k libsemanage-python x86_64 2.5-14.el7 os 113 k policycoreutils-python x86_64 2.5-34.el7 os 457 k python-IPy noarch 0.75-6.el7 os 32 k setools-libs x86_64 3.3.8-4.el7 os 620 k slirp4netns x86_64 0.4.3-4.el7_8 extras 81 k Transaction Summary ================================================================================================================================================== Install 3 Packages (+13 Dependent packages) Total download size: 95 M Installed size: 387 M Is this ok [y/d/N]: y Downloading packages: (1/16): container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm | 40 kB 00:00:00 (2/16): audit-libs-python-2.8.5-4.el7.x86_64.rpm | 76 kB 00:00:00 (3/16): checkpolicy-2.5-8.el7.x86_64.rpm | 295 kB 00:00:00 warning: /var/cache/yum/x86_64/7/docker-ce-stable/packages/docker-ce-20.10.12-3.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY Public key for docker-ce-20.10.12-3.el7.x86_64.rpm is not installed (4/16): docker-ce-20.10.12-3.el7.x86_64.rpm | 23 MB 00:03:30 (5/16): containerd.io-1.4.12-3.1.el7.x86_64.rpm | 28 MB 00:11:41 (6/16): docker-ce-rootless-extras-20.10.12-3.el7.x86_64.rpm | 8.0 MB 00:02:47 (7/16): fuse-overlayfs-0.7.2-6.el7_8.x86_64.rpm | 54 kB 00:00:00 (8/16): fuse3-libs-3.6.1-4.el7.x86_64.rpm | 82 kB 00:00:00 (9/16): libcgroup-0.41-21.el7.x86_64.rpm | 66 kB 00:00:00 (10/16): libsemanage-python-2.5-14.el7.x86_64.rpm | 113 kB 00:00:00 (11/16): python-IPy-0.75-6.el7.noarch.rpm | 32 kB 00:00:00 (12/16): policycoreutils-python-2.5-34.el7.x86_64.rpm | 457 kB 00:00:00 (13/16): slirp4netns-0.4.3-4.el7_8.x86_64.rpm | 81 kB 00:00:00 (14/16): setools-libs-3.3.8-4.el7.x86_64.rpm | 620 kB 00:00:00 (15/16): docker-scan-plugin-0.12.0-3.el7.x86_64.rpm | 3.7 MB 00:00:48 (16/16): docker-ce-cli-20.10.12-3.el7.x86_64.rpm | 30 MB 00:15:19 -------------------------------------------------------------------------------------------------------------------------------------------------- Total 86 kB/s | 95 MB 00:18:49 Retrieving key from https://download.docker.com/linux/centos/gpg Importing GPG key 0x621E9F35: Userid : "Docker Release (CE rpm) <docker@docker.com>" Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35 From : https://download.docker.com/linux/centos/gpg Is this ok [y/N]: y Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : docker-scan-plugin-0.12.0-3.el7.x86_64 1/16 Installing : 1:docker-ce-cli-20.10.12-3.el7.x86_64 2/16 Installing : libcgroup-0.41-21.el7.x86_64 3/16 Installing : setools-libs-3.3.8-4.el7.x86_64 4/16 Installing : audit-libs-python-2.8.5-4.el7.x86_64 5/16 Installing : python-IPy-0.75-6.el7.noarch 6/16 Installing : slirp4netns-0.4.3-4.el7_8.x86_64 7/16 Installing : libsemanage-python-2.5-14.el7.x86_64 8/16 Installing : fuse3-libs-3.6.1-4.el7.x86_64 9/16 Installing : fuse-overlayfs-0.7.2-6.el7_8.x86_64 10/16 Installing : checkpolicy-2.5-8.el7.x86_64 11/16 Installing : policycoreutils-python-2.5-34.el7.x86_64 12/16 Installing : 2:container-selinux-2.119.2-1.911c772.el7_8.noarch 13/16 setsebool: SELinux is disabled. Installing : containerd.io-1.4.12-3.1.el7.x86_64 14/16 Installing : docker-ce-rootless-extras-20.10.12-3.el7.x86_64 15/16 Installing : 3:docker-ce-20.10.12-3.el7.x86_64 16/16 Verifying : checkpolicy-2.5-8.el7.x86_64 1/16 Verifying : fuse3-libs-3.6.1-4.el7.x86_64 2/16 Verifying : 1:docker-ce-cli-20.10.12-3.el7.x86_64 3/16 Verifying : fuse-overlayfs-0.7.2-6.el7_8.x86_64 4/16 Verifying : libsemanage-python-2.5-14.el7.x86_64 5/16 Verifying : docker-scan-plugin-0.12.0-3.el7.x86_64 6/16 Verifying : slirp4netns-0.4.3-4.el7_8.x86_64 7/16 Verifying : 2:container-selinux-2.119.2-1.911c772.el7_8.noarch 8/16 Verifying : python-IPy-0.75-6.el7.noarch 9/16 Verifying : policycoreutils-python-2.5-34.el7.x86_64 10/16 Verifying : audit-libs-python-2.8.5-4.el7.x86_64 11/16 Verifying : docker-ce-rootless-extras-20.10.12-3.el7.x86_64 12/16 Verifying : containerd.io-1.4.12-3.1.el7.x86_64 13/16 Verifying : setools-libs-3.3.8-4.el7.x86_64 14/16 Verifying : 3:docker-ce-20.10.12-3.el7.x86_64 15/16 Verifying : libcgroup-0.41-21.el7.x86_64 16/16 Installed: containerd.io.x86_64 0:1.4.12-3.1.el7 docker-ce.x86_64 3:20.10.12-3.el7 docker-ce-cli.x86_64 1:20.10.12-3.el7 Dependency Installed: audit-libs-python.x86_64 0:2.8.5-4.el7 checkpolicy.x86_64 0:2.5-8.el7 container-selinux.noarch 2:2.119.2-1.911c772.el7_8 docker-ce-rootless-extras.x86_64 0:20.10.12-3.el7 docker-scan-plugin.x86_64 0:0.12.0-3.el7 fuse-overlayfs.x86_64 0:0.7.2-6.el7_8 fuse3-libs.x86_64 0:3.6.1-4.el7 libcgroup.x86_64 0:0.41-21.el7 libsemanage-python.x86_64 0:2.5-14.el7 policycoreutils-python.x86_64 0:2.5-34.el7 python-IPy.noarch 0:0.75-6.el7 setools-libs.x86_64 0:3.3.8-4.el7 slirp4netns.x86_64 0:0.4.3-4.el7_8 Complete! 启动 Docker 并配置自启动启动Dockersudo systemctl start docker设置开机自启动# 检查docker版本 [zhuzl@VM-16-6-centos wldata]$ docker -v Docker version 20.10.12, build e91ed57 # 查看docker已有镜像 [zhuzl@VM-16-6-centos wldata]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE # 设置docker开机启动 [zhuzl@VM-16-6-centos wldata]$ sudo systemctl enable docker Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service. [zhuzl@VM-16-6-centos wldata]$ 一些配置使用阿里云配置镜像加速sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://9643wkwg.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker安装portainer链接地址:https://docs.portainer.io/v/ce-2.11/start/install/server/docker/linux安装命令# 创建portainer挂载镜像 sudo docker volume create portainer_data # 查看磁盘卷信息 sudo docker inspect portainer_data # docker方式运行portainer sudo docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.11.0可以使用nginx代理9000端口端外提供服务
2022年01月21日
126 阅读
0 评论
0 点赞
2022-01-21
自动化项目部署系列:①环境准备
以前的项目有基于 devops 的方式来实现项目的开发、测试、上线部署,零零散散在带团队的过程中也有过一些尝试,但是一直没时间系统性的实践过。本次新购一台云服务器,准备进行一次实践。服务器在腾讯云上买的4H8G5M的配置,在这一台上部署相关的环境可能会很吃力,不过咱们也就基于学习研究的目的,够用就行。一、解析泛域名到云服务器系统安装完毕,为便于后续对外提供服务,我们先解析一个泛域名到这台服务器上,我注册的域名都在DNSPOD上管理,所以就在DNSPOD上配置了:解析配置好后,*.test.wljy.xyz都将被解析到 110.40.150.131 这个IP.二、初始配置服务器添加普通权限用户此处添加 zhuzl 用户,并为该用户设置登录密码:[root@VM-16-6-centos ~]# useradd zhuzl [root@VM-16-6-centos ~]# passwd zhuzl Changing password for user zhuzl. New password: Retype new password: passwd: all authentication tokens updated successfully.将用户添加到soduers/etc/sudoers文件添加写权限[root@VM-16-6-centos ~]# chmod +w /etc/sudoers编辑 /etc/sudoers[root@VM-16-6-centos ~]# vi /etc/sudoers找到 root ALL=(ALL) ALL 并在其下一行添加如下信息:zhuzl ALL=(ALL) NOPASSWD: ALL调整后的效果截图:取消/etc/sudoers 的写权限[root@VM-16-6-centos ~]# chmod -w /etc/sudoers创建数据目录并授权[root@VM-16-6-centos /]# mkdir /wldata [root@VM-16-6-centos /]# chown -R zhuzl:zhuzl /wldata/ 切换为普通用户[root@VM-16-6-centos /]# su zhuzl使用普通用户执行后续的安装操作,相关操作见后续章节。
2022年01月21日
82 阅读
0 评论
0 点赞
2021-12-29
初入职场注意事项
今天一个前不久离职的同事找到我聊聊天,刚加入了一家新公司,很多东西都不懂,同事关系处理的不是很好,之前经常看我的文章,想知道有没有什么技巧,可以更快学到东西,不用依靠同事,快速获得领导的认可。聊着聊着发现还真可以总结几点初入职场,经常犯的小错误,第一就要属爱当伸手党,有的时候爱向人请教,看上去是一个好习惯,但实际上请教的时候也要分请教的技巧,你不能什么不知道的都问,你应该经过思考以后提问。比如说你不会做一个PPT,你不能问对方说这个PPT应该怎么做呀,更好的提问方式是,这个PPT我想这么做,12345你帮我看看对不对,这样对方会比较容易愿意给出你指导,因为你是经过思考过的,而不是在一片空白的情况下,所有的空需要别人帮你填满。这种伸手党的行为是不可取的,职场不是学校,同事和领导没有义务替你回答所有的问题,替你把人生的空填上,而你什么都用疑问式的提问,很容易给别人留下什么都不懂,自己不爱动脑子的印象。第二,“我是来学东西的”,通过降低自己的身价来获取工作机会。比如说经常有人来跟我面试的时候说,我就是来学习的,只要给我这个学习机会,我什么都愿意做。看似这样很诚恳的发言,其实并不能帮他争取到工作机会,因为在我的视角里,我会这么判定这个人,他对自己的价值没有认知。也就是他提供不出与这个工作岗位匹配的价值。我开的不是学校,我开的是公司,我需要有人来干活儿,我愿意付他匹配的工资,只要他能把活干好,而不是找一群免费劳动力,我反而还要教他,浪费我的时间。刚入职场,一定要区分清楚职场跟学校之间的差别,建立自己的价值,用自己的价值去交换,而不是降低自己的身价。愿意给你这样工作机会的环境,也不是什么好环境,只是想占你便宜。最后说说获得领导的认可,我在一家公司的时候,我的一位领导跟我说了一句话,我一直记忆犹新,他说,向上管理,就是“管理好领导的期望”。这句话我默默记住了很久,后来过了两年才领悟这个意思。不是把一件事儿做完了,完成任务了,就交差了。留给领导去检查去吧,他提了意见我再改,很多人都是这样干的,领导就是你的免费改卷机器。后来改稿越来越多,领导累他也累。接收了一项工作任务,首先是要弄清楚,自己的领导在期待什么,他脑袋里对这件事情的蓝图是怎样的。然后需要做好反馈,她在什么点上需要了解情况,在什么点上她希望被你邀请介入,在什么点上觉得他应该听一次汇报,你得判断得出来这个节奏,然后再每一个期待的点上向领导进行反馈,最后交出的答卷再检查一遍是不是符合领导交代的要求。没有这个反馈的节奏,你就会导致你的上级对你失控,他对你一旦产生失控感,信任度就会下降,不安全感就会上升。以上内容来自老同事【文子】的朋友圈分享
2021年12月29日
99 阅读
0 评论
0 点赞
2021-12-29
王小波的计算机水平有多好?
转载自:https://www.zhihu.com/question/20964366/answer/95202867作者:姚勇今天逛知乎的时候,偶然看到王小波外甥,原水木年华成员,《QQ 炫舞》创始人——姚勇先生的一篇回答,讲述了他回忆中王小波在编程领域中的造诣,看完对王小波有了新的认识,现分享给大家看下。下面是正文:以下文字都是我本人写的。为了让阅读方便,减少模糊性。我在文中以第三人视角描述。而不用 “我舅舅 “,” 我姥姥 “,” 我大舅舅 “,” 我小舅舅 “之类的称呼。这是一个十几年软件工程师的习惯而已。我舅舅是王小波,我是个禁不住人肉的老百姓,资质平庸。王小波一篇《我是怎样做青年思想工作》的杂文在我青年单身适龄的年代,给我个人做了最大程度的广告,算是他老人家留给我最宝贵的遗产之一。除此之外,还有他那台用了很久的 PC,在他去世前一年送了我。他是汇编高手,自己用汇编写了 DOS 下的汉字输入法。输入法有个功能,可以加 4 声。一般拼音输入法没有这功能,这需要普通话读音正确的使用者,90 年代总共也没几种汉字输入法。看过他用自己输入法打汉字,速度几乎和盲打英文一样。那时候我大学,正在疯狂苦练吉他,并没有弄懂他用了何种技术。虽然我从小学也用 Z80 和 APPLE II 做些机器码编程做游戏,但到了中学为了高考,计算机就荒废了。他人生最后几年,WINDOWS 3.2 开始普及,然后是 WIN95。他开始从 DOS 转向 WIN32 SDK 编程。最终非常任性地熬夜苦干了很长时间,把输入法转为 WIN32 SDK 在 WINDOWS 下正常工作。当时 WINDOWS 已经有不少汉字输入法,尤其到了 WIN95 时代,他这么做也只是出于兴趣而不是在 DOS 时代的必须。就 WIN32 SDK 我们还讨论过一些。那时候 win32 sdk 真的是很难用。主要是互联网还没有(我是 96 年后用上的),资料很少,匈牙利命名法陌生。WIN32 的体系和 DOS 大相径庭,全部都很陌生,而且完全抛弃了 DOS 那套东西。所有 90 年代 DOS 底层程序员向 WIN32 的迁徙都是一部血泪史。他人生最后一年,多媒体开始普及。光驱,声卡,2D 加速卡普及。95-96 年他开始和我合计做多媒体出版。原因现在想起来很悲伤 ------ 他的书很难在大陆出版,他不得不想办法让他的作品能够让更多人看见,而平时维持生计,只能忍着严重的痔疮,每日给各种杂志写杂文稿件。多媒体的兴起,让他感觉也许利用他的技术优势,自行制作电子出版物。配上插图,音乐,用电子书籍方式可以让自己作品为大众所见。他给我看了已经制作了一部分的 DEMO,就和现在用 Micromedia 多媒体制作软件制作的电子多媒体制品很像。电子书内容是黄金时代,有图案的背景,按空格可以翻页。同时有音乐,好像偶尔还会有一点动画的特效(我记不清了) 。但当时的 DEMO 完全是他自己用 WIN32 写的 EXE 可执行程序,他那是从 WIN32 SDK 移植输入法时,基本掌握了消息处理,GDI,窗口控制等方法。还有一些底层的 TRICK。我大学后和王小波比较近,那几年每周末都在他母亲家相聚。他母亲 5 个儿女,只有他 1 个人在国内。于是他就经常住在母亲家,怕老人一个人,是个大孝子。母亲家旁边有个筒子楼里 2 间房的小屋,公共厕所和水房,冬天暖气烧得极热。偶尔我会和他住一块,里屋是他的生活起居和写作桌,外屋很小只有张床,他弟弟的孩子和我偶然会睡外屋。印象最深的就是他烧普洱茶的电炉和玻璃茶壶,里面总是有极浓的茶水,下面沉淀着大量茶叶,估计熬夜就靠那个。目睹了他后半截人生(从我记事起到他去世,中间他出过很多年),感慨很多。王小波有个八叔,当时双手打算盘,无比聪明是个天才。年少夭折。王小波父亲因为搞逻辑学,引起毛泽东注意,被毛接见聊了一下逻辑学的学术相关问题。69 心脏病发独自倒在家中过世。王小波去世方式和他父亲一模一样,区别仅在更加年轻。王小波哥哥在受文革影响挖了 10 年煤,后来去美国博士念数理逻辑,解决了一个 100 多年未解的数理逻辑问题。最后的博士毕业论文自己系的教授搞不定,专门找了数学系的教授来看。毕业后他哥哥专心开饭馆挣钱养育 2 个女儿成人。准备财务自由后再著书立传。我的最大感慨是,留得青山在,不怕没柴烧。天才也好,资质普通如我也好,人都只有一个人生。王小波妈妈去年 92 岁,10 月刚去世,白发人送走了自己两个儿子,又过了十几年才走。之前得过癌症,靠自己毅力锻炼,恢复了。王小波去世后一年,王小波弟弟又突然去世。当时孩子都没敢告诉老人。老太太感觉不对,但又无法得知真相,只是和我说她的疑心。当时国内只有我一人,只能瞒着,不停劝慰老人没事。老太太喃喃说,“除死无大事,除死无大事啊” 。除死无大事。人生在世,碰到什么坎,都只会是你人生中一个普通的节点。时间一长,什么都会成为过眼云烟。留份宽心,也许这样导致目标感没有强到能和社会精英逐鹿。但只要有耐心,不怕挫折,假以时日,目标总会实现的。作为一个 42 岁还在以玩游戏看动漫为生活主体的大叔,保持健康和有活力地追求智慧和有趣,做自己热爱的工作,保持善良,做精神自由的人,是我从王小波的人生学到最重要的东西。希望每个喜欢王小波的人,都有自己充实和健康的身体和精神。(完)
2021年12月29日
20 阅读
0 评论
0 点赞
2021-12-19
使用WinSW.exe安装FRP为系统启动服务
本机 FRP 所在目录:D:\greenSoft\FRP\frp_0.36.2_windows_amd64日常使用FRP,我们都需要使用命令行的方式启动,特此我准备了个startFRP.bat的启动文件:frpc.exe -c ./frpc.ini该方式可手工启动,但会打开一个命令行的黑窗口在桌面上,在使用电脑的过程中偶尔会由于误操作导致关闭了,根据以往在windows下使用nginx的经验,我们可以使用WinSW.exe这个小工具实现将FRP注册成系统服务即可,操作步骤如下:1、下载 WinSW.exe 文件到FRP所在目录2、在该目录下新建winsw.xml文件,文件内容如下所示:<service> <id>frp</id> <name>frp</name> <description>用frp发布本地电脑网站到外网</description> <executable>frpc</executable> <arguments>-c frpc.ini</arguments> <logmode>reset</logmode> </service>3、在命令行中使用 winsw install 安装为服务。执行该命令后会显示成功提示。4、进入windows 服务管理器,查看是否存在名称为frp的服务。
2021年12月19日
112 阅读
0 评论
0 点赞
2021-12-07
Typescript的14个基础语法
一.Ts是什么首先,强类型不允许随意的隐式类型转换,而弱类型是允许的。JavaScript就是经典的弱类型语言。而Typescript可以说是JavaScript的超集,在JS的基础上新增了许多语法特性,使得类型不再可以随意转换,能大大减少开发阶段的错误。二. 基本语法1.声明原始数据类型在变量后面指定一个关键字表示其只能为什么类型。// string类型: const a: string = 'auroras' // number类型: const b: number = 666 // 包括 NAN Infinity // boolean类型: const c: boolean = true // null类型: const d: null = null // undefined类型: const e: undefined = undefined // symbol类型: const h: symbol = Symbol()2.声明Object类型首先,object类型不单单可以指定对象,还可以指定数组或函数:const foo1: object = {}; const foo2: object = []; const foo3: object = function(){};如果只想指定为对象,如下,对象属性都要提前声明好类型:const obj: {name: string,age: number} = { name: '北极光', age:18 }3.1声明数组类型可以指定声明Array且通过<>指定元素类型,比如指定声明元素都为数字的数组:const arr: Array<number> = [1,2,3] // OR const arr: number[] = [1,2,3]3.2声明元组类型就是要提前指定数组里每个元素的类型,严格一一对应:const tuple: [number,string,boolean] = [666,'auraros',true]4.声明枚举类型通过关键字enum声明一个枚举类型,如:enum Status { pedding = 1, resolve = 2, reject = '3' } //访问 console.log(Status.pedding);如果全不写值,默认值为从0开始递增。如果第一个元素为字符类型,就必须全部定义值。如果第一个元素指定为一个数字,后面元素不写值,那值为第一个元素值按位置大小递增的结果。5.函数参数与返回类型函数声明式:指定函数传入参数类型,指定返回值类型,调用时传入参数个数与类型都必须相同:括号里指定每个参数类型,括号右边指定返回值的类型。function fun (name:string,age:number):string{ return 'sss' } fun('auroras',18);如果传入参数不确定传不传,那么可以给参数加个‘?’表明它是可选的:function fun (name:string,age?:number):string{ return 'sss' } fun('auroras');或者给参数添加默认值,那也会成为可选参数:function fun (name:string,age:number=666):string{ return 'sss' } fun('auroras');如果参数个数不确定,可以用扩展运算符加解构赋值表示,当然要传入与指定类型一致的:function fun (name:string,age:number=666,...res:number[]):string{ return 'sss' } fun('auroras',1,2,3);函数表达式:const fun2:(name:string,age:number)=>string = function(name:string,age:number){ return 'sss' }6.任意类型通过指定any关键字表示任意类型,跟原来 js 一样,可以任意赋不同类型的值:let num:any = 1; num = 'a'; num = true;7.类型断言类型断言就是明确的告诉typescript这个变量就是某种类型的,百分之百确定。不用typescript在一些情况下要自己推断某些没有明确定义或者多变的场景是什么类型。可以通过 as+类型 断言它就是某种类型的:const res = 1; const num = res as number;也可以通过 <类型> 形式断言(不推荐):const res = 1; const num = <number>res8.接口基本使用接口可以理解为一种规范,一种契约。可以约束一个对象里应该有哪些成员,这些成员都是怎么样的。通过interface定义一个Post接口,这个接口是一个对象,规则为有一个name属性类型为string,age属性类型为number。interface Post { name:string; age:number }然后比如有一个函数 printPost ,它的参数 post 使用我们定义的 Post 接口的规则,那么调用此函数传参时要传入符合 Post 接口规则的数据。interface Post { name:string; age:number } function printPost(post: Post){ console.log(post.name); console.log(post.age); } printPost({name:'asd',age:666})当然,函数传参时可能有些参数是可选的,那么我们可以给接口也定义可选的成员,通过属性后加一个‘ ? ’指定 可选成员 :interface Post { name:string; age:number; sex?:string; } const auroras: Post = { name:'asd', age: 18 }如果用 readonly 修饰成员,那么这个成员属性在初始化后便不可修改:interface Post { name:string; age:number; sex?:string; readonly like:string } const auroras: Post = { name:'asd', age: 18, like: 'natrue' } auroras.name = 'aaaa'; //保错 auroras.like = 'wind';如果连成员属性名称都不确定,那么可以声明 动态成员 ,要指定成员名字类型与成员值的类型,如:interface Post { [prop:string]:string } const auroras: Post = { name:'asd', like: 'natrue' }9.类基本使用描述一类具体事物的抽象特征。ts增强了es6中class类的相关语法。首先,类的属性使用前必须提前声明好:class Person { name: string; age: number; constructor(name:string,age:number){ this.name = name; this.age = age; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); } }10.类的访问修饰符private 修饰私有属性,只能在类内部访问。 public 修饰公用属性(默认),外部也可访问:class Person { public name: string; private age: number; constructor(name:string,age:number){ this.name = name; this.age = age; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } } const jack = new Person('jack',20); //Person类公有属性可以访问 console.log(jack.name); //Person类私有属性不可以访问 console.log(jack.age);protected 修饰为受保护的,外部也不可访问。但与 private 的区别是若是继承的子类是可以访问的。class Person { public name: string; private age: number; // protected protected gender: boolean; constructor(name:string,age:number){ this.name = name; this.age = age; this.gender = true; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } } class children extends Person{ constructor(name:string,age:number){ super(name,age,); //可以访问 console.log(this.gender); } }11.类只读属性给属性设置 readonly 则为只读属性,该属性初始化后便不可再修改。class Person { public name: string; private age: number; // readonly protected readonly gender: boolean; constructor(name:string,age:number){ this.name = name; this.age = age; this.gender = true; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } }12.类与接口一些类与类之间有些许共同的特征,这些共同的特征可以抽象成为接口。比如 Person 类和 Animal 类,虽然是不同类,但是人和动物都会吃东西和走路等,这些共同的特征可以由接口定义。最后一个特征就定义一个接口。//吃接口 interface Eat { eat(food:string):void } //行进接口 interface Run { run(behavior:string):void } //人 class People implements Eat,Run { eat(food:string){ console.log(`在餐桌上吃${food}`); } run(behavior:string){ console.log(`站着${behavior}`); } } //动物 class Animal implements Eat,Run { eat(food:string){ console.log(`在地上上吃${food}`); } run(behavior:string){ console.log(`爬着${behavior}`); } }13.抽象类约束子类必须有某些成员,有点类似接口,不同的是抽象类可以包含一些具体的实现。比如动物类应该为一个抽象类,它的子类有猫,狗,熊猫等。它们都是动物,也有一些共同的特征。定义一个类为抽象类后,就不能再new实例了,只能被其子类继承。其中 abstract 定义抽象类,类里用 abstract 定义一个抽象方法,子类必须实现抽象方法。abstract class Animal { eat(food:string){ console.log(`在地上吃${food}`); } abstract run (behavior:string):void } //猫 class Dog extends Animal{ run(behavior:string):void{ console.log(behavior); } } const d1 = new Dog(); d1.eat('骨头') d1.run('四脚爬行') //兔子 class rabbit extends Animal{ run(behavior:string):void{ console.log(behavior); } } const r1 = new rabbit(); d1.eat('萝卜') d1.run('蹦蹦跳跳') 14.泛型泛型就是在定义函数,接口或者类的时候没有指定具体类型,等到使用时才指定具体类型。极大程度的复用代码。比如有一个 identity 函数,这个函数会返回任何传入它的值,且传入的类型与返回的类型应该是相同的。如果传入数字,不用泛型的话,这个函数可能是下面这样: function identity(arg:number):number{ return arg }如果传入字符串,这个函数可能是下面这样: function identity(arg:string):string{ return arg }这样的话太麻烦,所以可以使用泛型,一般用大写 T 表示泛型,它可以适用于多个类型,且传入类型与返回类型是相同的。 function identity<T>(arg:T):T{ return arg }
2021年12月07日
117 阅读
0 评论
0 点赞
2021-11-30
简单理解 Typescript 的配置文件 tsconfig.json
TS 使用 tsconfig.json 作为其配置文件,他主要包括两块内容:指定待编译的文件定义编译选项一般来说, tsconfig.json 文件所处的路径就是当前 TS 项目的根路径。tsconfig.json 的配置项众多并且复杂。所有的选项可以参考官方文档:https://www.typescriptlang.org/zh/tsconfig 这里我们分析一个简单示例:{ "compilerOptions": { "module": "commonjs", "noImplicitAny": true, "sourceMap": true, "declaration": true }, "files": [ "app.ts", "foo.ts", ] }其中, compilerOptions 用来配置编译选项, files 用来指定待编译文件。这里的待编译文件是指入口文件,任何被入口文件依赖的文件。也可以使用 include 和 exclude 来指定和排除待编译文件:{ "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] }下面简述 compilerOptions 中的选项配置,这些配置简单来说就是影响整个编译的过程和编译的结果。module - 生成的 Javascript 模块形式:none、commonjs、amd、system、umd、es6、es2015 或 esnextnoImplicitAny - 存在隐式 any 时抛错 (默认为 false)sourceMap - 生成 map 文件 (默认为 false)declaration - 生成对应的 .d.ts 文件 (默认为 false)
2021年11月30日
269 阅读
0 评论
0 点赞
2021-11-05
win11资源管理器菜单栏+右键菜单改回win10风格
一、上方菜单栏1、win + R 输入 regedit 打开注册表2、依次展开(或地址栏复制)HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions3、右击 Shell Extensions 创建项key命名为 Blocked (如果没有)4、打开 Blocked ,右击空白处,新建字符串值。将值/名称命名为:{e2bf9676-5f8f-435c-97eb-11607a5bedf7}5、重启电脑注:如需调回至win 11 explorer,直接删除blocked 文件夹二、右键菜单1、win+r 输入 regedit 打开注册表2、依次展开(或地址栏复制)HKEY_CURRENT_USER\Software\Classes\CLSID3、右键CLSIDkey 然后新建项Key ,重命名为{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}4、右键此key {86ca1aa0-34aa-4e8b-a509-50c905bae2a2}, 新建一个key并重命名为 InprocServer325、打开 InprocServer32 ,右侧窗口双击打开 default 文件,回车保存。(设置空白text数据)6、关闭注册表,重启电脑或者使用如下修改注册表批处理语句:reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve taskkill /f /im explorer.exe & start explorer.exe若需还原把 reg add 改成 reg delete 即可
2021年11月05日
97 阅读
0 评论
0 点赞
2021-09-06
如何防止他人恶意调试你的web程序
前言看到社区很多都在讨论 如何调试,如何高级的调试,以及一些调试的奇技淫巧 ,今天我想和大家聊聊, 怎么禁止调试,禁止他人调试我们的程序 为什么会有这篇文章呢,源自一次我寻找盗版电影的遭遇,一次好奇心的驱使下,由于很多这种平台都是只做搬运,不做存储,因为存储盗版电影向他人提供是违法的,特别是那种刚出的新电影! 当时好奇想通过看某站的控制台,想了解一下他们是怎么是通过啥接口,怎么请求,请求来的格式啥样的,抱着这样的好奇心,开始了我的奇妙之旅... 看完本篇文章你将学会我无法断定你能学到什么,但是以下是我希望你能从本篇文章中学到的:1.如何简单的防止你的程序被他人恶意调试2.逆向思维学会如何更好的调试具体实现防止调试的方法,这里我们主要是通过不断 debugger 的方法来疯狂输出断点,让控制台打开后程序就无法正常执行我们都知道 debugger 只有在控制台被打开的时候才会执行,所以后面的所有方法都是围绕着这一特性来进行,废话不多说,我将通过以下几个案例向你们展示道高一尺魔高一丈的道理,先上代码:方法一:(() => { function block() { setInterval(() => { debugger; }, 50); } try { block(); } catch (err) {} })(); 通过上方的代码我们可以看到,在页面中打开控制台后,会有以下结果:需要在这里说明以下几点:程序被 debugger 阻泄了,我们无法像以往一样在 Source Tab 中的对应 js 代码处添加断点调试,无法调试程序的执行逻辑.在程序异常复杂且被混淆后的代码是异常难读的!通常我们会在 source 的左边加上 breakpoint 来让程序每次走到加点的地方停下来,以便让我们查看一些变量的值或是步骤的流程逻辑(如下图所示)我们都知道,第一次打开控制台是看不到 Network tab 中的任何请求的,所以我们想通过 Network tab 来查看网页都做了哪些请求,也是看不到的,当我们打开控制台就会出 debugger 阻挡我们,我们可以通过下面的解决方法来处理,或者是用抓包工具来查看具体的请求大家可以先不看解决方法,想想如果是你,这个时候怎么突破这个屏障呢? 第一次遇到这种情况我也是很懵,不知道咋处理,后面发现问题简直不要太简单,我们可以带着疑问来看: 对于第一个示例,我们如何解决?(绕过它) 答案是: 禁止断点 可以看到很简单,在 Chrome 控制台的 Source Tab 页点击 Deactivate breakpoints 按钮或者按下 Ctrl + f8(如下图所示)。但是对于控制台不熟悉的小伙伴,很难会想到这里去.但是,难道这篇文章就这样结束了?那我可顶不住小伙伴们的 "就这?" 其实,上面的解决方法并没有帮我们解决根本问题,我们需要做的是调试,上面虽然把debugger都去掉了,但是我们也无法在通过点击每一行代码左边的行号添加 breakpoint 了,所以根本性的问题,并没有解决,只是去除了那碍眼的疯狂 debugger,我们还是得另辟蹊径方法二:对对应的代码行,通过添加 logpoint 为 false,然后按回车后刷新网页,发现成功跳过无限 debugger,于是我们就可以愉快的自由调试了~对应的还有一种方法即通过 add script ignore list 来添加需要忽略执行代码行或文件可以看到,我们也可以通过删除 script ignore list 里已添加的忽略代码,恢复初始状态但是,你这么聪明,那人家不得想想对策?对于上面的第一个方法将setInterval(() => {debugger;}, 50);写在一行中,你即使通过添加logpoint为 false,也没用,仍然是疯狂 debugger,即使你可能想到,通过左下角的代码格式化,来格式一下setInterval(() => {debugger;}, 50);将它变成多行的,也是没用的,仍然会在刷新后重新弹 debugger(() => { function block() { setInterval(() => {debugger;}, 50); } try { block(); } catch (err) {} })();对于第二个方法,我们对代码进行如下改造(() => { function block() { setInterval(() => { Function("debugger")(); }, 50); } try { block(); } catch (err) {} })();我们可以通过将debugger改写成Function("debugger")();的形式,来应对;Function 构造器生成的 debugger 会在每一次执行时开启一个临时 js 文件,哈哈~对方表示好无奈于是会有以下结果 这无限套娃,真够狠的,我们要坚信正义最后总会胜利,不能给想非法调试我们程序的人机会,所以我们要把各种情况都考虑周全,可以说这种方法是最恨的,但是这还不算完~ (好家伙~ 想非法调试我程序,那你就得战胜我)强化以上方法 上面的代码由于没有加密混淆,多少可能还是会被别人读一些,那么我们加密混淆看看是啥样的好家伙,你这咋读?eval(function(c,g,a,b,d,e){d=String;if(!"".replace(/^/,String)){for(;a--;)e[a]=b[a]||a;b=[function(f){return e[f]}];d=function(){return"\\w+"};a=1}for(;a--;)b[a]&&(c=c.replace(new RegExp("\\b"+d(a)+"\\b","g"),b[a]));return c}('(()=>{1 0(){2(()=>{3("4")()},5)}6{0()}7(8){}})();',9,9,"block function setInterval Function debugger 50 try catch err".split(" "),0,{}));格式化后的样子我们继续对代码进行改造,让对方尽量的难以识别我们的代码将 Function("debugger").call() 改成 (function(){return false;})["constructor"]("debugger")["call"](); 并且,添加条件,当窗口外部宽高,和内部宽高的差值大于一定的值,我把 body 里的内容全部清空掉,看你还能不能操作我的按钮啊啥的~哈哈哈需要特别说明的是 : 像 toG 的项目或者是一些为了保护自己的版权又或者是一些比较敏感的项目,出于安全的考虑在部署到生产环境后最好是不让别人调试的,当然,前端所做的也就那么一些,需要前后端一起配合,便可以很好的对项目或者数据进行私密的保护 最后: 附上这份未混淆的来之不易的的代码(记得混淆后使用哦~) 一定要记得点赞加关注~原创太不容易了.你可以把它当作你的工具函数,在需要不让别人轻易调试的项目中引用 (当然它仍然有很多漏洞,但是我们可以用类似的逻辑方法,变化出很多更复杂的限制,最暴力的甚至可以当控制台打开后就立马通过window.close();来关闭调试窗口),欢迎大家在评论区留下更好玩的方法~共同学习(() => { function block() { if ( window.outerHeight - window.innerHeight > 200 || window.outerWidth - window.innerWidth > 200 ) { document.body.innerHTML = "检测到非法调试,请关闭后刷新重试!"; } setInterval(() => { (function () { return false; } ["constructor"]("debugger") ["call"]()); }, 50); } try { block(); } catch (err) {} })();推荐一个调试页面的小技巧说了那么多的防止被人调试,那么最后也说一个本人觉得眼前一亮的调试样式的方法通过给 style 标签添加 style="display: block" , contenteditable 两个属性实现在页面中便捷的调试样式复制下方代码到你的 html 文件中,玩一下~<!DOCTYPE html> <body> <div>来调试我吧~</div> <style style="display: block" contenteditable> body { background-color: rgb(140, 209, 230); color: white; } div { background-color: green; width: 300px; height: 300px; line-height: 300px; text-align: center; } </style> </body> 最后我所知道的禁止调试的方法就只有如上所述,但是肯定还有很多好玩的,小伙伴们可以在评论区留言,一起共同学习~最后抛出一个问题, 如何监测控制台是否被打开 (我上面提到的通过window内外高宽的差值其实可以通过独立调试窗口的方法绕过),网上找了一些方法,貌似都没用,感兴趣且有头绪,或者已经有方法的小伙伴可以小伙伴可以在评论下方说说自己的想法,{card-describe title="引用自"}作者:荣顶链接:https://juejin.cn/post/7000784414858805256来源:掘金{/card-describe}
2021年09月06日
59 阅读
0 评论
0 点赞
2021-07-14
在vue-cli3使用sass(scss)定义的全局样式及变量
为统一风格及便于后续维护,在项目中常用的主色调、圆角、阴影相关的样式定义到一个全局变量文件中,常规的使用需要每个Vue组件中进行import,该操作会比较繁琐,经过了解后发现可以基于webpack的loader参数引入全局变量的方式来实现,相关实现过程如下所示:vue.config.jsmodule.exports = { // ... css: { // 为便于在Vue组件中使用,全局引入variables.scss中定义的变量 loaderOptions: { sass: { prependData: `@import "@/styles/variables.scss";` } } } variables.css// base color $blue:#324157; $light-blue:#3A71A8; $red:#C03639; $pink: #E65D6E; $green: #30B08F; $tiffany: #4AB7BD; $yellow:#FEC171; $panGreen: #30B08F; $theme: #004ca1; // ...vue 组件<style lang="scss" scoped> .btn-cursor { cursor:pointer; color: $theme } </style>
2021年07月14日
440 阅读
0 评论
0 点赞
2021-06-30
一个简单的自定义工作流设计器实现
先瞅瞅产品提供的丑陋至极的原型效果再看看经过本人精雕细琢之后的惊艳效果Show me the code流程设计弹出层<template> <el-dialog width="760px" class="hkt-dlg-darkblue" :title="`流程设计:${formData.name}`" :visible.sync="isShow" destroy-on-close :close-on-click-modal="false"> <div class="dialog-wrap" v-loading="loading"> <div style="min-height:50vh"> <div class="info-block"> <el-row class="hkt-block-title"> <el-col :span="12"><div><span class="title-name">流程配置</span></div></el-col> <el-col :span="12" class="text-right"> <el-button type="text" @click="formModalChange('New', null)"><i class="el-icon-plus"></i> 添加审核节点</el-button> </el-col> </el-row> <div class="info-content"> <el-steps direction="vertical" :active="nodes.length"> <el-step v-for="(step, stepIndex) in nodes" class="step-item-wrap" :class="'step-item-signmodel-' + step.signModel" :key="step + stepIndex"> <div slot="title"> <div style="line-height:32px;heihgt:38px;"> <el-row> <el-col :span="12"> <span class="step-name" v-text="step.nodeName"></span> </el-col> <el-col :span="12"> <div class="step-item-oprations text-right"> <el-button size="mini" type="text" @click="stepSort(stepIndex, 'up')" v-if="stepIndex > 0"><i class="el-icon-top"></i> 上移</el-button> <el-button size="mini" type="text"@click="stepSort(stepIndex, 'down')" v-if="stepIndex < nodes.length - 1"><i class="el-icon-bottom"></i> 下移</el-button> <el-button size="mini" type="text" @click="formModalChange('Edit', step, stepIndex)"><i class="el-icon-edit"></i> 修改</el-button> <el-button size="mini" type="text" @click="removeStep(step, stepIndex)"><i class="el-icon-close"></i> 删除</el-button> <el-button size="mini" type="text" @click="addPersons(step, stepIndex)"><i class="el-icon-user"></i> 配置审批人</el-button> </div> </el-col> </el-row> </div> </div> <div slot="description"> <div v-if="step.approveNames.length === 0"> <span class="color-gray">暂未配置审批人员</span> </div> <div v-else class="step-item-content-wrap"> <div class="person-item"> <el-tag v-for="(person, personIndex) in step.approveNames" :key="person" disable-transitions @close="removePerson(stepIndex, personIndex)" closable>{{person}}</el-tag> </div> </div> </div> </el-step> </el-steps> <div v-if="nodes.length === 0"> <h3 style="padding-top:40px;font-weight:normal;color:#dedede;font-size: 22px; text-align:center"><p>当前流程暂未配置审核节点信息,</p><p>请单击右上角的“添加审核节点”按钮进行配置</p></h3> </div> </div> </div> </div> </div> <div slot="footer" class="dialog-footer-wrap text-center"> <el-button @click="isShow = false">取 消</el-button> <el-button type="primary" :loading="submitting" @click="save">{{submitting ? '保存中': '确 定'}}</el-button> </div> <step-form-modal :show.sync="formModalVisible" v-if="formModalVisible" :formData="currentRow" :mode="formMode" @callback="formCallback" /> </el-dialog> </template> <script> import stepFormModal from './stepFormModal.vue' export default { name: 'flowDesignModal', desc: '流程设计器', components: { stepFormModal }, props: { show: { type: Boolean, required: true, default: false }, formData: { // 适用于编辑 type: Object, required: false }, mode: { type: String, required: false } }, data () { return { loading: true, form: { }, nodes: [], formModalVisible: false, currentRow: null, currentStepIndex: null, formMode:'New', // New || Edit submitting: false } }, computed: { isShow: { get () { return this.show }, set (val) { this.$emit('update:show', val) } } }, created() { this.init() }, methods: { init () { if (this.formData) { this.getFlowNodes() // this.form = this.$hktUtils.deepClone(this.formData) } }, stepSort (index, type) { const steps = this.nodes if (type === 'up') { ;[steps[index], steps[index - 1]] = [steps[index - 1], steps[index]] } else { ;[steps[index], steps[index + 1]] = [steps[index + 1], steps[index]] } // 触发页面更新 this.nodes = steps.concat() }, async getFlowNodes () { this.loading = true const res = await this.$request.get(`/v1/manager/flow/node/listByFlowId?flowId=${this.formData.id}`) if (res.success) { this.nodes = res.data } this.loading = false }, // 添加或编辑流程节点 formModalChange (mode, formData, stepIndex) { this.formMode = mode this.currentRow = formData this.currentStepIndex = stepIndex this.formModalVisible = true }, formCallback (item) { // TODO 判断步骤名称是否已存在 if (this.formMode === 'New') { item.flowId = this.formData.id item.approveArray = [] item.approveNames = [] this.nodes.push(item) } else if (this.currentStepIndex >= 0) { this.nodes[this.currentStepIndex] = item this.currentStepIndex = null } }, addPersons (row, stepIndex) { const dialogProps = { multipleFlag: 'Y' } if (row.approveArray && row.approveArray.length > 0) { dialogProps.initRightUsers = row.approveArray.join(',') } window.hktCommon.selectUser(`配置 ${row.nodeName} 节点的审批人`, dialogProps, (res) => { row.approveArray = res.map(item => item.id) row.approveNames = res.map(item => item.name) this.nodes.splice(stepIndex, 1, this.$hktUtils.deepClone(row)) }) }, removePerson(stepIndex, personIndex) { this.nodes[stepIndex].approveArray.splice(personIndex, 1) this.nodes[stepIndex].approveNames.splice(personIndex, 1) }, removeStep(stepItem, stepIndex) { this.$confirm(`本操作不可恢复,确定删除该步骤(${stepItem.nodeName})?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(() => { this.nodes.splice(stepIndex, 1) }).catch(() => {}) }, // 保存 async save () { const flowNodes = this.$hktUtils.deepClone(this.nodes) const existNodeNames = []// 用于校验名称是否重复 for (let i = 0; i < flowNodes.length; i++) { const flowNode = flowNodes[i] if (flowNode.approveArray.length === 0) { this.$message({ message: `审核步骤(${flowNode.nodeName})至少需选择一个的审批人`, type: 'warning' }) return } if (existNodeNames.includes(flowNode.nodeName)) { this.$message({ message: `存在相同的审核节点名称:${flowNode.nodeName}`, type: 'warning' }) return } existNodeNames.push(flowNode.nodeName) flowNode.orders = i +1 flowNode.approveIds = flowNode.approveArray.join(',') } this.submitting = true // 执行保存入库相关操作 const res = await this.$request.post(`/v1/manager/flow/node/add`, flowNodes).catch(err => { this.submitting = false }) this.submitting = false if (res && res.success) { this.$emit('callback', flowNodes) this.isShow = false } } } } </script> <style lang="scss" scoped> .form-body-item { background-color:#fff; padding:10px; border-radius: 4px; margin-bottom: 10px; } .form-item-zones { border-bottom: solid 1px #DCDFE6 ; margin-bottom:20px; .block-title { font-weight:bold; display: inline-block; line-height: 36px; font-size:14px; } } .step-item-oprations { display: none; } .step-item-wrap { /deep/ .el-step__main { padding: 0 10px 10px; } } .step-item-wrap:hover { /deep/ .el-step__main { background-color:#F5F7FA; border-radius: 5px; } .step-item-oprations { display: block; } } .step-item-content-wrap { padding: 10px; } .btn-choose { margin-left:10px; vertical-align: middle; } .person-item /deep/ { display: inline-block; .el-tag { vertical-align: middle; position: relative; overflow: initial; margin-bottom:10px; .el-tag__close { padding: 2px; box-sizing: content-box; position:absolute; background-color: #D1E9FF; // display: none; top:-10px; right: -10px; &:hover { background-color: #1890ff; } } &:hover { .el-tag__close { display:block; } } } .el-tag + .el-tag { margin-left: 40px; &:before { content: '或'; position: absolute; left: -26px; color: #666666; } } } // 会签模式步骤的审批人之间是用和 .info-content /deep/ .step-item-signmodel-1 .person-item { .el-tag + .el-tag { &:before { content: '和' } } } .step-name { color:#101010; font-weight: bold; } </style> 步骤编辑弹出层<template> <el-dialog width="460px" class="hkt-dlg-darkblue" :title="(form.id ? '编辑' : '新建') + '步骤'" :visible.sync="isShow" append-to-body destroy-on-close :close-on-click-modal="false"> <div class="dialog-wrap"> <el-form ref="form" :model="form"> <el-form-item label="步骤名称" prop="nodeName" :rules="[{required: true, message: '请填写步骤名称', trigger: 'change'}]"> <el-input v-model="form.nodeName" style="width:250px"></el-input> </el-form-item> <el-form-item label="是否会签模式"> <el-switch v-model="form.signModel" :active-value="1" :inactive-value="2" active-text="是" inactive-text="否"></el-switch> </el-form-item> <el-form-item label="是否可办结"> <el-switch v-model="form.isOver" :active-value="1" :inactive-value="0" active-text="是" inactive-text="否"></el-switch> </el-form-item> </el-form> </div> <div slot="footer" class="dialog-footer-wrap text-center"> <el-button @click="isShow = false">取 消</el-button> <el-button type="primary" @click="save">确 定</el-button> </div> </el-dialog> </template> <script> export default { name: 'stepFormModal', desc: '流程步骤表单', props: { show: { type: Boolean, required: true, default: false }, formData: { // 适用于编辑 type: Object, required: false }, mode: { type: String, required: false } }, data () { return { form: { nodeName: '', signModel: 2, isOver: 0 } } }, computed: { isShow: { get () { return this.show }, set (val) { this.$emit('update:show', val) } } }, created() { this.init() }, methods: { init () { if (this.formData) { this.form = this.$hktUtils.deepClone(this.formData) } }, save () { this.$refs['form'].validate(async (valid) => { if (valid) { this.$emit('callback', this.form) this.isShow = false } }) } } } </script> <style lang="scss" scoped> .form-body-item { background-color:#fff; padding:10px; border-radius: 4px; margin-bottom: 10px; } .form-item-zones { border-bottom: solid 1px #DCDFE6 ; margin-bottom:20px; .block-title { font-weight:bold; display: inline-block; line-height: 36px; font-size:14px; } } .step-item-oprations { display: none; } .step-item-wrap:hover { background-color:#D1E9FF; .step-item-oprations { display: block; } } .step-item-content-wrap { padding: 10px; } .btn-choose { margin-left:10px; vertical-align: middle; } .person-item /deep/ { display: inline-block; .el-tag { vertical-align: middle; position: relative; overflow: initial; .el-tag__close { padding: 2px; box-sizing: content-box; position:absolute; background-color: #D1E9FF; // display: none; top:-10px; right: -10px; &:hover { background-color: #1890ff; } } &:hover { .el-tag__close { display:block; } } } .el-tag + .el-tag { margin-left: 40px; &:before { content: '或'; position: absolute; left: -26px; color: #666666; } } } .step-name { color:#101010; font-weight: bold; } </style> 该组件涉及人员选择相关公共组件的封装,详细见 分享一个在管理系统中一些公共组件的调用方式
2021年06月30日
193 阅读
0 评论
0 点赞
2021-06-30
分享一个在管理系统中一些公共组件的调用方式
公共组件效果查看合同:地图描点:公共资源文件上传:人员选择-多选:人员选择-单选:增加公共组件目录核心代码如下:<template> <div class="common-dialogs-wrap"> <!-- 公共资源上传 --> <resource-modal :title="resourcePickerDlg.dialogTitle" :resourceDialogProps.sync="resourcePickerDlg.resourceDialogProps" v-if="resourcePickerDlg.show" :show.sync="resourcePickerDlg.show" @callback="resourceCallback"></resource-modal> <!-- 公共人员选择 --> <select-user-modal :title="userSelectDlg.dialogTitle" :dialogProps.sync="userSelectDlg.dialogProps" v-if="userSelectDlg.show" :show.sync="userSelectDlg.show" @callback="userSelectedCallback" ></select-user-modal> <!-- 合同详情弹出层 --> <contract-detail-modal :show.sync="contractDetailDlg.show" v-if="contractDetailDlg.show" :detail-id="contractDetailDlg.dialogProps.contractId"></contract-detail-modal> <!-- 地图描点 --> <picker-q-map-position-modal :show.sync="qMaplDlg.show" v-if="qMaplDlg.show" @callback="qMapCallback"></picker-q-map-position-modal> <!-- 预留后续扩展其他公共组件 --> </div> </template> <script> const ResourceModal = () => import('./ResourceModal.vue') const SelectUserModal = () => import('./SelectUserModal.vue') const ContractDetailModal = () => import('@/views/contract-manage/contractList/DetailContractModel.vue') // 合同详情弹出层 const PickerQMapPositionModal = () => import('./PickerQMapPositionModal.vue') // 腾讯地图描点 var hktCommon = {} var uploadCallbackFn = null // 资源上传回调 var userSelectCallback = null // 用户选择回调 var qMapCallbackFn = null // 腾讯地图描点回调 export default { name: 'HktCommon', desc: '华宽通公共组件封装', components: { ResourceModal, SelectUserModal, ContractDetailModal, PickerQMapPositionModal }, data () { return { // 资源上传对话框默认参数 resourceDialogProps: { businessCode: 'resources', // 业务代码,默认为resources resourceType: 'file', // 资源类型,file||image||document||video||audio accept: '', // 接受上传的文件类型 multipleFlag: 'Y' // 是否允许多个 }, resourcePickerDlg: { show: false, dialogTitle: '选择资源', resourceDialogProps: {} }, userSelectDlg: { show: false, dialogTitle: '选择人员', dialogProps: { multipleFlag: 'N', // 是否支持多选 organizationId: '', // 机构ID ignoreUsernames: '', // 不能选择的人员用户名 initRightUsers: '' // 复选上的用户,多个使用逗号分隔 } }, // 合同详情弹出层 contractDetailDlg: { show: false, dialogTitle: '合同信息', dialogProps: { contractId: '' // 合同ID } }, // 合同详情弹出层 qMaplDlg: { show: false, dialogTitle: '地图描点', dialogProps: { } } } }, created () { window.hktCommon = hktCommon this.init() }, methods: { init () { // 初始化公共上传组件 this.initUpload() // 初始化用户选择组件 this.initSelectUser() // 初始化查看合同详情组件 this.initContractDetailModal() // 初始化查看合同详情组件 this.initQMapModal() // TODO:后续可继续扩展其他公共组件 }, initUpload () { // 上传图片 hktCommon.uploadImage = (title, props, callback) => { if (arguments.length === 1 && typeof arguments[0] === 'function') { title = '上传图片' props = { resourceType: 'image' } callback = arguments[0] } if (arguments.length === 2 && typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { props = { resourceType: 'image' } callback = arguments[1] } if (arguments.length === 2 && typeof arguments[0] === 'object' && typeof arguments[1] === 'function') { title = '上传图片' props = arguments[0] callback = arguments[1] } if (!props) { props = { resourceType: 'image' } } if (!props.accept) { props.accept = '.jpg,.png,.gif' } upload('image', title, props, callback) } // 上传视频 hktCommon.uploadVideo = (title, props, callback) => { if (arguments.length === 2 && typeof arguments[0] === 'object' && typeof arguments[1] === 'function') { title = '视频上传' props = arguments[0] callback = arguments[1] } upload('video', title, props, callback) } // 上传音频 hktCommon.uploadAudio = (title, props, callback) => { if (arguments.length === 2 && typeof arguments[0] === 'object' && typeof arguments[1] === 'function') { title = '音频上传' props = arguments[0] callback = arguments[1] } upload('audio', title, props, callback) } // 上传资源 hktCommon.uploadResource = (title, props, callback) => { if (arguments.length === 2 && typeof arguments[0] === 'object' && typeof arguments[1] === 'function') { title = '文件上传' props = arguments[0] callback = arguments[1] } let resourceType = 'file' if (props.resourceType) { resourceType = props.resourceType } upload(resourceType, title, props, callback) } // 定义公共上传方法 const upload = (type, title, props, callback) => { this.resourcePickerDlg.dialogTitle = title const resourceDialogProps = Object.assign({}, this.resourceDialogProps, props) resourceDialogProps.resourceType = type this.resourcePickerDlg.resourceDialogProps = resourceDialogProps this.resourcePickerDlg.show = true if (callback) { uploadCallbackFn = callback } else { uploadCallbackFn = null } } // 完全自主控制上传方式 hktCommon.upload = upload }, initSelectUser() { const self = this /** * 公共选择用户方法 * @param title 对话框标题 * @param props 人员选择配置信息,配置属性见:userSelectDlg.dialogProps * @param callback 选择人员后的回调 */ hktCommon.selectUser = function(title, props, callback) { if (arguments.length === 2 && typeof arguments[0] === 'object' && typeof arguments[1] === 'function') { title = '选择用户' props = arguments[0] callback = arguments[1] } else if (arguments.length === 2 && typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { callback = arguments[1] props = { multipleFlag: 'N', // 是否支持多选 organizationId: '', // 机构ID ignoreUsernames: '' // 不能选择的人员用户名 } } self.userSelectDlg.dialogTitle = title self.userSelectDlg.dialogProps = props self.userSelectDlg.show = true if (callback) { userSelectCallback = callback } else { userSelectCallback = null } } }, // 初始化合同详情界面 initContractDetailModal () { const self = this hktCommon.showContract = function (contractId) { self.contractDetailDlg.dialogProps.contractId = contractId self.contractDetailDlg.show = true } }, // 初始化腾讯地图选择弹出层 initQMapModal () { const self = this hktCommon.pickQMap = function (callback) { self.qMaplDlg.show = true if (callback) { qMapCallbackFn = callback } else { qMapCallbackFn = null } } }, // 选择资源后的回调 resourceCallback (resourceData) { // 可以通过事件机制获取选择后的资源 if (window.eventHub && typeof window.eventHub.$emit === 'function') { window.eventHub.$emit('resourcePicked', resourceData) } if (typeof uploadCallbackFn === 'function') { uploadCallbackFn(resourceData) uploadCallbackFn = null } }, // 选择人员回调 userSelectedCallback(userData) { // 可以通过事件机制获取选择后的资源 if (window.eventHub && typeof window.eventHub.$emit === 'function') { window.eventHub.$emit('userSelected', userData) } if (typeof userSelectCallback === 'function') { userSelectCallback(userData) userSelectCallback = null } }, // 地图描点后的回调 qMapCallback (latLng) { // 可以通过事件机制获取选择后的资源 if (window.eventHub && typeof window.eventHub.$emit === 'function') { window.eventHub.$emit('qMapCallPicked', latLng) } if (typeof qMapCallbackFn === 'function') { qMapCallbackFn(latLng) qMapCallbackFn = null } }, } } </script> main.js主方法中引入公共组件:import HktCommon from './views/hktcommon/HktCommon.vue' // 增加公共组件对象 const commonEl = document.createElement('div') document.body.appendChild(commonEl) new Vue({ name: 'AppCommonRoot', el: commonEl, render: h => h(HktCommon) })在其他组件中调用全局方法:// 上传资源 hktCommon.uploadResource(this.dialogTitle, dialogProps, (resources) => { this.uploadCallback(resources) }) // 选择用户: window.hktCommon.selectUser(`配置 ${row.nodeName} 节点的审批人`, dialogProps, (res) => { row.approveArray = res.map(item => item.id) row.approveNames = res.map(item => item.name) this.nodes.splice(stepIndex, 1, this.$hktUtils.deepClone(row)) }) // 显示合同信息 hktCommon.showContract = function (contractId) { self.contractDetailDlg.dialogProps.contractId = contractId self.contractDetailDlg.show = true } // 地图描点 window.hktCommon.pickQMap((res) => { self.projectForm.areaCode = `${res.latitude},${res.longitude}` })
2021年06月30日
68 阅读
0 评论
0 点赞
2021-06-30
记一次根据经纬度计算距离的项目实践
近期公司接的公租房项目,在小程序模块中有用到离我最近的房源列表的功能,经过项目实践相关实现过程如下:功能演示PC后台配置小区位置:单击地图描点后打开如下图所示的描点对话框,描点选择后单击确定按钮返回经纬度信息:小程序中获取位置后调用接口显示距离:{lamp/}代码实现:管理后台描点Vue组件核心代码<template> <el-dialog width="95%" class="hkt-dlg-darkblue resource-modal" top="5vh" :title="title" :visible.sync="isShow" destroy-on-close :close-on-click-modal="false"> <div class="map-container" ref="mapContainer"></div> <div slot="footer" class="dialog-footer dialog-footer-wrap text-center"> <el-button @click="isShow = false">取 消</el-button> <el-button type="primary" :disabled="!latitude" @click="pickedHandler">{{'确 定'}}</el-button> </div> </el-dialog> </template> <script> export default { name: 'PickerQMapPositionModal', props: { show: { type: Boolean, default: false }, title: { type: String, default: '地图描点' }, dialogProps: { type: Object, reuired: true } }, data () { return { latitude: '', longitude: '' } }, computed: { isShow: { get () { return this.show }, set (val) { this.$emit('update:show', val) } } }, mounted () { this.init() }, methods: { init () { this.initMap() }, async initMap () { // if (!window.TMap) { // } await this.$hktUtils.loadJS('https://map.qq.com/api/gljs?v=1.exp&key=VQ6BZ-ZFSW6-H36SN-E7TZL-QZ6U6-O3F24') var center = new TMap.LatLng(28.239377,112.866161) //定义map变量,调用 TMap.Map() 构造函数创建地图 var map = new TMap.Map(this.$refs.mapContainer, { center: center,//设置地图中心点坐标 zoom: 15, //设置地图缩放级别 // pitch: 43.5, //设置俯仰角 // rotation: 45 //设置地图旋转角度 }); //初始化marker图层 var markerLayer = new TMap.MultiMarker({ id: 'marker-layer', map: map }); map.on("click", (evt) => { if(markerLayer.geometries && markerLayer.geometries.length > 0) { markerLayer.remove(markerLayer.geometries[0].id) } markerLayer.add({ position: evt.latLng }); console.log('evt.latLng', evt.latLng, evt) this.latitude = evt.latLng.lat.toFixed(7) this.longitude = evt.latLng.lng.toFixed(7) }) }, pickedHandler () { this.$emit('callback', { latitude: this.latitude, longitude: this.longitude }) this.isShow = false } } } </script> <style lang="scss" scoped> .map-container { width:100%; height:70vh; } </style> Java端计算距离核心代码package com.hkt.jianfa.rental.housing.manager.wx.util; /** * 根据经纬度计算距离的工具类 * * @author 朱治龙(i@zhuzhilong.cn) * @since 2021-06-29 16:22:18 */ public class DistanceUtil { //地球平均半径 private static final double EARTH_RADIUS = 6378137; //把经纬度转为度(°) private static double rad(double d) { return d * Math.PI / 180.0; } /** * 根据两点间经纬度坐标(double值),计算两点间距离,单位为米 * * @param lng1 第1个坐标的经度值 * @param lat1 第1个坐标的纬度值 * @param lng2 第2个坐标的经度值 * @param lat2 第2个坐标的纬度值 * @return */ public static double getDistance(double lng1, double lat1, double lng2, double lat2) { double radLat1 = rad(lat1); double radLat2 = rad(lat2); double a = radLat1 - radLat2; double b = rad(lng1) - rad(lng2); double s = 2 * Math.asin( Math.sqrt( Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2) ) ); s = s * EARTH_RADIUS; s = Math.round(s * 10000) / 10000; return s; } /** * 传入逗号分隔的两个经纬度的值计算巨鹿 * * @param position1 第一个经纬度 * @param position2 第二个经纬度 * @return */ public static double getDistance(String position1, String position2) { if (position1.contains(",") && position2.contains(",")) { String[] point1 = position1.split(","); String[] point2 = position2.split(","); return getDistance(Double.parseDouble(point1[1]), Double.parseDouble(point1[0]), Double.parseDouble(point2[1]), Double.parseDouble(point2[0])); } return 0; } /** * 将距离数值转换为前端显示所需的字符串信息 * * @param distance * @return */ public static String decodeDistance(double distance) { if (distance < 1000) { return "<1km"; } else if (distance / 1000 > 100) { return ">100km"; } else { return new Double(distance / 1000).intValue() + "km"; } } } 业务逻辑类中调用DistanceUtil方法计算距离:小程序中获取位置后,将经纬度信息传给后端计算距离及排序核心代码如下:uni.getLocation({ type: 'gcj02', success: (res) => { this.searchForm.sort = 'distance' this.searchForm.location = res.latitude + ',' + res.longitude this.getProjects() }, fail: (err) => { this.getProjects() } })
2021年06月30日
139 阅读
0 评论
3 点赞
2021-06-02
33个JavaScript常用函数封装方法汇总
这是我在实际开发中常用的一些js函数方法,今天总结了一下,以便以后查询,有需要的小伙伴可以参考下。有些人或许会觉得忘了百度就完事儿,No no no!这事儿我真的亲自实践过好多次,百度一次记住了还好,记不住下次碰着了还得找度娘简直是拉低工作效率。1、加载js || css || style const loadRes = function(name, type, fn) { // 加载js || css || style let ref if (type === 'js') { // 外部js ref = document.createElement('script') ref.setAttribute('type', 'text/JavaScript') ref.setAttribute('src', name) } else if (type === 'css') { // 外部css ref = document.createElement('link') ref.setAttribute('rel', 'stylesheet') ref.setAttribute('type', 'text/css') ref.setAttribute('href', name) } else if (type === 'style') { // style ref = document.createElement('style') ref.innerhtml = name } if (typeof ref !== 'undefined') { document.getElementsByTagName('head')[0].appendChild(ref) ref.onload = function() { // 加载完成执行 typeof fn === 'function' && fn() } } }2、获取url参数const getUrlParam = function(name) { // 获取url参数 let reg = new RegExp('(^|&?)' + name + '=([^&]*)(&|$)', 'i') let r = window.location.href.substr(1).match(reg) if (r != null) { return decodeURI(r[2]) } return undefined }3、本地存储const store = { // 本地存储 set: function(name, value, day) { // 设置 let d = new Date() let time = 0 day = (typeof(day) === 'undefined' || !day) ? 1 : day // 时间,默认存储1天 time = d.setHours(d.getHours() + (24 * day)) // 毫秒 localStorage.setItem(name, JSON.stringify({ data: value, time: time })) }, get: function(name) { // 获取 let data = localStorage.getItem(name) if (!data) { return null } let obj = JSON.parse(data) if (new Date().getTime() > obj.time) { // 过期 localStorage.removeItem(name) return null } else { return obj.data } }, clear: function(name) { // 清空 if (name) { // 删除键为name的缓存 localStorage.removeItem(name) } else { // 清空全部 localStorage.clear() } } }4、cookie操作【set,get,del】const cookie = { // cookie操作【set,get,del】 set: function(name, value, day) { let oDate = new Date() oDate.setDate(oDate.getDate() + (day || 30)) document.cookie = name + '=' + value + ';expires=' + oDate + "; path=/;" }, get: function(name) { let str = document.cookie let arr = str.split('; ') for (let i = 0; i < arr.length; i++) { let newArr = arr[i].split('=') if (newArr[0] === name) { return newArr[1] } } }, del: function(name) { this.set(name, '', -1) } }5、Js获取元素样式【支持内联】const getRealStyle = function(obj, styleName) { // Js获取元素样式【支持内联】 var realStyle = null if (obj.currentStyle) { realStyle = obj.currentStyle[styleName] } else if (window.getComputedStyle) { realStyle = window.getComputedStyle(obj, null)[styleName] } return realStyle }6、时间格式化const formatDate = function(fmt, date) { // 时间格式化 【'yyyy-MM-dd hh:mm:ss',时间】 if (typeof date !== 'object') { date = !date ? new Date() : new Date(date) } var o = { 'M+': date.getMonth() + 1, // 月份 'd+': date.getDate(), // 日 'h+': date.getHours(), // 小时 'm+': date.getMinutes(), // 分 's+': date.getSeconds(), // 秒 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度 'S': date.getMilliseconds() // 毫秒 } if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) } for (var k in o) { if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) } } return fmt }7、原生ajax操作const ajax = function(conf) { // ajax操作 let url = conf.url, data = conf.data, senData = [], // 封装后的数据 async = conf.async !== undefined ? conf.async : true, // ture为异步请求 type = conf.type || 'get', // 默认请求方式get dataType = conf.dataType || 'json', contenType = conf.contenType || 'application/x-www-form-urlencoded', success = conf.success, error = conf.error, isForm = conf.isForm || false, // 是否formdata header = conf.header || {}, // 头部信息 xhr = '' // 创建ajax引擎对象 if (data == null) { senData = '' } else if (typeof data === 'object' && !isForm) { // 如果data是对象,转换为字符串 for (var k in data) { senData.push(encodeURIComponent(k) + '=' + encodeURIComponent(data[k])) } senData = senData.join('&') } else { senData = data } try { xhr = new ActiveXObject('microsoft.xmlhttp') // IE内核系列浏览器 } catch (e1) { try { xhr = new XMLHttpRequest() // 非IE内核浏览器 } catch (e2) { if (error != null) { error('不支持ajax请求') } } }; xhr.open(type, type !== 'get' ? url : url + '?' + senData, async) if (type !== 'get' && !isForm) { xhr.setRequestHeader('content-type', contenType) } for (var h in header) { xhr.setRequestHeader(h, header[h]) } xhr.send(type !== 'get' ? senData : null) xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { if (dataType === 'json' && success != null) { let res = '' try { res = eval('(' + xhr.responseText + ')') } catch (e) { console.log(e) } success(res) // 将json字符串转换为js对象 }; } else { if (error != null) { error('通讯失败!' + xhr.status) } } } } }8、fetch请求的封装const fetch = function(url, setting) { // fetch请求的封装 let opts = { // 设置参数的初始值 method: (setting.method || 'GET').toUpperCase(), // 请求方式 headers: setting.headers || {}, // 请求头设置 credentials: setting.credentials || true, // 设置cookie是否一起发送 body: setting.body || {}, mode: setting.mode || 'no-cors', // 可以设置 cors, no-cors, same-origin redirect: setting.redirect || 'follow', // follow, error, manual cache: setting.cache || 'default' // 设置 cache 模式 (default, reload, no-cache) } let dataType = setting.dataType || 'json' // 解析方式 let data = setting.data || '' // 参数 let paramsFormat = function(obj) { // 参数格式 var str = '' for (var i in obj) { str += `${i}=${obj[i]}&` } return str.split('').slice(0, -1).join('') } if (opts.method === 'GET') { url = url + (data ? `?${paramsFormat(data)}` : '') } else { setting.body = data || {} } return new Promise((resolve, reject) => { fetch(url, opts).then(async res => { let data = dataType === 'text' ? await res.text() : dataType === 'blob' ? await res.blob() : await res.json() resolve(data) }).catch(e => { reject(e) }) }) }9、设备判断:android、ios、webconst isDevice = function() { // 判断是android还是ios还是web var ua = navigator.userAgent.toLowerCase() if (ua.match(/iPhone\sOS/i) === 'iphone os' || ua.match(/iPad/i) === 'ipad') { // ios return 'iOS' } if (ua.match(/Android/i) === 'android') { return 'Android' } return 'Web' }10、判断是否为微信const isWx = function() { // 判断是否为微信 var ua = window.navigator.userAgent.toLowerCase() if (ua.match(/MicroMessenger/i) === 'micromessenger') { return true } return false }11、文本复制功能const copyTxt = function(text, fn) { // 复制功能 if (typeof document.execCommand !== 'function') { console.log('复制失败,请长按复制') return } var dom = document.createElement('textarea') dom.value = text dom.setAttribute('style', 'display: block;width: 1px;height: 1px;') document.body.appendChild(dom) dom.select() var result = document.execCommand('copy') document.body.removeChild(dom) if (result) { console.log('复制成功') typeof fn === 'function' && fn() return } if (typeof document.createRange !== 'function') { console.log('复制失败,请长按复制') return } var range = document.createRange() var div = document.createElement('div') div.innerhtml = text div.setAttribute('style', 'height: 1px;fontSize: 1px;overflow: hidden;') document.body.appendChild(div) range.selectNode(div) var selection = window.getSelection() console.log(selection) if (selection.rangeCount > 0) { selection.removeAllRanges() } selection.addRange(range) document.execCommand('copy') typeof fn === 'function' && fn() console.log('复制成功') }12、判断是否是一个数组const isArray = function(arr) { // 判断是否是一个数组 return Object.prototype.toString.call(arr) === '[object Array]' }13、判断两个数组是否相等const arrayEqual = function(arr1, arr2) { //判断两个数组是否相等 if (arr1 === arr2) return true; if (arr1.length != arr2.length) return false; for (let i = 0; i < arr1.length; ++i) { if (arr1[i] !== arr2[i]) return false; } return true; }14、时间与时间戳转换const stamp = { // 时间,时间戳转换 getTime: function(time) { // 时间转10位时间戳 let date = time ? new Date(time) : new Date() return Math.round(date.getTime() / 1000) }, timeToStr: function(time, fmt) { // 10位时间戳转时间 return new Date(time * 1000).pattern(fmt || 'yyyy-MM-dd') } }15、常用正则验证const checkStr = function(str, type) { // 常用正则验证,注意type大小写 switch (type) { case 'phone': // 手机号码 return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str) case 'tel': // 座机 return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str) case 'card': // 身份证 return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str) case 'pwd': // 密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线 return /^[a-zA-Z]\w{5,17}$/.test(str) case 'postal': // 邮政编码 return /[1-9]\d{5}(?!\d)/.test(str) case 'QQ': // QQ号 return /^[1-9][0-9]{4,9}$/.test(str) case 'email': // 邮箱 return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str) case 'money': // 金额(小数点2位) return /^\d*(?:\.\d{0,2})?$/.test(str) case 'URL': // 网址 return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str) case 'IP': // IP return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str) case 'date': // 日期时间 return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str) case 'number': // 数字 return /^[0-9]$/.test(str) case 'english': // 英文 return /^[a-zA-Z]+$/.test(str) case 'chinese': // 中文 return /^[\u4E00-\u9FA5]+$/.test(str) case 'lower': // 小写 return /^[a-z]+$/.test(str) case 'upper': // 大写 return /^[A-Z]+$/.test(str) case 'HTML': // HTML标记 return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str) default: return true } }16、是否为PC端const isPC = function() { // 是否为PC端 let userAgentInfo = navigator.userAgent let Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'] let flag = true for (let v = 0; v < Agents.length; v++) { if (userAgentInfo.indexOf(Agents[v]) > 0) { flag = false break } } return flag }17、去除字符串空格const trim = function(str, type) { // 去除空格, type: 1-所有空格 2-前后空格 3-前空格 4-后空格 type = type || 1 switch (type) { case 1: return str.replace(/\s+/g, '') case 2: return str.replace(/(^\s*)|(\s*$)/g, '') case 3: return str.replace(/(^\s*)/g, '') case 4: return str.replace(/(\s*$)/g, '') default: return str } }18、字符串大小写转换const changeCase = function(str, type) { // 字符串大小写转换 type: 1:首字母大写 2:首页母小写 3:大小写转换 4:全部大写 5:全部小写 type = type || 4 switch (type) { case 1: return str.replace(/\b\w+\b/g, function(word) { return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase() }) case 2: return str.replace(/\b\w+\b/g, function(word) { return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase() }) case 3: return str.split('').map(function(word) { if (/[a-z]/.test(word)) { return word.toUpperCase() } else { return word.toLowerCase() } }).join('') case 4: return str.toUpperCase() case 5: return str.toLowerCase() default: return str } }19、过滤html代码const filterTag = function(str) { // 过滤html代码(把<>转换) str = str.replace(/&/ig, '&') str = str.replace(/</ig, '<') str = str.replace(/>/ig, '>') str = str.replace(' ', ' ') return str }20、生成随机数范围const random = function(min, max) { // 生成随机数范围 if (arguments.length === 2) { return Math.floor(min + Math.random() * ((max + 1) - min)) } else { return null } }21、阿拉伯数字转中文大写数字const numberToChinese = function(num) { // 将阿拉伯数字翻译成中文的大写数字 let AA = new Array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十') let BB = new Array('', '十', '百', '仟', '萬', '億', '点', '') let a = ('' + num).replace(/(^0*)/g, '').split('.') let k = 0 let re = '' for (let i = a[0].length - 1; i >= 0; i--) { switch (k) { case 0: re = BB[7] + re break case 4: if (!new RegExp('0{4}//d{' + (a[0].length - i - 1) + '}$').test(a[0])) { re = BB[4] + re } break case 8: re = BB[5] + re BB[7] = BB[5] k = 0 break } if (k % 4 === 2 && a[0].charAt(i + 2) !== 0 && a[0].charAt(i + 1) === 0) { re = AA[0] + re } if (a[0].charAt(i) !== 0) { re = AA[a[0].charAt(i)] + BB[k % 4] + re } k++ } if (a.length > 1) { // 加上小数部分(如果有小数部分) re += BB[6] for (let i = 0; i < a[1].length; i++) { re += AA[a[1].charAt(i)] } } if (re === '一十') { re = '十' } if (re.match(/^一/) && re.length === 3) { re = re.replace('一', '') } return re }22、原生dom操作const dom = { $: function(selector) { let type = selector.substring(0, 1) if (type === '#') { if (document.querySelecotor) return document.querySelector(selector) return document.getElementById(selector.substring(1)) } else if (type === '.') { if (document.querySelecotorAll) return document.querySelectorAll(selector) return document.getElementsByClassName(selector.substring(1)) } else { return document['querySelectorAll' ? 'querySelectorAll' : 'getElementsByTagName'](selector) } }, hasClass: function(ele, name) { /* 检测类名 */ return ele.className.match(new RegExp('(\\s|^)' + name + '(\\s|$)')) }, addClass: function(ele, name) { /* 添加类名 */ if (!this.hasClass(ele, name)) ele.className += ' ' + name }, removeClass: function(ele, name) { /* 删除类名 */ if (this.hasClass(ele, name)) { let reg = new RegExp('(\\s|^)' + name + '(\\s|$)') ele.className = ele.className.replace(reg, '') } }, replaceClass: function(ele, newName, oldName) { /* 替换类名 */ this.removeClass(ele, oldName) this.addClass(ele, newName) }, siblings: function(ele) { /* 获取兄弟节点 */ console.log(ele.parentNode) let chid = ele.parentNode.children, eleMatch = [] for (let i = 0, len = chid.length; i < len; i++) { if (chid[i] !== ele) { eleMatch.push(chid[i]) } } return eleMatch }, getByStyle: function(obj, name) { /* 获取行间样式属性 */ if (obj.currentStyle) { return obj.currentStyle[name] } else { return getComputedStyle(obj, false)[name] } }, domToStirng: function(htmlDOM) { /* DOM转字符串 */ var div = document.createElement('div') div.appendChild(htmlDOM) return div.innerHTML }, stringToDom: function(htmlString) { /* 字符串转DOM */ var div = document.createElement('div') div.innerHTML = htmlString return div.children[0] } }23、判断图片加载完成const imgLoadAll = function(arr, callback) { // 图片加载 let arrImg = [] for (let i = 0; i < arr.length; i++) { let img = new Image() img.src = arr[i] img.onload = function() { arrImg.push(this) if (arrImg.length == arr.length) { callback && callback() } } } }24、音频加载完成操作const loadAudio = function(src, callback) { // 音频加载 var audio = new Audio(src) audio.onloadedmetadata = callback audio.src = src }25、光标所在位置插入字符const insertAtCursor = function(dom, val) { // 光标所在位置插入字符 if (document.selection) { dom.focus() let sel = document.selection.createRange() sel.text = val sel.select() } else if (dom.selectionStart || dom.selectionStart == '0') { let startPos = dom.selectionStart let endPos = dom.selectionEnd let restoreTop = dom.scrollTop dom.value = dom.value.substring(0, startPos) + val + dom.value.substring(endPos, dom.value.length) if (restoreTop > 0) { dom.scrollTop = restoreTop } dom.focus() dom.selectionStart = startPos + val.length dom.selectionEnd = startPos + val.length } else { dom.value += val dom.focus() } }26、图片地址转base64const getBase64 = function(img) { //传入图片路径,返回base64,使用getBase64(url).then(function(base64){},function(err){}); let getBase64Image = function(img, width, height) { //width、height调用时传入具体像素值,控制大小,不传则默认图像大小 let canvas = document.createElement("canvas"); canvas.width = width ? width : img.width; canvas.height = height ? height : img.height; let ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); let dataURL = canvas.toDataURL(); return dataURL; } let image = new Image(); image.crossOrigin = ''; image.src = img; let deferred = $.Deferred(); if (img) { image.onload = function() { deferred.resolve(getBase64Image(image)); } return deferred.promise(); } }27、base64图片下载功能const downloadFile = function(base64, fileName) { //base64图片下载功能 let base64ToBlob = function(code) { let parts = code.split(';base64,'); let contentType = parts[0].split(':')[1]; let raw = window.atob(parts[1]); let rawLength = raw.length; let uInt8Array = new Uint8Array(rawLength); for (let i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); } return new Blob([uInt8Array], { type: contentType }); }; let aLink = document.createElement('a'); let blob = base64ToBlob(base64); //new Blob([content]); let evt = document.createEvent("HTMLEvents"); evt.initEvent("click", true, true); //initEvent不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为 aLink.download = fileName; aLink.href = URL.createObjectURL(blob); aLink.click(); }28、浏览器是否支持webP格式图片const isSupportWebP = function() { //判断浏览器是否支持webP格式图片 return !![].map && document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0; }29、url参数转对象const parseQueryString = function(url) { //url参数转对象 url = !url ? window.location.href : url; if (url.indexOf('?') === -1) { return {}; } let search = url[0] === '?' ? url.substr(1) : url.substring(url.lastIndexOf('?') + 1); if (search === '') { return {}; } search = search.split('&'); let query = {}; for (let i = 0; i < search.length; i++) { let pair = search[i].split('='); query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || ''); } return query; }30、对象序列化【对象转url参数】const stringfyQueryString = function(obj) { //对象序列化【对象转url参数】 if (!obj) return ''; let pairs = []; for (let key in obj) { let value = obj[key]; if (value instanceof Array) { for (let i = 0; i < value.length; ++i) { pairs.push(encodeURIComponent(key + '[' + i + ']') + '=' + encodeURIComponent(value[i])); } continue; } pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])); } return pairs.join('&'); }31、H5软键盘缩回、弹起回调const h5Resize = function(downCb, upCb) { //当软件键盘弹起会改变当前 window.innerHeight,监听这个值变化 [downCb 当软键盘弹起后,缩回的回调,upCb 当软键盘弹起的回调] var clientHeight = window.innerHeight; downCb = typeof downCb === 'function' ? downCb : function() {} upCb = typeof upCb === 'function' ? upCb : function() {} window.addEventListener('resize', () => { var height = window.innerHeight; if (height === clientHeight) { downCb(); } if (height < clientHeight) { upCb(); } }); }32、函数防抖const debounce = function(func, wait, immediate) { //函数防抖[func 函数,wait 延迟执行毫秒数,immediate true 表立即执行,false 表非立即执行,立即执行是触发事件后函数会立即执行,然后n秒内不触发事件才能继续执行函数的效果] let timeout; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } else { timeout = setTimeout(function() { func.apply(context, args) }, wait); } } }33、函数节流const throttle = function(func, wait ,type) { //函数节流 [func 函数 wait 延迟执行毫秒数 type 1 表时间戳版,2 表定时器版] if(type===1){ let previous = 0; }else if(type===2){ let timeout; } return function() { let context = this; let args = arguments; if(type===1){ let now = Date.now(); if (now - previous > wait) { func.apply(context, args); previous = now; } }else if(type===2){ if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) } } } }整理至此,请用心记!!!!以上方法可通过该工具自动获取生成哦:http://www.fly63.com/tool/code/来源 | http://www.fly63.com/article/detial/10362
2021年06月02日
124 阅读
0 评论
0 点赞
2021-05-26
node安装node-sass失败的处理方案
安装 node-sass 的时候总是会各种不成功,大部分安装不成功的原因都源自这里,因为 GitHub Releases 里的文件都托管在 s3.amazonaws.com上面,而这个网址在国内总是网络不稳定,所以我们需要通过第三方服务器下载这个文件。方法一:使用淘宝源npm config set sass_binary_site=https://npmmirror.com/mirrors/node-sass/ npm config set phantomjs_cdnurl=https://npmmirror.com/mirrors/phantomjs/ npm config set electron_mirror=https://npmmirror.com/mirrors/electron/ npm config set registry=https://registry.npmmirror.com这样使用 npm install 安装 node-sass、electron 和 phantomjs 时都能自动从淘宝源上下载。方法二:安装cnpm >>> 也是淘宝源的做法npm install -g cnpm cnpm install这样也可以成功安装node-sass方法三:使用VPNnpm config set proxy (http://127.0.0.1:1080)此处是VPN的代理地址 npm i node-sass # 下载完成后删除 http 代理 npm config delete proxy
2021年05月26日
128 阅读
0 评论
0 点赞
我的日常开发工具分享
今天跟大家分享下我日常工作中常用的一些工具,或许可以帮到你提升日常的协作效率1.写作篇 ✏️1.1 EdiaryEdiary是我坚持使用最久的一款日常工作记录及知识沉淀的工具,作者也是一个很有情怀的人,从1999年发布第一个版本以来,一直维护到现在, 官方链接1.2 语雀语雀是一个蚂蚁金服孵化出来的专业的云端知识库,类似wiki,目前已经覆盖了10 万阿里员工的使用,来进行文档编写及知识沉淀 官方链接语雀我常用的两个方面思维导图:一个是语雀自带的思维导图,个人觉得UI体验很强(外表协会)日记编排:用语雀来保持记录每天在前端开发中遇到的问题及心得体会,方便复盘和回归,最重要的是排版体验高,支持编排,当你回顾你写的文章的时候,阅读体验高,像是在翻书一样1.3 ProcessOnProcessOn是一个在线协作绘图平台,为用户提供最强大、易用的作图工具。支持在线创作流程图、思维导图、组织结构图、网络拓扑图、BPMN、UML图、UI界面原型设计等我主要用ProcessOn来绘制交互图及流程图,支持在线实时编辑,不足的就是如果非付费用户则会限制绘制图的数量,下面是操作页面1.4 CarbonCarbon 用来创建美化版的代码片段,可筛选多种主题切换,然后生成你想要效果的代码片段图 官方链接1.5 Mdnicemdnicde全名为Markdown Nice,支持给markdown添加“主题元素”,有点像换肤的感觉,支持多种主观,让你的文章仿佛披上了嫁衣,最重要的是支持微信公众号、知乎、还有掘金!官方链接1.6 TyporaTypora是一款轻便简洁的Markdown编辑器,支持即时渲染技术,这也是与其他Markdown编辑器最显著的区别,将写作与预览窗口相结合,为用户呈现所见即所得的编辑模式,支持Markdown的各种基础语法,支持快捷键操作。官方链接1.7 封面模版很多童鞋很好奇,我每次文章都会附上一张主题图,是不是自己P的,虽然我会用PS做些简单的P图,但是设计还是蛮琐碎和耗时的活,时间应该用在更宝贵的地方,这里介绍的就是我使用的模版在线编辑工具 - 凡科快图 官方链接 或者 canva 官方链接1.8 Shieldsshields.io 主要是用来可以生成 在Markdown 文档中的徽章,我们经常在github的项目上看到这些徽章,来表述比如单元测试覆盖率、打包的大小、版本信息、认证信息等 官方链接1.9 Gif截图有时候图片无法去表达我们想要阐述的内容,这个时候动态图就起了很重要的作用,可以更直观的描述整个过程,我个人常用的工具为ScreenToGif官方链接 ,是一款小巧、免费、开源且功能强大的工具,1.10 网页OR屏幕截屏文章素材需要网页截图?很长时间我要给当前网页截图,一般我们常用的桌面版IM工具(如QQ、微信、钉钉)都能使用快捷键很方便的实现截屏功能,但是面对滚动截图、截取后二次编辑等功能时,这些工具就有些捉襟见肘了,在此个人推荐使用FastStone Capture官方链接。2.效率篇 ⏰在日常开发中,效率工具的使用,往往可以给我减少很多不必要时间的浪费,通过工具赋能,帮助我们提高生产效能2.1 Iconfont 图标库Iconfont 是阿里打造的图片管理平台,涵盖海量图标库,可讲选择的图标导出字体文件。 官方链接2.3 Postwoman 接口调试利器它不仅免费开源、轻量级、快速,而且还有美观的API调试工具,原名为Postwoman。能帮助我们节省时间,提升工作效率。官方链接2.4 CanIuse 兼容性查询can I use? 顾名思义:我能使用吗,能快速让我们查看浏览器对某个属性语法的兼容情况,场景应用当前在某个浏览器可以正常使用,可是换了另一个浏览器之后就不支持了,这个时候就得我们防患于未然,在对某个属性使用前,做好足够得调研,而不是等到上线才发现问题官方链接2.5 Prettier Playground 代码在线格式化应用场景:当我使用的电脑没有安装IDE,但是我又需要看别人写的代码,这个时候 Prettier Playground可以帮我将原本凌乱的代码改头换面,大大提高可读性 官方链接左边为源代码,右边为格式化后的代码
2021年05月10日
117 阅读
0 评论
0 点赞
2021-05-09
学会尊重,从我做起!
把“随便”改成“听你的”;把“我不会”改成“我可以学”;把“听明白了吗?”改成“我说明白了吗”沟通让人感到尊重的温柔!努力习惯温柔的沟通方式~~
2021年05月09日
51 阅读
0 评论
0 点赞
2021-05-09
观《新喜剧之王》有感
趁这段时间没那么紧迫的工作节奏,在陪老婆和邵邵看完《哪吒重生》后意犹未尽,挑了几个家庭云盘中尘封已久的高清大片看看,看完《新喜剧之王》后,感觉剧中主角的精神特别适合现今浮躁的社会环境。芸芸众生,我们都是小人物,小人物的人生可以平凡,但是都有追梦的权利。而梦想和权利都值得尊重。平凡人在平凡的世界里辛苦奋斗,为的是追求一丁点“不平凡”的权利。让自己不放弃对更好生活的追求,又不让梦想把自己吞噬。我们就是靠着一点点坚持,在漫长的人生中,走过来的。只要你坚持做一件事,时间都会给你馈赠。也许不能获得多伟大的成就,但最终能让一个平凡的生命闪起微光来。鸡蛋,从外打破是食物,从内打破是生命。人生亦是,从外打破是压力,从内打破是成长。如果你等待别人从外打破你,那么你注定成为别人的食物;如果能让自己从内打破,那么你会发现自己的成长相当于一种重生。
2021年05月09日
38 阅读
0 评论
0 点赞
2020-12-14
CentOS中JDK及Tomcat安装记录
本文仅作为日常工作中的部署记录,相关操作仅供参考一、安装JDK及配置安装JDK文件拷贝到/data/webapps/目录cp jdk-8u271-linux-x64.tar.gz /usr/local/jdk/进入目录cd /usr/local/jdk/解压到当前目录tar -zxvf jdk-8u271-linux-x64.tar.gz配置环境变量编辑/etc/profile文件sudo vi /etc/profile在文件底部追加如下环境变量设置信息JAVA_HOME=/usr/local/jdk/jdk1.8.0_271 PATH=$JAVA_HOME/bin:$PATH CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export JAVA_HOME export PATH export CLASSPATH执行如下命令更新环境变量source /etc/profile验证是否生效[root@VM-0-17-centos jdk1.8.0_271]# java -version java version "1.8.0_271" Java(TM) SE Runtime Environment (build 1.8.0_271-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode) [root@VM-0-17-centos jdk1.8.0_271]# 二、部署Tomcat创建Tomcat安装目录mkdir -p /wxdata/javaapps/拷贝文件到安装目录cp apache-tomcat-8.5.46.tar.gz /wxdata/javaapps/进入安装目录cd /wxdata/javaapps/解压安装文件tar -zxvf apache-tomcat-8.5.59.tar.gz 修改目录名为tomcat8-pmsdemomv apache-tomcat-8.5.59 tomcat8-pmsdemo
2020年12月14日
74 阅读
0 评论
0 点赞
1
...
5
6
7
8