风驰电掣又一年

文章目录
  1. 每日打卡:
  2. 编程:
  3. 德州

不知不觉一年过去了,马上就又要春节了,去年过年期间逛古镇,坐游轮的那些回忆仿佛都发生在昨天,时间对于我来说,正在以诡异的加速度一路向前飞驰。

这一年还是有很多改变和成长,也一直让自己刻意保持着仿佛年轻人一般的好奇心,坚持着自律,结果每日的打卡内容又多了好几项,再加上工作内容的改变,自己仿佛变成了一只陀螺,还好是一只快乐的陀螺……

每日打卡:

  1. 每天日记:7266天
  2. 扇贝单词:2281天
  3. 健身运动:2168天
  4. (新增)微信读书:256天,1015小时
  5. ……

编程:

之前多少年一直都只用 java ,直到 24 年开始尝试使用 python,才发现原来真的是“人生苦短,我用python”啊

  1. B站高清视频下载:262 行
  2. XX 网站资源的下载:417行
  3. fastapi 框架 vs springboot

德州

年前因为部门的团建入坑德州,结果原本每周25小时+的微信读书,因为德州的吸引,骤降到10小时+了,这下过年时可以召集一大家子人快乐的游戏了。:)

龙年到,又到了搬迁时刻

文章目录
  1. 迁移 Nginx
    1. Nginx 中的配置
  2. 迁移 Gogs
  3. Git Repo 的配置

去年此时,用了三年的两台华为云主机到期了,再续费成本已是天价。原本准备搬迁到成本更低的云服务厂商,结果发现自己实在懒得搬迁 nginx,gogs 等一堆的服务,最后降主机数量,降配置,降带宽续了1年,现在马上又要到期了,此时手里已经有了腾讯云的3年便宜云主机,必须要搬迁了。

不想再跟以前一样一个个的去搭建各种服务,于是尝试容器化部署。对 docker 实在还是不熟悉,前后折腾了快一天,才算勉强在容器上跑起了 nginx 和 gogs。其实自己挺愿意探索技术,写点心得什么的,只是这几年经济形势不好,公司组织结构调整,部门转型做产品,早已没有了往日的那份清闲,终日卷的要死,我的心中一直很矛盾,一方面恨不得马上退休享受生活,另一方面又暗暗盼望着哪怕这样卷着,自己也能一直在公司里狗下去,毕竟就算不再升级,当前的收入也是让人安心的。只是未来太多不确定性,我找不到平衡点,难以做决定,未来总是在迷雾中,向前的每一步都是摸索,只有回头时才会发现当年的自己有多么幼稚和愚蠢,然后周而复始……

# 服务搬迁:
  1. 从原来的主机服务迁移到容器化部署
  2. 迁移 Nginx(含证书)
  3. 迁移 GOGS
  4. 迁移相关定时任务和脚本

迁移 Nginx

启动 Nginx 服务

1
docker run -d -p 80:80 -p 443:443 --name nginx --add-host host.docker.internal:host-gateway --network ice-network --network-alias nginx -v /root/opt/nginx/html:/usr/share/nginx/html -v /root/opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /root/opt/nginx/logs:/var/log/nginx -v /root/opt/nginx/cert:/data/cert nginx
  1. –add-host :使容器可以访问本地的服务
  2. –network:使容器间共享网络,可以彼此访问
  3. -v:将配置文件、内容、日志、证书目录映射到本地

证书之前用的是 certbot 的免费证书,每3个月更新一次,有点麻烦,刚才迁移服务时才发现腾讯云提供免费的证书,每年更新即可。

Nginx 中的配置

可以直接使用 –network-alias gogs 中的别名,注意后面的端口号是容器内的端口号

可以使用 host.docker.internal 访问宿主机上的服务

upstream gitserver {
  server gogs:3000;
}
upstream grafana {
  server host.docker.internal:2999;
}

配置 SSL 访问和证书、秘钥路劲

listen  443 ssl default_server;
listen  [::]:443 ssl default_server;
server_name  welooking.cn;
#rewrite ^(.*)$ https://$host$1 permanent;
if ($server_port = 80) {
  rewrite ^(.*)$ https://$host$1 permanent;
}
root    /usr/share/nginx/html/blog;

ssl_certificate "/data/cert/welooking.cn_bundle.crt";
ssl_certificate_key "/data/cert/welooking.cn.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout  10m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;

#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;

迁移 Gogs

1
docker run -d --name=gogs --network ice-network --network-alias gogs -p 10022:22 -p 10300:3000 -v /root/opt/gogs:/data gogs/gogs
  1. –network:使容器间共享网络,可以彼此访问
  2. –network-alias:指定别名,以便在容器中使用
  3. -v:将数据目录映射到本地

Git Repo 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
将原本华为云主机上的 git repo 目录拷贝到腾讯云后,会出现无法 git pull 的问题

git pull
hint: Pulling without specifying how to reconcile divergent branches is
hint: discouraged. You can squelch this message by running one of the following
hint: commands sometime before your next pull:
hint:
hint: git config pull.rebase false # merge (the default strategy)
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Authentication failed for 'http://welooking.cn/xxx/xxx/xxx.git/'

处理方案:

  1. 执行 git config pull.rebase false
  2. 修改 .git/config 文件,修改其中的 url,注意这里是 https
1
2
3
[remote "origin"]
url = https://username:password@welooking.cn/xxx/xxx/xxx.git
fetch = +refs/heads/master:refs/remotes/origin/master

让人抓狂的问题:不管怎么尝试,死活无法push,在gogs页面上也不能上传文件,编辑或者新建都失败……

网上搜了半天都是说什么权限问题,可以强制提交什么,都是扯淡……

1
2
3
4
5
6
7
8
9
10
11
12
git credential-'cache store: -c: line 0: unexpected EOF while looking for matching `''
git credential-'cache store: -c: line 1: syntax error: unexpected end of file
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 3.18 KiB | 3.18 MiB/s, done.
Total 5 (delta 2), reused 0 (delta 0)
remote: hooks/pre-receive: line 2: /home/git/gogs/gogs: No such file or directory
To https://welooking.cn/gogs/ice/hexo.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://welooking.cn/xxx/xxx/xxx.git'

主要原因就是在于 gogs 有一大堆默认的 hook 要执行,这些 hook 跟之前安装的 gogs 路径有关,需要做重置操作。

1
控制面板-> 管理员操作-> 重新同步所有仓库的钩子

PS:8天的春节假期一闪而过,明早又要上班了,可我还想,再放……500天……

通过 FRP 使外网可以访问内网主机上的服务

文章目录
  1. 1、下载 frp
  2. 2、在云主机上启动 frps 服务
  3. 3、在本地主机上启动 frpc 服务
  4. 4、在本地主机上启动服务,验证外网访问

背景:云上的服务太贵了,1C1G 最小配置,1M 带宽的 ECS 主机一年近 700¥ 勉强能接受,一套最小配置的 kafka,一套最小配置的 elasticsearch 集群一个月就要近 2000¥,实在不是作为业余爱好能消费的起的。所以想这些服务就用家里的主机搭建,外部能访问即可。

解决方案:

  1. 购买云主机和公网 IP,部署 nginx 等不怎么消耗资源的接入服务。
  2. 在云主机上启动 frps 服务。
  3. 在家里的台式机上部署 kafka、elasticsearch、kibana、微服务等消耗资源的服务。
  4. 在家里的台式机上启动 frpc 服务,连接云主机上的 frps,对外提供台式机上部署的服务。
  5. 只要家里主机开启,即可通过第一步中购买的公网 IP(或者 DNS)来访问了。

具体步骤如下:

1、下载 frp

frp 在 github 官网上直接 下载 即可:

1
wget https://github.com/fatedier/frp/releases/download/v0.47.0/frp_0.47.0_linux_amd64.tar.gz

注意:
1、最新的 frp 0.47.0 的 release 列表中没有 windows 下的版本了。
2、但是实际路径依然存在,可以通过如下地址直接下载:https://github.com/fatedier/frp/releases/download/v0.47.0/frp_0.47.0_windows_amd64.zip

2、在云主机上启动 frps 服务

我的云主机是 centOS 系统,下载对应 OS 的 frp 后解压缩,编辑配置文件,然后启动服务端:

1
2
3
4
tar xf frp_0.47.0_linux_amd64.tar.gz
cd frp_0.47.0_linux_amd64
vi frps.ini
nohup ./frps -c frps.ini > /dev/null 2>&1 &

配置文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
[common]
bind_port = 7000 # 默认绑定的端口号
token = 12345678 # 增强安全的 token
# 默认启动的 dashboard 相关信息
dashboard_addr = 0.0.0.0
dashboard_port= 7500
dashboard_user = username
dashboard_pwd = password
# 日志配置
log_file = ./frps.log
log_level = info
log_max_days = 3

正常启动后,可以在日志文件中看到如下信息:

1
2
3
4
2023/02/12 13:52:10 [I] [root.go:206] frps uses config file: frps.ini
2023/02/12 13:52:10 [I] [service.go:200] frps tcp listen on 0.0.0.0:7000
2023/02/12 13:52:10 [I] [service.go:317] Dashboard listen on 0.0.0.0:7500
2023/02/12 13:52:10 [I] [root.go:215] frps started successfully

在浏览器中输入 http://你的公网IP或者域名:7500 ,可以看到 frp 的管理面 dashboard:

注意:
1、如果访问不通,请确定你的云主机上开启了正确的安全组策略。
2、可参考如下的教程: 阿里、华为、腾讯 云服务器端口配置教程汇总

3、在本地主机上启动 frpc 服务

我本地主机是 win10 系统,按第一步下载对应 OS 的 frp 包后解压缩,编辑配置文件,然后启动客户端:

  1. 解压缩下载的 zip 包:frp_0.47.0_windows_amd64.zip
  2. 进入解压缩目录,编辑 frpc.ini 文件,内容如下:
  3. 启动 frpc 服务:frpc -c frpc.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[common]
server_addr = xxx.xxx.xxx.xxx # 你的公网 IP 地址
server_port = 7000 # 之前配置的 frps 的端口
token = 12345678 # 之前配置的 frps 的 token

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 3389
remote_port = 10000

[elastic] # 任意你需要添加代理的服务
type = tcp # 注意这里是 TCP
local_ip = 127.0.0.1
local_port = 9200
remote_port = 10001

[kibana]
type = tcp # 注意这里是 TCP
local_ip = 127.0.0.1
local_port = 5601
remote_port = 10002

可能的问题:

  1. 本地安装的防火墙、杀毒软件捣乱:我的 win10 系统上的 360 杀毒总是把下载的 frp 包当病毒给自动删除了
  2. 即使找回了删除的文件,运行时也被 360 阻断,执行 frpc 时总是提示:“拒绝访问。”,所以要么加入到白名单,要么执行时关掉杀毒软件
  3. 代理的服务如 elastic 或者 kibana 访问时都是 http 协议的,但是如果在配置时 type 配置成 http,启动时会报错,提示如下:failed to parse proxy elastic, err: custom_domains and subdomain should set at least one of them

4、在本地主机上启动服务,验证外网访问

将刚才配置在客户端配置中的服务启动,在 frps 的 dashboard -> proxies -> TCP 菜单上可以看到我们当前已经建立的 ssh、elasticsearch、kibana 这三个 端口、流量、状态等信息:

用手机访问如下地址验证了,确实可以从外部访问我本地搭建的这些服务了

  1. 访问 elasticsearch:http://我的域名:10001
  2. 访问 kibana:http://我的域名:10002

感觉一下省了大几千……

收到续费提醒,才发现3年就这么过去了

文章目录

昨天收到华为云的续费提醒短信,才发现3年前购买的两台华为云主机已经马上到期了,很是感叹,3年前一腔热血的想构建自己的线上王国,结果是买完服务器就一直荒在那里,工作和生活上的压力导致最近2年根本就没有一丝一毫精力能投在上面,我真不是创业型的人,也没有多强的执行力,一个原本的技术博客没多久变成了心情日记,现在则是年记了,上一条差不多就是1年前的样子了。

疫情就这么突兀的结束了,工作和生活还要继续,这个博客虽然只是自己心血来潮创建的,也不怎么更新,但是想想还是不忍心就这样彻底放弃,于是准备续费,只是发现当初花了500多买了2台2c4g云主机3年的使用时间,现在如果要续费,1台1年就要近2000,这就有些无法接受了,于是开始有些能体会到企业上云后的IT成本压力了,云也不是万能的,云也也是要吸金要钱的啊。各种搜索省钱的方案,要不就是用全新的账号申请新主机,能享受到云厂商的新手大礼包优惠,要么就得换云厂商,不管是前者还是后者,都要涉及到已经搭建在上面的服务的迁移,实在是不想,也没有时间和心力折腾了,只好从简配方面来想办法了。

最终方案如下:

  1. 数量减少: 2 台主机减少为 1 台。
  2. 主机简配:从 2C4G 降低为 1C1G 。
  3. 带框降低:从 2M 带宽降低到 1M 带宽。

即使这样,一年费用算下来也要 670 左右,比之前 1 台高配主机 3 年的总费用还要高,只能感叹,上船容易下船难啊。

域名重备案,翻看历史文章才发现被评论攻击了……

文章目录

最近1年真是忙得团团转了,当初还雄心勃勃的要打造自己的技术博客,要沉下心来好好写写文章,还特意去买了云主机,搭建自己的博客系统,结果最近12个月一篇都没再写了。工作上是忙,但是真是没时间吗?肯定也不是,真是每天回家或者周末放假时只想着要好好放松休息,打游戏,刷抖音总是很容易让人上瘾,对比起来认真的写文章确实是有点对抗天性了。

上周因为疫情居家办公时,意外的接到阿里云客服的电话,说是我的网站现在已经没有在它们的服务器上了,但是网站备案是在它们那里做的。所以要求我尽快把备案迁移到现在的服务器提供商处,原本以为只是简单的做个迁移即可,结果实际上发现是要完全重新备案,填写各种信息上传身份证也就罢了,麻烦的是那个承诺书,要手写签名加印章,疫情封闭在家,根本没法打印,就只好等到这周解封后去公司打印了,晚上回到家速度上传资料申请备案后,就顺便翻了下博客上的历史文章,结果大吃一惊,好几篇博客都无法打开了,点击页面后赫然出现这样的页面,第一反应是遭到攻击了吧?

速度ssh登录到服务器上看,发现 last 命令失败,提示 wtmp 文件不存在,手忙脚乱的恢复后查了半天也没看出来有人恶意更改我的页面。折腾到12点半没找到原因,无奈修改了 root 的密码后先睡了。今天下班后回来继续分析原因,才发现居然是评论系统的 Valine 的锅,有人在评论中恶意的刷了如下代码,导致每次页面载入后一加载评论就会出现上面的页面。

最终的解决方案:上 LeanCloud 把丫的病毒评论统统删除!

PS:华为云备案审核居然没通过,说是打我电话没接通,此外网站最下方的备案号没有连接备案管理系统的网站,只好再提一次备案,希望这次别再中午午休时打我电话了,听不到啊!

Win10下Flink探索(1)

文章目录
  1. 下载 Flink
  2. 启动服务
  3. 创建 Flink 项目
  4. 运行 WordCount 代码(批处理)
  5. 运行 StreamWordCount 代码(流处理)
  6. 其他

下载 Flink

在 flink 官网上 下载 旧版本:

1
wget https://archive.apache.org/dist/flink/flink-1.9.3/flink-1.9.3-bin-scala_2.12.tgz

注意:
1、最新的 flink 1.12.2 版本不支持windows,下载后在其bin目录下没找到启动的批处理。
2、flink 1.9.3 和 flink 1.10.0经过测试都可以win10下启动(flink 1.10.3也没有windows下启动的批处理文件)

启动服务

解压缩上面下载的包,直接在bin目录下运行 start-cluster.bat 即可:

1
2
cd flink-1.9.3
bin\start-cluster.bat

正常启动后会打开两个命令行窗口,此时在浏览器中访问 http://localhost:8081 即可看到 flink 的 UI 界面。

注意:
1、如果是 flink-1.10.0版本,启动后一开始显示两个命令行窗口,然后很快其中一个会被关掉,在界面上看不到任何 Task Manager 信息。
2、参考 Window10安装Flink1.10.0-大坑 的尝试,不建议大家在win10下使用这个版本。

创建 Flink 项目

1、通过如下 maven 命令创建 flink项目:

1
mvn archetype:generate -DarchetypeGroupId=org.apache.flink -DarchetypeArtifactId=flink-quickstart-java -DarchetypeVersion=1.10.0

2、启动 Idea 导入 上面创建的 mvn 项目,自动创建的目录结构可能如下:

1
2
3
4
5
6
--src
--main
--java
--com.ice.stream # 上一步创建时自定义的 groupId
BatchJob.java
StreamingJob.java

运行 WordCount 代码(批处理)

1、新增如下 WordCount 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.util.Collector;

public class WordCount {
public static void main(String[] args) throws Exception {
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
DataSet<String> source = env.fromElements("I love Beijing", "I love China", "Beijing is the capital of China");
source.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words = value.split(" ");
for (String w : words) {
out.collect(new Tuple2<String, Integer>(w, 1));
}
}
}).groupBy(0).sum(1).print();
env.execute("Java WordCount from Example");
}
}

2、运行:有两种方式,一种是IDE内运行,直接在 WordCount.java 上单击右键运行:

注意:因为 pom.xml 中对 flink 的依赖包设定了 provided scope,如果直接在 IDE 中运行会报找不到 Flink 相关类的错误,所以需要编辑启动配置,选中 ‘Include dependencies with “Provided” scope’ 即可:

1
2
3
4
5
6
7
8
9
10
11
12
><dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>

3、另外一种方式是打包后提交到 flink ui 上运行:通过如下命令打包

1
mvn clean package

生成的 flink-1.0-SNAPSHOT.jar 大小约 10k (不带 flink core依赖),在 UI 界面上点击 “submit new job”,点击”add new”,选择上一步打好的包。然后单击 submit 提交,即可在 jobs 页面查看正在运行的 job。

问题:win10下 task manager 的Stdout一直没有输出,但是可以在 task manager的命令行窗口看到输出。原因大致是因为平台差异所致。(参考 windows下flink 8081页面taskmanager无输出 的说法,flink 在 linux 下启动就没有这种问题。

运行 StreamWordCount 代码(流处理)

1、新增如下 StreamWordCount 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;

public class StreamWordCount {
public static void main(String[] args) throws Exception {
//参数检查
if (args.length != 2) {
System.err.println("USAGE:\nSocketTextStreamWordCount <hostname> <port>");
return;
}
String hostname = args[0];
Integer port = Integer.parseInt(args[1]);
// set up the streaming execution environment
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//获取数据
DataStreamSource<String> stream = env.socketTextStream(hostname, port);
//计数
SingleOutputStreamOperator<Tuple2<String, Integer>> sum = stream.flatMap(new LineSplitter())
.keyBy(0)
.sum(1);
sum.print();
env.execute("Java WordCount from SocketTextStream Example");
}
public static final class LineSplitter implements FlatMapFunction<String, Tuple2<String, Integer>> {
@Override
public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) {
String[] tokens = s.toLowerCase().split("\\W+");
for (String token : tokens) {
if (token.length() > 0) {
collector.collect(new Tuple2<String, Integer>(token, 1));
}
}
}
}
}

2、通过 nc 开启 9999 端口:

1
netcat-win32-1.12\nc -L -p 9999

3、重新打包 flink 应用,通过如下命令启动流处理:

1
2
set FLINK_CONF_DIR=flink-1.9.3\conf
flink-1.9.3\bin\flink.bat run -c com.ice.stream.StreamWordCount flink\target\flink-1.0-SNAPSHOT.jar 127.0.0.1 9999

4、在 nc 开的窗口中输入随机字符串,即可在 flink 的 task manager的命令行窗口看到流处理统计的结果。例如当输入多行记录a,b,c,a,a,b,显示如下:

1
2
3
(a,3)
(b,2)
(c,1)

其他

1、win10 下安装 nc:直接在如下地址下载

1
https://eternallybored.org/misc/netcat/

2、注意:下载后如果有安装360,会报检测到病毒并直接删除。需要关闭后才能正常下载。

搭建本地的spring initializr服务

文章目录
  1. 准备源码
  2. 编译
  3. 运行
  4. 问题
  5. 解决方案

参考文档:

准备源码

在github上下载源码或者git clone:

1
2
git clone https://github.com/spring-io/initializr
git clone https://github.com/spring-io/start.spring.io

注意:

1、网上的老教程基本都是只下载编译 https://github.com/spring-io/initializr 上的源码,然后启动initializr-service,但是现在这个服务在0.6版之后被移除了。0.7版本后被独立成一个新项目:start.spring.io

2、如果github上下载或者clone速度太慢,可以使用gitee:https://gitee.com/czweicc/start.spring.io

编译

1、编译 initializer:

1
2
3
cd initializr-master
mvn spring-javaformat:apply
mvn clean install -Dmaven.test.skip=true

2、编译 start.spring.io:

1
2
3
cd start.spring.io-master
mvn spring-javaformat:apply
mvn clean package -Dmaven.test.skip=true

注意:

1、如果是直接下载源码编译可能会遇到报错说没有.git目录,可以在pom.xml中添加如下配置:

1
2
3
4
5
6
7
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>

2、正常编译完后可以在.m2目录下看到 initializer 项目生成的一系列 jar 包,在 start.spring.io-master 目录下能看到打包的 start-site-exec.jar 文件。

运行

1、执行 start-site-exec.jar:

1
2
cd start.spring.io-master
java -Dserver.port=9000 -jar start-site\target\start-site-exec.jar

2、在浏览器中访问: http://localhost:9000 应该可以看到 spring initializer 熟悉的界面了。

问题

1、界面上所有可选项都是灰色,console 中显示如下异常:

1
2
2021-03-06 21:41:54.785  INFO 10876 --- [nio-9000-exec-5] .s.SaganInitializrMetadataUpdateStrategy : Fetching Spring Boot metadata from https://spring.io/project_metadata/spring-boot
2021-03-06 21:42:17.686 WARN 10876 --- [nio-9000-exec-1] .s.SaganInitializrMetadataUpdateStrategy : Failed to fetch Spring Boot metadata

2、原因在于 https://spring.io/project_metadata/spring-boot 性能不稳定,有时能访问有时不能访问。如果正常访问,响应内容可能如下(依据不同版本会有变化)

1
{"id":"spring-boot","name":"Spring Boot","projectReleases":[{"version":"2.5.0-SNAPSHOT","versionDisplayName":"2.5.0-SNAPSHOT","current":false,"releaseStatus":"SNAPSHOT","snapshot":true},{"version":"2.5.0-M2","versionDisplayName":"2.5.0-M2","current":false,"releaseStatus":"PRERELEASE","snapshot":false},{"version":"2.4.4-SNAPSHOT","versionDisplayName":"2.4.4-SNAPSHOT","current":false,"releaseStatus":"SNAPSHOT","snapshot":true},{"version":"2.4.3","versionDisplayName":"2.4.3","current":true,"releaseStatus":"GENERAL_AVAILABILITY","snapshot":false},{"version":"2.3.10.BUILD-SNAPSHOT","versionDisplayName":"2.3.10.BUILD-SNAPSHOT","current":false,"releaseStatus":"SNAPSHOT","snapshot":true},{"version":"2.3.9.RELEASE","versionDisplayName":"2.3.9.RELEASE","current":false,"releaseStatus":"GENERAL_AVAILABILITY","snapshot":false},{"version":"2.2.13.RELEASE","versionDisplayName":"2.2.13.RELEASE","current":false,"releaseStatus":"GENERAL_AVAILABILITY","snapshot":false},{"version":"2.1.18.RELEASE","versionDisplayName":"2.1.18.RELEASE","current":false,"releaseStatus":"GENERAL_AVAILABILITY","snapshot":false}]}

原本自己搭建服务就是不希望受到 spring.io 的网络制约,结果服务是在本地了。meta data数据还要依赖远程……

解决方案

1、打开IDE,引入刚才下载的 initializr 项目源码。

2、进入 initializer-web 项目,修改 io.spring.initializr.web.support 包下的 类 SpringBootMetadataReader的构造函数如下:

1
2
3
4
5
6
SpringBootMetadataReader(ObjectMapper objectMapper, RestTemplate restTemplate, String url) throws IOException {
// this.content = objectMapper.readTree(restTemplate.getForObject(url,String.class));
// 直接返回响应值,不然每次都要去 https://spring.io/project_metadata/spring-boot 下载,会导致超时失败。
String json = "{\"id\":\"spring-boot\",\"name\":\"Spring Boot\",\"projectReleases\":[{\"version\":\"2.5.0-SNAPSHOT\",\"versionDisplayName\":\"2.5.0-SNAPSHOT\",\"current\":false,\"releaseStatus\":\"SNAPSHOT\",\"snapshot\":true},{\"version\":\"2.5.0-M2\",\"versionDisplayName\":\"2.5.0-M2\",\"current\":false,\"releaseStatus\":\"PRERELEASE\",\"snapshot\":false},{\"version\":\"2.4.4-SNAPSHOT\",\"versionDisplayName\":\"2.4.4-SNAPSHOT\",\"current\":false,\"releaseStatus\":\"SNAPSHOT\",\"snapshot\":true},{\"version\":\"2.4.3\",\"versionDisplayName\":\"2.4.3\",\"current\":true,\"releaseStatus\":\"GENERAL_AVAILABILITY\",\"snapshot\":false},{\"version\":\"2.3.10.BUILD-SNAPSHOT\",\"versionDisplayName\":\"2.3.10.BUILD-SNAPSHOT\",\"current\":false,\"releaseStatus\":\"SNAPSHOT\",\"snapshot\":true},{\"version\":\"2.3.9.RELEASE\",\"versionDisplayName\":\"2.3.9.RELEASE\",\"current\":false,\"releaseStatus\":\"GENERAL_AVAILABILITY\",\"snapshot\":false},{\"version\":\"2.2.13.RELEASE\",\"versionDisplayName\":\"2.2.13.RELEASE\",\"current\":false,\"releaseStatus\":\"GENERAL_AVAILABILITY\",\"snapshot\":false},{\"version\":\"2.1.18.RELEASE\",\"versionDisplayName\":\"2.1.18.RELEASE\",\"current\":false,\"releaseStatus\":\"GENERAL_AVAILABILITY\",\"snapshot\":false}]}";
this.content = objectMapper.readTree(json);
}

3、尝试再访问,速度如飞。

放下过去,新的开始

文章目录

一转眼居然半年没更新博客了,想想年初的时候还豪情壮志,信心满满的要开始自己的事业,踏上新征程,做各种计划,申请域名,购买资源,结果随着公司形势的变化,工作的压力一下陡增,再也没有以往那种轻松的心情和宽裕的时间了。创业的想法慢慢的搁浅了,但是心中还是有些不甘,老板也是在我这个年龄才开始创业的吧,30多年后做到让这个世界上最强大的国家都害怕了,我肯定比不了他的境界,但是,也是要有追求的……

总觉得自己应该算是有些自律能力的,日记写了15年,单词背了900天,从今天开始要坚持读书了,想不清楚未来,看不清楚方向,就多读读书吧,那么多聪明、智慧的人总会给予我帮助的。

小宝已经会清晰的叫妈妈了,疲惫的时候看到他圆圆的小脸就会充满力量,加油吧,为了自己,也为了家人。

PS:太久没更新了,已经忘了怎么用 hexo 了,什么事情都是会遗忘的啊……

迁移

文章目录

不知不觉居然已经快半年过去了,阿里云上的EC2要到期了,看了看续期的价格,1C1G1M的配置,居然也要五百多,也是无语了,还是迁移吧,之前在华为云上买了2台云耀云服务器,自己也没搞清楚是什么原因,为何2C4G2M的配置,3年一共才1K多,但是用起来并没有感觉有什么问题……

迁移始终是件麻烦的事儿,得弄清楚以前到底在服务器上都部署了什么东西,版本管理,web server,各种中间件,数据库,还好,数据库里并没有什么有价值的信息,可以不考虑了。

前后折腾了2个多小时,最重要的blog和版本管理服务已经迁移ok了,后面应该能消停到2023年了吧。

今年,特别的不一样……

groovy实现AES加解密

文章目录
  1. 不推荐使用的 DES 加密
  2. 如何使用 groovy 实现 AES 加解密

主题:

  • 如何使用 groovy 实现 DES 加解密
  • 如何使用 groovy 实现 AES 加解密

不推荐使用的 DES 加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.security.*
import javax.crypto.*
import javax.crypto.spec.*

//不安全,不推荐使用了
class DESCodec {
static encode = { String target ->
def cipher = getCipher(Cipher.ENCRYPT_MODE)
return cipher.doFinal(target.bytes).encodeBase64()
}

static decode = { String target ->
def cipher = getCipher(Cipher.DECRYPT_MODE)
return new String(cipher.doFinal(target.decodeBase64()))
}

private static getCipher(mode) {
def keySpec = new DESKeySpec(getPassword())
def cipher = Cipher.getInstance("DES")
def keyFactory = SecretKeyFactory.getInstance("DES")
cipher.init(mode, keyFactory.generateSecret(keySpec))
return cipher
}
private static getPassword() { "password".getBytes("UTF-8") }
}
//具体使用案例
def encode=DESCodec.encode(this.args[0])
def decode=DESCodec.decode(encode.toString())
println encode
println decode

如何使用 groovy 实现 AES 加解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.apache.commons.codec.binary.Base64;
//满足公司安全要求的 AES 加密算法
class AESCodec {
public static String encrypt(String key, String initVector, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string: "+ Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}

public static String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
//具体使用案例
def key = "Bar12345Bar12345" // 128 bit key
def initVector = "RandomInitVector" // 16 bytes IV
def account=AESCodec.decrypt(key,initVector,properties.account)
def password=AESCodec.decrypt(key,initVector,properties.password)
println account
println password