0%

基于 Nodejs 的 gitbook, 感觉和 hexo 大同小意,不过还有额外的制作 pdf 和 ebook 等功能,值得一试

安装

最终各软件版本信息如下

  • node: v13.14.0
  • CLI version: 2.3.2
  • GitBook version: 3.2.3
1
2
3
4
# 安装
npm install -g gitbook-cli
# 检测
gitbook-cli -V

安装抛错

1
2
3
4
5
6
7
8
9
10
No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.

gyp: No Xcode or CLT version detected!
/usr/local/lib/node_modules/gitbook-cli/node_modules/npm/node_modules/graceful-fs/polyfills.js:287
if (cb) cb.apply(this, arguments)
^

重新安装 xcode-select, 去 app store 中搜索 xcode 并安装,挺花时间的,后年还要重新签一下协议。。。

折腾一阵子还是失败了,最后搜了下谁是 gitbook 使用的 polyfills.js 还是旧版的,没有跟新,可以直接去这个文件中,将饮用的语句删掉,或者更新对用的库文件即可,我用了后者

根据提示,打开文件,将该文件中的引用语句注释掉, 再试运行,正常

1
2
3
// fs.stat = statFix(fs.stat)
// fs.fstat = statFix(fs.fstat)
// fs.lstat = statFix(fs.lstat)

gitbook init 又报错了

1
TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received an instance of Promise

说是版本过高。。。。草了, 打算使用 nvm 降一下

1
2
3
4
5
6
7
8
9
10
11
12
13
# 然而 DNS 被污染了,并不能拿到对应的文件,直接下载过到本地就行了, 然后 bash install.sh 即可
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash

source ~/.zshrc

# 查看安装结果,nvm 提示很完善
nvm --version

nvm ls-remote

nvm install v13.14.0

nvm use v13.14.0

切换版本之后,运行正常, 我估计可能 nvm 之后前面的那些改 js 文件的操作都可以省了

gitbook 使用

  1. 创建书本文件并 gitbook init 生成目录
  2. gitbook serve 生成本地版电子书,访问 4000 端口阅读

常用规则

常用插件

  • gitbook-plugin-summary 可以更具文件夹目录帮你自动生成对应的 summary 文件内容,安装完后输入 book sm 自动更新

通过 Redis 搭建 docker 实验环境

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
docker pull redis

# 创建容器
docker run -itd --name redis-test -p 6379:6379 redis

# 进入容器
docker exec -it redis-test /bin/bash

# 开启客户端
redis-cli
# 启动远程客户端
# redis-cli -h host -p port -a password

# 测试
ping
# PONG

# 默认有 16 个数据库,默认用第 0 个
select 1

# 显示当前库下所有的键
keys *

# 清空当前 DB
flushdb

# 删除所有数据库,危
flushall

Issues

清空的时候抛错,我估计是我的 docker redis 没有配置本地存储信息,并不能进行本地化相关操作,创建的时候挂在到本地可能就行了

1
2
flushdb 
(error) MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

猜测失败,是配置问题,关闭了快找功能,导致保存失败,可以在客户端使用 config set stop-writes-on-bgsave-error no 解决问题

数据类型

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 单个值最大能存储 512M
set name "Jack"

# 拿值
get name

# 查看类型
type name

# 存储 hash
HMSET runoob field1 "Hello" field2 "World"

# hash 取值
HGET runoob field1
#"Hello"
HGET runoob field2
#"World"

# list 列表,左序存入
lpush runoob redis
lpush runoob mongodb
lpush runoob rabbitmq

lrange runoob 0 10
# 1) "rabbitmq"
# 2) "mongodb"
# 3) "redis"

# 查看列表大小
llen runoob

# Set 无序集合
sadd members jack
sadd members tom
sadd members tom
smembers members
# 1) "tom"
# 2) "jack"

# 查看大小
scard members

# zset 有序集合
zadd dbs 0 mongodb
zadd dbs 0 redis
zadd dbs 0 rabit

ZRANGEBYSCORE dbs 0 10000
# 1) "mongodb"
# 2) "rabit"
# 3) "redis"

# 查看大小
zcard dbs

Using Redis in Python

1
2
3
4
5
6
7
8
9
10
11
# 安装依赖
pip install redis

# ipython 操作
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
r.set('foo', 'bar')
print(r['foo'])
# b'bar'
print(type(r.get('foo')))
# <class 'bytes'>

Setup MongoDB the Docker Way

  • 镜像地址, 包含了很多常用操作,比如挂载卷,导出数据,设置密码等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 下载并启动一个镜像, 映射到 27017 端口并设置密码访问
# docker run -itd --name mymongo -p 27017:27017 mongo --auth
# 测试时不要加 --auth, 自找麻烦
docker run -itd --name mymongo -v /Users/i306454/mongodb/data/db:/data/db -p 27017:27017 mongo

# 链接到 db 终端
docker exec -it mymongo mongo admin

# 创建 root/root 用户, 指定可操作的数据库
db.createUser({ user:'root',pwd:'root',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

# 以指定用户登陆
db.auth('root', 'root')
# 1 授权成功

use admin
# 查看系统信息
db.getCollectionNames()

Issues

mymongo 启动失败(之前遇到过,我记得我记录过了,怎么找不到那片文章了呢(; ̄ェ ̄)), 使用 docker logs mymongo 可以看到异常信息 “{“t”:{“$date”:”2022-01-18T08:26:55.448+00:00”},”s”:”E”, “c”:”STORAGE”, “id”:22312, “ctx”:”initandlisten”,”msg”:”Error creating journal directory”,”attr”:{“directory”:”/data/db/journal”,”error”:”boost::filesystem::create_directory: No space left on device: "/data/db/journal"“}}”,创建容器时指定挂在位置即可

MongoDB 基本操作

RDBMS MongoDB
集合
文档
字段
表联合 嵌入文档
主键 主键(MongoDB 提供了 key 为 _id)
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# 显示当前库对象,默认为 test 库
db

# 创建并使用库
use local


# 插入数据时会自动创建数据库
db.local.insert({"name":"Jack"})

# 删除数据库
use local
db.dropDatabase()
# 查看结果
show dbs

# 创建集合
db.createCollection("runoob")

# 查看集合
show collections

# 创建集合并指定参数
db.createCollection("mycol", { capped: true, autoIndexId: true, size: 6142800, max: 10000})

# 其实不需要特别创建集合,插入文档时会自动生成
db.mycal2.insert({"name":"Jack"})
> show collections
mycal2
mycol
runoob

# 删除集合
db.mycal2.drop()

# 插入文档
db.collection_name.insert(doc)

# 插入多个文档
# db.collection.insertMany(
# [ <document 1> , <document 2>, ... ],
# {
# writeConcern: <document>,
# ordered: <boolean>
# }
# )
db.runoob.insertMany([{"key":"name"}, {"a":1}])

# 查看已插入的文档
db.runoob.find()

# 更新文档
db.runoob.update({"name":"Jack"}, {$set:{"name":"Jerry"}})
# 修改多条
db.col.update({"name":"Jack"}, {$set:{"name":"Jerry"}},{multi:true})
# save 主键存在就更新,不存在就插入

# 删除文档
# db.collection.remove(
# <query>,
# <justOne>
# )
# 2.6以上版本
# db.collection.remove(
# <query>,
# {
# justOne: <boolean>,
# writeConcern: <document>
# }
# )
db.runoob.remove({"a":1})
# remove 已过时,官方推荐 deleteOne(), deleteMany()

# 查询文档
# db.collection.find(query, projection)
# .pretty() 格式化输出
db.runoob.find({$or:[{"name":"Jerry"}, {"key":"test"}]}).pretty()

# AND + OR 的例子
db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()

# 条件操作
# (>) 大于 - $gt
# (<) 小于 - $lt
# (>=) 大于等于 - $gte
# (<= ) 小于等于 - $lte

# 清空集合
db.col.remove({})
# 查看 likes > 100 的数据
db.col.find({likes : {$gt : 100}})

# type 操作
db.col.find({title: {$type:2}})
# or
db.col.find({title: {$type:'string'}})

# limit, 同 SQL 中的 limit
# db.collection.find(query, projection)
# 查询返回所有数据,只显示 title, _id 属性
db.col.find({},{"title":1,_id:0}).limit(2)

# skip 跳过指定数量的数据
db.col.find({},{"title":1,_id:0}).limit(1).skip(1)

# 排序,1 升序,-1 降序
db.col.find({},{"title":1,_id:0}).sort({"likes":-1})

# 创建索引
db.col.createIndex({"title":1})
# 也可以创建复合索引
# 索引可以有额外参数
db.values.createIndex({open: 1, close: 1}, {background: true})

# 聚合,类似 count(*)
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

# 其实只是 count 的话有更简单的方法
db.col.count()
db.col.count({'age':24})

集成 pymongo

安装 lib pip install pymongo

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from pymongo import MongoClient

# 如果是默认配置
client = MongoClient()
# 如果特殊配制
# myclient = pymongo.MongoClient("mongodb://localhost:27017/")

# 显示 db 名字
client.list_database_names()

# 创建集合
collection = client["ttt"]

# 展示集合名字
collection.list_collection_names()

# 创建文档
mydoc = collection["sites"]
# 插入集合
mydict = { "name": "RUNOOB", "alexa": "10000", "url": "https://www.runoob.com" }
mydoc.insert_one(mydict)
# 插入多条
mydoc.insert_many(mylist)

# 查询
mydoc.find_one()
# 查询所有
for sub in mydoc.find():
print(sub)

# 指定字段
for x in mydoc.find({},{ "_id": 0, "name": 1, "alexa": 1 }):
print(x)

# 指定条件
mydoc.find({ "name": "RUNOOB" })
# 比较
mydoc.find({ "name": { "$gt": "H" } })
# 正则
mydoc.find({ "name": { "$regex": "^R" } })
# 限制数量
mydoc.find().limit(3)

# 修改
myquery = { "alexa": "10000" }
newvalues = { "$set": { "alexa": "12345" } }
mydoc.update_one(myquery, newvalues)

# 排序
mydoc.find().sort("alexa")
mydoc.find().sort("alexa", -1)

# 删除
myquery = { "name": "Taobao" }
mydoc.delete_one(myquery)
# 删除多个
myquery = { "name": {"$regex": "^F"} }
mydoc.delete_many(myquery)
# 删除所有
mydoc.delete_many({})
# 删除集合
mydoc.drop()

本文主要 focus 在 xml 到 bean definition 转化的过程,即 AbstractApplicationContext 的 refresh 方法的 obtainFreshBeanFactory()。转化过程是这个方法的一部分。本文会先介绍一些这个过程中用到的一些底层类实现,最后再总的将这部分内容捋一遍。

Document

BeanDefinitionHolder

BeanDefinitionHolder 是解析 xml 时的一个中间类,不对外暴露。只包含了三个属性 beanDefinition, beanName 和 alias。代表一个被解析的 bean 节点。

指南

数据结构和算法学习指南

数据结构的存储方式只有两种:数组(顺序存储) 和 链表(链式存储)。其他的结构,如队列,栈,图等都是以这两种为基础演变的。

数据结构的基本操作:遍历 + 访问,具体一点就是:增删改查。数据结构类型有很多,但是他们的目的都是在不同的应用场景下,尽可能高效的增删改查,这就是数据结构的使命。

数组遍历是典型的线性迭代结构,链表便利兼具迭代和递归,二叉树则是典型的非线性递归。

数据结构是工具,算法则是通过合适的工具解决特定问题的方法。算法刷题建议从二叉树开始。二叉树最容易培养框架思维,大部分算法技巧,本质上都是树的遍历问题。

刷通二叉树第一期

前置的一些基本概念:深度遍历/广度遍历。深度遍历有前序,中序和后序三种遍历方式。广度便利及我们平时说的层次遍历。

前序遍历: 根结点 -> 左子树 -> 右子树

中序遍历: 左子树 -> 根结点 -> 右子树

后序遍历: 左子树 -> 右子树 -> 根结点

层次便利: 只需按层次遍历既可

PS: 吐槽一下前中后的定义,老是搞错,抓住根本,这些形容词都是用来表述根节点的。前序就是 root 先,左右子树的顺序都是固定的。

完美二叉树(Perfect Binary Tree):也翻译为满二叉树,理解为正三角形就行

完全二叉树(Complete Binary Tree):倒数第二层为完美二叉树,最后一层不全,叶子结点左对齐

完满二叉树(Full Binary Tree): 只要有孩子,就是两个

第一期

通过练习,熟悉树的遍历框架

1
2
3
4
5
6
7
8
/* 二叉树遍历框架 */
void traverse(TreeNode root) {
// 前序遍历
traverse(root.left)
// 中序遍历
traverse(root.right)
// 后序遍历
}

搭建 Webssh2 实验平台,熟悉工具使用模式,等后期试着拆解一下这个项目的细节,用到自己的小项目上。感觉道路有点崎岖。。。。

这个东西本地部分挺简单的,clone 下来之后直接启动就行了,但是作为目标对象,需要一个测试用虚拟机,打算用 docker 起一个

Docker 测试对象创建

之前还打算用 Centos 镜像自己搞一个的,结果各种换源出问题,然后找找 Ubuntu 的资源,直接发现一个配置好的镜像资源,6 啊,直接拿来用,香

1
2
3
4
5
6
7
8
9
10
11
# 作者在官方镜像基础上搭建的 https://hub.docker.com/r/rastasheep/ubuntu-sshd/
docker pull rastasheep/ubuntu-sshd

docker run -d -P --name test_sshd rastasheep/ubuntu-sshd

# 显示本地映射的端口
docker port test_sshd 22
# 0.0.0.0:55000

# 本地测试,默认密码 root, 成功
ssh root@localhost -p 55000

webssh2 测试

1
2
3
4
5
6
7
git clone git@github.com:billchurch/webssh2.git

cd webssh2/app

npm install --production

npm start

然后开启 browser 并访问 http://localhost:2222/ssh/host/127.0.0.1?port=55000&header=My%20Header&headerBackground=red 即可访问网站。而且貌似还能记住密码,登陆一次之后就不需要再次输入了

使用 Docker 的方式安装 MongoDB

  1. docker pull mongo
  2. docker run --name mymongo -d mongo 使用默认设置启动
  3. docker exec -it mymongo bash 链接控制台输入 mongod --version 验证安装情况
  4. mongo 链接数据库, exit 退出

基本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
show dbs -- 查看库

db -- 当前库名

use 库名 -- 使用

> db.students.insertOne({"name":"Jack"}) -- 插入数据
{
"acknowledged" : true,
"insertedId" : ObjectId("61a8bfa9e0344414ad0ee1e3")
}

> show collections -- 查看插入结果
students

> db.students.find() -- 查询
{ "_id" : ObjectId("61a8bfa9e0344414ad0ee1e3"), "name" : "Jack" }

问题

Mac 上测试,启动立马停止,通过 docker logs mymongo 可以看到异常

1
{"t":{"$date":"2021-12-02T12:12:30.478+00:00"},"s":"E",  "c":"STORAGE",  "id":22312,   "ctx":"initandlisten","msg":"Error creating journal directory","attr":{"directory":"/data/db/journal","error":"boost::filesystem::create_directory: No space left on device: \"/data/db/journal\""}}

Google 了一下,说是 Mac 才有的,docker volumn 不够了,可以通过指定挂在的 volumn 或者清理不用的 volumn 解决问题

1
2
3
4
5
6
7
8
docker run -d -p 3000:27017 -v /Users/user/work/m1:/data/db --name m1 --net mongo-net mongo mongod
# or
docker volume prune
# 最后,上面那个 prune 没用,用了下面这个简化版的
docker run -d -p 3000:27017 -v /Users/xxxx/mongodb/data/db:/data/db --name mymongo mongo

docker exec -it some-mongo bash
docker logs some-mongo

Refer: StackOverflow

结论:先执行 try 中内容,再执行关闭资源的行为,然后是 catch 最后再 finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CloseableDummy implements Closeable {
public void close() {
System.out.println("closing");
}
}

public class CloseableDemo {
public static void main(String[] args) {
try (CloseableDummy closableDummy = new CloseableDummy()) {
System.out.println("try exit");
throw new Exception();
} catch (Exception ex) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
}
}

// try exit
// closing
// catch
// finally

根据官方定义, 简单来说,bean definition 就是一个 bean 的定义

A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container (for example, in the form of XML definitions).

Within the container itself, these bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:

  • A package-qualified class name: typically, the actual implementation class of the bean being defined.
  • Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
  • References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
  • Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.

bean definition 包含:

  • 全名限定,通常是实现类的全名限定
  • bean 相关配置,包括 scope, lifecycle 等
  • bean 的依赖
  • 实例化的属性,比如 pool size 之类的

参考

如果是 null 返回默认值

1
2
3
4
5
System.out.println(Optional.ofNullable("a").orElse("b")); // a
System.out.println(Optional.ofNullable(null).orElse("b")); // b

// 如果是 JDK9 还可以使用 Objects
Objects.requireNonNullElse(T obj, T defaultObj);