diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000..55754d07
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,3 @@
+{
+ "compact": false
+}
diff --git a/.editorconfig b/.editorconfig
index ee762040..d72a75ea 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -19,7 +19,7 @@ insert_final_newline = true
[*.{bat, cmd}]
end_of_line = crlf
-[*.{java, gradle, groovy, kt, sh, xml}]
+[*.{java, gradle, groovy, kt, sh}]
indent_size = 4
[*.md]
diff --git a/.gitattributes b/.gitattributes
index 07962a1f..eaae227f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -22,6 +22,7 @@
*.less text
*.sql text
*.properties text
+*.md text
# unix style
*.sh text eol=lf
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 00000000..04010943
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,36 @@
+name: CI
+
+# 在master分支发生push事件时触发。
+on:
+ push:
+ branches:
+ - master
+
+env: # 设置环境变量
+ TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间)
+
+jobs:
+ build: # 自定义名称
+ runs-on: ubuntu-latest # 运行在虚拟机环境ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [16.x]
+
+ steps:
+ # 使用的动作。格式:userName/repoName。作用:检出仓库,获取源码。 官方actions库:https://github.com/actions
+ - name: Checkout
+ uses: actions/checkout@master
+
+ # 指定 nodejs 版本
+ - name: Use Nodejs ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ # 部署
+ - name: Deploy
+ env: # 设置环境变量
+ GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
+ GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }}
+ run: npm install && npm run deploy
diff --git a/.gitignore b/.gitignore
index 83948575..7d98dac9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,7 +29,6 @@ hs_err_pid*
# maven plugin temp files
.flattened-pom.xml
-package-lock.json
# ------------------------------- javascript -------------------------------
@@ -37,10 +36,12 @@ package-lock.json
node_modules
# temp folders
-.temp
+build
dist
_book
_jsdoc
+.temp
+.deploy*/
# temp files
*.log
@@ -48,7 +49,11 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
bundle*.js
+.DS_Store
+Thumbs.db
+db.json
book.pdf
+package-lock.json
# ------------------------------- intellij -------------------------------
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 47463f91..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-# 持续集成 CI
-# @see https://docs.travis-ci.com/user/tutorial/
-
-language: node_js
-
-sudo: required
-
-node_js: '16.13.0'
-
-branches:
- only:
- - master
-
-before_install:
- - export TZ=Asia/Shanghai
-
-script: bash ./scripts/deploy.sh
-
-notifications:
- email:
- recipients:
- - forbreak@163.com
- on_success: change
- on_failure: always
diff --git a/README.md b/README.md
index 99fa8c21..7d3dbdd3 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,27 @@
children = client.getChildren().forPath("/zkid");
+ if (CollectionUtil.isNotEmpty(children)) {
+ for (String child : children) {
+ client.delete().forPath("/zkid/" + child);
+ }
+ }
+ client.delete().forPath("/zkid");
+
+ // 关闭客户端
+ client.close();
+ }
+
+}
diff --git a/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java b/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java
new file mode 100644
index 00000000..69d5d543
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java
@@ -0,0 +1,46 @@
+package io.github.dunwu.distributed.id;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.curator.RetryPolicy;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.atomic.AtomicValue;
+import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+
+/**
+ * ZK 分布式 ID
+ *
+ * 基于原子计数器生成 ID
+ *
+ * @author Zhang Peng
+ * @date 2024-12-20
+ */
+@Slf4j
+public class ZookeeperDistributedId2 {
+
+ public static void main(String[] args) throws Exception {
+
+ // 获取客户端
+ RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
+ CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", retryPolicy);
+ DistributedAtomicLong atomicLong = new DistributedAtomicLong(client, "/zkid", retryPolicy);
+
+ // 开启会话
+ client.start();
+
+ // 基于原子计数器生成 ID
+ AtomicValue id1 = atomicLong.increment();
+ log.info("id: {}", id1.postValue());
+
+ AtomicValue id2 = atomicLong.increment();
+ log.info("id: {}", id2.postValue());
+
+ // 清理节点
+ client.delete().forPath("/zkid");
+
+ // 关闭客户端
+ client.close();
+ }
+
+}
diff --git a/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua
new file mode 100644
index 00000000..e0c9ad00
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua
@@ -0,0 +1,21 @@
+-- 缓存 Key
+local key = KEYS[1]
+-- 访问请求数
+local permits = tonumber(ARGV[1])
+-- 过期时间
+local seconds = tonumber(ARGV[2])
+-- 限流阈值
+local limit = tonumber(ARGV[3])
+
+-- 获取统计值
+local count = tonumber(redis.call('GET', key) or "0")
+
+if count + permits > limit then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ redis.call('INCRBY', key, permits)
+ redis.call('EXPIRE', key, seconds)
+ return count + permits
+end
\ No newline at end of file
diff --git a/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua
new file mode 100644
index 00000000..541d70c9
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua
@@ -0,0 +1,39 @@
+local tokenKey = KEYS[1]
+local timeKey = KEYS[2]
+
+-- 申请令牌数
+local permits = tonumber(ARGV[1])
+-- QPS
+local qps = tonumber(ARGV[2])
+-- 桶的容量
+local capacity = tonumber(ARGV[3])
+-- 当前时间(单位:毫秒)
+local nowMillis = tonumber(ARGV[4])
+-- 填满令牌桶所需要的时间
+local fillTime = capacity / qps
+local ttl = math.min(capacity, math.floor(fillTime * 2))
+
+local currentTokenNum = tonumber(redis.call("GET", tokenKey))
+if currentTokenNum == nil then
+ currentTokenNum = capacity
+end
+
+local endTimeMillis = tonumber(redis.call("GET", timeKey))
+if endTimeMillis == nil then
+ endTimeMillis = 0
+end
+
+local gap = nowMillis - endTimeMillis
+local newTokenNum = math.max(0, gap * qps / 1000)
+local currentTokenNum = math.min(capacity, currentTokenNum + newTokenNum)
+
+if currentTokenNum < permits then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ local finalTokenNum = currentTokenNum - permits
+ redis.call("SETEX", tokenKey, ttl, finalTokenNum)
+ redis.call("SETEX", timeKey, ttl, nowMillis)
+ return finalTokenNum
+end
diff --git a/codes/java-distributed/java-load-balance/pom.xml b/codes/java-distributed/java-load-balance/pom.xml
index 5f14ae1a..b4e73f0f 100644
--- a/codes/java-distributed/java-load-balance/pom.xml
+++ b/codes/java-distributed/java-load-balance/pom.xml
@@ -3,11 +3,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- io.github.dunwu.javatech
+ io.github.dunwu.distributed
java-load-balance
1.0.0
jar
- ${project.artifactId}
UTF-8
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
index e4f03ab2..ebb317a8 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import cn.hutool.core.collection.CollectionUtil;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
similarity index 99%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
index 42394a12..c67558a2 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
index 00be0c93..3d71cbb7 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
similarity index 98%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
index 25dc6f13..23a7f03c 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
similarity index 86%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
index 046734af..f2d0c561 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
similarity index 97%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
index 1077f48e..57dc61f1 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
@@ -1,6 +1,10 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
/**
* 负载均衡算法测试例
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
similarity index 97%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
index ad0c8ed4..2fc9c712 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.Objects;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
index 8f4b7d8d..5b775dd2 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
index d14b251d..c0858152 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
similarity index 95%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
index 50eaa59a..cbb66d13 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
public class StatisticsUtil {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
index a3f1c853..c7135667 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
similarity index 99%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
index 3180958d..3f71a573 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
similarity index 76%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
index 8633bb5a..4d8b7a26 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
@@ -4,4 +4,4 @@
* @author Zhang Peng
* @since 2020-01-22
*/
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
similarity index 98%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
index 8622bb51..5c732a5b 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.nio.charset.StandardCharsets;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
similarity index 92%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
index 807f3c33..fc7cea13 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public class FnvHashStrategy implements HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
similarity index 59%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
index 2ad6deef..f574c86e 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public interface HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
similarity index 77%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
index f4a8389c..6541e2a4 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public class JdkHashCodeStrategy implements HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
index 8e98ef1f..ef479aaf 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
index a100f3d3..82ee1620 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
diff --git a/codes/java-distributed/java-rate-limit/pom.xml b/codes/java-distributed/java-rate-limit/pom.xml
new file mode 100644
index 00000000..312d7f21
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+ io.github.dunwu.distributed
+ java-rate-limit
+ 1.0.0
+ jar
+
+
+ UTF-8
+ 1.8
+ ${java.version}
+ ${java.version}
+
+
+
+
+ redis.clients
+ jedis
+ 5.1.0
+
+
+ cn.hutool
+ hutool-all
+ 5.8.25
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+ true
+
+
+
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java
new file mode 100644
index 00000000..0af8d142
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java
@@ -0,0 +1,59 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 固定时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class FixedWindowRateLimiter implements RateLimiter {
+
+ /**
+ * 允许的最大请求数
+ */
+ private final long maxPermits;
+
+ /**
+ * 窗口期时长
+ */
+ private final long periodMillis;
+
+ /**
+ * 窗口期截止时间
+ */
+ private long lastPeriodMillis;
+
+ /**
+ * 请求计数
+ */
+ private AtomicLong count = new AtomicLong(0);
+
+ public FixedWindowRateLimiter(long qps) {
+ this(qps, 1000, TimeUnit.MILLISECONDS);
+ }
+
+ public FixedWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit) {
+ this.maxPermits = maxPermits;
+ this.periodMillis = timeUnit.toMillis(period);
+ this.lastPeriodMillis = System.currentTimeMillis() + this.periodMillis;
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ if (lastPeriodMillis <= now) {
+ this.lastPeriodMillis = now + this.periodMillis;
+ count = new AtomicLong(0);
+ }
+ if (count.get() + permits <= maxPermits) {
+ count.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java
new file mode 100644
index 00000000..0d99a227
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java
@@ -0,0 +1,64 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 漏桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class LeakyBucketRateLimiter implements RateLimiter {
+
+ /**
+ * QPS
+ */
+ private final int qps;
+
+ /**
+ * 桶的容量
+ */
+ private final long capacity;
+
+ /**
+ * 计算的起始时间
+ */
+ private long beginTimeMillis;
+
+ /**
+ * 桶中当前的水量
+ */
+ private final AtomicLong waterNum = new AtomicLong(0);
+
+ public LeakyBucketRateLimiter(int qps, int capacity) {
+ this.qps = qps;
+ this.capacity = capacity;
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+
+ // 如果桶中没有水,直接放行
+ if (waterNum.get() == 0) {
+ beginTimeMillis = System.currentTimeMillis();
+ waterNum.addAndGet(permits);
+ return true;
+ }
+
+ // 计算水量
+ long leakedWaterNum = ((System.currentTimeMillis() - beginTimeMillis) / 1000) * qps;
+ long currentWaterNum = waterNum.get() - leakedWaterNum;
+ waterNum.set(Math.max(0, currentWaterNum));
+
+ // 重置时间
+ beginTimeMillis = System.currentTimeMillis();
+
+ if (waterNum.get() + permits < capacity) {
+ waterNum.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java
new file mode 100644
index 00000000..4fbc9646
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java
@@ -0,0 +1,13 @@
+package io.github.dunwu.distributed.ratelimit;
+
+/**
+ * 限流器
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public interface RateLimiter {
+
+ boolean tryAcquire(int permits);
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java
new file mode 100644
index 00000000..e4a50641
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java
@@ -0,0 +1,95 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.RandomUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 限流器示例
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+@Slf4j
+public class RateLimiterDemo {
+
+ public static void main(String[] args) {
+
+ // ============================================================================
+
+ int qps = 20;
+
+ System.out.println("======================= 固定时间窗口限流算法 =======================");
+ FixedWindowRateLimiter fixedWindowRateLimiter = new FixedWindowRateLimiter(qps);
+ testRateLimit(fixedWindowRateLimiter, qps);
+
+ System.out.println("======================= 滑动时间窗口限流算法 =======================");
+ SlidingWindowRateLimiter slidingWindowRateLimiter = new SlidingWindowRateLimiter(qps, 10);
+ testRateLimit(slidingWindowRateLimiter, qps);
+
+ System.out.println("======================= 漏桶限流算法 =======================");
+ LeakyBucketRateLimiter leakyBucketRateLimiter = new LeakyBucketRateLimiter(qps, 100);
+ testRateLimit(leakyBucketRateLimiter, qps);
+
+ System.out.println("======================= 令牌桶限流算法 =======================");
+ TokenBucketRateLimiter tokenBucketRateLimiter = new TokenBucketRateLimiter(qps, 100);
+ testRateLimit(tokenBucketRateLimiter, qps);
+ }
+
+ private static void testRateLimit(RateLimiter rateLimiter, int qps) {
+
+ AtomicInteger okNum = new AtomicInteger(0);
+ AtomicInteger limitNum = new AtomicInteger(0);
+ ExecutorService executorService = ThreadUtil.newFixedExecutor(10, "限流测试", true);
+ long beginTime = System.currentTimeMillis();
+
+ int threadNum = 4;
+ final CountDownLatch latch = new CountDownLatch(threadNum);
+ for (int i = 0; i < threadNum; i++) {
+ executorService.submit(() -> {
+ try {
+ batchRequest(rateLimiter, okNum, limitNum, 1000);
+ } catch (Exception e) {
+ log.error("发生异常!", e);
+ } finally {
+ latch.countDown();
+ }
+ });
+ }
+
+ try {
+ latch.await(10, TimeUnit.SECONDS);
+ long endTime = System.currentTimeMillis();
+ long gap = endTime - beginTime;
+ log.info("限流 QPS: {} -> 实际结果:耗时 {} ms,{} 次请求成功,{} 次请求被限流,实际 QPS: {}",
+ qps, gap, okNum.get(), limitNum.get(), okNum.get() * 1000 / gap);
+ if (okNum.get() == qps) {
+ log.info("限流符合预期");
+ }
+ } catch (Exception e) {
+ log.error("发生异常!", e);
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ private static void batchRequest(RateLimiter rateLimiter, AtomicInteger okNum, AtomicInteger limitNum, int num)
+ throws InterruptedException {
+ for (int j = 0; j < num; j++) {
+ if (rateLimiter.tryAcquire(1)) {
+ log.info("请求成功");
+ okNum.getAndIncrement();
+ } else {
+ log.info("请求限流");
+ limitNum.getAndIncrement();
+ }
+ TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(0, 10));
+ }
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java
new file mode 100644
index 00000000..ec5d77d9
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java
@@ -0,0 +1,100 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于 Redis + Lua 实现的固定时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-23
+ */
+public class RedisFixedWindowRateLimiter implements RateLimiter {
+
+ private static final String REDIS_HOST = "localhost";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final Jedis JEDIS;
+
+ public static final String SCRIPT;
+
+ static {
+ // Jedis 有多种构造方法,这里选用最简单的一种情况
+ JEDIS = new Jedis(REDIS_HOST, REDIS_PORT);
+
+ // 触发 ping 命令
+ try {
+ JEDIS.ping();
+ System.out.println("jedis 连接成功");
+ } catch (JedisConnectionException e) {
+ e.printStackTrace();
+ }
+
+ SCRIPT = FileUtil.readString(ResourceUtil.getResource("scripts/fixed_window_rate_limit.lua"),
+ StandardCharsets.UTF_8);
+ }
+
+ private final long maxPermits;
+ private final long periodSeconds;
+ private final String key;
+
+ public RedisFixedWindowRateLimiter(long qps, String key) {
+ this(qps * 60, 60, TimeUnit.SECONDS, key);
+ }
+
+ public RedisFixedWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit, String key) {
+ this.maxPermits = maxPermits;
+ this.periodSeconds = timeUnit.toSeconds(period);
+ this.key = key;
+ }
+
+ @Override
+ public boolean tryAcquire(int permits) {
+ List keys = Collections.singletonList(key);
+ List args = CollectionUtil.newLinkedList(String.valueOf(permits), String.valueOf(periodSeconds),
+ String.valueOf(maxPermits));
+ Object eval = JEDIS.eval(SCRIPT, keys, args);
+ long value = (long) eval;
+ return value != -1;
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+
+ int qps = 20;
+ RateLimiter jedisFixedWindowRateLimiter = new RedisFixedWindowRateLimiter(qps, "rate:limit:20240122210000");
+
+ // 模拟在一分钟内,不断收到请求,限流是否有效
+ int seconds = 60;
+ long okNum = 0L;
+ long total = 0L;
+ long beginTime = System.currentTimeMillis();
+ int num = RandomUtil.randomInt(qps, 100);
+ for (int second = 0; second < seconds; second++) {
+ for (int i = 0; i < num; i++) {
+ total++;
+ if (jedisFixedWindowRateLimiter.tryAcquire(1)) {
+ okNum++;
+ System.out.println("请求成功");
+ } else {
+ System.out.println("请求限流");
+ }
+ }
+ TimeUnit.SECONDS.sleep(1);
+ }
+ long endTime = System.currentTimeMillis();
+ long time = (endTime - beginTime) / 1000;
+ System.out.println(StrUtil.format("请求通过数:{},总请求数:{},实际 QPS:{}", okNum, total, okNum / time));
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java
new file mode 100644
index 00000000..9dd219df
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java
@@ -0,0 +1,104 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于 Redis + Lua 实现的令牌桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-23
+ */
+public class RedisTokenBucketRateLimiter implements RateLimiter {
+
+ private static final String REDIS_HOST = "localhost";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final Jedis JEDIS;
+
+ public static final String SCRIPT;
+
+ static {
+ // Jedis 有多种构造方法,这里选用最简单的一种情况
+ JEDIS = new Jedis(REDIS_HOST, REDIS_PORT);
+
+ // 触发 ping 命令
+ try {
+ JEDIS.ping();
+ System.out.println("jedis 连接成功");
+ } catch (JedisConnectionException e) {
+ e.printStackTrace();
+ }
+
+ SCRIPT = FileUtil.readString(ResourceUtil.getResource("scripts/token_bucket_rate_limit.lua"),
+ StandardCharsets.UTF_8);
+ }
+
+ private final long qps;
+ private final long capacity;
+ private final String tokenKey;
+ private final String timeKey;
+
+ public RedisTokenBucketRateLimiter(long qps, long capacity, String tokenKey, String timeKey) {
+ this.qps = qps;
+ this.capacity = capacity;
+ this.tokenKey = tokenKey;
+ this.timeKey = timeKey;
+ }
+
+ @Override
+ public boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ List keys = CollectionUtil.newLinkedList(tokenKey, timeKey);
+ List args = CollectionUtil.newLinkedList(String.valueOf(permits), String.valueOf(qps),
+ String.valueOf(capacity), String.valueOf(now));
+ Object eval = JEDIS.eval(SCRIPT, keys, args);
+ long value = (long) eval;
+ return value != -1;
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+
+ int qps = 20;
+ int bucket = 100;
+ RedisTokenBucketRateLimiter redisTokenBucketRateLimiter =
+ new RedisTokenBucketRateLimiter(qps, bucket, "token:rate:limit", "token:rate:limit:time");
+
+ // 先将令牌桶预热令牌申请完,后续才能真实反映限流 QPS
+ redisTokenBucketRateLimiter.tryAcquire(bucket);
+ TimeUnit.SECONDS.sleep(1);
+
+ // 模拟在一分钟内,不断收到请求,限流是否有效
+ int seconds = 60;
+ long okNum = 0L;
+ long total = 0L;
+ long beginTime = System.currentTimeMillis();
+ for (int second = 0; second < seconds; second++) {
+ int num = RandomUtil.randomInt(qps, 100);
+ for (int i = 0; i < num; i++) {
+ total++;
+ if (redisTokenBucketRateLimiter.tryAcquire(1)) {
+ okNum++;
+ System.out.println("请求成功");
+ } else {
+ System.out.println("请求限流");
+ }
+ }
+ TimeUnit.SECONDS.sleep(1);
+ }
+ long endTime = System.currentTimeMillis();
+ long time = (endTime - beginTime) / 1000;
+ System.out.println(StrUtil.format("请求通过数:{},总请求数:{},实际 QPS:{}", okNum, total, okNum / time));
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java
new file mode 100644
index 00000000..a93613a2
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java
@@ -0,0 +1,87 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 滑动时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class SlidingWindowRateLimiter implements RateLimiter {
+
+ /**
+ * 允许的最大请求数
+ */
+ private final long maxPermits;
+
+ /**
+ * 窗口期时长
+ */
+ private final long periodMillis;
+
+ /**
+ * 分片窗口期时长
+ */
+ private final long shardPeriodMillis;
+
+ /**
+ * 窗口期截止时间
+ */
+ private long lastPeriodMillis;
+
+ /**
+ * 分片窗口数
+ */
+ private final int shardNum;
+
+ /**
+ * 请求总计数
+ */
+ private final AtomicLong totalCount = new AtomicLong(0);
+
+ /**
+ * 分片窗口计数列表
+ */
+ private final List countList = new LinkedList<>();
+
+ public SlidingWindowRateLimiter(long qps, int shardNum) {
+ this(qps, 1000, TimeUnit.MILLISECONDS, shardNum);
+ }
+
+ public SlidingWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit, int shardNum) {
+ this.maxPermits = maxPermits;
+ this.periodMillis = timeUnit.toMillis(period);
+ this.lastPeriodMillis = System.currentTimeMillis();
+ this.shardPeriodMillis = timeUnit.toMillis(period) / shardNum;
+ this.shardNum = shardNum;
+ for (int i = 0; i < shardNum; i++) {
+ countList.add(new AtomicLong(0));
+ }
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ if (now > lastPeriodMillis) {
+ for (int shardId = 0; shardId < shardNum; shardId++) {
+ long shardCount = countList.get(shardId).get();
+ totalCount.addAndGet(-shardCount);
+ countList.set(shardId, new AtomicLong(0));
+ lastPeriodMillis += shardPeriodMillis;
+ }
+ }
+ int shardId = (int) (now % periodMillis / shardPeriodMillis);
+ if (totalCount.get() + permits <= maxPermits) {
+ countList.get(shardId).addAndGet(permits);
+ totalCount.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java
new file mode 100644
index 00000000..e03e4c7d
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java
@@ -0,0 +1,59 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 令牌桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class TokenBucketRateLimiter implements RateLimiter {
+
+ /**
+ * QPS
+ */
+ private final long qps;
+
+ /**
+ * 桶的容量
+ */
+ private final long capacity;
+
+ /**
+ * 上一次令牌发放时间
+ */
+ private long endTimeMillis;
+
+ /**
+ * 桶中当前的令牌数量
+ */
+ private final AtomicLong tokenNum = new AtomicLong(0);
+
+ public TokenBucketRateLimiter(long qps, long capacity) {
+ this.qps = qps;
+ this.capacity = capacity;
+ this.endTimeMillis = System.currentTimeMillis();
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+
+ long now = System.currentTimeMillis();
+ long gap = now - endTimeMillis;
+
+ // 计算令牌数
+ long newTokenNum = (gap * qps / 1000);
+ long currentTokenNum = tokenNum.get() + newTokenNum;
+ tokenNum.set(Math.min(capacity, currentTokenNum));
+
+ if (tokenNum.get() < permits) {
+ return false;
+ } else {
+ tokenNum.addAndGet(-permits);
+ endTimeMillis = now;
+ return true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua
new file mode 100644
index 00000000..e0c9ad00
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua
@@ -0,0 +1,21 @@
+-- 缓存 Key
+local key = KEYS[1]
+-- 访问请求数
+local permits = tonumber(ARGV[1])
+-- 过期时间
+local seconds = tonumber(ARGV[2])
+-- 限流阈值
+local limit = tonumber(ARGV[3])
+
+-- 获取统计值
+local count = tonumber(redis.call('GET', key) or "0")
+
+if count + permits > limit then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ redis.call('INCRBY', key, permits)
+ redis.call('EXPIRE', key, seconds)
+ return count + permits
+end
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua
new file mode 100644
index 00000000..541d70c9
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua
@@ -0,0 +1,39 @@
+local tokenKey = KEYS[1]
+local timeKey = KEYS[2]
+
+-- 申请令牌数
+local permits = tonumber(ARGV[1])
+-- QPS
+local qps = tonumber(ARGV[2])
+-- 桶的容量
+local capacity = tonumber(ARGV[3])
+-- 当前时间(单位:毫秒)
+local nowMillis = tonumber(ARGV[4])
+-- 填满令牌桶所需要的时间
+local fillTime = capacity / qps
+local ttl = math.min(capacity, math.floor(fillTime * 2))
+
+local currentTokenNum = tonumber(redis.call("GET", tokenKey))
+if currentTokenNum == nil then
+ currentTokenNum = capacity
+end
+
+local endTimeMillis = tonumber(redis.call("GET", timeKey))
+if endTimeMillis == nil then
+ endTimeMillis = 0
+end
+
+local gap = nowMillis - endTimeMillis
+local newTokenNum = math.max(0, gap * qps / 1000)
+local currentTokenNum = math.min(capacity, currentTokenNum + newTokenNum)
+
+if currentTokenNum < permits then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ local finalTokenNum = currentTokenNum - permits
+ redis.call("SETEX", tokenKey, ttl, finalTokenNum)
+ redis.call("SETEX", timeKey, ttl, nowMillis)
+ return finalTokenNum
+end
diff --git a/codes/java-distributed/java-task/pom.xml b/codes/java-distributed/java-task/pom.xml
new file mode 100644
index 00000000..8d7cc462
--- /dev/null
+++ b/codes/java-distributed/java-task/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+
+ io.github.dunwu.distributed
+ java-distributed
+ 1.0.0
+
+
+ io.github.dunwu.distributed
+ java-task
+ 1.0.0
+ jar
+
+
+ UTF-8
+ 1.8
+ ${java.version}
+ ${java.version}
+
+
+
+
+ cn.hutool
+ hutool-all
+
+
+ org.projectlombok
+ lombok
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+ true
+
+
+
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java
new file mode 100644
index 00000000..d510eed1
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java
@@ -0,0 +1,52 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class DelayQueueExample {
+
+ public static void main(String[] args) throws InterruptedException {
+ BlockingQueue delayQueue = new DelayQueue<>();
+ long now = System.currentTimeMillis();
+ delayQueue.put(new SampleTask(now + 1000));
+ delayQueue.put(new SampleTask(now + 2000));
+ delayQueue.put(new SampleTask(now + 3000));
+ for (int i = 0; i < 3; i++) {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(delayQueue.take().getTime()), "yyyy-MM-dd HH:mm:ss"));
+ }
+ }
+
+ static class SampleTask implements Delayed {
+
+ long time;
+
+ public SampleTask(long time) {
+ this.time = time;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ @Override
+ public int compareTo(Delayed o) {
+ return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
+ }
+
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+ }
+
+ }
+
+}
+
+
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java
new file mode 100644
index 00000000..78e8f5bd
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java
@@ -0,0 +1,37 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class ScheduledExecutorServiceExample {
+
+ public static void main(String[] args) {
+ // 创建一个 ScheduledExecutorService 对象,它将使用一个线程池来执行任务
+ ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
+ // 创建一个 Runnable 对象,这个任务将在 2 秒后执行,并且每 1 秒重复执行一次
+ Runnable task = () -> {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+ };
+
+ // 安排任务在 2 秒后执行,并且每 1 秒重复执行一次
+ executor.scheduleAtFixedRate(task, 2, 1, TimeUnit.SECONDS);
+
+ // 主线程等待 10 秒后结束
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // 关闭 executor,这将停止所有正在执行的任务,并拒绝新任务的提交
+ executor.shutdown();
+ }
+
+}
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java
new file mode 100644
index 00000000..ce1d7756
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java
@@ -0,0 +1,39 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+@Slf4j
+public class TimerExample {
+
+ public static void main(String[] args) {
+ // 创建一个 Timer 对象
+ Timer timer = new Timer();
+
+ // 创建一个 TimerTask 对象,这个任务将在 2 秒后执行,并且每 1 秒重复执行一次
+ TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+ }
+ };
+
+ // 安排任务在 2 秒后执行,并且每 1 秒重复执行一次
+ timer.schedule(task, 2000, 1000);
+
+ // 主线程等待 10 秒后结束
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // 取消定时器和所有已安排的任务
+ timer.cancel();
+ }
+
+}
diff --git a/codes/java-distributed/pom.xml b/codes/java-distributed/pom.xml
index 35fd5860..aa88d15d 100644
--- a/codes/java-distributed/pom.xml
+++ b/codes/java-distributed/pom.xml
@@ -3,15 +3,52 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- io.github.dunwu.javatech
+ io.github.dunwu.distributed
java-distributed
1.0.0
pom
- JAVA-DISTRIBUTED
- JAVA-DISTRIBUTED 示例源码
java-load-balance
+ java-rate-limit
+ java-distributed-id
+ java-task
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ 3.9.2
+
+
+ org.apache.curator
+ curator-recipes
+ 4.3.0
+
+
+ redis.clients
+ jedis
+ 5.1.0
+
+
+ cn.hutool
+ hutool-all
+ 5.8.34
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+
+
+ ch.qos.logback
+ logback-classic
+ 1.4.12
+ true
+
+
+
+
diff --git a/codes/javatech/javatech-cache/pom.xml b/codes/javatech/javatech-cache/pom.xml
index c6b35c9a..4503c60c 100644
--- a/codes/javatech/javatech-cache/pom.xml
+++ b/codes/javatech/javatech-cache/pom.xml
@@ -13,7 +13,7 @@
javatech-cache
1.0.0
jar
- Java 缓存
+ JAVATECH-缓存示例
diff --git a/codes/javatech/javatech-io/javatech-bean/README.md b/codes/javatech/javatech-io/javatech-bean/README.md
deleted file mode 100644
index 3b9709fa..00000000
--- a/codes/javatech/javatech-io/javatech-bean/README.md
+++ /dev/null
@@ -1,373 +0,0 @@
-# Lombok 应用指南
-
-
-
-- [1. Lombok 简介](#1-lombok-简介)
-- [2. Lombok 安装](#2-lombok-安装)
-- [3. Lombok 使用](#3-lombok-使用)
- - [3.1. @Getter and @Setter](#31-getter-and-setter)
- - [3.2. @NonNull](#32-nonnull)
- - [3.3. @ToString](#33-tostring)
- - [3.4. @EqualsAndHashCode](#34-equalsandhashcode)
- - [3.5. @Data](#35-data)
- - [3.6. @Cleanup](#36-cleanup)
- - [3.7. @Synchronized](#37-synchronized)
- - [3.8. @SneakyThrows](#38-sneakythrows)
- - [3.9. 示例源码](#39-示例源码)
-- [4. 参考资料](#4-参考资料)
-
-
-
-## 1. Lombok 简介
-
-Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现 Lombok,开发人员可以节省构建诸如 `hashCode()` 和 `equals()` 、`getter / setter` 这样的方法以及以往用来分类各种 accessor 和 mutator 的大量时间。
-
-## 2. Lombok 安装
-
-使 IntelliJ IDEA 支持 Lombok 方式如下:
-
-- **Intellij 设置支持注解处理**
- - 点击 File > Settings > Build > Annotation Processors
- - 勾选 Enable annotation processing
-- **安装插件**
- - 点击 Settings > Plugins > Browse repositories
- - 查找 Lombok Plugin 并进行安装
- - 重启 IntelliJ IDEA
-- **将 lombok 添加到 pom 文件**
-
-```xml
-
- org.projectlombok
- lombok
- 1.16.8
-
-```
-
-## 3. Lombok 使用
-
-Lombok 提供注解 API 来修饰指定的类:
-
-### 3.1. @Getter and @Setter
-
-[@Getter and @Setter](http://jnb.ociweb.com/jnb/jnbJan2010.html#gettersetter) Lombok 代码:
-
-```java
-@Getter @Setter private boolean employed = true;
-@Setter(AccessLevel.PROTECTED) private String name;
-```
-
-等价于 Java 源码:
-
-```java
-private boolean employed = true;
-private String name;
-
-public boolean isEmployed() {
- return employed;
-}
-
-public void setEmployed(final boolean employed) {
- this.employed = employed;
-}
-
-protected void setName(final String name) {
- this.name = name;
-}
-```
-
-### 3.2. @NonNull
-
-[@NonNull](http://jnb.ociweb.com/jnb/jnbJan2010.html#nonnull) Lombok 代码:
-
-```java
-@Getter @Setter @NonNull
-private List members;
-```
-
-等价于 Java 源码:
-
-```java
-@NonNull
-private List members;
-
-public Family(@NonNull final List members) {
- if (members == null) throw new java.lang.NullPointerException("members");
- this.members = members;
-}
-
-@NonNull
-public List getMembers() {
- return members;
-}
-
-public void setMembers(@NonNull final List members) {
- if (members == null) throw new java.lang.NullPointerException("members");
- this.members = members;
-}
-```
-
-### 3.3. @ToString
-
-[@ToString](http://jnb.ociweb.com/jnb/jnbJan2010.html#tostring) Lombok 代码:
-
-```java
-@ToString(callSuper=true,exclude="someExcludedField")
-public class Foo extends Bar {
- private boolean someBoolean = true;
- private String someStringField;
- private float someExcludedField;
-}
-```
-
-等价于 Java 源码:
-
-```java
-public class Foo extends Bar {
- private boolean someBoolean = true;
- private String someStringField;
- private float someExcludedField;
-
- @java.lang.Override
- public java.lang.String toString() {
- return "Foo(super=" + super.toString() +
- ", someBoolean=" + someBoolean +
- ", someStringField=" + someStringField + ")";
- }
-}
-```
-
-### 3.4. @EqualsAndHashCode
-
-[@EqualsAndHashCode](http://jnb.ociweb.com/jnb/jnbJan2010.html#equals) Lombok 代码:
-
-```java
-@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
-public class Person extends SentientBeing {
- enum Gender { Male, Female }
-
- @NonNull private String name;
- @NonNull private Gender gender;
-
- private String ssn;
- private String address;
- private String city;
- private String state;
- private String zip;
-}
-```
-
-等价于 Java 源码:
-
-```java
-public class Person extends SentientBeing {
-
- enum Gender {
- /*public static final*/ Male /* = new Gender() */,
- /*public static final*/ Female /* = new Gender() */;
- }
- @NonNull
- private String name;
- @NonNull
- private Gender gender;
- private String ssn;
- private String address;
- private String city;
- private String state;
- private String zip;
-
- @java.lang.Override
- public boolean equals(final java.lang.Object o) {
- if (o == this) return true;
- if (o == null) return false;
- if (o.getClass() != this.getClass()) return false;
- if (!super.equals(o)) return false;
- final Person other = (Person)o;
- if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
- if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
- if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
- return true;
- }
-
- @java.lang.Override
- public int hashCode() {
- final int PRIME = 31;
- int result = 1;
- result = result * PRIME + super.hashCode();
- result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
- result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
- result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
- return result;
- }
-}
-```
-
-### 3.5. @Data
-
-[@Data](http://jnb.ociweb.com/jnb/jnbJan2010.html#data) Lombok 代码:
-
-```java
-@Data(staticConstructor="of")
-public class Company {
- private final Person founder;
- private String name;
- private List employees;
-}
-```
-
-等价于 Java 源码:
-
-```java
-public class Company {
- private final Person founder;
- private String name;
- private List employees;
-
- private Company(final Person founder) {
- this.founder = founder;
- }
-
- public static Company of(final Person founder) {
- return new Company(founder);
- }
-
- public Person getFounder() {
- return founder;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(final String name) {
- this.name = name;
- }
-
- public List getEmployees() {
- return employees;
- }
-
- public void setEmployees(final List employees) {
- this.employees = employees;
- }
-
- @java.lang.Override
- public boolean equals(final java.lang.Object o) {
- if (o == this) return true;
- if (o == null) return false;
- if (o.getClass() != this.getClass()) return false;
- final Company other = (Company)o;
- if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
- if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
- if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
- return true;
- }
-
- @java.lang.Override
- public int hashCode() {
- final int PRIME = 31;
- int result = 1;
- result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
- result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
- result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
- return result;
- }
-
- @java.lang.Override
- public java.lang.String toString() {
- return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
- }
-}
-```
-
-### 3.6. @Cleanup
-
-[@Cleanup](http://jnb.ociweb.com/jnb/jnbJan2010.html#cleanup) Lombok 代码:
-
-```java
-public void testCleanUp() {
- try {
- @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
- baos.write(new byte[] {'Y','e','s'});
- System.out.println(baos.toString());
- } catch (IOException e) {
- e.printStackTrace();
- }
-}
-```
-
-等价于 Java 源码:
-
-```java
-public void testCleanUp() {
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- baos.write(new byte[]{'Y', 'e', 's'});
- System.out.println(baos.toString());
- } finally {
- baos.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-}
-```
-
-### 3.7. @Synchronized
-
-[@Synchronized](http://jnb.ociweb.com/jnb/jnbJan2010.html#synchronized) Lombok 代码:
-
-```java
-private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");
-
-@Synchronized
-public String synchronizedFormat(Date date) {
- return format.format(date);
-}
-```
-
-等价于 Java 源码:
-
-```java
-private final java.lang.Object $lock = new java.lang.Object[0];
-private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");
-
-public String synchronizedFormat(Date date) {
- synchronized ($lock) {
- return format.format(date);
- }
-}
-```
-
-### 3.8. @SneakyThrows
-
-[@SneakyThrows](http://jnb.ociweb.com/jnb/jnbJan2010.html#sneaky) Lombok 代码:
-
-```java
-@SneakyThrows
-public void testSneakyThrows() {
- throw new IllegalAccessException();
-}
-```
-
-等价于 Java 源码:
-
-```java
-public void testSneakyThrows() {
- try {
- throw new IllegalAccessException();
- } catch (java.lang.Throwable $ex) {
- throw lombok.Lombok.sneakyThrow($ex);
- }
-}
-```
-
-### 3.9. 示例源码
-
-> 示例源码:[javalib-bean](https://github.com/dunwu/java-tutorial/tree/master/javalib-bean)
-
-## 4. 参考资料
-
-- [Lombok 官网](https://projectlombok.org/)
-- [Lombok Github](https://github.com/rzwitserloot/lombok)
-- [IntelliJ IDEA - Lombok Plugin](http://plugins.jetbrains.com/plugin/6317-lombok-plugin)
diff --git a/codes/javatech/javatech-io/javatech-bean/pom.xml b/codes/javatech/javatech-io/javatech-bean/pom.xml
deleted file mode 100644
index 63f2dbe8..00000000
--- a/codes/javatech/javatech-io/javatech-bean/pom.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
- 4.0.0
-
-
- io.github.dunwu
- dunwu-parent
- 1.0.7
-
-
- io.github.dunwu.javatech
- javatech-bean
- 1.0.0
- jar
- Java IO Bean 操作示例
-
-
-
- cn.hutool
- hutool-all
-
-
- org.projectlombok
- lombok
-
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
- ch.qos.logback
- logback-classic
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
- org.assertj
- assertj-core
- test
-
-
- org.mockito
- mockito-core
- test
-
-
-
-
diff --git a/codes/javatech/javatech-io/javatech-file-parser/pom.xml b/codes/javatech/javatech-io/javatech-file-parser/pom.xml
deleted file mode 100644
index 5dbe3e7f..00000000
--- a/codes/javatech/javatech-io/javatech-file-parser/pom.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
- 4.0.0
-
-
- io.github.dunwu
- dunwu-parent
- 1.0.7
-
-
- io.github.dunwu.javatech
- javatech-file-parser
- 1.0.0
- jar
- Java IO 文件解析
-
-
- 4.0.0
-
-
-
-
-
- org.apache.poi
- poi
- ${poi.version}
-
-
- org.apache.poi
- poi-ooxml
- ${poi.version}
-
-
- org.apache.poi
- poi-scratchpad
- ${poi.version}
-
-
-
-
-
- com.github.promeg
- tinypinyin
- 2.0.3
-
-
- com.github.promeg
- tinypinyin-lexicons-java-cncity
- 2.0.3
-
-
-
-
- com.github.javaparser
- javaparser-symbol-solver-core
- 3.24.0
-
-
-
- cn.hutool
- hutool-all
-
-
- org.projectlombok
- lombok
-
-
- com.alibaba
- easyexcel
- 2.2.6
-
-
- com.alibaba
- fastjson
-
-
- org.hibernate.validator
- hibernate-validator
- 6.0.20.Final
-
-
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
- junit
- junit
- test
-
-
- org.assertj
- assertj-core
- test
-
-
-
diff --git a/codes/javatech/javatech-io/javatech-json/pom.xml b/codes/javatech/javatech-io/javatech-json/pom.xml
deleted file mode 100644
index 9f836e2a..00000000
--- a/codes/javatech/javatech-io/javatech-json/pom.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
- 4.0.0
-
-
- io.github.dunwu
- dunwu-parent
- 1.0.7
-
-
- io.github.dunwu.javatech
- javatech-json
- 1.0.0
- jar
- Java IO JSON 示例
-
-
-
- com.alibaba
- fastjson
-
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
- com.google.code.gson
- gson
-
-
- cn.hutool
- hutool-all
-
-
- org.projectlombok
- lombok
-
-
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
- junit
- junit
- test
-
-
- org.assertj
- assertj-core
- test
-
-
-
-
diff --git a/codes/javatech/javatech-io/javatech-serialize/pom.xml b/codes/javatech/javatech-io/javatech-serialize/pom.xml
deleted file mode 100644
index 6203d0b2..00000000
--- a/codes/javatech/javatech-io/javatech-serialize/pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
- 4.0.0
-
-
- io.github.dunwu
- dunwu-parent
- 1.0.7
-
-
- io.github.dunwu.javatech
- javatech-serialize
- 1.0.0
- jar
- Java IO 序列化示例
-
-
-
-
-
-
-
- de.ruedigermoeller
- fst
- 2.56
-
-
- com.esotericsoftware
- kryo
- 5.0.0-RC4
-
-
- cn.hutool
- hutool-all
-
-
- org.projectlombok
- lombok
-
-
-
-
- junit
- junit
- test
-
-
- org.assertj
- assertj-core
- test
-
-
-
-
diff --git a/codes/javatech/javatech-io/pom.xml b/codes/javatech/javatech-io/pom.xml
deleted file mode 100644
index ed8b3f0c..00000000
--- a/codes/javatech/javatech-io/pom.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- 4.0.0
-
- io.github.dunwu.javatech
- javatech-io
- 1.0.0
- pom
- Java IO
-
-
- javatech-bean
- javatech-json
- javatech-serialize
- javatech-file-parser
-
-
diff --git a/codes/javatech/javatech-lib/pom.xml b/codes/javatech/javatech-lib/pom.xml
index d500e8c9..7c6da10b 100644
--- a/codes/javatech/javatech-lib/pom.xml
+++ b/codes/javatech/javatech-lib/pom.xml
@@ -7,41 +7,167 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-lib
1.0.0
+ JAVATECH-工具包示例
+
+
+ 5.2.2
+ 1.22
+
+
+ cn.hutool
+ hutool-all
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ com.alibaba
+ fastjson
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.google.code.gson
+ gson
+
+
+
+
+ de.ruedigermoeller
+ fst
+ 2.56
+
+
+ com.esotericsoftware
+ kryo
+ 5.3.0
+
+
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
org.reflections
reflections
0.10.2
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.10.0
+
+
+
+
+ org.apache.poi
+ poi
+ ${poi.version}
+
+
+ org.apache.poi
+ poi-ooxml
+ ${poi.version}
+
+
+ org.apache.poi
+ poi-scratchpad
+ ${poi.version}
+
+
+
+
+ com.alibaba
+ easyexcel
+ 3.1.1
+
+
+
org.dom4j
dom4j
2.1.3
-
+
- org.junit.jupiter
- junit-jupiter
- test
+ com.github.javaparser
+ javaparser-symbol-solver-core
+ 3.24.2
+
+
+
+
+ com.github.promeg
+ tinypinyin
+ 2.0.3
+
+
+ com.github.promeg
+ tinypinyin-lexicons-java-cncity
+ 2.0.3
+
+
+
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+
+
+
+
+
junit
junit
test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
org.assertj
assertj-core
test
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.hamcrest
+ hamcrest
+ 2.2
+ test
+
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo01.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo01.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo01.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo01.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo02.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo02.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo02.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/BuilderDemo02.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/DataDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/DataDemo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/DataDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/DataDemo.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/EqualsAndHashCodeDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/EqualsAndHashCodeDemo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/EqualsAndHashCodeDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/EqualsAndHashCodeDemo.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/GetterAndSetterDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/GetterAndSetterDemo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/GetterAndSetterDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/GetterAndSetterDemo.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/NonNullDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/NonNullDemo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/NonNullDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/NonNullDemo.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/Person.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/Person.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/Person.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/Person.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/ToStringDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/ToStringDemo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/ToStringDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/ToStringDemo.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/User.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/User.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/User.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/User.java
diff --git a/codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/package-info.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/package-info.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/main/java/io/github/dunwu/javatech/bean/lombok/package-info.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/lombok/package-info.java
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Group.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Group.java
similarity index 93%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Group.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Group.java
index aee30634..f07b3e08 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Group.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Group.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.bean.sample;
import java.util.ArrayList;
import java.util.List;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Person.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Person.java
similarity index 93%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Person.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Person.java
index 9fb539b8..8d87dddd 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/Person.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/Person.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.bean.sample;
import java.io.Serializable;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean.java
similarity index 96%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean.java
index dc597764..b53be676 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.bean.sample;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean2.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean2.java
similarity index 95%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean2.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean2.java
index ea1cfe88..ac3a80e7 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/TestBean2.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/TestBean2.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.bean.sample;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/User.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/User.java
similarity index 91%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/User.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/User.java
index 758293e3..b2418eb9 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/User.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/bean/sample/User.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.bean.sample;
public class User {
diff --git a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java
similarity index 97%
rename from codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java
index 2dff353e..ce44dbb9 100644
--- a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JMHSample_34_SafeLooping.java
@@ -151,10 +151,7 @@ public static void sink(int v) {
*/
public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(JMHSample_34_SafeLooping.class.getSimpleName())
- .forks(3)
- .build();
+ Options opt = new OptionsBuilder().include(JMHSample_34_SafeLooping.class.getSimpleName()).forks(3).build();
new Runner(opt).run();
}
diff --git a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java
similarity index 87%
rename from codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java
index c00183d7..7b16bcc1 100644
--- a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/JmhQuickStart.java
@@ -15,10 +15,7 @@
public class JmhQuickStart {
public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(JmhQuickStart.class.getSimpleName())
- .forks(1)
- .build();
+ Options opt = new OptionsBuilder().include(JmhQuickStart.class.getSimpleName()).forks(1).build();
new Runner(opt).run();
}
diff --git a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java
similarity index 82%
rename from codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java
index c479c545..00ee2ea4 100644
--- a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/jmh/StringBuilderBenchmark.java
@@ -17,10 +17,9 @@
public class StringBuilderBenchmark {
public static void main(String[] args) throws RunnerException {
- Options options = new OptionsBuilder()
- .include(StringBuilderBenchmark.class.getSimpleName())
- .output("d:/Benchmark.log")
- .build();
+ Options options = new OptionsBuilder().include(StringBuilderBenchmark.class.getSimpleName())
+ .output("d:/Benchmark.log")
+ .build();
new Runner(options).run();
}
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/excel/ExcelUtil.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/excel/ExcelUtil.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/excel/ExcelUtil.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/excel/ExcelUtil.java
index d20095f9..e75cd267 100644
--- a/codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/excel/ExcelUtil.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/excel/ExcelUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.excel;
+package io.github.dunwu.javatech.poi.excel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/word/WordUtil.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/word/WordUtil.java
similarity index 99%
rename from codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/word/WordUtil.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/word/WordUtil.java
index f40a2364..bda492cb 100644
--- a/codes/javatech/javatech-io/javatech-file-parser/src/main/java/io/github/dunwu/javatech/word/WordUtil.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/poi/word/WordUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.word;
+package io.github.dunwu.javatech.poi.word;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.SummaryInformation;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/FstDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/FstDemo.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/FstDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/FstDemo.java
index 0ea4cc52..05af588a 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/FstDemo.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/FstDemo.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io;
+package io.github.dunwu.javatech.seriralize;
import org.nustaq.serialization.FSTConfiguration;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/JdkSerializeDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/JdkSerializeDemo.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/JdkSerializeDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/JdkSerializeDemo.java
index 7c86ae32..0043a5c7 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/JdkSerializeDemo.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/JdkSerializeDemo.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io;
+package io.github.dunwu.javatech.seriralize;
import java.io.*;
import java.nio.charset.StandardCharsets;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/KryoDemo.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/KryoDemo.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/KryoDemo.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/KryoDemo.java
index bf333215..29d45909 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/KryoDemo.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/KryoDemo.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io;
+package io.github.dunwu.javatech.seriralize;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/BeanUtils.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/BeanUtils.java
similarity index 97%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/BeanUtils.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/BeanUtils.java
index 11411834..33499166 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/BeanUtils.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/BeanUtils.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.seriralize.util;
import java.time.LocalDate;
import java.time.LocalDateTime;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/DateUtil.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/DateUtil.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/DateUtil.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/DateUtil.java
index ce95f6ce..31a92651 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/DateUtil.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/DateUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.seriralize.util;
import java.time.Duration;
import java.time.LocalDateTime;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Group.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Group.java
similarity index 92%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Group.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Group.java
index 5e985bf8..43343474 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Group.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Group.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.seriralize.util;
import java.util.ArrayList;
import java.util.List;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Person.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Person.java
similarity index 93%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Person.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Person.java
index ed356a1a..8ca18c91 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/util/Person.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/Person.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.util;
+package io.github.dunwu.javatech.seriralize.util;
import java.io.Serializable;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean.java
similarity index 95%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean.java
index 61600f3f..5a3afe11 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.seriralize.util;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean2.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean2.java
similarity index 94%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean2.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean2.java
index 5ee6e62c..7f2881e5 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/TestBean2.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/TestBean2.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.seriralize.util;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/User.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/User.java
similarity index 90%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/User.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/User.java
index 987441b7..785788f0 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/User.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/seriralize/util/User.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.seriralize.util;
public class User {
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/BeanUtils.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/BeanUtils.java
similarity index 89%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/BeanUtils.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/BeanUtils.java
index 06d6fe5f..72a05d1f 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/BeanUtils.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/BeanUtils.java
@@ -1,4 +1,9 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.util;
+
+import io.github.dunwu.javatech.bean.sample.Group;
+import io.github.dunwu.javatech.bean.sample.TestBean;
+import io.github.dunwu.javatech.bean.sample.TestBean2;
+import io.github.dunwu.javatech.bean.sample.User;
import java.time.LocalDate;
import java.time.LocalDateTime;
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/DateUtil.java b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/DateUtil.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/DateUtil.java
rename to codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/DateUtil.java
index 5e8554e7..90c70d98 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/main/java/io/github/dunwu/javatech/io/util/DateUtil.java
+++ b/codes/javatech/javatech-lib/src/main/java/io/github/dunwu/javatech/util/DateUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.io.util;
+package io.github.dunwu.javatech.util;
import java.time.Duration;
import java.time.LocalDateTime;
diff --git a/codes/javatech/javatech-io/javatech-bean/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java
similarity index 96%
rename from codes/javatech/javatech-io/javatech-bean/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java
index e1bc3fd7..9efadb20 100644
--- a/codes/javatech/javatech-io/javatech-bean/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/bean/BeanConvertTest.java
@@ -2,6 +2,7 @@
import cn.hutool.core.bean.BeanUtil;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
@@ -11,6 +12,7 @@
public class BeanConvertTest {
@Test
+ @DisplayName("Bean 转换测试")
public void convertTest() {
Person person = new Person();
person.setName("Jack").setAge(20).setSex(Sex.MALE);
@@ -26,6 +28,7 @@ public enum Sex {
FEMALE
}
+
static class User {
private String name;
@@ -63,6 +66,7 @@ public User setSex(String sex) {
}
+
static class Person {
private String name;
diff --git a/codes/javatech/javatech-io/javatech-bean/src/test/java/io/github/dunwu/javatech/bean/lombok/LombokTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/bean/lombok/LombokTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-bean/src/test/java/io/github/dunwu/javatech/bean/lombok/LombokTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/bean/lombok/LombokTest.java
diff --git a/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/http/OkHttpTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/http/OkHttpTests.java
new file mode 100644
index 00000000..f5f66c12
--- /dev/null
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/http/OkHttpTests.java
@@ -0,0 +1,63 @@
+package io.github.dunwu.javatech.http;
+
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * okhttp API 测试
+ *
+ * @author Zhang Peng
+ * @date 2022-06-09
+ */
+@Slf4j
+public class OkHttpTests {
+
+ OkHttpClient client = new OkHttpClient();
+
+ @Test
+ @DisplayName("OkHttp 同步 Get 请求")
+ public void testSyncGet() throws IOException {
+ String ip = "127.0.0.1";
+ String url = "http://realip.cc/?ip=" + ip;
+ Request request = new Request.Builder().url(url).build();
+
+ try (Response response = client.newCall(request).execute()) {
+ String json = response.body().string();
+ System.out.println("请求结果:" + json);
+ }
+ }
+
+ @Test
+ @DisplayName("OkHttp 异步 Get 请求")
+ public void testAsyncGet() {
+ String ip = "127.0.0.1";
+ String url = "http://realip.cc/?ip=" + ip;
+ Request request = new Request.Builder().url(url).build();
+
+ client.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ if (!response.isSuccessful())
+ throw new IOException("Unexpected code " + response);
+
+ Headers responseHeaders = response.headers();
+ for (int i = 0, size = responseHeaders.size(); i < size; i++) {
+ System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
+ }
+
+ String json = response.body().string();
+ System.out.println("请求结果:" + json);
+ }
+ });
+ }
+
+}
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserCommentReporterTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserCommentReporterTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserCommentReporterTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserCommentReporterTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserLexicalPreservationTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserLexicalPreservationTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserLexicalPreservationTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserLexicalPreservationTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserModifyingVisitorTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserModifyingVisitorTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserModifyingVisitorTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserModifyingVisitorTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserPerttyPrintTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserPerttyPrintTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserPerttyPrintTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserPerttyPrintTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserVoidVisitorTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserVoidVisitorTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/JavaParserVoidVisitorTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/JavaParserVoidVisitorTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/A.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/A.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/A.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/A.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/Bar.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/Bar.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/Bar.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/Bar.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CaptchaTypeEnum.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CaptchaTypeEnum.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CaptchaTypeEnum.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CaptchaTypeEnum.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CodeBiEnum.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CodeBiEnum.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CodeBiEnum.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CodeBiEnum.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CodeEnum.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CodeEnum.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CodeEnum.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CodeEnum.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CommentGenerator.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CommentGenerator.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CommentGenerator.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CommentGenerator.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CommentRemover.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CommentRemover.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/CommentRemover.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/CommentRemover.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/Foo.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/Foo.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/Foo.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/Foo.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/LexicalPreservation.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/LexicalPreservation.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/LexicalPreservation.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/LexicalPreservation.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/ReversePolishNotation.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/ReversePolishNotation.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/ReversePolishNotation.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/ReversePolishNotation.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/WebSocketMsgType.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/WebSocketMsgType.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/java/samples/WebSocketMsgType.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/java/samples/WebSocketMsgType.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/pinyin/PinyinParserTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/pinyin/PinyinParserTest.java
similarity index 100%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/pinyin/PinyinParserTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/pinyin/PinyinParserTest.java
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/excel/ExcelTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/excel/ExcelTest.java
similarity index 76%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/excel/ExcelTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/excel/ExcelTest.java
index 1a894a9d..c5e03cfc 100644
--- a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/excel/ExcelTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/excel/ExcelTest.java
@@ -1,32 +1,28 @@
-package io.github.dunwu.javatech.excel;
+package io.github.dunwu.javatech.poi.excel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
+import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import javax.validation.constraints.NotBlank;
/**
* @author Zhang Peng
* @since 2020-07-01
*/
+@Slf4j
public class ExcelTest {
- private static final Logger LOGGER = LoggerFactory.getLogger(ExcelTest.class);
-
- public static final String OUT_FILE = "d:\\temp-" + System.currentTimeMillis() + ".xlsx";
- public static final String IN_FILE = "d:\\属性列表模板.xlsx";
+ public static final String OUT_FILE = "d:\\temp.xlsx";
@Test
public void simpleWrite() {
@@ -59,10 +55,10 @@ public void dynamicHeadWrite() {
demo.setD("分析维度4");
EasyExcel.write(OUT_FILE)
- // 这里放入动态头
- .head(head()).sheet("模板")
- // 当然这里数据也可以用 List> 去传入
- .doWrite(Collections.singletonList(demo));
+ // 这里放入动态头
+ .head(head()).sheet("模板")
+ // 当然这里数据也可以用 List> 去传入
+ .doWrite(Collections.singletonList(demo));
}
private List> head() {
@@ -94,7 +90,6 @@ public static class BeanDemo {
private String c;
@ExcelProperty("衍生函数名称")
private String d;
- @NotBlank
@ExcelProperty("衍生函数实例参数")
private String e;
@ExcelProperty("参数配置示例")
@@ -103,26 +98,30 @@ public static class BeanDemo {
}
@Test
- public void syncRead() throws FileNotFoundException {
- File file = new File(IN_FILE);
+ public void syncRead() throws IOException {
+ File file = new File(OUT_FILE);
InputStream inputStream = new FileInputStream(file);
List eventAttrDefExcelDTOS = ExcelUtil.readSync(inputStream, BeanDemo.class);
+ inputStream.close();
System.out.println(eventAttrDefExcelDTOS);
}
@Test
- public void syncRead2() throws FileNotFoundException {
- File file = new File("d:\\temp-1595405363178.xlsx");
+ public void syncRead2() throws IOException {
+ File file = new File(OUT_FILE);
InputStream inputStream = new FileInputStream(file);
List list = ExcelUtil.readSync(inputStream, BeanDemo.class);
+ inputStream.close();
System.out.println(list);
}
@Test
- public void asyncReadByCustom() throws FileNotFoundException {
- File file = new File("d:\\temp-1595405363178.xlsx");
+ public void asyncReadByCustom() throws IOException {
+ File file = new File(OUT_FILE);
InputStream inputStream = new FileInputStream(file);
List list = ExcelUtil.readSync(inputStream, BeanDemo.class);
+ inputStream.close();
System.out.println(list);
}
+
}
diff --git a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/word/WordUtilTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/word/WordUtilTest.java
similarity index 96%
rename from codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/word/WordUtilTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/word/WordUtilTest.java
index 781e5ea2..9e49ca07 100644
--- a/codes/javatech/javatech-io/javatech-file-parser/src/test/java/io/github/dunwu/javatech/word/WordUtilTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/poi/word/WordUtilTest.java
@@ -1,7 +1,6 @@
-package io.github.dunwu.javatech.word;
+package io.github.dunwu.javatech.poi.word;
-import io.github.dunwu.javatech.word.WordUtil;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/reflections/MyTestModelStore.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/reflections/MyTestModelStore.java
index 0e56d110..63a145fa 100644
--- a/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/reflections/MyTestModelStore.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/reflections/MyTestModelStore.java
@@ -1,4 +1,4 @@
-//generated using Reflections JavaCodeSerializer [Tue Jan 25 15:26:09 CST 2022]
+//generated using Reflections JavaCodeSerializer [Thu Jun 09 20:34:19 CST 2022]
package io.github.dunwu.javatech.reflections;
public interface MyTestModelStore {
diff --git a/codes/javatech/javatech-io/javatech-serialize/src/test/java/io/github/dunwu/javatech/io/SerializePerformanceTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/binary/BinarySerializePerformanceTest.java
similarity index 83%
rename from codes/javatech/javatech-io/javatech-serialize/src/test/java/io/github/dunwu/javatech/io/SerializePerformanceTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/binary/BinarySerializePerformanceTest.java
index 7c551739..cb0a67d6 100644
--- a/codes/javatech/javatech-io/javatech-serialize/src/test/java/io/github/dunwu/javatech/io/SerializePerformanceTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/binary/BinarySerializePerformanceTest.java
@@ -1,8 +1,11 @@
-package io.github.dunwu.javatech.io;
+package io.github.dunwu.javatech.seriralize.binary;
-import io.github.dunwu.javatech.io.util.BeanUtils;
-import io.github.dunwu.javatech.io.util.TestBean;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.TestBean;
+import io.github.dunwu.javatech.seriralize.FstDemo;
+import io.github.dunwu.javatech.seriralize.JdkSerializeDemo;
+import io.github.dunwu.javatech.seriralize.KryoDemo;
+import io.github.dunwu.javatech.util.BeanUtils;
+import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -14,7 +17,7 @@
* @author Zhang Peng
* @since 2019-11-22
*/
-public class SerializePerformanceTest {
+public class BinarySerializePerformanceTest {
private static final int BATCH_SIZE = 100000;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonAnnotationBean.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonAnnotationBean.java
similarity index 98%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonAnnotationBean.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonAnnotationBean.java
index 8de7a863..836a0793 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonAnnotationBean.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonAnnotationBean.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.fastjson;
+package io.github.dunwu.javatech.seriralize.json.fastjson;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonCaseTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonCaseTests.java
similarity index 91%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonCaseTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonCaseTests.java
index 7257b48e..66a7d131 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonCaseTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonCaseTests.java
@@ -1,11 +1,11 @@
-package io.github.dunwu.javatech.json.fastjson;
+package io.github.dunwu.javatech.seriralize.json.fastjson;
import com.alibaba.fastjson.JSON;
-import io.github.dunwu.javatech.json.util.Group;
-import io.github.dunwu.javatech.json.util.DateUtil;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.Group;
+import io.github.dunwu.javatech.util.DateUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonPerformanceTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonPerformanceTests.java
similarity index 86%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonPerformanceTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonPerformanceTests.java
index 54243c13..4911e3b8 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/fastjson/FastjsonPerformanceTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/fastjson/FastjsonPerformanceTests.java
@@ -1,9 +1,9 @@
-package io.github.dunwu.javatech.json.fastjson;
+package io.github.dunwu.javatech.seriralize.json.fastjson;
import com.alibaba.fastjson.JSON;
-import io.github.dunwu.javatech.json.util.TestBean2;
-import io.github.dunwu.javatech.json.util.BeanUtils;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.TestBean2;
+import io.github.dunwu.javatech.util.BeanUtils;
+import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonAnnotationBean.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonAnnotationBean.java
similarity index 95%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonAnnotationBean.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonAnnotationBean.java
index f8b81504..a043da79 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonAnnotationBean.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonAnnotationBean.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.gson;
+package io.github.dunwu.javatech.seriralize.json.gson;
import com.google.gson.annotations.SerializedName;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonCaseTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonCaseTests.java
similarity index 96%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonCaseTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonCaseTests.java
index ab6c1494..324c3c31 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonCaseTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonCaseTests.java
@@ -1,8 +1,8 @@
-package io.github.dunwu.javatech.json.gson;
+package io.github.dunwu.javatech.seriralize.json.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.lang.reflect.Modifier;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonPerformanceTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonPerformanceTests.java
similarity index 88%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonPerformanceTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonPerformanceTests.java
index 4a43e6f5..dcc35a5d 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/GsonPerformanceTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/GsonPerformanceTests.java
@@ -1,10 +1,10 @@
-package io.github.dunwu.javatech.json.gson;
+package io.github.dunwu.javatech.seriralize.json.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import io.github.dunwu.javatech.json.util.TestBean2;
-import io.github.dunwu.javatech.json.util.BeanUtils;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.TestBean2;
+import io.github.dunwu.javatech.util.BeanUtils;
+import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/VersionedClass.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/VersionedClass.java
similarity index 86%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/VersionedClass.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/VersionedClass.java
index 14e79f1d..cf4878a5 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/gson/VersionedClass.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/gson/VersionedClass.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.gson;
+package io.github.dunwu.javatech.seriralize.json.gson;
import com.google.gson.annotations.Since;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonAnnotationBean.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonAnnotationBean.java
similarity index 94%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonAnnotationBean.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonAnnotationBean.java
index bf5f6f0f..4777ca61 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonAnnotationBean.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonAnnotationBean.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.json.jackson;
+package io.github.dunwu.javatech.seriralize.json.jackson;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonPerformanceTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonPerformanceTests.java
similarity index 87%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonPerformanceTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonPerformanceTests.java
index ed0054f2..e8efe4f8 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonPerformanceTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonPerformanceTests.java
@@ -1,9 +1,9 @@
-package io.github.dunwu.javatech.json.jackson;
+package io.github.dunwu.javatech.seriralize.json.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
-import io.github.dunwu.javatech.json.util.TestBean2;
-import io.github.dunwu.javatech.json.util.BeanUtils;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.TestBean2;
+import io.github.dunwu.javatech.util.BeanUtils;
+import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
diff --git a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonTests.java
similarity index 86%
rename from codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonTests.java
index 84104588..884496db 100644
--- a/codes/javatech/javatech-io/javatech-json/src/test/java/io/github/dunwu/javatech/json/jackson/JacksonTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/seriralize/json/jackson/JacksonTests.java
@@ -1,10 +1,10 @@
-package io.github.dunwu.javatech.json.jackson;
+package io.github.dunwu.javatech.seriralize.json.jackson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import io.github.dunwu.javatech.json.util.Person;
-import org.junit.Assert;
-import org.junit.Test;
+import io.github.dunwu.javatech.bean.sample.Person;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
@@ -34,7 +34,7 @@ public void serialize() {
} catch (JsonProcessingException e) {
e.printStackTrace();
}
- Assert.assertNotNull(json);
+ Assertions.assertNotNull(json);
System.out.println("json = [" + json + "]");
}
@@ -50,7 +50,7 @@ public void deserialize() {
} catch (IOException e) {
e.printStackTrace();
}
- Assert.assertNotNull(p);
+ Assertions.assertNotNull(p);
System.out.println("p = [" + p + "]");
}
@@ -78,7 +78,7 @@ public void serialize2() {
e.printStackTrace();
}
- Assert.assertNotNull(json);
+ Assertions.assertNotNull(json);
System.out.println("json = [" + json + "]");
}
@@ -94,7 +94,7 @@ public void serialize3() {
} catch (JsonProcessingException e) {
e.printStackTrace();
}
- Assert.assertNotNull(json);
+ Assertions.assertNotNull(json);
System.out.println("json = [" + json + "]");
}
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit4/JUnitTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit4/JUnitTest.java
similarity index 97%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit4/JUnitTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit4/JUnitTest.java
index 7f914913..ef852879 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit4/JUnitTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit4/JUnitTest.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit4;
+package io.github.dunwu.javatech.test.junit4;
import org.junit.*;
import org.junit.runners.MethodSorters;
diff --git a/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AassertjAssertionsTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AassertjAssertionsTests.java
new file mode 100644
index 00000000..7abd1e3a
--- /dev/null
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AassertjAssertionsTests.java
@@ -0,0 +1,26 @@
+package io.github.dunwu.javatech.test.junit5;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * assertj Assertions 示例
+ * @author Zhang Peng
+ * @date 2022-07-29
+ */
+public class AassertjAssertionsTests {
+
+ @Test
+ void exceptionTesting() {
+ Throwable exception = Assertions.catchThrowable(() -> {
+ throw new IllegalArgumentException("a message");
+ });
+ Assertions.assertThat(exception.getMessage()).isEqualTo("a message");
+ }
+
+ @Test
+ void standardAssertions() {
+ Assertions.assertThat(2).isEqualTo(2);
+ Assertions.assertThat('a').isLessThan('b');
+ }
+}
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssertionsTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssertionsTests.java
similarity index 94%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssertionsTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssertionsTests.java
index 3ad5d90a..d5b17dfe 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssertionsTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssertionsTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
@@ -34,7 +34,7 @@ void dependentAssertions() {
// Executed only if the previous assertion is valid.
assertAll("first name", () -> assertTrue(firstName.startsWith("J")),
- () -> assertTrue(firstName.endsWith("n")));
+ () -> assertTrue(firstName.endsWith("n")));
}, () -> {
// Grouped assertion, so processed independently
// of results of first name assertions.
@@ -43,7 +43,7 @@ void dependentAssertions() {
// Executed only if the previous assertion is valid.
assertAll("last name", () -> assertTrue(lastName.startsWith("D")),
- () -> assertTrue(lastName.endsWith("e")));
+ () -> assertTrue(lastName.endsWith("e")));
});
}
@@ -60,7 +60,7 @@ void groupedAssertions() {
// In a grouped assertion all assertions are executed, and any
// failures will be reported together.
assertAll("person", () -> assertEquals("John", person.getFirstName()),
- () -> assertEquals("Doe", person.getLastName()));
+ () -> assertEquals("Doe", person.getLastName()));
}
@Test
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssumptionsTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssumptionsTests.java
similarity index 85%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssumptionsTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssumptionsTests.java
index 023120c6..01527245 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/AssumptionsTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/AssumptionsTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -35,8 +35,7 @@ void testOnlyOnCiServer() {
@Test
void testOnlyOnDeveloperWorkstation() {
- assumeTrue("DEV".equals(System.getenv("ENV")),
- () -> "Aborting test: not on developer workstation");
+ assumeTrue("DEV".equals(System.getenv("ENV")), () -> "Aborting test: not on developer workstation");
// remainder of test
}
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DisplayNameTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DisplayNameTests.java
similarity index 93%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DisplayNameTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DisplayNameTests.java
index d6308357..b85bcd47 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DisplayNameTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DisplayNameTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DynamicTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DynamicTests.java
similarity index 63%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DynamicTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DynamicTests.java
index 1f317ab2..b464d840 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/DynamicTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/DynamicTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DynamicNode;
@@ -11,10 +11,7 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
@@ -23,36 +20,34 @@ class DynamicTests {
@TestFactory
DynamicTest[] dynamicTestsFromArray() {
- return new DynamicTest[] {
- dynamicTest("7th dynamic test", () -> assertTrue(true)),
+ return new DynamicTest[] { dynamicTest("7th dynamic test", () -> assertTrue(true)),
dynamicTest("8th dynamic test", () -> assertEquals(4, 2 * 2)) };
}
@TestFactory
Collection dynamicTestsFromCollection() {
return Arrays.asList(dynamicTest("1st dynamic test", () -> assertTrue(true)),
- dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2)));
+ dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2)));
}
@TestFactory
Stream dynamicTestsFromIntStream() {
// Generates tests for the first 10 even integers.
- return IntStream.iterate(0, n -> n + 2).limit(10)
- .mapToObj(n -> dynamicTest("test" + n, () -> assertTrue(n % 2 == 0)));
+ return IntStream.iterate(0, n -> n + 2)
+ .limit(10)
+ .mapToObj(n -> dynamicTest("test" + n, () -> assertEquals(0, n % 2)));
}
@TestFactory
Iterable dynamicTestsFromIterable() {
return Arrays.asList(dynamicTest("3rd dynamic test", () -> assertTrue(true)),
- dynamicTest("4th dynamic test", () -> assertEquals(4, 2 * 2)));
+ dynamicTest("4th dynamic test", () -> assertEquals(4, 2 * 2)));
}
@TestFactory
Iterator dynamicTestsFromIterator() {
- return Arrays
- .asList(dynamicTest("5th dynamic test", () -> assertTrue(true)),
- dynamicTest("6th dynamic test", () -> assertEquals(4, 2 * 2)))
- .iterator();
+ return Arrays.asList(dynamicTest("5th dynamic test", () -> assertTrue(true)),
+ dynamicTest("6th dynamic test", () -> assertEquals(4, 2 * 2))).iterator();
}
@TestFactory
@@ -64,18 +59,14 @@ Stream dynamicTestsFromStream() {
@TestFactory
Stream dynamicTestsWithContainers() {
- return Stream
- .of("A", "B", "C").map(
- input -> dynamicContainer("Container " + input, Stream
- .of(dynamicTest("not null", () -> assertNotNull(input)),
- dynamicContainer("properties",
- Stream.of(
- dynamicTest("length > 0",
- () -> assertTrue(input
- .length() > 0)),
- dynamicTest("not empty",
- () -> assertFalse(input
- .isEmpty())))))));
+ return Stream.of("A", "B", "C")
+ .map(input -> dynamicContainer("Container " + input,
+ Stream.of(dynamicTest("not null", () -> assertNotNull(input)),
+ dynamicContainer("properties", Stream.of(
+ dynamicTest("length > 0",
+ () -> assertTrue(input.length() > 0)),
+ dynamicTest("not empty",
+ () -> assertFalse(input.isEmpty())))))));
}
// This will result in a JUnitException!
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/NestedTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/NestedTests.java
similarity index 87%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/NestedTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/NestedTests.java
index 6811ec10..9a912779 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/NestedTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/NestedTests.java
@@ -1,14 +1,11 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.*;
import java.util.EmptyStackException;
import java.util.Stack;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
@Disabled
@DisplayName("A stack")
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/ParameterizedTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/ParameterizedTests.java
similarity index 84%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/ParameterizedTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/ParameterizedTests.java
index 43c2c278..860cb28d 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/ParameterizedTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/ParameterizedTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
@@ -18,7 +18,7 @@ class ParameterizedTests {
void add(int first, int second, int expectedResult) {
Calculator calculator = new Calculator();
assertEquals(expectedResult, calculator.add(first, second),
- () -> first + " + " + second + " should equal " + expectedResult);
+ () -> first + " + " + second + " should equal " + expectedResult);
}
class Calculator {
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/RepeatedTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/RepeatedTests.java
similarity index 86%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/RepeatedTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/RepeatedTests.java
index d83fc813..99072fe5 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/RepeatedTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/RepeatedTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.*;
@@ -12,8 +12,8 @@ void beforeEach(TestInfo testInfo, RepetitionInfo repetitionInfo) {
int currentRepetition = repetitionInfo.getCurrentRepetition();
int totalRepetitions = repetitionInfo.getTotalRepetitions();
String methodName = testInfo.getTestMethod().get().getName();
- System.out.println(String.format("About to execute repetition %d of %d for %s", //
- currentRepetition, totalRepetitions, methodName));
+ System.out.printf("About to execute repetition %d of %d for %s%n", //
+ currentRepetition, totalRepetitions, methodName);
}
@RepeatedTest(value = 1, name = "{displayName} {currentRepetition}/{totalRepetitions}")
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/StandardTests.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/StandardTests.java
similarity index 95%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/StandardTests.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/StandardTests.java
index e342eea6..e11aa491 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/junit5/StandardTests.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5/StandardTests.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.junit5;
+package io.github.dunwu.javatech.test.junit5;
import org.junit.jupiter.api.*;
diff --git a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/mockito/MockitoTest.java b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/mockito/MockitoTest.java
similarity index 99%
rename from codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/mockito/MockitoTest.java
rename to codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/mockito/MockitoTest.java
index 6211d1a7..ddc87549 100644
--- a/codes/javatech/javatech-test/src/test/java/io/github/dunwu/javatech/mockito/MockitoTest.java
+++ b/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/mockito/MockitoTest.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.mockito;
+package io.github.dunwu.javatech.test.mockito;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/codes/javatech/javatech-log/javatech-log4j/pom.xml b/codes/javatech/javatech-log/javatech-log4j/pom.xml
index 92dd9e50..528a5b66 100644
--- a/codes/javatech/javatech-log/javatech-log4j/pom.xml
+++ b/codes/javatech/javatech-log/javatech-log4j/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-log4j
1.0.0
jar
- Java 日志 Log4j
+ JAVATECH-日志示例-Log4j
UTF-8
diff --git a/codes/javatech/javatech-log/javatech-log4j2/pom.xml b/codes/javatech/javatech-log/javatech-log4j2/pom.xml
index 36f51efc..85642321 100644
--- a/codes/javatech/javatech-log/javatech-log4j2/pom.xml
+++ b/codes/javatech/javatech-log/javatech-log4j2/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-log4j2
1.0.0
jar
- Java 日志 Log4j2
+ JAVATECH-日志示例-Log4j2
UTF-8
diff --git a/codes/javatech/javatech-log/javatech-logback/pom.xml b/codes/javatech/javatech-log/javatech-logback/pom.xml
index ea94efb5..a368fa06 100644
--- a/codes/javatech/javatech-log/javatech-logback/pom.xml
+++ b/codes/javatech/javatech-log/javatech-logback/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-logback
1.0.0
jar
- Java 日志 Logback
+ JAVATECH-日志示例-Logback
UTF-8
diff --git a/codes/javatech/javatech-log/javatech-logstash/pom.xml b/codes/javatech/javatech-log/javatech-logstash/pom.xml
index 20f20855..feb0336a 100644
--- a/codes/javatech/javatech-log/javatech-logstash/pom.xml
+++ b/codes/javatech/javatech-log/javatech-logstash/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-logstash
1.0.0
jar
- Java 日志 Logstash
+ JAVATECH-日志示例-Logstash
UTF-8
diff --git a/codes/javatech/javatech-log/pom.xml b/codes/javatech/javatech-log/pom.xml
index 1ac991b2..94448ef8 100644
--- a/codes/javatech/javatech-log/pom.xml
+++ b/codes/javatech/javatech-log/pom.xml
@@ -8,7 +8,7 @@
javatech-log
1.0.0
pom
- Java 日志
+ JAVATECH-日志示例
javatech-log4j
diff --git a/codes/javatech/javatech-mq/javatech-kafka-springboot/pom.xml b/codes/javatech/javatech-mq/javatech-kafka-springboot/pom.xml
index e4d7d44d..f185b997 100644
--- a/codes/javatech/javatech-mq/javatech-kafka-springboot/pom.xml
+++ b/codes/javatech/javatech-mq/javatech-kafka-springboot/pom.xml
@@ -4,16 +4,16 @@
4.0.0
- io.github.dunwu
- dunwu-starter-parent
- 0.5.6
+ io.github.dunwu.boot
+ dunwu-boot
+ 1.0.8
io.github.dunwu.javatech
javatech-kafka-springboot
1.0.0
jar
- Java 消息队列 Kafka + Spring Boot
+ JAVATECH-MQ示例-Kafka+SpringBoot
UTF-8
diff --git a/codes/javatech/javatech-mq/javatech-kafka/pom.xml b/codes/javatech/javatech-mq/javatech-kafka/pom.xml
index bee96913..19ab59b3 100644
--- a/codes/javatech/javatech-mq/javatech-kafka/pom.xml
+++ b/codes/javatech/javatech-mq/javatech-kafka/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-kafka
1.0.0
jar
- Java 消息队列 Kafka
+ JAVATECH-MQ示例-Kafka
UTF-8
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/pom.xml b/codes/javatech/javatech-mq/javatech-rocketmq/pom.xml
index 2f2d5ca8..9bbc6d7b 100644
--- a/codes/javatech/javatech-mq/javatech-rocketmq/pom.xml
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-rocketmq
1.0.0
jar
- Java 消息队列 Rocketmq
+ JAVATECH-MQ示例-Rocketmq
UTF-8
@@ -27,7 +27,12 @@
org.apache.rocketmq
rocketmq-client
- 4.2.0
+ 4.9.4
+
+
+ org.apache.rocketmq
+ rocketmq-logging
+ 4.9.4
ch.qos.logback
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/AsyncProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/AsyncProducer.java
deleted file mode 100644
index 75ee2eb6..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/AsyncProducer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.client.producer.SendCallback;
-import org.apache.rocketmq.client.producer.SendResult;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-
-/**
- * 发送可靠的异步消息示例 异步传输通常用于响应时间敏感的业务场景。
- *
- * @author Zhang Peng
- */
-public class AsyncProducer {
-
- public static void main(String[] args) throws Exception {
- // Instantiate with a producer group name.
- DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
- producer.setNamesrvAddr(RocketConfig.HOST);
- // Launch the instance.
- producer.start();
- producer.setRetryTimesWhenSendAsyncFailed(0);
- for (int i = 0; i < 100; i++) {
- final int index = i;
- // Create a message instance, specifying topic, tag and message body.
- Message msg = new Message("TopicTest", "TagA", "OrderID188",
- "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
- producer.send(msg, new SendCallback() {
- @Override
- public void onSuccess(SendResult sendResult) {
- System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId());
- }
-
- @Override
- public void onException(Throwable e) {
- System.out.printf("%-10d Exception %s %n", index, e);
- e.printStackTrace();
- }
- });
- }
- // Shut down once the producer instance is not longer in use.
- producer.shutdown();
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BatchProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BatchProducer.java
deleted file mode 100644
index d75b0ff0..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BatchProducer.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.common.message.Message;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 批量发送消息
- *
- * @author Zhang Peng
- */
-public class BatchProducer {
-
- public static void main(String[] args) throws Exception {
- // Instantiate with a producer group name.
- DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
- producer.setNamesrvAddr(RocketConfig.HOST);
- producer.start();
- producer.setRetryTimesWhenSendAsyncFailed(0);
-
- String topic = "BatchTest";
- List messages = new ArrayList<>();
- messages.add(new Message(topic, "TagA", "OrderID001", "Hello world 0".getBytes()));
- messages.add(new Message(topic, "TagA", "OrderID002", "Hello world 1".getBytes()));
- messages.add(new Message(topic, "TagA", "OrderID003", "Hello world 2".getBytes()));
- // then you could split the large list into small ones:
- ListSplitter splitter = new ListSplitter(messages);
-
- while (splitter.hasNext()) {
- List listItem = splitter.next();
- producer.send(listItem);
- }
-
- // Shut down once the producer instance is not longer in use.
- producer.shutdown();
- }
-
- public static class ListSplitter implements Iterator> {
-
- private final int SIZE_LIMIT = 1000 * 1000;
-
- private final List messages;
-
- private int currIndex;
-
- public ListSplitter(List messages) {
- this.messages = messages;
- }
-
- @Override
- public boolean hasNext() {
- return currIndex < messages.size();
- }
-
- @Override
- public List next() {
- int nextIndex = currIndex;
- int totalSize = 0;
- for (; nextIndex < messages.size(); nextIndex++) {
- Message message = messages.get(nextIndex);
- int tmpSize = message.getTopic().length() + message.getBody().length;
- Map properties = message.getProperties();
- for (Map.Entry entry : properties.entrySet()) {
- tmpSize += entry.getKey().length() + entry.getValue().length();
- }
- tmpSize = tmpSize + 20; // for log overhead
- if (tmpSize > SIZE_LIMIT) {
- // it is unexpected that single message exceeds the SIZE_LIMIT
- // here just let it go, otherwise it will block the splitting process
- if (nextIndex - currIndex == 0) {
- // if the next sublist has no element, add this one and then
- // break, otherwise just break
- nextIndex++;
- }
- break;
- }
- if (tmpSize + totalSize > SIZE_LIMIT) {
- break;
- } else {
- totalSize += tmpSize;
- }
- }
- List subList = messages.subList(currIndex, nextIndex);
- currIndex = nextIndex;
- return subList;
- }
-
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastConsumer.java
deleted file mode 100644
index f20e91da..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastConsumer.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
-import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
-import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
-import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
-
-import java.util.List;
-
-/**
- * 接收广播消息示例
- *
- * @author Zhang Peng
- */
-public class BroadcastConsumer {
-
- public static void main(String[] args) throws Exception {
- DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");
- consumer.setNamesrvAddr(RocketConfig.HOST);
-
- consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
-
- // set to broadcast mode
- consumer.setMessageModel(MessageModel.BROADCASTING);
-
- consumer.subscribe("TopicTest", "TagA || TagC || TagD");
-
- consumer.registerMessageListener(new MessageListenerConcurrently() {
-
- @Override
- public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
- System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
- return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
- }
- });
-
- consumer.start();
- System.out.printf("Broadcast Consumer Started.%n");
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastProducer.java
deleted file mode 100644
index b35b37eb..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/BroadcastProducer.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.client.producer.SendResult;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-
-/**
- * 发送广播消息示例
- *
- * @author Zhang Peng
- */
-public class BroadcastProducer {
-
- public static void main(String[] args) throws Exception {
- DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
- producer.setNamesrvAddr(RocketConfig.HOST);
- producer.start();
-
- for (int i = 0; i < 100; i++) {
- Message msg = new Message("TopicTest", "TagA", "OrderID188",
- "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
- SendResult sendResult = producer.send(msg);
- System.out.printf("%s%n", sendResult);
- }
- producer.shutdown();
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OnewayProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OnewayProducer.java
deleted file mode 100644
index b231aa5e..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OnewayProducer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-
-/**
- * 单向传输示例 单向传输用于需要中等可靠性的情况,例如日志收集。
- *
- * @author Zhang Peng
- */
-public class OnewayProducer {
-
- public static void main(String[] args) throws Exception {
- // Instantiate with a producer group name.
- DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
- producer.setNamesrvAddr(RocketConfig.HOST);
- // Launch the instance.
- producer.start();
- for (int i = 0; i < 100; i++) {
- // Create a message instance, specifying topic, tag and message body.
- Message msg = new Message("TopicTest" /* Topic */, "TagA" /* Tag */, ("Hello RocketMQ " + i)
- .getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
- );
- // Call send message to deliver message to one of brokers.
- producer.sendOneway(msg);
- }
- // Shut down once the producer instance is not longer in use.
- producer.shutdown();
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedConsumer.java
deleted file mode 100644
index c960cb9c..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedConsumer.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
-import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
-import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
-import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
-import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
-import org.apache.rocketmq.common.message.MessageExt;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * 接收全局和分区排序的消息。
- *
- * @author Zhang Peng
- */
-public class OrderedConsumer {
-
- public static void main(String[] args) throws Exception {
- DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");
- consumer.setNamesrvAddr(RocketConfig.HOST);
-
- consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
-
- consumer.subscribe("TopicTest", "TagA || TagC || TagD");
-
- consumer.registerMessageListener(new MessageListenerOrderly() {
-
- AtomicLong consumeTimes = new AtomicLong(0);
-
- @Override
- public ConsumeOrderlyStatus consumeMessage(List msgs, ConsumeOrderlyContext context) {
- context.setAutoCommit(false);
- System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
- this.consumeTimes.incrementAndGet();
- if ((this.consumeTimes.get() % 2) == 0) {
- return ConsumeOrderlyStatus.SUCCESS;
- } else if ((this.consumeTimes.get() % 3) == 0) {
- return ConsumeOrderlyStatus.ROLLBACK;
- } else if ((this.consumeTimes.get() % 4) == 0) {
- return ConsumeOrderlyStatus.COMMIT;
- } else if ((this.consumeTimes.get() % 5) == 0) {
- context.setSuspendCurrentQueueTimeMillis(3000);
- return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
- }
- return ConsumeOrderlyStatus.SUCCESS;
- }
- });
-
- consumer.start();
-
- System.out.printf("Consumer Started.%n");
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConfig.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConfig.java
deleted file mode 100644
index a9e00062..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConfig.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-/**
- * @author Zhang Peng
- */
-public class RocketConfig {
-
- public static final String HOST = "192.168.28.32:9876";
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConstant.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConstant.java
new file mode 100644
index 00000000..d932c10b
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/RocketConstant.java
@@ -0,0 +1,10 @@
+package io.github.dunwu.javatech.rocketmq;
+
+/**
+ * @author Zhang Peng
+ */
+public class RocketConstant {
+
+ public static final String HOST = "localhost:9876";
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageConsumer.java
deleted file mode 100644
index eb131b47..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageConsumer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
-import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
-import org.apache.rocketmq.common.message.MessageExt;
-
-import java.util.List;
-
-/**
- * 接收定时消息
- *
- * @author Zhang Peng
- */
-public class ScheduledMessageConsumer {
-
- public static void main(String[] args) throws Exception {
- // Instantiate message consumer
- DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ExampleConsumer");
- // Subscribe topics
- consumer.subscribe("TestTopic", "*");
- // Register message listener
- consumer.registerMessageListener(new MessageListenerConcurrently() {
- @Override
- public ConsumeConcurrentlyStatus consumeMessage(List messages,
- ConsumeConcurrentlyContext context) {
- for (MessageExt message : messages) {
- // Print approximate delay time period
- System.out.println("Receive message[msgId=" + message.getMsgId() + "] "
- + (System.currentTimeMillis() - message.getStoreTimestamp()) + "ms later");
- }
- return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
- }
- });
- // Launch consumer
- consumer.start();
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/SyncProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/SyncProducer.java
deleted file mode 100644
index 6d60e61f..00000000
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/SyncProducer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package io.github.dunwu.javatech.rocketmq;
-
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.client.producer.SendResult;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-
-/**
- * 发送可靠的同步消息示例 可靠的同步传输用于广泛的场景,如重要的通知消息,短信通知,短信营销系统等。
- *
- * @author Zhang Peng
- */
-public class SyncProducer {
-
- public static void main(String[] args) throws Exception {
- // Instantiate with a producer group name.
- DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
- producer.setNamesrvAddr(RocketConfig.HOST);
- // Launch the instance.
- producer.start();
- for (int i = 0; i < 100; i++) {
- // Create a message instance, specifying topic, tag and message body.
- Message msg = new Message("TopicTest" /* Topic */, "TagA" /* Tag */, ("Hello RocketMQ " + i)
- .getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
- );
- // Call send message to deliver message to one of brokers.
- SendResult sendResult = producer.send(msg);
- System.out.printf("%s%n", sendResult);
- }
- // Shut down once the producer instance is not longer in use.
- producer.shutdown();
- }
-
-}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchConsumer.java
new file mode 100644
index 00000000..b05bbcd1
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchConsumer.java
@@ -0,0 +1,41 @@
+package io.github.dunwu.javatech.rocketmq.batch;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+public class BatchConsumer {
+
+ public static void main(String[] args) throws InterruptedException, MQClientException {
+
+ // Instantiate with specified consumer group name.
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ExampleProducerGroup");
+
+ // Specify name server addresses.
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+
+ // Subscribe one more more topics to consume.
+ consumer.subscribe("BatchTest", "*");
+ // Register callback to execute on arrival of messages fetched from brokers.
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
+ System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+
+ //Launch the consumer instance.
+ consumer.start();
+
+ System.out.printf("Consumer Started.%n");
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer.java
new file mode 100644
index 00000000..c567d532
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer.java
@@ -0,0 +1,40 @@
+package io.github.dunwu.javatech.rocketmq.batch;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.message.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 批量发送消息(一次发送消息大小不超过 1MB)
+ *
+ * @author Zhang Peng
+ */
+public class BatchProducer {
+
+ public static void main(String[] args) throws Exception {
+ // Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ producer.start();
+ producer.setRetryTimesWhenSendAsyncFailed(0);
+
+ String topic = "BatchTest";
+ List messages = new ArrayList<>();
+ messages.add(new Message(topic, "TagA", "OrderID001", "Hello world 0".getBytes()));
+ messages.add(new Message(topic, "TagA", "OrderID002", "Hello world 1".getBytes()));
+ messages.add(new Message(topic, "TagA", "OrderID003", "Hello world 2".getBytes()));
+ try {
+ producer.send(messages);
+ } catch (Exception e) {
+ e.printStackTrace();
+ //handle the error
+ }
+
+ // Shut down once the producer instance is not longer in use.
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer2.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer2.java
new file mode 100644
index 00000000..a1ae8715
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/BatchProducer2.java
@@ -0,0 +1,41 @@
+package io.github.dunwu.javatech.rocketmq.batch;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.message.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 批量发送消息(一次发送消息大小超过 1MB)
+ *
+ * @author Zhang Peng
+ */
+public class BatchProducer2 {
+
+ public static void main(String[] args) throws Exception {
+ // Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ producer.start();
+ producer.setRetryTimesWhenSendAsyncFailed(0);
+
+ String topic = "BatchTest";
+ List messages = new ArrayList<>();
+ messages.add(new Message(topic, "TagA", "OrderID001", "Hello world 0".getBytes()));
+ messages.add(new Message(topic, "TagA", "OrderID002", "Hello world 1".getBytes()));
+ messages.add(new Message(topic, "TagA", "OrderID003", "Hello world 2".getBytes()));
+ // then you could split the large list into small ones:
+ ListSplitter splitter = new ListSplitter(messages);
+
+ while (splitter.hasNext()) {
+ List listItem = splitter.next();
+ producer.send(listItem);
+ }
+
+ // Shut down once the producer instance is not longer in use.
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/ListSplitter.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/ListSplitter.java
new file mode 100644
index 00000000..837fc117
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/ListSplitter.java
@@ -0,0 +1,57 @@
+package io.github.dunwu.javatech.rocketmq.batch;
+
+import org.apache.rocketmq.common.message.Message;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class ListSplitter implements Iterator> {
+
+ private final int SIZE_LIMIT = 1000 * 1000;
+ private final List messages;
+ private int currIndex;
+
+ public ListSplitter(List messages) {
+ this.messages = messages;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currIndex < messages.size();
+ }
+
+ @Override
+ public List next() {
+ int nextIndex = currIndex;
+ int totalSize = 0;
+ for (; nextIndex < messages.size(); nextIndex++) {
+ Message message = messages.get(nextIndex);
+ int tmpSize = message.getTopic().length() + message.getBody().length;
+ Map properties = message.getProperties();
+ for (Map.Entry entry : properties.entrySet()) {
+ tmpSize += entry.getKey().length() + entry.getValue().length();
+ }
+ tmpSize = tmpSize + 20; //for log overhead
+ if (tmpSize > SIZE_LIMIT) {
+ //it is unexpected that single message exceeds the SIZE_LIMIT
+ //here just let it go, otherwise it will block the splitting process
+ if (nextIndex - currIndex == 0) {
+ //if the next sublist has no element, add this one and then break, otherwise just break
+ nextIndex++;
+ }
+ break;
+ }
+ if (tmpSize + totalSize > SIZE_LIMIT) {
+ break;
+ } else {
+ totalSize += tmpSize;
+ }
+
+ }
+ List subList = messages.subList(currIndex, nextIndex);
+ currIndex = nextIndex;
+ return subList;
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/README.md b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/README.md
new file mode 100644
index 00000000..5d9c24c2
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/batch/README.md
@@ -0,0 +1,11 @@
+# Rocket 官方示例之 Batch Example
+
+批量发送消息提高了传递小消息的性能。
+
+同一批次的消息应该具有:相同的主题、相同的 waitStoreMsgOK 并且不支持调度。
+
+此外,一批消息的总大小不应超过 1MiB。
+
+## 参考资料
+
+- [Batch Example](https://rocketmq.apache.org/docs/batch-example/)
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastConsumer.java
new file mode 100644
index 00000000..5c1c97d5
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastConsumer.java
@@ -0,0 +1,45 @@
+package io.github.dunwu.javatech.rocketmq.broadcast;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+
+import java.util.List;
+
+/**
+ * 接收广播消息示例
+ *
+ * @author Zhang Peng
+ */
+public class BroadcastConsumer {
+
+ public static void main(String[] args) throws Exception {
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+
+ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+
+ //set to broadcast mode
+ consumer.setMessageModel(MessageModel.BROADCASTING);
+
+ consumer.subscribe("TopicTest", "TagA || TagC || TagD");
+
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
+ System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+
+ consumer.start();
+ System.out.printf("Broadcast Consumer Started.%n");
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastProducer.java
new file mode 100644
index 00000000..10628dd7
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/BroadcastProducer.java
@@ -0,0 +1,30 @@
+package io.github.dunwu.javatech.rocketmq.broadcast;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+/**
+ * 发送广播消息示例
+ *
+ * @author Zhang Peng
+ */
+public class BroadcastProducer {
+
+ public static void main(String[] args) throws Exception {
+ DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ producer.start();
+
+ for (int i = 0; i < 100; i++) {
+ Message msg = new Message("TopicTest", "TagA", "OrderID188",
+ "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
+ SendResult sendResult = producer.send(msg);
+ System.out.printf("%s%n", sendResult);
+ }
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/README.md b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/README.md
new file mode 100644
index 00000000..104b6eb0
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/broadcast/README.md
@@ -0,0 +1,7 @@
+# Rocket 官方示例之 Broadcasting Example
+
+- 广播是向主题的所有订阅者发送消息。如果您希望所有订阅者都收到有关某个主题的消息,广播是一个不错的选择。
+
+## 参考资料
+
+- [Broadcasting Example](https://rocketmq.apache.org/docs/broadcast-example/)
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterConsumer.java
new file mode 100644
index 00000000..635f125e
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterConsumer.java
@@ -0,0 +1,33 @@
+package io.github.dunwu.javatech.rocketmq.filter;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.MessageSelector;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+public class FilterConsumer {
+
+ public static void main(String[] args) throws InterruptedException, MQClientException {
+
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
+ // Specify name server addresses.
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+ // only subsribe messages have property a, also a >=0 and a <= 3
+ consumer.subscribe("TopicTest", MessageSelector.bySql("a between 0 and 3"));
+
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+ consumer.start();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterProducer.java
new file mode 100644
index 00000000..1a0c2f94
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/filter/FilterProducer.java
@@ -0,0 +1,37 @@
+package io.github.dunwu.javatech.rocketmq.filter;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+/**
+ * 批量发送消息(一次发送消息大小不超过 1MB)
+ *
+ * @author Zhang Peng
+ */
+public class FilterProducer {
+
+ public static void main(String[] args) throws Exception {
+ // Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ producer.start();
+
+ String[] tags = new String[] { "TagA", "TagB", "TagC", "TagD", "TagE" };
+ for (int i = 0; i < 100; i++) {
+ //Create a message instance, specifying topic, tag and message body.
+ Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i,
+ ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
+ // Set some properties.
+ msg.putUserProperty("a", String.valueOf(i));
+ SendResult sendResult = producer.send(msg);
+
+ System.out.printf("%s%n", sendResult);
+ }
+
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedConsumer.java
new file mode 100644
index 00000000..da3361b7
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedConsumer.java
@@ -0,0 +1,58 @@
+package io.github.dunwu.javatech.rocketmq.order;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 接收全局和分区排序的消息。
+ *
+ * @author Zhang Peng
+ */
+public class OrderedConsumer {
+
+ public static void main(String[] args) throws Exception {
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+
+ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+
+ consumer.subscribe("TopicTest", "TagA || TagC || TagD");
+
+ consumer.registerMessageListener(new MessageListenerOrderly() {
+
+ AtomicLong consumeTimes = new AtomicLong(0);
+
+ @Override
+ public ConsumeOrderlyStatus consumeMessage(List msgs, ConsumeOrderlyContext context) {
+ context.setAutoCommit(false);
+ System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
+ this.consumeTimes.incrementAndGet();
+ if ((this.consumeTimes.get() % 2) == 0) {
+ return ConsumeOrderlyStatus.SUCCESS;
+ } else if ((this.consumeTimes.get() % 3) == 0) {
+ return ConsumeOrderlyStatus.ROLLBACK;
+ } else if ((this.consumeTimes.get() % 4) == 0) {
+ return ConsumeOrderlyStatus.COMMIT;
+ } else if ((this.consumeTimes.get() % 5) == 0) {
+ context.setSuspendCurrentQueueTimeMillis(3000);
+ return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
+ }
+ return ConsumeOrderlyStatus.SUCCESS;
+
+ }
+ });
+
+ consumer.start();
+
+ System.out.printf("Consumer Started.%n");
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedProducer.java
similarity index 64%
rename from codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedProducer.java
rename to codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedProducer.java
index e736448a..6362ad8c 100644
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/OrderedProducer.java
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/OrderedProducer.java
@@ -1,7 +1,7 @@
-package io.github.dunwu.javatech.rocketmq;
+package io.github.dunwu.javatech.rocketmq.order;
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.client.producer.MQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
@@ -18,17 +18,18 @@
public class OrderedProducer {
public static void main(String[] args) throws Exception {
- // Instantiate with a producer group name.
- MQProducer producer = new DefaultMQProducer("example_group_name");
- ((DefaultMQProducer) producer).setNamesrvAddr(RocketConfig.HOST);
- // Launch the instance.
+ //Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("example_group_name");
+ // Specify name server addresses.
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ //Launch the instance.
producer.start();
String[] tags = new String[] { "TagA", "TagB", "TagC", "TagD", "TagE" };
for (int i = 0; i < 100; i++) {
int orderId = i % 10;
- // Create a message instance, specifying topic, tag and message body.
- Message msg = new Message("TopicTestjjj", tags[i % tags.length], "KEY" + i,
- ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
+ //Create a message instance, specifying topic, tag and message body.
+ Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i,
+ ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List mqs, Message msg, Object arg) {
@@ -40,7 +41,7 @@ public MessageQueue select(List mqs, Message msg, Object arg) {
System.out.printf("%s%n", sendResult);
}
- // server shutdown
+ //server shutdown
producer.shutdown();
}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/README.md b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/README.md
new file mode 100644
index 00000000..1ebbff2f
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/order/README.md
@@ -0,0 +1,7 @@
+# Rocket 官方示例之 Order Message Example
+
+- RocketMQ 使用 FIFO 顺序提供有序消息。
+
+## 参考资料
+
+- [Order Example](https://rocketmq.apache.org/docs/order-example/)
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/README.md b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/README.md
new file mode 100644
index 00000000..c233a4ca
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/README.md
@@ -0,0 +1,7 @@
+# Rocket 官方示例之 Schedule Example
+
+- 定时消息与普通消息的不同之处在于,它们要等到指定的时间后才会发送。
+
+## 参考资料
+
+- [Schedule Example](https://rocketmq.apache.org/docs/schedule-example/)
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageConsumer.java
new file mode 100644
index 00000000..2724afa4
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageConsumer.java
@@ -0,0 +1,44 @@
+package io.github.dunwu.javatech.rocketmq.scheduled;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+/**
+ * 接收定时消息
+ *
+ * @author Zhang Peng
+ */
+public class ScheduledMessageConsumer {
+
+ public static void main(String[] args) throws Exception {
+ // Instantiate message consumer
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ExampleConsumer");
+ // Specify name server addresses.
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+ // Subscribe topics
+ consumer.subscribe("TestTopic", "*");
+ // Register message listener
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List messages,
+ ConsumeConcurrentlyContext context) {
+ for (MessageExt message : messages) {
+ // Print approximate delay time period
+ System.out.println(
+ "Receive message[msgId=" + message.getMsgId() + "] " + (System.currentTimeMillis()
+ - message.getStoreTimestamp()) + "ms later");
+ }
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+ // Launch consumer
+ consumer.start();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageProducer.java
similarity index 80%
rename from codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageProducer.java
rename to codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageProducer.java
index 9096412f..855fd5e1 100644
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/ScheduledMessageProducer.java
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/scheduled/ScheduledMessageProducer.java
@@ -1,5 +1,6 @@
-package io.github.dunwu.javatech.rocketmq;
+package io.github.dunwu.javatech.rocketmq.scheduled;
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
@@ -13,6 +14,8 @@ public class ScheduledMessageProducer {
public static void main(String[] args) throws Exception {
// Instantiate a producer to send scheduled messages
DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
+ // Specify name server addresses.
+ producer.setNamesrvAddr(RocketConstant.HOST);
// Launch producer
producer.start();
int totalMessagesToSend = 100;
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/AsyncProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/AsyncProducer.java
new file mode 100644
index 00000000..4640fd94
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/AsyncProducer.java
@@ -0,0 +1,60 @@
+package io.github.dunwu.javatech.rocketmq.simple;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 异步发送 RocketMQ 消息示例
+ *
+ * 异步传输通常用于响应时间敏感的业务场景。
+ *
+ * @author Zhang Peng
+ */
+public class AsyncProducer {
+
+ public static void main(String[] args) throws Exception {
+ //Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
+ // Specify name server addresses.
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ //Launch the instance.
+ producer.start();
+ producer.setRetryTimesWhenSendAsyncFailed(0);
+
+ int messageCount = 100;
+ final CountDownLatch countDownLatch = new CountDownLatch(messageCount);
+ for (int i = 0; i < messageCount; i++) {
+ try {
+ final int index = i;
+ Message msg = new Message("Jodie_topic_1023", "TagA", "OrderID188",
+ "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
+ producer.send(msg, new SendCallback() {
+ @Override
+ public void onSuccess(SendResult sendResult) {
+ countDownLatch.countDown();
+ System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId());
+ }
+
+ @Override
+ public void onException(Throwable e) {
+ countDownLatch.countDown();
+ System.out.printf("%-10d Exception %s %n", index, e);
+ e.printStackTrace();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ countDownLatch.await(5, TimeUnit.SECONDS);
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/Consumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/Consumer.java
new file mode 100644
index 00000000..247dd27a
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/Consumer.java
@@ -0,0 +1,41 @@
+package io.github.dunwu.javatech.rocketmq.simple;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+public class Consumer {
+
+ public static void main(String[] args) throws InterruptedException, MQClientException {
+
+ // Instantiate with specified consumer group name.
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
+
+ // Specify name server addresses.
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+
+ // Subscribe one more more topics to consume.
+ consumer.subscribe("TopicTest", "*");
+ // Register callback to execute on arrival of messages fetched from brokers.
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
+ System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+
+ //Launch the consumer instance.
+ consumer.start();
+
+ System.out.printf("Consumer Started.%n");
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/OnewayProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/OnewayProducer.java
new file mode 100644
index 00000000..638fa690
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/OnewayProducer.java
@@ -0,0 +1,36 @@
+package io.github.dunwu.javatech.rocketmq.simple;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+/**
+ * 单向发送 RocketMQ 消息示例
+ *
+ * 单向传输用于需要中等可靠性的情况,例如日志收集。
+ *
+ * @author Zhang Peng
+ */
+public class OnewayProducer {
+
+ public static void main(String[] args) throws Exception {
+ //Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
+ // Specify name server addresses.
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ //Launch the instance.
+ producer.start();
+ for (int i = 0; i < 100; i++) {
+ //Create a message instance, specifying topic, tag and message body.
+ Message msg = new Message("TopicTest" /* Topic */, "TagA" /* Tag */, ("Hello RocketMQ " + i).getBytes(
+ RemotingHelper.DEFAULT_CHARSET) /* Message body */);
+ //Call send message to deliver message to one of brokers.
+ producer.sendOneway(msg);
+ }
+ //Wait for sending to complete
+ Thread.sleep(5000);
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/README.md b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/README.md
new file mode 100644
index 00000000..4ebebf39
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/README.md
@@ -0,0 +1,8 @@
+# Rocket 官方示例之 Simple Message Example
+
+- 使用 RocketMQ 通过三种方式发送消息:可靠同步、可靠异步、单向传输。
+- 使用 RocketMQ 消费消息。
+
+## 参考资料
+
+- [Simple Message Example](https://rocketmq.apache.org/docs/simple-example/)
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/SyncProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/SyncProducer.java
new file mode 100644
index 00000000..55bff356
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/simple/SyncProducer.java
@@ -0,0 +1,37 @@
+package io.github.dunwu.javatech.rocketmq.simple;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+/**
+ * 同步发送 RocketMQ 消息示例
+ *
+ * 可靠同步传输应用场景广泛,如重要通知消息、短信通知、短信营销系统等。
+ *
+ * @author Zhang Peng
+ */
+public class SyncProducer {
+
+ public static void main(String[] args) throws Exception {
+ //Instantiate with a producer group name.
+ DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
+ // Specify name server addresses.
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ //Launch the instance.
+ producer.start();
+ for (int i = 0; i < 100; i++) {
+ //Create a message instance, specifying topic, tag and message body.
+ Message msg = new Message("TopicTest" /* Topic */, "TagA" /* Tag */, ("Hello RocketMQ " + i).getBytes(
+ RemotingHelper.DEFAULT_CHARSET) /* Message body */);
+ //Call send message to deliver message to one of brokers.
+ SendResult sendResult = producer.send(msg);
+ System.out.printf("%s%n", sendResult);
+ }
+ //Shut down once the producer instance is not longer in use.
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionConsumer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionConsumer.java
new file mode 100644
index 00000000..d8a28443
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionConsumer.java
@@ -0,0 +1,41 @@
+package io.github.dunwu.javatech.rocketmq.transaction;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+public class TransactionConsumer {
+
+ public static void main(String[] args) throws InterruptedException, MQClientException {
+
+ // Instantiate with specified consumer group name.
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
+
+ // Specify name server addresses.
+ consumer.setNamesrvAddr(RocketConstant.HOST);
+
+ // Subscribe one more more topics to consume.
+ consumer.subscribe("TopicTestTx", "*");
+ // Register callback to execute on arrival of messages fetched from brokers.
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
+ System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+
+ //Launch the consumer instance.
+ consumer.start();
+
+ System.out.printf("Consumer Started.%n");
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionListenerImpl.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionListenerImpl.java
new file mode 100644
index 00000000..fe2f2d83
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionListenerImpl.java
@@ -0,0 +1,41 @@
+package io.github.dunwu.javatech.rocketmq.transaction;
+
+import org.apache.rocketmq.client.producer.LocalTransactionState;
+import org.apache.rocketmq.client.producer.TransactionListener;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TransactionListenerImpl implements TransactionListener {
+
+ private AtomicInteger transactionIndex = new AtomicInteger(0);
+
+ private ConcurrentHashMap localTrans = new ConcurrentHashMap<>();
+
+ @Override
+ public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
+ int value = transactionIndex.getAndIncrement();
+ int status = value % 3;
+ localTrans.put(msg.getTransactionId(), status);
+ return LocalTransactionState.UNKNOW;
+ }
+
+ @Override
+ public LocalTransactionState checkLocalTransaction(MessageExt msg) {
+ Integer status = localTrans.get(msg.getTransactionId());
+ if (null != status) {
+ switch (status) {
+ case 0:
+ return LocalTransactionState.UNKNOW;
+ case 1:
+ return LocalTransactionState.COMMIT_MESSAGE;
+ case 2:
+ return LocalTransactionState.ROLLBACK_MESSAGE;
+ }
+ }
+ return LocalTransactionState.COMMIT_MESSAGE;
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionProducer.java b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionProducer.java
new file mode 100644
index 00000000..b0aabfa5
--- /dev/null
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/java/io/github/dunwu/javatech/rocketmq/transaction/TransactionProducer.java
@@ -0,0 +1,56 @@
+package io.github.dunwu.javatech.rocketmq.transaction;
+
+import io.github.dunwu.javatech.rocketmq.RocketConstant;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.TransactionListener;
+import org.apache.rocketmq.client.producer.TransactionMQProducer;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.*;
+
+public class TransactionProducer {
+
+ public static void main(String[] args) throws MQClientException, InterruptedException {
+ TransactionListener transactionListener = new TransactionListenerImpl();
+ TransactionMQProducer producer = new TransactionMQProducer("please_rename_unique_group_name");
+ producer.setNamesrvAddr(RocketConstant.HOST);
+ ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS,
+ new ArrayBlockingQueue(2000),
+ new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(r);
+ thread.setName(
+ "client-transaction-msg-check-thread");
+ return thread;
+ }
+ });
+
+ producer.setExecutorService(executorService);
+ producer.setTransactionListener(transactionListener);
+ producer.start();
+
+ String[] tags = new String[] { "TagA", "TagB", "TagC", "TagD", "TagE" };
+ for (int i = 0; i < 10; i++) {
+ try {
+ Message msg = new Message("TopicTestTx", tags[i % tags.length], "KEY" + i,
+ ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
+ SendResult sendResult = producer.sendMessageInTransaction(msg, null);
+ System.out.printf("%s%n", sendResult);
+
+ Thread.sleep(10);
+ } catch (MQClientException | UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ for (int i = 0; i < 100000; i++) {
+ Thread.sleep(1000);
+ }
+ producer.shutdown();
+ }
+
+}
diff --git a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/resources/logback.xml b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/resources/logback.xml
index 3be789cb..0645b04e 100644
--- a/codes/javatech/javatech-mq/javatech-rocketmq/src/main/resources/logback.xml
+++ b/codes/javatech/javatech-mq/javatech-rocketmq/src/main/resources/logback.xml
@@ -3,49 +3,57 @@
-
-
-
-
-
- 10
- 100
-
-
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%p] %c{36}#%M - %m%n
-
-
-
-
-
- ${LOG_PATH}/logs/${FILE_NAME}-error.%d{yyyy-MM-dd}.log
- 30
-
-
-
-
- 10MB
-
-
-
- ERROR
- ACCEPT
- DENY
-
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%p] %c{36}#%M - %m%n
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ 10
+ 100
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%p] %c{36}#%M - %m%n
+
+
+
+
+
+ ${LOG_PATH}/logs/${FILE_NAME}-error.%d{yyyy-MM-dd}.log
+ 30
+
+
+
+
+ 10MB
+
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%p] %c{36}#%M - %m%n
+
+
+
+
+ 1024
+ 80
+ 2000
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/codes/javatech/javatech-mq/pom.xml b/codes/javatech/javatech-mq/pom.xml
index 1599ba76..2f13cdbb 100644
--- a/codes/javatech/javatech-mq/pom.xml
+++ b/codes/javatech/javatech-mq/pom.xml
@@ -8,7 +8,7 @@
javatech-mq
1.0.0
pom
- Java 消息队列
+ JAVATECH-MQ示例
javatech-kafka
diff --git a/codes/javatech/javatech-others/javatech-cli/pom.xml b/codes/javatech/javatech-others/javatech-cli/pom.xml
index 51d3c2ef..8b946f64 100644
--- a/codes/javatech/javatech-others/javatech-cli/pom.xml
+++ b/codes/javatech/javatech-others/javatech-cli/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-cli
1.0.0
jar
- Java 其他 - 命令行
+ JAVATECH-其他示例-命令行
UTF-8
diff --git a/codes/javatech/javatech-others/javatech-ruleengine/pom.xml b/codes/javatech/javatech-others/javatech-ruleengine/pom.xml
index d1812974..bc10ab25 100644
--- a/codes/javatech/javatech-others/javatech-ruleengine/pom.xml
+++ b/codes/javatech/javatech-others/javatech-ruleengine/pom.xml
@@ -8,14 +8,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-ruleengine
1.0.0
jar
- Java 其他 - 规则引擎
+ JAVATECH-其他示例-规则引擎
3.4.0
diff --git a/codes/javatech/javatech-others/javatech-zookeeper/pom.xml b/codes/javatech/javatech-others/javatech-zookeeper/pom.xml
index cd59a365..37774d2b 100644
--- a/codes/javatech/javatech-others/javatech-zookeeper/pom.xml
+++ b/codes/javatech/javatech-others/javatech-zookeeper/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-zookeeper
1.0.0
jar
- Java 其他 - Zookeeper
+ JAVATECH-其他示例-Zookeeper
diff --git a/codes/javatech/javatech-others/pom.xml b/codes/javatech/javatech-others/pom.xml
index d5cb439f..221f2bcf 100644
--- a/codes/javatech/javatech-others/pom.xml
+++ b/codes/javatech/javatech-others/pom.xml
@@ -8,7 +8,7 @@
javatech-others
1.0.0
pom
- Java 其他
+ JAVATECH-其他示例
javatech-cli
diff --git a/codes/javatech/javatech-server/pom.xml b/codes/javatech/javatech-server/pom.xml
index 576eab62..b4879ebd 100644
--- a/codes/javatech/javatech-server/pom.xml
+++ b/codes/javatech/javatech-server/pom.xml
@@ -7,14 +7,14 @@
io.github.dunwu
dunwu-parent
- 1.0.7
+ 1.0.8
io.github.dunwu.javatech
javatech-server
1.0.0
war
- Java 服务器
+ JAVATECH-服务器示例
[8.5.40,)
@@ -29,7 +29,7 @@
org.logback-extensions
logback-ext-spring
- 0.1.2
+ 0.1.5
org.slf4j
@@ -75,6 +75,20 @@
org.springframework
spring-webmvc
+
+ org.springframework
+ spring-test
+
+
+ junit
+ junit
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
diff --git a/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/controller/HelloController.java b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/controller/HelloController.java
index 9588d2b0..07e678e0 100644
--- a/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/controller/HelloController.java
+++ b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/controller/HelloController.java
@@ -1,7 +1,9 @@
package io.github.dunwu.javatech.controller;
+import io.github.dunwu.javatech.service.HelloService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -21,6 +23,9 @@ public class HelloController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
+ @Autowired
+ private HelloService helloService;
+
/**
*
* 在本例中,Spring将会将数据传给 hello.jsp
@@ -31,7 +36,7 @@ public class HelloController {
public ModelAndView hello(@RequestParam("name") String name) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", "你好," + name);
- mav.setViewName("hello");
+ mav.setViewName(helloService.hello());
return mav;
}
diff --git a/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java
new file mode 100644
index 00000000..75d9b577
--- /dev/null
+++ b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java
@@ -0,0 +1,15 @@
+package io.github.dunwu.javatech.service;
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Zhang Peng
+ * @date 2022-07-28
+ */
+@Service
+public class HelloService {
+
+ public String hello() {
+ return "hello";
+ }
+}
diff --git a/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java b/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java
new file mode 100644
index 00000000..946e65de
--- /dev/null
+++ b/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java
@@ -0,0 +1,28 @@
+package io.github.dunwu.javatech;
+
+import io.github.dunwu.javatech.service.HelloService;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * 单元测试
+ * @author Zhang Peng
+ * @date 2022-07-28
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {"classpath:spring/spring-servlet.xml"})
+public class HelloControllerTests {
+
+ @Autowired
+ private HelloService service;
+
+ @Test
+ public void test() {
+ String msg = service.hello();
+ Assertions.assertThat("hello").isEqualTo(msg);
+ }
+}
diff --git a/codes/javatech/javatech-test/pom.xml b/codes/javatech/javatech-test/pom.xml
deleted file mode 100644
index 172c6722..00000000
--- a/codes/javatech/javatech-test/pom.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
- 4.0.0
-
-
- io.github.dunwu
- dunwu-parent
- 1.0.7
-
-
- io.github.dunwu.javatech
- javatech-test
- 1.0.0
- jar
- Java 测试
-
-
- 1.22
-
-
-
-
- ch.qos.logback
- logback-classic
-
-
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
-
-
- junit
- junit
- test
-
-
-
-
- org.assertj
- assertj-core
- test
-
-
- org.mockito
- mockito-core
- test
-
-
-
- org.openjdk.jmh
- jmh-core
- ${jmh.version}
-
-
- org.openjdk.jmh
- jmh-generator-annprocess
- ${jmh.version}
- provided
-
-
-
-
diff --git a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Calculator.java b/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Calculator.java
deleted file mode 100644
index 26c99915..00000000
--- a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Calculator.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.github.dunwu.javatech.bean.lombok;
-
-public class Calculator {
-
- public int add(int a, int b) {
- return a + b;
- }
-
-}
diff --git a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Person.java b/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Person.java
deleted file mode 100644
index 6ae9aa14..00000000
--- a/codes/javatech/javatech-test/src/main/java/io/github/dunwu/javatech/lombok/Person.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package io.github.dunwu.javatech.bean.lombok;
-
-/**
- * @author Zhang Peng
- * @since 2018-11-29
- */
-public class Person {
-
- private String firstName;
-
- private String lastName;
-
- public Person(String firstName, String lastName) {
- this.firstName = firstName;
- this.lastName = lastName;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
-}
diff --git a/codes/javatech/javatech-test/src/main/resources/logback.xml b/codes/javatech/javatech-test/src/main/resources/logback.xml
deleted file mode 100644
index 240ee4c6..00000000
--- a/codes/javatech/javatech-test/src/main/resources/logback.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- %d{HH:mm:ss.SSS} [%boldYellow(%thread)] [%highlight(%-5level)] %boldGreen(%c{36}.%M) - %boldBlue(%m%n)
-
-
-
-
-
-
-
-
-
-
diff --git a/codes/javatech/pom.xml b/codes/javatech/pom.xml
index def6c001..8bfcf17b 100644
--- a/codes/javatech/pom.xml
+++ b/codes/javatech/pom.xml
@@ -12,12 +12,10 @@
javatech-cache
- javatech-io
javatech-lib
javatech-log
javatech-mq
javatech-server
- javatech-test
javatech-others
diff --git a/codes/javatool/javatool-monitor/javatool-zipkin-spring/pom.xml b/codes/javatool/javatool-monitor/javatool-zipkin-spring/pom.xml
index 4225461a..8ada12b7 100644
--- a/codes/javatool/javatool-monitor/javatool-zipkin-spring/pom.xml
+++ b/codes/javatool/javatool-monitor/javatool-zipkin-spring/pom.xml
@@ -1,205 +1,204 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- io.github.dunwu.javatool
- javatool-zipkin-spring
- 1.0.0
- war
- ${project.artifactId}
- Java distributed tracing implementation compatible with Zipkin backend services.
+ io.github.dunwu.javatool
+ javatool-zipkin-spring
+ 1.0.0
+ war
+ JAVATOOL-监控-Zipkin(Spring)
-
- UTF-8
- 1.7
- 1.7
+
+ UTF-8
+ 1.7
+ 1.7
- 4.3.26.RELEASE
- 2.13.0
- 5.10.1
-
+ 4.3.26.RELEASE
+ 2.13.0
+ 5.10.1
+
-
-
-
- io.zipkin.brave
- brave-bom
- ${brave.version}
- pom
- import
-
-
-
-
-
-
- javax.servlet
- javax.servlet-api
- 3.1.0
- provided
-
-
- org.springframework
- spring-webmvc
- ${spring.version}
-
-
- org.springframework
- spring-web
- ${spring.version}
-
-
- org.apache.httpcomponents
- httpclient
- 4.5.11
-
+
+
+
+ io.zipkin.brave
+ brave-bom
+ ${brave.version}
+ pom
+ import
+
+
+
-
-
- io.zipkin.brave
- brave-instrumentation-spring-webmvc
-
-
-
- io.zipkin.brave
- brave-instrumentation-httpclient
-
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
+
+
+ org.springframework
+ spring-webmvc
+ ${spring.version}
+
+
+ org.springframework
+ spring-web
+ ${spring.version}
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.11
+
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-jul
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-jcl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
- ${log4j.version}
-
-
- io.zipkin.brave
- brave-context-log4j2
-
+
+
+ io.zipkin.brave
+ brave-instrumentation-spring-webmvc
+
+
+
+ io.zipkin.brave
+ brave-instrumentation-httpclient
+
-
-
- io.zipkin.brave
- brave-spring-beans
-
-
- io.zipkin.brave
- brave
-
-
- io.zipkin.reporter2
- zipkin-sender-okhttp3
-
-
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-jul
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-jcl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j.version}
+
+
+ io.zipkin.brave
+ brave-context-log4j2
+
-
-
-
- maven-compiler-plugin
- 3.8.1
-
+
+
+ io.zipkin.brave
+ brave-spring-beans
+
+
+ io.zipkin.brave
+ brave
+
+
+ io.zipkin.reporter2
+ zipkin-sender-okhttp3
+
+
-
- maven-enforcer-plugin
- 3.0.0-M3
-
-
- enforce-java
-
- enforce
-
-
-
-
-
- [1.7.0_80,)
-
-
-
-
-
-
+
+
+
+ maven-compiler-plugin
+ 3.8.1
+
-
- maven-war-plugin
- 3.2.3
-
- false
- WEB-INF/lib/servlet-api-*.jar
-
-
-
-
-
-
- org.eclipse.jetty
- jetty-maven-plugin
- 9.4.26.v20200117
-
-
-
-
+
+ maven-enforcer-plugin
+ 3.0.0-M3
+
+
+ enforce-java
+
+ enforce
+
+
+
+
+
+ [1.7.0_80,)
+
+
+
+
+
+
-
-
- frontend
-
-
-
- org.eclipse.jetty
- jetty-maven-plugin
-
-
- 8081
-
-
-
- zipkin.service
- frontend
-
-
-
-
+
+ maven-war-plugin
+ 3.2.3
+
+ false
+ WEB-INF/lib/servlet-api-*.jar
+
+
-
-
-
- backend
-
-
-
- org.eclipse.jetty
- jetty-maven-plugin
-
-
- 9000
-
-
-
- zipkin.service
- backend
-
-
-
-
-
-
-
-
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ 9.4.26.v20200117
+
+
+
+
+
+
+
+ frontend
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+
+
+ 8081
+
+
+
+ zipkin.service
+ frontend
+
+
+
+
+
+
+
+
+ backend
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+
+
+ 9000
+
+
+
+ zipkin.service
+ backend
+
+
+
+
+
+
+
+
diff --git a/codes/javatool/javatool-monitor/javatool-zipkin-springboot/pom.xml b/codes/javatool/javatool-monitor/javatool-zipkin-springboot/pom.xml
index b314e9e5..7d99565f 100644
--- a/codes/javatool/javatool-monitor/javatool-zipkin-springboot/pom.xml
+++ b/codes/javatool/javatool-monitor/javatool-zipkin-springboot/pom.xml
@@ -1,108 +1,106 @@
- 4.0.0
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- io.github.dunwu.javatool
- javatool-zipkin-springboot
- 1.0.0
- jar
- ${project.artifactId}
- Example using Brave to trace RPCs from Spring Web MVC
+ io.github.dunwu.javatool
+ javatool-zipkin-springboot
+ 1.0.0
+ jar
+ JAVATOOL-监控-Zipkin(SpringBoot)
-
- UTF-8
- 1.7
- 1.7
+
+ UTF-8
+ 1.7
+ 1.7
+ 2.7.2
+ 5.10.1
+
- 1.5.22.RELEASE
- 5.10.1
-
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+ io.zipkin.brave
+ brave-bom
+ ${brave.version}
+ pom
+ import
+
+
+
-
-
- org.springframework.boot
- spring-boot-dependencies
- ${spring-boot.version}
- pom
- import
-
-
- io.zipkin.brave
- brave-bom
- ${brave.version}
- pom
- import
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.apache.httpcomponents
- httpclient
-
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.apache.httpcomponents
+ httpclient
+
-
-
- io.zipkin.brave
- brave-instrumentation-spring-webmvc
-
-
-
- io.zipkin.brave
- brave-instrumentation-httpclient
-
+
+
+ io.zipkin.brave
+ brave-instrumentation-spring-webmvc
+
+
+
+ io.zipkin.brave
+ brave-instrumentation-httpclient
+
-
-
- io.zipkin.brave
- brave-context-slf4j
-
+
+
+ io.zipkin.brave
+ brave-context-slf4j
+
-
-
- io.zipkin.brave
- brave
-
-
- io.zipkin.reporter2
- zipkin-sender-okhttp3
-
-
+
+
+ io.zipkin.brave
+ brave
+
+
+ io.zipkin.reporter2
+ zipkin-sender-okhttp3
+
+
-
-
-
- maven-compiler-plugin
- 3.8.1
-
+
+
+
+ maven-compiler-plugin
+ 3.8.1
+
-
- maven-enforcer-plugin
- 3.0.0-M3
-
-
- enforce-java
-
- enforce
-
-
-
-
-
- [1.7.0_80,)
-
-
-
-
-
-
-
-
+
+ maven-enforcer-plugin
+ 3.0.0-M3
+
+
+ enforce-java
+
+ enforce
+
+
+
+
+
+ [1.7.0_80,)
+
+
+
+
+
+
+
+
diff --git a/codes/javatool/javatool-monitor/pom.xml b/codes/javatool/javatool-monitor/pom.xml
index b3497277..027eca63 100644
--- a/codes/javatool/javatool-monitor/pom.xml
+++ b/codes/javatool/javatool-monitor/pom.xml
@@ -1,17 +1,17 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- io.github.dunwu.javatool
- javatool-monitor
- 1.0.0
- pom
- ${project.artifactId}
+ io.github.dunwu.javatool
+ javatool-monitor
+ 1.0.0
+ pom
+ JAVATOOL-监控
-
- javatool-zipkin-spring
- javatool-zipkin-springboot
-
+
+ javatool-zipkin-spring
+ javatool-zipkin-springboot
+
diff --git a/codes/javatool/pom.xml b/codes/javatool/pom.xml
index 96d1160e..86b22be9 100644
--- a/codes/javatool/pom.xml
+++ b/codes/javatool/pom.xml
@@ -1,16 +1,16 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- io.github.dunwu.javatool
- javatool
- 1.0.0
- pom
- JAVATOOL
+ io.github.dunwu.javatool
+ javatool
+ 1.0.0
+ pom
+ JAVATOOL
-
- javatool-monitor
-
+
+ javatool-monitor
+
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index d71b76ca..6bba8f05 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -1,174 +1,209 @@
-/**
- * @see https://vuepress.vuejs.org/zh/
- */
+const baiduCode = require('./config/baiduCode.js') // 百度统计hm码
+const htmlModules = require('./config/htmlModules.js')
+
module.exports = {
port: '4000',
- dest: 'dist',
- base: '/java-tutorial/',
+ dest: 'docs/.temp',
+ base: '/java-tutorial/', // 默认'/'。如果你想将你的网站部署到如 https://foo.github.io/bar/,那么 base 应该被设置成 "/bar/",(否则页面将失去样式等文件)
title: 'JAVA-TUTORIAL',
- description: 'Java 教程',
- head: [['link', { rel: 'icon', href: `/favicon.ico` }]],
+ description: '☕ java-tutorial 是一个 Java 教程,汇集一个老司机在 Java 领域的十年积累。',
+ theme: 'vdoing', // 使用依赖包主题
+ // theme: require.resolve('../../vdoing'), // 使用本地主题
+ head: [
+ // 注入到页面 中的标签,格式[tagName, { attrName: attrValue }, innerHTML?]
+ ['link', { rel: 'icon', href: '/img/favicon.ico' }], //favicons,资源放在public文件夹
+ ['meta', { name: 'keywords', content: 'vuepress,theme,blog,vdoing' }],
+ ['meta', { name: 'theme-color', content: '#11a8cd' }], // 移动浏览器主题颜色
+
+ ['meta', { name: 'wwads-cn-verify', content: 'mxqWx62nfQQ9ocT4e5DzISHzOWyF4s' }], // 广告相关,你可以去掉
+ ['script', { src: 'https://cdn.wwads.cn/js/makemoney.js', type: 'text/javascript' }] // 广告相关,你可以去掉
+ ],
markdown: {
+ // lineNumbers: true,
+ extractHeaders: ['h2', 'h3', 'h4', 'h5', 'h6'], // 提取标题到侧边栏的级别,默认['h2', 'h3']
externalLinks: {
target: '_blank',
- rel: 'noopener noreferrer',
- },
+ rel: 'noopener noreferrer'
+ }
},
+ // 主题配置
themeConfig: {
- logo: 'https://raw.githubusercontent.com/dunwu/images/dev/common/dunwu-logo-200.png',
- repo: 'dunwu/java-tutorial',
- repoLabel: 'Github',
- docsDir: 'docs',
- docsBranch: 'master',
- editLinks: true,
- smoothScroll: true,
- locales: {
- '/': {
- label: '简体中文',
- selectText: 'Languages',
- editLinkText: '帮助我们改善此页面!',
- lastUpdated: '上次更新',
- nav: [
- {
- text: 'JavaEE',
- link: '/javaee/',
- },
- {
- text: '框架',
- link: '/framework/',
- },
- {
- text: '缓存',
- link: '/cache/',
- },
- {
- text: '消息队列',
- link: '/mq/',
- },
- {
- text: 'LIB库',
- link: '/lib/',
- },
- {
- text: '微服务',
- link: '/microservice/',
- },
- {
- text: '安全',
- link: '/security/',
- },
- {
- text: '测试',
- link: '/test/',
- },
- {
- text: '服务器',
- link: '/server/',
- },
- {
- text: '工具',
- link: '/tool/',
- items: [
- {
- text: '构建',
- link: '/tool/build/',
- },
- {
- text: 'IDE',
- link: '/tool/ide/',
- },
- {
- text: '监控',
- link: '/tool/monitor/',
- },
- ],
- },
- {
- text: '✨ Java系列',
- ariaLabel: 'Java',
- items: [
- {
- text: 'Java 教程 📚',
- link: 'https://dunwu.github.io/java-tutorial/',
- target: '_blank',
- rel: '',
- },
- {
- text: 'JavaCore 教程 📚',
- link: 'https://dunwu.github.io/javacore/',
- target: '_blank',
- rel: '',
- },
- {
- text: 'Spring 教程 📚',
- link: 'https://dunwu.github.io/spring-tutorial/',
- target: '_blank',
- rel: '',
- },
- {
- text: 'Spring Boot 教程 📚',
- link: 'https://dunwu.github.io/spring-boot-tutorial/',
- target: '_blank',
- rel: '',
- },
- ],
- },
- {
- text: '🎯 博客',
- link: 'https://github.com/dunwu/blog',
- target: '_blank',
- rel: '',
- },
- ],
- sidebar: 'auto',
- sidebarDepth: 2,
+ nav: [
+ { text: '首页', link: '/' },
+ { text: 'JavaEE', link: '/01.Java/02.JavaEE/' },
+ {
+ text: 'Java软件',
+ link: '/01.Java/11.软件/',
+ items: [
+ { text: 'Java 构建', link: '/01.Java/11.软件/01.构建/' },
+ { text: 'Java IDE', link: '/01.Java/11.软件/02.IDE/' },
+ { text: 'Java 监控诊断', link: '/01.Java/11.软件/03.监控诊断/' }
+ ]
+ },
+ {
+ text: 'Java工具',
+ link: '/01.Java/12.工具/',
+ items: [
+ { text: 'Java IO 工具', link: '/01.Java/12.工具/01.IO/' },
+ { text: 'JavaBean 工具', link: '/01.Java/12.工具/02.JavaBean/' },
+ { text: 'Java 模板引擎', link: '/01.Java/12.工具/03.模板引擎/' },
+ { text: 'Java 测试工具', link: '/01.Java/12.工具/04.测试/' }
+ ]
},
+ { text: 'Java框架', link: '/01.Java/13.框架/' },
+ { text: 'Java中间件', link: '/01.Java/14.中间件/' },
+ {
+ text: '✨ Java系列',
+ ariaLabel: 'Java',
+ items: [
+ { text: 'Java 教程 📚', link: 'https://dunwu.github.io/java-tutorial/', target: '_blank' },
+ { text: 'JavaCore 教程 📚', link: 'https://dunwu.github.io/javacore/', target: '_blank' }
+ ]
+ }
+ ],
+ sidebarDepth: 2, // 侧边栏显示深度,默认1,最大2(显示到h3标题)
+ logo: 'https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png', // 导航栏logo
+ repo: 'dunwu/java-tutorial', // 导航栏右侧生成Github链接
+ searchMaxSuggestions: 10, // 搜索结果显示最大数
+ lastUpdated: '上次更新', // 更新的时间,及前缀文字 string | boolean (取值为git提交时间)
+
+ docsDir: 'docs', // 编辑的文件夹
+ editLinks: true, // 编辑链接
+ editLinkText: '📝 帮助改善此页面!',
+
+ // 以下配置是Vdoing主题改动的和新增的配置
+ sidebar: { mode: 'structuring', collapsable: true }, // 侧边栏 'structuring' | { mode: 'structuring', collapsable:
+ // Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页
+
+ sidebarOpen: true, // 初始状态是否打开侧边栏,默认true
+ updateBar: {
+ // 最近更新栏
+ showToArticle: true // 显示到文章页底部,默认true
+ // moreArticle: '/archives' // “更多文章”跳转的页面,默认'/archives'
+ },
+ // titleBadge: false, // 文章标题前的图标是否显示,默认true
+ // titleBadgeIcons: [ // 文章标题前图标的地址,默认主题内置图标
+ // '图标地址1',
+ // '图标地址2'
+ // ],
+ // bodyBgImg: [
+ // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175828.jpeg',
+ // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175845.jpeg',
+ // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175846.jpeg'
+ // ], // body背景大图,默认无。 单张图片 String || 多张图片 Array, 多张图片时每隔15秒换一张。
+
+ // categoryText: '随笔', // 碎片化文章(_posts文件夹的文章)预设生成的分类值,默认'随笔'
+
+ // contentBgStyle: 1,
+
+ category: true, // 是否打开分类功能,默认true。 如打开,会做的事情有:1. 自动生成的frontmatter包含分类字段 2.页面中显示与分类相关的信息和模块 3.自动生成分类页面(在@pages文件夹)。如关闭,则反之。
+ tag: true, // 是否打开标签功能,默认true。 如打开,会做的事情有:1. 自动生成的frontmatter包含标签字段 2.页面中显示与标签相关的信息和模块 3.自动生成标签页面(在@pages文件夹)。如关闭,则反之。
+ archive: true, // 是否打开归档功能,默认true。 如打开,会做的事情有:1.自动生成归档页面(在@pages文件夹)。如关闭,则反之。
+
+ author: {
+ // 文章默认的作者信息,可在md文件中单独配置此信息 String | {name: String, href: String}
+ name: 'dunwu', // 必需
+ href: 'https://github.com/dunwu' // 可选的
+ },
+ social: {
+ // 社交图标,显示于博主信息栏和页脚栏
+ // iconfontCssFile: '//at.alicdn.com/t/font_1678482_u4nrnp8xp6g.css', // 可选,阿里图标库在线css文件地址,对于主题没有的图标可自由添加
+ icons: [
+ {
+ iconClass: 'icon-youjian',
+ title: '发邮件',
+ link: 'mailto:forbreak@163.com'
+ },
+ {
+ iconClass: 'icon-github',
+ title: 'GitHub',
+ link: 'https://github.com/dunwu'
+ }
+ ]
},
+ footer: {
+ // 页脚信息
+ createYear: 2019, // 博客创建年份
+ copyrightInfo: '钝悟(dunwu) | CC-BY-SA-4.0' // 博客版权信息,支持a标签
+ },
+ htmlModules
},
+
+ // 插件
plugins: [
[
- '@vuepress/active-header-links',
+ require('./plugins/love-me'),
{
- sidebarLinkSelector: '.sidebar-link',
- headerAnchorSelector: '.header-anchor',
- },
+ // 鼠标点击爱心特效
+ color: '#11a8cd', // 爱心颜色,默认随机色
+ excludeClassName: 'theme-vdoing-content' // 要排除元素的class, 默认空''
+ }
],
- ['@vuepress/back-to-top', true],
+
+ ['fulltext-search'], // 全文搜索
+
+ // ['thirdparty-search', { // 可以添加第三方搜索链接的搜索框(原官方搜索框的参数仍可用)
+ // thirdparty: [ // 可选,默认 []
+ // {
+ // title: '在GitHub中搜索',
+ // frontUrl: 'https://github.com/search?q=', // 搜索链接的前面部分
+ // behindUrl: '' // 搜索链接的后面部分,可选,默认 ''
+ // },
+ // {
+ // title: '在npm中搜索',
+ // frontUrl: 'https://www.npmjs.com/search?q=',
+ // },
+ // {
+ // title: '在Bing中搜索',
+ // frontUrl: 'https://cn.bing.com/search?q='
+ // }
+ // ]
+ // }],
+
[
- '@vuepress/pwa',
+ 'one-click-copy',
{
- serviceWorker: true,
- updatePopup: true,
- },
+ // 代码块复制按钮
+ copySelector: ['div[class*="language-"] pre', 'div[class*="aside-code"] aside'], // String or Array
+ copyMessage: '复制成功', // default is 'Copy successfully and then paste it for use.'
+ duration: 1000, // prompt message display time.
+ showInMobile: false // whether to display on the mobile side, default: false.
+ }
],
[
- '@vuepress/last-updated',
+ 'demo-block',
{
- transformer: (timestamp, lang) => {
- // 不要忘了安装 moment
- const moment = require('moment')
- moment.locale(lang)
- return moment(timestamp).fromNow()
- },
- },
+ // demo演示模块 https://github.com/xiguaxigua/vuepress-plugin-demo-block
+ settings: {
+ // jsLib: ['http://xxx'], // 在线示例(jsfiddle, codepen)中的js依赖
+ // cssLib: ['http://xxx'], // 在线示例中的css依赖
+ // vue: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', // 在线示例中的vue依赖
+ jsfiddle: false, // 是否显示 jsfiddle 链接
+ codepen: true, // 是否显示 codepen 链接
+ horizontal: false // 是否展示为横向样式
+ }
+ }
],
- ['@vuepress/medium-zoom', true],
[
- 'container',
+ 'vuepress-plugin-zooming', // 放大图片
{
- type: 'vue',
- before: '',
- after: '
',
- },
+ selector: '.theme-vdoing-content img:not(.no-zoom)',
+ options: {
+ bgColor: 'rgba(0,0,0,0.6)'
+ }
+ }
],
[
- 'container',
+ '@vuepress/last-updated', // "上次更新"时间格式
{
- type: 'upgrade',
- before: (info) => ``,
- after: '',
- },
- ],
- ['flowchart'],
+ transformer: (timestamp, lang) => {
+ const dayjs = require('dayjs') // https://day.js.org/
+ return dayjs(timestamp).format('YYYY/MM/DD, HH:mm:ss')
+ }
+ }
+ ]
],
+
+ // 监听文件变化并重新构建
+ extraWatchFiles: ['.vuepress/config.js', '.vuepress/config/htmlModules.js']
}
diff --git a/docs/.vuepress/config/baiduCode.js b/docs/.vuepress/config/baiduCode.js
new file mode 100644
index 00000000..b0c50903
--- /dev/null
+++ b/docs/.vuepress/config/baiduCode.js
@@ -0,0 +1 @@
+module.exports = ''
diff --git a/docs/.vuepress/config/htmlModules.js b/docs/.vuepress/config/htmlModules.js
new file mode 100644
index 00000000..fc0a47eb
--- /dev/null
+++ b/docs/.vuepress/config/htmlModules.js
@@ -0,0 +1,69 @@
+/** 插入自定义html模块 (可用于插入广告模块等)
+ * {
+ * homeSidebarB: htmlString, 首页侧边栏底部
+ *
+ * sidebarT: htmlString, 全局左侧边栏顶部
+ * sidebarB: htmlString, 全局左侧边栏底部
+ *
+ * pageT: htmlString, 全局页面顶部
+ * pageB: htmlString, 全局页面底部
+ * pageTshowMode: string, 页面顶部-显示方式:未配置默认全局;'article' => 仅文章页①; 'custom' => 仅自定义页①
+ * pageBshowMode: string, 页面底部-显示方式:未配置默认全局;'article' => 仅文章页①; 'custom' => 仅自定义页①
+ *
+ * windowLB: htmlString, 全局左下角②
+ * windowRB: htmlString, 全局右下角②
+ * }
+ *
+ * ①注:在.md文件front matter配置`article: false`的页面是自定义页,未配置的默认是文章页(首页除外)。
+ * ②注:windowLB 和 windowRB:1.展示区块最大宽高200px*400px。2.请给自定义元素定一个不超过200px*400px的宽高。3.在屏幕宽度小于960px时无论如何都不会显示。
+ */
+
+module.exports = {
+ // 万维广告
+ // pageT: `
+ //
+ //
+ // `,
+ windowRB: `
+
+
+ `,
+}
+
+// module.exports = {
+// homeSidebarB: `自定义模块测试
`,
+// sidebarT: `自定义模块测试
`,
+// sidebarB: `自定义模块测试
`,
+// pageT: `自定义模块测试
`,
+// pageB: `自定义模块测试
`,
+// windowLB: `自定义模块测试
`,
+// windowRB: `自定义模块测试
`,
+// }
diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js
index 7b3605fc..5bfa34f4 100644
--- a/docs/.vuepress/enhanceApp.js
+++ b/docs/.vuepress/enhanceApp.js
@@ -1,7 +1,59 @@
-export default ({ Vue, isServer }) => {
+/**
+ * to主题使用者:你可以去掉本文件的所有代码
+ */
+export default ({
+ Vue, // VuePress 正在使用的 Vue 构造函数
+ options, // 附加到根实例的一些选项
+ router, // 当前应用的路由实例
+ siteData, // 站点元数据
+ isServer // 当前应用配置是处于 服务端渲染 还是 客户端
+}) => {
+
+ // 用于监控在路由变化时检查广告拦截器 (to主题使用者:你可以去掉本文件的所有代码)
if (!isServer) {
- import('vue-toasted' /* webpackChunkName: "notification" */).then(module => {
- Vue.use(module.default)
+ router.afterEach(() => {
+ //check if wwads' fire function was blocked after document is ready with 3s timeout (waiting the ad loading)
+ docReady(function () {
+ setTimeout(function () {
+ if (window._AdBlockInit === undefined) {
+ ABDetected();
+ }
+ }, 3000);
+ });
+
+ // 删除事件改为隐藏事件
+ setTimeout(() => {
+ const pageAD = document.querySelector('.page-wwads');
+ if (!pageAD) return;
+ const btnEl = pageAD.querySelector('.wwads-hide');
+ if (btnEl) {
+ btnEl.onclick = () => {
+ pageAD.style.display = 'none';
+ }
+ }
+ // 显示广告模块
+ if (pageAD.style.display === 'none') {
+ pageAD.style.display = 'flex';
+ }
+ }, 900);
})
}
}
+
+
+function ABDetected() {
+ const h = "
";
+ const wwadsEl = document.getElementsByClassName("wwads-cn");
+ const wwadsContentEl = document.querySelector('.wwads-content');
+ if (wwadsEl[0] && !wwadsContentEl) {
+ wwadsEl[0].innerHTML = h;
+ }
+};
+
+//check document ready
+function docReady(t) {
+ "complete" === document.readyState ||
+ "interactive" === document.readyState
+ ? setTimeout(t, 1)
+ : document.addEventListener("DOMContentLoaded", t);
+}
diff --git a/docs/.vuepress/plugins/love-me/index.js b/docs/.vuepress/plugins/love-me/index.js
new file mode 100644
index 00000000..2851beb0
--- /dev/null
+++ b/docs/.vuepress/plugins/love-me/index.js
@@ -0,0 +1,12 @@
+const path = require('path')
+const LoveMyPlugin = (options = {}) => ({
+ define() {
+ const COLOR =
+ options.color ||
+ 'rgb(' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ')'
+ const EXCLUDECLASS = options.excludeClassName || ''
+ return { COLOR, EXCLUDECLASS }
+ },
+ enhanceAppFiles: [path.resolve(__dirname, 'love-me.js')]
+})
+module.exports = LoveMyPlugin
diff --git a/docs/.vuepress/plugins/love-me/love-me.js b/docs/.vuepress/plugins/love-me/love-me.js
new file mode 100644
index 00000000..5c0369ac
--- /dev/null
+++ b/docs/.vuepress/plugins/love-me/love-me.js
@@ -0,0 +1,89 @@
+export default () => {
+ if (typeof window !== 'undefined') {
+ ;(function (e, t, a) {
+ function r() {
+ for (var e = 0; e < s.length; e++)
+ s[e].alpha <= 0
+ ? (t.body.removeChild(s[e].el), s.splice(e, 1))
+ : (s[e].y--,
+ (s[e].scale += 0.004),
+ (s[e].alpha -= 0.013),
+ (s[e].el.style.cssText =
+ 'left:' +
+ s[e].x +
+ 'px;top:' +
+ s[e].y +
+ 'px;opacity:' +
+ s[e].alpha +
+ ';transform:scale(' +
+ s[e].scale +
+ ',' +
+ s[e].scale +
+ ') rotate(45deg);background:' +
+ s[e].color +
+ ';z-index:99999'))
+ requestAnimationFrame(r)
+ }
+ function n() {
+ var t = 'function' == typeof e.onclick && e.onclick
+
+ e.onclick = function (e) {
+ // 过滤指定元素
+ let mark = true
+ EXCLUDECLASS &&
+ e.path &&
+ e.path.forEach((item) => {
+ if (item.nodeType === 1) {
+ typeof item.className === 'string' && item.className.indexOf(EXCLUDECLASS) > -1 ? (mark = false) : ''
+ }
+ })
+
+ if (mark) {
+ t && t(), o(e)
+ }
+ }
+ }
+ function o(e) {
+ var a = t.createElement('div')
+ ;(a.className = 'heart'),
+ s.push({
+ el: a,
+ x: e.clientX - 5,
+ y: e.clientY - 5,
+ scale: 1,
+ alpha: 1,
+ color: COLOR
+ }),
+ t.body.appendChild(a)
+ }
+ function i(e) {
+ var a = t.createElement('style')
+ a.type = 'text/css'
+ try {
+ a.appendChild(t.createTextNode(e))
+ } catch (t) {
+ a.styleSheet.cssText = e
+ }
+ t.getElementsByTagName('head')[0].appendChild(a)
+ }
+ // function c() {
+ // return "rgb(" + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + ")"
+ // }
+ var s = []
+ ;(e.requestAnimationFrame =
+ e.requestAnimationFrame ||
+ e.webkitRequestAnimationFrame ||
+ e.mozRequestAnimationFrame ||
+ e.oRequestAnimationFrame ||
+ e.msRequestAnimationFrame ||
+ function (e) {
+ setTimeout(e, 1e3 / 60)
+ }),
+ i(
+ ".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
+ ),
+ n(),
+ r()
+ })(window, document)
+ }
+}
diff --git a/docs/.vuepress/public/images/dunwu-logo-100.png b/docs/.vuepress/public/images/dunwu-logo-100.png
deleted file mode 100644
index 12d81778..00000000
Binary files a/docs/.vuepress/public/images/dunwu-logo-100.png and /dev/null differ
diff --git a/docs/.vuepress/public/images/dunwu-logo-200.png b/docs/.vuepress/public/images/dunwu-logo-200.png
deleted file mode 100644
index ea0a019c..00000000
Binary files a/docs/.vuepress/public/images/dunwu-logo-200.png and /dev/null differ
diff --git a/docs/.vuepress/public/images/dunwu-logo-50.png b/docs/.vuepress/public/images/dunwu-logo-50.png
deleted file mode 100644
index 90a19762..00000000
Binary files a/docs/.vuepress/public/images/dunwu-logo-50.png and /dev/null differ
diff --git a/docs/.vuepress/public/img/bg.gif b/docs/.vuepress/public/img/bg.gif
new file mode 100644
index 00000000..d4bf3c41
Binary files /dev/null and b/docs/.vuepress/public/img/bg.gif differ
diff --git a/docs/.vuepress/public/images/dunwu-logo.png b/docs/.vuepress/public/img/dunwu-logo.png
similarity index 100%
rename from docs/.vuepress/public/images/dunwu-logo.png
rename to docs/.vuepress/public/img/dunwu-logo.png
diff --git a/docs/.vuepress/public/img/favicon.ico b/docs/.vuepress/public/img/favicon.ico
new file mode 100644
index 00000000..51e9bfa0
Binary files /dev/null and b/docs/.vuepress/public/img/favicon.ico differ
diff --git a/docs/.vuepress/public/img/more.png b/docs/.vuepress/public/img/more.png
new file mode 100644
index 00000000..830613ba
Binary files /dev/null and b/docs/.vuepress/public/img/more.png differ
diff --git a/docs/.vuepress/public/img/other.png b/docs/.vuepress/public/img/other.png
new file mode 100644
index 00000000..87f80989
Binary files /dev/null and b/docs/.vuepress/public/img/other.png differ
diff --git a/docs/.vuepress/public/markmap/01.html b/docs/.vuepress/public/markmap/01.html
new file mode 100644
index 00000000..c4e0bdbc
--- /dev/null
+++ b/docs/.vuepress/public/markmap/01.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+ Markmap
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl
new file mode 100644
index 00000000..3113dd61
--- /dev/null
+++ b/docs/.vuepress/styles/index.styl
@@ -0,0 +1,93 @@
+.home-wrapper .banner .banner-conent .hero h1{
+ font-size 2.8rem!important
+}
+// 文档中适配
+table
+ width auto
+.page >*:not(.footer),.card-box
+ box-shadow: none!important
+
+.page
+ @media (min-width $contentWidth + 80)
+ padding-top $navbarHeight!important
+.home-wrapper .banner .banner-conent
+ padding 0 2.9rem
+ box-sizing border-box
+.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a
+ h2
+ margin-top 2rem
+ font-size 1.2rem!important
+ p
+ padding 0 1rem
+
+// 评论区颜色重置
+.gt-container
+ .gt-ico-tip
+ &::after
+ content: '。( Win + . ) or ( ⌃ + ⌘ + ␣ ) open Emoji'
+ color: #999
+ .gt-meta
+ border-color var(--borderColor)!important
+ .gt-comments-null
+ color var(--textColor)
+ opacity .5
+ .gt-header-textarea
+ color var(--textColor)
+ background rgba(180,180,180,0.1)!important
+ .gt-btn
+ border-color $accentColor!important
+ background-color $accentColor!important
+ .gt-btn-preview
+ background-color rgba(255,255,255,0)!important
+ color $accentColor!important
+ a
+ color $accentColor!important
+ .gt-svg svg
+ fill $accentColor!important
+ .gt-comment-content,.gt-comment-admin .gt-comment-content
+ background-color rgba(150,150,150,0.1)!important
+ &:hover
+ box-shadow 0 0 25px rgba(150,150,150,.5)!important
+ .gt-comment-body
+ color var(--textColor)!important
+
+
+// qq徽章
+.qq
+ position: relative;
+.qq::after
+ content: "可撩";
+ background: $accentColor;
+ color:#fff;
+ padding: 0 5px;
+ border-radius: 10px;
+ font-size:12px;
+ position: absolute;
+ top: -4px;
+ right: -35px;
+ transform:scale(0.85);
+
+// demo模块图标颜色
+body .vuepress-plugin-demo-block__wrapper
+ &,.vuepress-plugin-demo-block__display
+ border-color rgba(160,160,160,.3)
+ .vuepress-plugin-demo-block__footer:hover
+ .vuepress-plugin-demo-block__expand::before
+ border-top-color: $accentColor !important;
+ border-bottom-color: $accentColor !important;
+ svg
+ fill: $accentColor !important;
+
+
+// 全文搜索框
+.suggestions
+ overflow: auto
+ max-height: calc(100vh - 6rem)
+ @media (max-width: 719px) {
+ width: 90vw;
+ min-width: 90vw!important;
+ margin-right: -20px;
+ }
+ .highlight
+ color: $accentColor
+ font-weight: bold
diff --git a/docs/.vuepress/styles/palette.styl b/docs/.vuepress/styles/palette.styl
new file mode 100644
index 00000000..d98e697a
--- /dev/null
+++ b/docs/.vuepress/styles/palette.styl
@@ -0,0 +1,62 @@
+
+// 原主题变量已弃用,以下是vdoing使用的变量,你可以在这个文件内修改它们。
+
+//***vdoing主题-变量***//
+
+// // 颜色
+
+// $bannerTextColor = #fff // 首页banner区(博客标题)文本颜色
+// $accentColor = #11A8CD
+// $arrowBgColor = #ccc
+// $badgeTipColor = #42b983
+// $badgeWarningColor = darken(#ffe564, 35%)
+// $badgeErrorColor = #DA5961
+
+// // 布局
+// $navbarHeight = 3.6rem
+// $sidebarWidth = 18rem
+// $contentWidth = 860px
+// $homePageWidth = 1100px
+// $rightMenuWidth = 230px // 右侧菜单
+
+// // 代码块
+// $lineNumbersWrapperWidth = 2.5rem
+
+// 浅色模式
+.theme-mode-light
+ --bodyBg: rgba(255,255,255,1)
+ --mainBg: rgba(255,255,255,1)
+ --sidebarBg: rgba(255,255,255,.8)
+ --blurBg: rgba(255,255,255,.9)
+ --textColor: #004050
+ --textLightenColor: #0085AD
+ --borderColor: rgba(0,0,0,.15)
+ --codeBg: #f6f6f6
+ --codeColor: #525252
+ codeThemeLight()
+
+// 深色模式
+.theme-mode-dark
+ --bodyBg: rgba(30,30,34,1)
+ --mainBg: rgba(30,30,34,1)
+ --sidebarBg: rgba(30,30,34,.8)
+ --blurBg: rgba(30,30,34,.8)
+ --textColor: rgb(140,140,150)
+ --textLightenColor: #0085AD
+ --borderColor: #2C2C3A
+ --codeBg: #252526
+ --codeColor: #fff
+ codeThemeDark()
+
+// 阅读模式
+.theme-mode-read
+ --bodyBg: rgba(245,245,213,1)
+ --mainBg: rgba(245,245,213,1)
+ --sidebarBg: rgba(245,245,213,.8)
+ --blurBg: rgba(245,245,213,.9)
+ --textColor: #004050
+ --textLightenColor: #0085AD
+ --borderColor: rgba(0,0,0,.15)
+ --codeBg: #282c34
+ --codeColor: #fff
+ codeThemeDark()
diff --git a/docs/javaee/javaee-servlet.md "b/docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
similarity index 90%
rename from docs/javaee/javaee-servlet.md
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
index 9de27a64..2133814e 100644
--- a/docs/javaee/javaee-servlet.md
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
@@ -1,29 +1,23 @@
-# Servlet 指南
-
-
-
-- [1. JavaWeb 简介](#1-javaweb-简介)
- - [1.1. Web 应用程序](#11-web-应用程序)
- - [1.2. 常见 Web 服务器](#12-常见-web-服务器)
-- [2. Servlet 简介](#2-servlet-简介)
- - [2.1. 什么是 Servlet](#21-什么是-servlet)
- - [2.2. Servlet 和 CGI 的区别](#22-servlet-和-cgi-的区别)
- - [2.3. Servlet 版本以及主要特性](#23-servlet-版本以及主要特性)
- - [2.4. Servlet 任务](#24-servlet-任务)
- - [2.5. Servlet 生命周期](#25-servlet-生命周期)
-- [3. Servlet API](#3-servlet-api)
- - [3.1. Servlet 包](#31-servlet-包)
- - [3.2. Servlet 接口](#32-servlet-接口)
-- [4. Servlet 和 HTTP 状态码](#4-servlet-和-http-状态码)
- - [4.1. HTTP 状态码](#41-http-状态码)
- - [4.2. 设置 HTTP 状态码的方法](#42-设置-http-状态码的方法)
- - [4.3. HTTP 状态码实例](#43-http-状态码实例)
+---
+title: JavaWeb 之 Servlet 指南
+date: 2020-08-24 19:41:46
+order: 01
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - Java
+ - JavaWeb
+ - Servlet
+permalink: /pages/e98894/
+---
-
+# JavaWeb 之 Servlet 指南
-## 1. JavaWeb 简介
+## JavaWeb 简介
-### 1.1. Web 应用程序
+### Web 应用程序
Web,在英语中 web 即表示网页的意思,它用于表示 Internet 主机上供外界访问的资源。
@@ -34,7 +28,7 @@ Internet 上供外界访问的 Web 资源分为:
- 静态 web 资源:指 web 页面中供人们浏览的数据始终是不变。常见静态资源文件:html、css、各种图片类型(jpg、png)
- 动态 web 资源:指 web 页面中供人们浏览的数据是由程序产生的,不同时间点访问 web 页面看到的内容各不相同。常见动态资源技术:JSP/Servlet、ASP、PHP
-### 1.2. 常见 Web 服务器
+### 常见 Web 服务器
- [Tomcat](http://tomcat.apache.org/)
- [Jetty](http://www.eclipse.org/jetty/)
@@ -45,9 +39,9 @@ Internet 上供外界访问的 Web 资源分为:
- [WebLogic](https://www.oracle.com/middleware/technologies/weblogic.html)
- JBoss
-## 2. Servlet 简介
+## Servlet 简介
-### 2.1. 什么是 Servlet
+### 什么是 Servlet
Servlet(Server Applet),即小服务程序或服务连接器。Servlet 是 Java 编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态 Web 内容。
@@ -56,14 +50,14 @@ Servlet(Server Applet),即小服务程序或服务连接器。Servlet 是
Servlet 运行于支持 Java 的应用服务器中。从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下 Servlet 只用来扩展基于 HTTP 协议的 Web 服务器。
-### 2.2. Servlet 和 CGI 的区别
+### Servlet 和 CGI 的区别
Servlet 技术出现之前,Web 主要使用 CGI 技术。它们的区别如下:
- Servlet 是基于 Java 编写的,处于服务器进程中,他能够通过多线程方式运行 service() 方法,一个实例可以服务于多个请求,而且一般不会销毁;
- CGI(Common Gateway Interface),即通用网关接口。它会为每个请求产生新的进程,服务完成后销毁,所以效率上低于 Servlet。
-### 2.3. Servlet 版本以及主要特性
+### Servlet 版本以及主要特性
| 版本 | 日期 | JAVA EE/JDK 版本 | 特性 |
| ----------- | ------------- | ------------------ | --------------------------------------------------------------------- |
@@ -78,7 +72,7 @@ Servlet 技术出现之前,Web 主要使用 CGI 技术。它们的区别如下
| Servlet 2.0 | | JDK 1.1 | Part of Java Servlet Development Kit 2.0 |
| Servlet 1.0 | 1997 年 6 月 | | |
-### 2.4. Servlet 任务
+### Servlet 任务
Servlet 执行以下主要任务:
@@ -88,7 +82,7 @@ Servlet 执行以下主要任务:
- 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
- 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
-### 2.5. Servlet 生命周期
+### Servlet 生命周期

@@ -100,9 +94,9 @@ Servlet 生命周期如下:
4. **销毁** - Servlet 通过调用 **destroy()** 方法终止(结束)。
5. **卸载** - Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
-## 3. Servlet API
+## Servlet API
-### 3.1. Servlet 包
+### Servlet 包
Java Servlet 是运行在带有支持 Java Servlet 规范的解释器的 web 服务器上的 Java 类。
@@ -110,7 +104,7 @@ Servlet 可以使用 **javax.servlet** 和 **javax.servlet.http** 包创建,
Java Servlet 就像任何其他的 Java 类一样已经被创建和编译。在您安装 Servlet 包并把它们添加到您的计算机上的 Classpath 类路径中之后,您就可以通过 JDK 的 Java 编译器或任何其他编译器来编译 Servlet。
-### 3.2. Servlet 接口
+### Servlet 接口
Servlet 接口定义了下面五个方法:
@@ -201,7 +195,7 @@ destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调
}
```
-## 4. Servlet 和 HTTP 状态码
+## Servlet 和 HTTP 状态码
title: JavaEE Servlet HTTP 状态码
date: 2017-11-08
@@ -213,7 +207,7 @@ categories:
- servlet
- http
-### 4.1. HTTP 状态码
+### HTTP 状态码
HTTP 请求和 HTTP 响应消息的格式是类似的,结构如下:
@@ -262,7 +256,7 @@ HeaderN: ...
- 500:服务器端在执行请求时发生了错误
- 503:服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
-### 4.2. 设置 HTTP 状态码的方法
+### 设置 HTTP 状态码的方法
下面的方法可用于在 Servlet 程序中设置 HTTP 状态码。这些方法通过 `HttpServletResponse` 对象可用。
@@ -272,7 +266,7 @@ HeaderN: ...
| 2 | **public void sendRedirect(String url)**该方法生成一个 302 响应,连同一个带有新文档 URL 的 _Location_ 头。 |
| 3 | **public void sendError(int code, String message)**该方法发送一个状态码(通常为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。 |
-### 4.3. HTTP 状态码实例
+### HTTP 状态码实例
下面的例子把 407 错误代码发送到客户端浏览器,浏览器会显示 "Need authentication!!!" 消息。
@@ -316,4 +310,4 @@ Apache Tomcat/5.5.29
## 参考资料
- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
-- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
\ No newline at end of file
diff --git a/docs/javaee/javaee-jsp.md "b/docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
similarity index 93%
rename from docs/javaee/javaee-jsp.md
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
index 37e6fa66..32b8ab7c 100644
--- a/docs/javaee/javaee-jsp.md
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
@@ -1,12 +1,27 @@
-# JSP 指南
+---
+title: JavaWeb 之 Jsp 指南
+date: 2020-02-07 23:04:47
+order: 02
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - Java
+ - JavaWeb
+ - JSP
+permalink: /pages/8cc787/
+---
-## 1. 简介
+# JavaWeb 之 Jsp 指南
-### 1.1. 什么是 Java Server Pages
+## 简介
+
+### 什么是 Java Server Pages
`JSP`全称`Java Server Pages`,是一种动态网页开发技术。
-它使用 JSP 标签在 HTML 网页中插入 Java 代码。标签通常以`<%`开头以`%>`结束。
+它使用 JSP 标签在 HTML 网页中插入 Java 代码。标签通常以 `<%` 开头以 `%>` 结束。
JSP 是一种 Java servlet,主要用于实现 Java web 应用程序的用户界面部分。网页开发者们通过结合 HTML 代码、XHTML 代码、XML 元素以及嵌入 JSP 操作和命令来编写 JSP。
@@ -14,7 +29,7 @@ JSP 通过网页表单获取用户输入数据、访问数据库及其他数据
JSP 标签有多种功能,比如访问数据库、记录用户选择信息、访问 JavaBeans 组件等,还可以在不同的网页中传递控制信息和共享信息。
-### 1.2. 为什么使用 JSP
+### 为什么使用 JSP
JSP 也是一种 Servlet,因此 JSP 能够完成 Servlet 能完成的任何工作。
@@ -27,7 +42,7 @@ JSP 程序与 CGI 程序有着相似的功能,但和 CGI 程序相比,JSP
最后,JSP 是 Java EE 不可或缺的一部分,是一个完整的企业级应用平台。这意味着 JSP 可以用最简单的方式来实现最复杂的应用。
-### 1.3. JSP 的优势
+### JSP 的优势
以下列出了使用 JSP 带来的其他好处:
@@ -37,7 +52,7 @@ JSP 程序与 CGI 程序有着相似的功能,但和 CGI 程序相比,JSP
- 与 JavaScript 相比:虽然 JavaScript 可以在客户端动态生成 HTML,但是很难与服务器交互,因此不能提供复杂的服务,比如访问数据库和图像处理等等。
- 与静态 HTML 相比:静态 HTML 不包含动态信息。
-## 2. JSP 工作原理
+## JSP 工作原理
**JSP 是一种 Servlet**,但工作方式和 Servlet 有所差别。
@@ -47,7 +62,7 @@ Jsp 是先将源代码部署到服务器再编译,**先部署后编译**。
Jsp 会在客户端第一次请求 Jsp 文件时被编译为 HttpJspPage 类(Servlet 的一个子类)。该类会被服务器临时存放在服务器工作目录里。所以,第一次请求 Jsp 后,访问速度会变快就是这个道理。
-### 2.1. JSP 工作流程
+### JSP 工作流程
网络服务器需要一个 JSP 引擎,也就是一个容器来处理 JSP 页面。容器负责截获对 JSP 页面的请求。本教程使用内嵌 JSP 容器的 Apache 来支持 JSP 开发。
@@ -57,7 +72,7 @@ JSP 容器与 Web 服务器协同合作,为 JSP 的正常运行提供必要的

-#### 2.1.1. 工作步骤
+#### 工作步骤
以下步骤表明了 Web 服务器是如何使用 JSP 来创建网页的:
@@ -73,7 +88,7 @@ JSP 容器与 Web 服务器协同合作,为 JSP 的正常运行提供必要的
一般情况下,JSP 引擎会检查 JSP 文件对应的 servlet 是否已经存在,并且检查 JSP 文件的修改日期是否早于 servlet。如果 JSP 文件的修改日期早于对应的 servlet,那么容器就可以确定 JSP 文件没有被修改过并且 servlet 有效。这使得整个流程与其他脚本语言(比如 PHP)相比要高效快捷一些。
-### 2.2. JSP 生命周期
+### JSP 生命周期
理解 JSP 底层功能的关键就是去理解它们所遵守的生命周期。
@@ -90,7 +105,7 @@ JSP 生命周期就是从创建到销毁的整个过程,类似于 servlet 生

-#### 2.2.1. JSP 编译
+#### JSP 编译
当浏览器请求 JSP 页面时,JSP 引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个 JSP 文件。
@@ -100,7 +115,7 @@ JSP 生命周期就是从创建到销毁的整个过程,类似于 servlet 生
- 将 JSP 文件转为 servlet。
- 编译 servlet。
-#### 2.2.2. JSP 初始化
+#### JSP 初始化
容器载入 JSP 文件后,它会在为请求提供任何服务前调用 jspInit()方法。如果您需要执行自定义的 JSP 初始化任务,复写 jspInit()方法就行了,就像下面这样:
@@ -112,7 +127,7 @@ public void jspInit(){
一般来讲程序只初始化一次,servlet 也是如此。通常情况下您可以在 jspInit()方法中初始化数据库连接、打开文件和创建查询表。
-#### 2.2.3. JSP 执行
+#### JSP 执行
这一阶段描述了 JSP 生命周期中一切与请求相关的交互行为,直到被销毁。
@@ -129,7 +144,7 @@ void _jspService(HttpServletRequest request,
`_jspService()` 方法在每个 request 中被调用一次并且负责产生与之相对应的 response,并且它还负责产生所有 7 个 HTTP 方法的回应,比如 GET、POST、DELETE 等等。
-#### 2.2.4. JSP 清理
+#### JSP 清理
JSP 生命周期的销毁阶段描述了当一个 JSP 网页从容器中被移除时所发生的一切。
@@ -143,9 +158,9 @@ public void jspDestroy() {
}
```
-## 3. 语法
+## 语法
-### 3.1. 脚本
+### 脚本
脚本程序可以包含任意量的 Java 语句、变量、方法或表达式,只要它们在脚本语言中是有效的。
@@ -185,7 +200,7 @@ public void jspDestroy() {

-#### 3.1.1. 中文编码问题
+#### 中文编码问题
如果我们要在页面正常显示中文,我们需要在 JSP 文件头部添加以下代码:`<>`
@@ -214,7 +229,7 @@ pageEncoding="UTF-8"%>
这样中文就可以正常显示了。
-### 3.2. JSP 声明
+### JSP 声明
一个声明语句可以声明一个或多个变量、方法,供后面的 Java 代码使用。在 JSP 文件中,您必须先声明这些变量和方法然后才能使用它们。
@@ -238,7 +253,7 @@ JSP 声明的语法格式:
<%! int i = 0; %> <%! int a, b, c; %> <%! Circle a = new Circle(2.0); %>
```
-### 3.3. JSP 表达式
+### JSP 表达式
一个 JSP 表达式中包含的脚本语言表达式,先被转化成 String,然后插入到表达式出现的地方。
@@ -287,7 +302,7 @@ pageEncoding="UTF-8"%>
---
-### 3.4. JSP 注释
+### JSP 注释
JSP 注释主要有两个作用:为代码作注释以及将某段代码注释掉。
@@ -319,20 +334,20 @@ pageEncoding="UTF-8"%>
不同情况下使用注释的语法规则:
-| **语法** | 描述 |
-| ---------------- | ----------------------------------------------------- |
-| `<%-- 注释 --%>` | JSP 注释,注释内容不会被发送至浏览器甚至不会被编译 |
+| **语法** | 描述 |
+| ---------------- |-------------------------------|
+| `<%-- 注释 --%>` | JSP 注释,注释内容不会被发送至浏览器甚至不会被编译 |
| `` | HTML 注释,通过浏览器查看网页源代码时可以看见注释内容 |
-| `<%` | 代表静态 <%常量 |
-| `%>` | 代表静态 %> 常量 |
-| `'` | 在属性中使用的单引号 |
-| `"` | 在属性中使用的双引号 |
+| `<%` | 代表静态 `<%` 常量 |
+| `%>` | 代表静态 `%>` 常量 |
+| `'` | 在属性中使用的单引号 |
+| `"` | 在属性中使用的双引号 |
-### 3.5. 控制语句
+### 控制语句
JSP 提供对 Java 语言的全面支持。您可以在 JSP 程序中使用 Java API 甚至建立 Java 代码块,包括判断语句和循环语句等等。
-#### 3.5.1. if…else 语句
+#### if…else 语句
`If…else`块,请看下面这个例子:
@@ -363,7 +378,7 @@ IF...ELSE 实例
今天不是周末
```
-#### 3.5.2. switch…case 语句
+#### switch…case 语句
现在来看看 switch…case 块,与 if…else 块有很大的不同,它使用 out.println(),并且整个都装在脚本程序的标签中,就像下面这样:
@@ -394,7 +409,7 @@ SWITCH...CASE 实例
星期三
```
-#### 3.5.3. 循环语句
+#### 循环语句
在 JSP 程序中可以使用 Java 的三个基本循环类型:for,while,和 do…while。
@@ -456,25 +471,25 @@ JSP 支持所有 Java 逻辑和算术运算符。
下表罗列出了 JSP 常见运算符,优先级从高到底:
-| **类别** | **操作符** | **结合性** |
-| --------- | ----------------------------------- | ---------- |
-| 后缀 | `() [] .` (点运算符) | 左到右 |
-| 一元 | `++ - - ! ~` | 右到左 |
-| 可乘性 | `* / %` | 左到右 |
-| 可加性 | `+ -` | 左到右 |
-| 移位 | `>> >>> <<` | 左到右 |
-| 关系 | `> >= < <=` | 左到右 |
-| 相等/不等 | `== !=` | 左到右 |
-| 位与 | `&` | 左到右 |
-| 位异或 | `^` | 左到右 |
-| 位或 | `|` | 左到右 |
-| 逻辑与 | `&&` | 左到右 |
-| 逻辑或 | `||` | 左到右 |
-| 条件判断 | `?:` | 右到左 |
-| 赋值 | `= += -= *= /= %= >>= <<= &= ^= |=` | 右到左 |
-| 逗号 | `,` | 左到右 |
-
-### 3.6. JSP 字面量
+| **类别** | **操作符** | **结合性** |
+| --------- | ------------------------------------- | ---------- |
+| 后缀 | `() [] .` (点运算符) | 左到右 |
+| 一元 | `++ - - ! ~` | 右到左 |
+| 可乘性 | `* / %` | 左到右 |
+| 可加性 | `+ -` | 左到右 |
+| 移位 | `>> >>> <<` | 左到右 |
+| 关系 | `> >= < <=` | 左到右 |
+| 相等/不等 | `== !=` | 左到右 |
+| 位与 | `&` | 左到右 |
+| 位异或 | `^` | 左到右 |
+| 位或 | `|` | 左到右 |
+| 逻辑与 | `&&` | 左到右 |
+| 逻辑或 | `| |` | 左到右 |
+| 条件判断 | `?:` | 右到左 |
+| 赋值 | `= += -= \*= /= %= >>= <<= &= ^= | =` | 右到左 |
+| 逗号 | `,` | 左到右 |
+
+### JSP 字面量
JSP 语言定义了以下几个字面量:
@@ -484,7 +499,7 @@ JSP 语言定义了以下几个字面量:
- 字符串(string):以单引号或双引号开始和结束;
- Null:null。
-## 4. 指令
+## 指令
JSP 指令用来设置整个 JSP 页面相关的属性,如网页的编码方式和脚本语言。
@@ -506,7 +521,7 @@ JSP 中的三种指令标签:
| `<%@ include ... %>` | 包含其他文件 |
| `<%@ taglib ... %>` | 引入标签库的定义,可以是自定义标签 |
-### 4.1. Page 指令
+### Page 指令
Page 指令为容器提供当前页面的使用说明。一个 JSP 页面可以包含多个`page`指令。
@@ -529,7 +544,7 @@ Page 指令的语法格式:
pageEncoding="UTF-8" %>
```
-#### 4.1.1. 属性
+#### 属性
下表列出与 Page 指令相关的属性:
@@ -549,7 +564,7 @@ pageEncoding="UTF-8" %>
| isELIgnored | 指定是否执行 EL 表达式 |
| isScriptingEnabled | 确定脚本元素能否被使用 |
-### 4.2. Include 指令
+### Include 指令
JSP 可以通过`include`指令来包含其他文件。
@@ -571,7 +586,7 @@ Include 指令的语法格式如下:
```
-### 4.3. Taglib 指令
+### Taglib 指令
JSP 允许用户自定义标签,一个自定义标签库就是自定义标签的集合。
@@ -591,7 +606,7 @@ uri 属性确定标签库的位置,prefix 属性指定标签库的前缀。
```
-## 5. JSP 动作元素
+## JSP 动作元素
JSP 动作元素是一组 JSP 内置的标签,只需要书写很少的标记代码就能使用 JSP 提供的丰富功能。JSP 动作元素是对常用的 JSP 功能的抽象与封装,包括两种,自定义 JSP 动作元素与标准 JSP 动作元素。
@@ -620,14 +635,14 @@ JSP 动作元素是一组 JSP 内置的标签,只需要书写很少的标记
| jsp:body | 设置动态定义的 XML 元素内容。 |
| jsp:text | 在 JSP 页面和文档中使用写入文本的模板 |
-### 5.1. 常见的属性
+### 常见的属性
所有的动作要素都有两个属性:id 属性和 scope 属性。
- **id 属性:**id 属性是动作元素的唯一标识,可以在 JSP 页面中引用。动作元素创建的 id 值可以通过 PageContext 来调用。
- **scope 属性:**该属性用于识别动作元素的生命周期。 id 属性和 scope 属性有直接关系,scope 属性定义了相关联 id 对象的寿命。 scope 属性有四个可能的值: (a) page, (b)request, (c)session, 和 (d) application。
-### 5.2. ``
+### ``
`` 用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。
@@ -688,7 +703,7 @@ include 动作实例
今天的日期是: 2016-6-25 14:08:17
```
-### 5.3. ``
+### ``
**jsp:useBean** 动作用来加载一个将在 JSP 页面中使用的 JavaBean。
@@ -712,7 +727,7 @@ jsp:useBean 动作最简单的语法为:
在给出具体实例前,让我们先来看下 jsp:setProperty 和 jsp:getProperty 动作元素:
-### 5.4. ``
+### ``
jsp:setProperty 用来设置已经实例化的 Bean 对象的属性,有两种用法。首先,你可以在 jsp:useBean 元素的外面(后面)使用 jsp:setProperty,如下所示:
@@ -742,7 +757,7 @@ jsp:setProperty 动作有下面四个属性,如下表:
| value | value 属性是可选的。该属性用来指定 Bean 属性的值。字符串数据会在目标类中通过标准的 valueOf 方法自动转换成数字、boolean、Boolean、 byte、Byte、char、Character。例如,boolean 和 Boolean 类型的属性值(比如"true")通过 Boolean.valueOf 转换,int 和 Integer 类型的属性值(比如"42")通过 Integer.valueOf 转换。 value 和 param 不能同时使用,但可以使用其中任意一个。 |
| param | param 是可选的。它指定用哪个请求参数作为 Bean 属性的值。如果当前请求没有参数,则什么事情也不做,系统不会把 null 传递给 Bean 属性的 set 方法。因此,你可以让 Bean 自己提供默认属性值,只有当请求参数明确指定了新值时才修改默认属性值。 |
-### 5.5. ``
+### ``
jsp:getProperty 动作提取指定 Bean 属性的值,转换成字符串,然后输出。语法格式如下:
@@ -820,7 +835,7 @@ pageEncoding="UTF-8"%>

-### 5.6. ``
+### ``
jsp:forward 动作把请求转到另外的页面。jsp:forward 标记只有一个属性 page。语法格式如下所示:
@@ -872,7 +887,7 @@ pageEncoding="UTF-8"%>
今天的日期是: 2016-6-25 14:37:25
```
-### 5.7. ``
+### ``
jsp:plugin 动作用来根据浏览器的类型,插入通过 Java 插件 运行 Java Applet 所必需的 OBJECT 或 EMBED 元素。
@@ -897,7 +912,7 @@ plugin 动作有多个对应 HTML 元素的属性用于格式化 Java 组件。p
如果你有兴趣可以尝试使用 applet 来测试 `jsp:plugin` 动作元素,`` 元素是一个新元素,在组件出现故障的错误是发送给用户错误信息。
-### 5.8. `` 、 ``、``
+### `` 、 ``、``
`` 、 ``、`` 动作元素动态定义 XML 元素。动态是非常重要的,这就意味着 XML 元素在编译时是动态生成的而非静态。
@@ -929,7 +944,7 @@ pageEncoding="UTF-8"%>

-### 5.9. ``
+### ``
动作元素允许在 JSP 页面和文档中使用写入文本的模板,语法格式如下:
@@ -963,7 +978,7 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
你可以对以上实例尝试使用及不使用该动作元素执行结果的区别。
-## 6. JSP 隐式对象
+## JSP 隐式对象
JSP 隐式对象是 JSP 容器为每个页面提供的 Java 对象,开发者可以直接使用它们而不用显式声明。JSP 隐式对象也被称为预定义变量。
@@ -981,7 +996,7 @@ JSP 所支持的九大隐式对象:
| page | 类似于 Java 类中的 this 关键字 |
| Exception | **Exception**类的对象,代表发生错误的 JSP 页面中对应的异常对象 |
-### 6.1. request 对象
+### request 对象
`request`对象是`javax.servlet.http.HttpServletRequest` 类的实例。
@@ -989,7 +1004,7 @@ JSP 所支持的九大隐式对象:
`request`对象提供了一系列方法来获取 HTTP 头信息,cookies,HTTP 方法等等。
-### 6.2. response 对象
+### response 对象
`response`对象是`javax.servlet.http.HttpServletResponse`类的实例。
@@ -997,7 +1012,7 @@ JSP 所支持的九大隐式对象:
`response`对象也定义了处理 HTTP 头模块的接口。通过这个对象,开发者们可以添加新的 cookies,时间戳,HTTP 状态码等等。
-### 6.3. out 对象
+### out 对象
`out`对象是`javax.servlet.jsp.JspWriter`类的实例,用来在`response`对象中写入内容。
@@ -1013,13 +1028,13 @@ JSP 所支持的九大隐式对象:
| **out.println(dataType dt)** | 输出 Type 类型的值然后换行 |
| **out.flush()** | 刷新输出流 |
-### 6.4. session 对象
+### session 对象
`session`对象是`javax.servlet.http.HttpSession`类的实例。和 Java Servlets 中的`session`对象有一样的行为。
`session`对象用来跟踪在各个客户端请求间的会话。
-### 6.5. application 对象
+### application 对象
`application`对象直接包装了 servlet 的`ServletContext`类的对象,是`javax.servlet.ServletContext`类的实例。
@@ -1027,7 +1042,7 @@ JSP 所支持的九大隐式对象:
通过向`application`中添加属性,则所有组成您 web 应用的 JSP 文件都能访问到这些属性。
-### 6.6. config 对象
+### config 对象
`config`对象是`javax.servlet.ServletConfig`类的实例,直接包装了 servlet 的`ServletConfig`类的对象。
@@ -1041,7 +1056,7 @@ config.getServletName();
它返回包含在``元素中的 servlet 名字,注意,``元素在`WEB-INF\web.xml`文件中定义。
-### 6.7. pageContext 对象
+### pageContext 对象
`pageContext`对象是`javax.servlet.jsp.PageContext`类的实例,用来代表整个 JSP 页面。
@@ -1059,23 +1074,23 @@ config.getServletName();
pageContext.removeAttribute("attrName", PAGE_SCOPE);
```
-### 6.8. page 对象
+### page 对象
这个对象就是页面实例的引用。它可以被看做是整个 JSP 页面的代表。
`page`对象就是`this`对象的同义词。
-### 6.9. exception 对象
+### exception 对象
`exception`对象包装了从先前页面中抛出的异常信息。它通常被用来产生对出错条件的适当响应。
-## 7. EL 表达式
+## EL 表达式
EL 表达式是用`${}`括起来的脚本,用来更方便地读取对象。EL 表达式写在 JSP 的 HTML 代码中,而不能写在`<%`与`%>`引起的 JSP 脚本中。
JSP 表达式语言(EL)使得访问存储在 JavaBean 中的数据变得非常简单。JSP EL 既可以用来创建算术表达式也可以用来创建逻辑表达式。在 JSP EL 表达式内可以使用整型数,浮点数,字符串,常量 true、false,还有 null。
-### 7.1. 一个简单的语法
+### 一个简单的语法
典型的,当您需要在 JSP 标签中指定一个属性值时,只需要简单地使用字符串即可:
@@ -1129,7 +1144,7 @@ ${expr}
这样,EL 表达式就会被忽略。若设为 false,则容器将会计算 EL 表达式。
-### 7.2. EL 中的基础操作符
+### EL 中的基础操作符
EL 表达式支持大部分 Java 所提供的算术和逻辑操作符:
@@ -1154,7 +1169,7 @@ EL 表达式支持大部分 Java 所提供的算术和逻辑操作符:
| ! or not | 测试取反 |
| empty | 测试是否空值 |
-### 7.3. JSP EL 中的函数
+### JSP EL 中的函数
JSP EL 允许您在表达式中使用函数。这些函数必须被定义在自定义标签库中。函数的使用语法如下:
@@ -1170,7 +1185,7 @@ ${fn:length("Get my length")}
要使用任何标签库中的函数,您需要将这些库安装在服务器中,然后使用 `` 标签在 JSP 文件中包含这些库。
-### 7.4. JSP EL 隐含对象
+### JSP EL 隐含对象
JSP EL 支持下表列出的隐含对象:
@@ -1190,7 +1205,7 @@ JSP EL 支持下表列出的隐含对象:
您可以在表达式中使用这些对象,就像使用变量一样。接下来会给出几个例子来更好的理解这个概念。
-### 7.5. pageContext 对象
+### pageContext 对象
pageContext 对象是 JSP 中 pageContext 对象的引用。通过 pageContext 对象,您可以访问 request 对象。比如,访问 request 对象传入的查询字符串,就像这样:
@@ -1198,13 +1213,13 @@ pageContext 对象是 JSP 中 pageContext 对象的引用。通过 pageContext
${pageContext.request.queryString}
```
-### 7.6. Scope 对象
+### Scope 对象
pageScope,requestScope,sessionScope,applicationScope 变量用来访问存储在各个作用域层次的变量。
举例来说,如果您需要显式访问在 applicationScope 层的 box 变量,可以这样来访问:applicationScope.box。
-### 7.7. param 和 paramValues 对象
+### param 和 paramValues 对象
param 和 paramValues 对象用来访问参数值,通过使用 request.getParameter 方法和 request.getParameterValues 方法。
@@ -1232,7 +1247,7 @@ Param"; %>
param 对象返回单一的字符串,而 paramValues 对象则返回一个字符串数组。
-### 7.8. header 和 headerValues 对象
+### header 和 headerValues 对象
header 和 headerValues 对象用来访问信息头,通过使用 request.getHeader 方法和 request.getHeaders 方法。
@@ -1264,7 +1279,7 @@ Example"; %>
header 对象返回单一值,而 headerValues 则返回一个字符串数组。
-## 8. JSTL
+## JSTL
JSP 标准标签库(JSTL)是一个 JSP 标签集合,它封装了 JSP 应用的通用核心功能。
@@ -1278,7 +1293,7 @@ JSTL 支持通用的、结构化的任务,比如迭代,条件判断,XML
- **XML 标签**
- **JSTL 函数**
-### 8.1. JSTL 库安装
+### JSTL 库安装
Apache Tomcat 安装 JSTL 库步骤如下:
@@ -1339,9 +1354,9 @@ Apache Tomcat 安装 JSTL 库步骤如下:
```
-使用任何库,你必须在每个 JSP 文件中的头部包含 **** 标签。
+使用任何库,你必须在每个 JSP 文件中的头部包含 **``** 标签。
-### 8.2. 核心标签
+### 核心标签
核心标签是最常用的 JSTL 标签。引用核心标签库的语法如下:
@@ -1349,24 +1364,24 @@ Apache Tomcat 安装 JSTL 库步骤如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
```
-| 标签 | 描述 |
-| :---------------------------------------------------------------------- | :-------------------------------------------------------------------------- |
-| [``](http://www.runoob.com/jsp/jstl-core-out-tag.html) | 用于在 JSP 中显示数据,就像<%= ... > |
-| [``](http://www.runoob.com/jsp/jstl-core-set-tag.html) | 用于保存数据 |
-| [``](http://www.runoob.com/jsp/jstl-core-remove-tag.html) | 用于删除数据 |
-| [``](http://www.runoob.com/jsp/jstl-core-catch-tag.html) | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
-| [``](http://www.runoob.com/jsp/jstl-core-if-tag.html) | 与我们在一般程序中用的 if 一样 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 本身只当做和的父标签 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 的子标签,用来判断条件是否成立 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 的子标签,接在标签后,当标签判断为 false 时被执行 |
-| [``](http://www.runoob.com/jsp/jstl-core-import-tag.html) | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
-| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 基础迭代标签,接受多种集合类型 |
-| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 根据指定的分隔符来分隔内容并迭代输出 |
-| [``](http://www.runoob.com/jsp/jstl-core-param-tag.html) | 用来给包含或重定向的页面传递参数 |
-| [``](http://www.runoob.com/jsp/jstl-core-redirect-tag.html) | 重定向至一个新的 URL. |
-| [``](http://www.runoob.com/jsp/jstl-core-url-tag.html) | 使用可选的查询参数来创造一个 URL |
-
-### 8.3. 格式化标签
+| 标签 | 描述 |
+| :---------------------------------------------------------------------- |:------------------------------------------------------------------|
+| [``](http://www.runoob.com/jsp/jstl-core-out-tag.html) | 用于在 JSP 中显示数据,就像<%= ... > |
+| [``](http://www.runoob.com/jsp/jstl-core-set-tag.html) | 用于保存数据 |
+| [``](http://www.runoob.com/jsp/jstl-core-remove-tag.html) | 用于删除数据 |
+| [``](http://www.runoob.com/jsp/jstl-core-catch-tag.html) | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
+| [``](http://www.runoob.com/jsp/jstl-core-if-tag.html) | 与我们在一般程序中用的 if 一样 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 本身只当做 `` 和 `` 的父标签 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | `` 的子标签,用来判断条件是否成立 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | `` 的子标签,接在 `` 标签后,当 `` 标签判断为 false 时被执行 |
+| [``](http://www.runoob.com/jsp/jstl-core-import-tag.html) | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
+| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 基础迭代标签,接受多种集合类型 |
+| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 根据指定的分隔符来分隔内容并迭代输出 |
+| [``](http://www.runoob.com/jsp/jstl-core-param-tag.html) | 用来给包含或重定向的页面传递参数 |
+| [``](http://www.runoob.com/jsp/jstl-core-redirect-tag.html) | 重定向至一个新的 URL. |
+| [``](http://www.runoob.com/jsp/jstl-core-url-tag.html) | 使用可选的查询参数来创造一个 URL |
+
+### 格式化标签
JSTL 格式化标签用来格式化并输出文本、日期、时间、数字。引用格式化标签库的语法如下:
@@ -1388,7 +1403,7 @@ JSTL 格式化标签用来格式化并输出文本、日期、时间、数字。
| [``](http://www.runoob.com/jsp/jstl-format-message-tag.html) | 显示资源配置文件信息 |
| [``](http://www.runoob.com/jsp/jstl-format-requestencoding-tag.html) | 设置 request 的字符编码 |
-### 8.4. SQL 标签
+### SQL 标签
JSTL SQL 标签库提供了与关系型数据库(Oracle,MySQL,SQL Server 等等)进行交互的标签。引用 SQL 标签库的语法如下:
@@ -1405,7 +1420,7 @@ JSTL SQL 标签库提供了与关系型数据库(Oracle,MySQL,SQL Server
| [``](http://www.runoob.com/jsp/jstl-sql-dateparam-tag.html) | 将 SQL 语句中的日期参数设为指定的 java.util.Date 对象值 |
| [``](http://www.runoob.com/jsp/jstl-sql-transaction-tag.html) | 在共享数据库连接中提供嵌套的数据库行为元素,将所有语句以一个事务的形式来运行 |
-### 8.5. XML 标签
+### XML 标签
JSTL XML 标签库提供了创建和操作 XML 文档的标签。引用 XML 标签库的语法如下:
@@ -1423,20 +1438,20 @@ JSTL XML 标签库提供了创建和操作 XML 文档的标签。引用 XML 标
下载地址:
-| 标签 | 描述 |
-| :----------------------------------------------------------------------- | :---------------------------------------------------------- |
-| [``](http://www.runoob.com/jsp/jstl-xml-out-tag.html) | 与<%= ... >,类似,不过只用于 XPath 表达式 |
-| [``](http://www.runoob.com/jsp/jstl-xml-parse-tag.html) | 解析 XML 数据 |
-| [``](http://www.runoob.com/jsp/jstl-xml-set-tag.html) | 设置 XPath 表达式 |
-| [``](http://www.runoob.com/jsp/jstl-xml-if-tag.html) | 判断 XPath 表达式,若为真,则执行本体中的内容,否则跳过本体 |
-| [``](http://www.runoob.com/jsp/jstl-xml-foreach-tag.html) | 迭代 XML 文档中的节点 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 和的父标签 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 的子标签,用来进行条件判断 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 的子标签,当判断为 false 时被执行 |
-| [``](http://www.runoob.com/jsp/jstl-xml-transform-tag.html) | 将 XSL 转换应用在 XML 文档中 |
-| [``](http://www.runoob.com/jsp/jstl-xml-param-tag.html) | 与共同使用,用于设置 XSL 样式表 |
-
-### 8.6. JSTL 函数
+| 标签 | 描述 |
+| :----------------------------------------------------------------------- |:----------------------------------------------|
+| [``](http://www.runoob.com/jsp/jstl-xml-out-tag.html) | 与 `<%= ... >`,类似,不过只用于 XPath 表达式 |
+| [``](http://www.runoob.com/jsp/jstl-xml-parse-tag.html) | 解析 XML 数据 |
+| [``](http://www.runoob.com/jsp/jstl-xml-set-tag.html) | 设置 XPath 表达式 |
+| [``](http://www.runoob.com/jsp/jstl-xml-if-tag.html) | 判断 XPath 表达式,若为真,则执行本体中的内容,否则跳过本体 |
+| [``](http://www.runoob.com/jsp/jstl-xml-foreach-tag.html) | 迭代 XML 文档中的节点 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 和 `` 的父标签 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 的子标签,用来进行条件判断 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 的子标签,当 `` 判断为 false 时被执行 |
+| [``](http://www.runoob.com/jsp/jstl-xml-transform-tag.html) | 将 XSL 转换应用在 XML 文档中 |
+| [``](http://www.runoob.com/jsp/jstl-xml-param-tag.html) | 与 `` 共同使用,用于设置 XSL 样式表 |
+
+### JSTL 函数
JSTL 包含一系列标准函数,大部分是通用的字符串处理函数。引用 JSTL 函数库的语法如下:
@@ -1463,9 +1478,9 @@ JSTL 包含一系列标准函数,大部分是通用的字符串处理函数。
| [fn:toUpperCase()](http://www.runoob.com/jsp/jstl-function-touppercase.html) | 将字符串中的字符转为大写 |
| [fn:trim()](http://www.runoob.com/jsp/jstl-function-trim.html) | 移除首尾的空白符 |
-## 9. Taglib
+## Taglib
-### 9.1. JSP 自定义标签
+### JSP 自定义标签
自定义标签是用户定义的 JSP 语言元素。当 JSP 页面包含一个自定义标签时将被转化为 servlet,标签转化为对被 称为 tag handler 的对象的操作,即当 servlet 执行时 Web container 调用那些操作。
@@ -1473,7 +1488,7 @@ JSP 标签扩展可以让你创建新的标签并且可以直接插入到一个
你可以继承 SimpleTagSupport 类并重写的 doTag()方法来开发一个最简单的自定义标签。
-### 9.2. 创建"Hello"标签
+### 创建"Hello"标签
接下来,我们想创建一个自定义标签叫作,标签格式为:
@@ -1527,7 +1542,7 @@ JspWriter out = getJspContext().getOut(); out.println("Hello Custom Tag!"); } }
Hello Custom Tag!
```
-### 9.3. 访问标签体
+### 访问标签体
你可以像标准标签库一样在标签中包含消息内容。如我们要在我们自定义的 Hello 中包含内容,格式如下:
@@ -1596,7 +1611,7 @@ public class HelloTag extends SimpleTagSupport {
This is message body
```
-### 9.4. 自定义标签属性
+### 自定义标签属性
你可以在自定义标准中设置各种属性,要接收属性,值自定义标签类必须实现 setter 方法, JavaBean 中的 setter 方法如下所示:
@@ -1635,7 +1650,7 @@ public class HelloTag extends SimpleTagSupport {
}
```
-属性的名称是"message",所以 setter 方法是的 setMessage()。现在让我们在 TLD 文件中使用的元素添加此属性:
+属性的名称是"message",所以 setter 方法是的 setMessage()。现在让我们在 TLD 文件中使用的 `` 元素添加此属性:
```
@@ -1713,4 +1728,4 @@ This is custom tag
java.util.Date
.....
-```
+```
\ No newline at end of file
diff --git a/docs/javaee/javaee-filter-listener.md "b/docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
similarity index 88%
rename from docs/javaee/javaee-filter-listener.md
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
index 0abf6400..aea60247 100644
--- a/docs/javaee/javaee-filter-listener.md
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
@@ -1,32 +1,32 @@
-# JavaEE 之 Filter 和 Listener
+---
+title: JavaWeb 之 Filter 和 Listener
+date: 2020-08-24 19:41:46
+order: 03
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - Java
+ - JavaWeb
+ - Filter
+ - Listener
+permalink: /pages/82df5f/
+---
+
+# JavaWeb 之 Filter 和 Listener
引入了 Servlet 规范后,你不需要关心 Socket 网络通信、不需要关心 HTTP 协议,也不需要关心你的业务类是如何被实例化和调用的,因为这些都被 Servlet 规范标准化了,你只要关心怎么实现的你的业务逻辑。这对于程序员来说是件好事,但也有不方便的一面。所谓规范就是说大家都要遵守,就会千篇一律,但是如果这个规范不能满足你的业务的个性化需求,就有问题了,因此设计一个规范或者一个中间件,要充分考虑到可扩展性。Servlet 规范提供了两种扩展机制:**Filter**和**Listener**。
-
-
-- [1. Filter](#1-filter)
- - [1.1. 过滤器方法](#11-过滤器方法)
- - [1.2. 过滤器配置](#12-过滤器配置)
-- [2. Listener](#2-listener)
- - [2.1. 监听器的分类](#21-监听器的分类)
- - [2.2. 监听对象的创建和销毁](#22-监听对象的创建和销毁)
- - [2.3. 监听对象的属性变化](#23-监听对象的属性变化)
- - [2.4. 监听 Session 内的对象](#24-监听-session-内的对象)
-- [3. Filter 和 Listener](#3-filter-和-listener)
-- [4. 示例代码](#4-示例代码)
-- [5. 参考资料](#5-参考资料)
-
-
-
-## 1. Filter
+## Filter
**Filter 是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理**。
Filter 提供了过滤链(Filter Chain)的概念,一个过滤链包括多个 Filter。客户端请求 request 在抵达 Servlet 之前会经过过滤链的所有 Filter,服务器响应 response 从 Servlet 抵达客户端浏览器之前也会经过过滤链的所有 FIlter。
-
+
-### 1.1. 过滤器方法
+### 过滤器方法
Filter 接口有三个方法:
@@ -71,7 +71,7 @@ public interface Filter {
}
```
-### 1.2. 过滤器配置
+### 过滤器配置
`Filter` 需要配置在 `web.xml` 中才能生效。一个 `Filter` 需要配置 `` 与 `` 标签。
@@ -85,13 +85,13 @@ public interface Filter {
- INCLUDE - JSP 中可以通过 `` 请求某 Servlet。仅在这种情况表有效。
- ERROR - JSP 中可以通过 `<%@ page errorPage="error.jsp" %>` 指定错误处理页面。仅在这种情况表有效。
-## 2. Listener
+## Listener
监听器(`Listener`)用于监听 web 应用程序中的`ServletContext`, `HttpSession`和 `ServletRequest`等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
使用 `Listener` 不需要关注该类事件时怎样触发或者怎么调用相应的 `Listener`,只要记住该类事件触发时一定会调用相应的 `Listener`,遵循 Servlet 规范的服务器会自动完成相应工作。
-### 2.1. 监听器的分类
+### 监听器的分类
在 Servlet 规范中定义了多种类型的监听器,它们用于监听的事件源分别为`ServletContext`,`HttpSession`和`ServletRequest`这三个域对象
Servlet 规范针对这三个对象上的操作,又把多种类型的监听器划分为三种类型:
@@ -100,16 +100,16 @@ Servlet 规范针对这三个对象上的操作,又把多种类型的监听器
2. 监听域对象中的属性的增加和删除的事件监听器。
3. 监听绑定到 HttpSession 域中的某个对象的状态的事件监听器。
-### 2.2. 监听对象的创建和销毁
+### 监听对象的创建和销毁
-#### 2.2.1. HttpSessionListener
+#### HttpSessionListener
**`HttpSessionListener` 接口用于监听 `HttpSession` 对象的创建和销毁。**
- 创建一个 `Session` 时,激发 `sessionCreated (HttpSessionEvent se)` 方法
- 销毁一个 `Session` 时,激发 `sessionDestroyed (HttpSessionEvent se)` 方法。
-#### 2.2.2. ServletContextListener
+#### ServletContextListener
**`ServletContextListener` 接口用于监听 `ServletContext` 对象的创建和销毁事件。**
@@ -123,7 +123,7 @@ Servlet 规范针对这三个对象上的操作,又把多种类型的监听器
- 创建:服务器启动针对每一个 Web 应用创建 `ServletContext`
- 销毁:服务器关闭前先关闭代表每一个 web 应用的 `ServletContext`
-#### 2.2.3. ServletRequestListener
+#### ServletRequestListener
**`ServletRequestListener` 接口用于监听 `ServletRequest` 对象的创建和销毁。**
@@ -135,12 +135,12 @@ Servlet 规范针对这三个对象上的操作,又把多种类型的监听器
- 创建:用户每一次访问都会创建 request 对象
- 销毁:当前访问结束,request 对象就会销毁
-### 2.3. 监听对象的属性变化
+### 监听对象的属性变化
域对象中属性的变更的事件监听器就是用来监听 `ServletContext`、`HttpSession`、`HttpServletRequest` 这三个对象中的属性变更信息事件的监听器。
这三个监听器接口分别是 `ServletContextAttributeListener`、`HttpSessionAttributeListener` `和 ServletRequestAttributeListener`,这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
-#### 2.3.1. attributeAdded 方法
+#### attributeAdded 方法
当向被监听对象中增加一个属性时,web 容器就调用事件监听器的 `attributeAdded` 方法进行响应,这个方法接收一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象
各个域属性监听器中的完整语法定义为:
@@ -151,7 +151,7 @@ public void attributeReplaced(HttpSessionBindingEvent hsbe)
public void attributeRmoved(ServletRequestAttributeEvent srae)
```
-#### 2.3.2. attributeRemoved 方法
+#### attributeRemoved 方法
当删除被监听对象中的一个属性时,web 容器调用事件监听器的 `attributeRemoved` 方法进行响应
各个域属性监听器中的完整语法定义为:
@@ -162,7 +162,7 @@ public void attributeRemoved(HttpSessionBindingEvent hsbe)
public void attributeRemoved(ServletRequestAttributeEvent srae)
```
-#### 2.3.3. attributeReplaced 方法
+#### attributeReplaced 方法
当监听器的域对象中的某个属性被替换时,web 容器调用事件监听器的 `attributeReplaced` 方法进行响应
各个域属性监听器中的完整语法定义为:
@@ -173,7 +173,7 @@ public void attributeReplaced(HttpSessionBindingEvent hsbe)
public void attributeReplaced(ServletRequestAttributeEvent srae)
```
-### 2.4. 监听 Session 内的对象
+### 监听 Session 内的对象
保存在 Session 域中的对象可以有多种状态:
@@ -186,33 +186,33 @@ Servlet 规范中定义了两个特殊的监听器接口 `HttpSessionBindingList
实现这两个接口的类不需要 `web.xml` 文件中进行注册。
-#### 2.4.1. HttpSessionBindingListener
+#### HttpSessionBindingListener
`HttpSessionBindingListener` 接口的 JavaBean 对象可以感知自己被绑定或解绑定到 `Session` 中的事件。
- 当对象被绑定到 `HttpSession` 对象中时,web 服务器调用该对象的 `valueBound(HttpSessionBindingEvent event)` 方法。
- 当对象从 `HttpSession` 对象中解除绑定时,web 服务器调用该对象的 `valueUnbound(HttpSessionBindingEvent event)` 方法。
-#### 2.4.2. HttpSessionActivationListener
+#### HttpSessionActivationListener
实现了 `HttpSessionActivationListener` 接口的 JavaBean 对象可以感知自己被活化(反序列化)和钝化(序列化)的事件。
- 当绑定到 `HttpSession` 对象中的 JavaBean 对象将要随 `HttpSession` 对象被序列化之前,web 服务器调用该 JavaBean 对象的 `sessionWillPassivate(HttpSessionEvent event)` 方法。这样 JavaBean 对象就可以知道自己将要和 `HttpSession` 对象一起被序列化到硬盘中.
- 当绑定到 `HttpSession` 对象中的 JavaBean 对象将要随 `HttpSession` 对象被反序列化之后,web 服务器调用该 JavaBean 对象的 `sessionDidActive(HttpSessionEvent event)` 方法。这样 JavaBean 对象就可以知道自己将要和 `HttpSession` 对象一起被反序列化回到内存中
-## 3. Filter 和 Listener
+## Filter 和 Listener
Filter 和 Listener 的本质区别:
- **Filter 是干预过程的**,它是过程的一部分,是基于过程行为的。
- **Listener 是基于状态的**,任何行为改变同一个状态,触发的事件是一致的。
-## 4. 示例代码
+## 示例代码
- `Filter` 的示例源码:[源码](https://github.com/dunwu/javatech/tree/master/codes/javaee-tutorial/javaee-tutorial-filter)
- `Listener` 的示例源码:[源码](https://github.com/dunwu/javatech/tree/master/codes/javaee-tutorial/javaee-tutorial-listener)
-## 5. 参考资料
+## 参考资料
- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
-- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
\ No newline at end of file
diff --git a/docs/javaee/javaee-cookie-sesion.md "b/docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
similarity index 96%
rename from docs/javaee/javaee-cookie-sesion.md
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
index 50953642..3729f4a6 100644
--- a/docs/javaee/javaee-cookie-sesion.md
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
@@ -1,12 +1,28 @@
-# JavaEE 之 Cookie 和 Session
-
-## 1. Cookie
+---
+title: JavaWeb 之 Cookie 和 Session
+date: 2020-08-24 19:41:46
+order: 04
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - Java
+ - JavaWeb
+ - Cookie
+ - Session
+permalink: /pages/c46bff/
+---
+
+# JavaWeb 之 Cookie 和 Session
+
+## Cookie
由于 Http 是一种无状态的协议,服务器单从网络连接上无从知道客户身份。
会话跟踪是 Web 程序中常用的技术,用来跟踪用户的整个会话。常用会话跟踪技术是 Cookie 与 Session。
-### 1.1. Cookie 是什么
+### Cookie 是什么
Cookie 实际上是存储在客户端上的文本信息,并保留了各种跟踪的信息。
@@ -16,11 +32,11 @@ Cookie 实际上是存储在客户端上的文本信息,并保留了各种跟
2. 客户端浏览器会把 Cookie 保存下来。
3. 当浏览器再请求该网站时,浏览器把该请求的网址连同 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。
-***注:Cookie 功能需要浏览器的支持,如果浏览器不支持 Cookie 或者 Cookie 禁用了,Cookie 功能就会失效。***
+**_注:Cookie 功能需要浏览器的支持,如果浏览器不支持 Cookie 或者 Cookie 禁用了,Cookie 功能就会失效。_**
Java 中把 Cookie 封装成了`javax.servlet.http.Cookie`类。
-### 1.2. Cookie 剖析
+### Cookie 剖析
Cookies 通常设置在 HTTP 头信息中(虽然 JavaScript 也可以直接在浏览器上设置一个 Cookie)。
@@ -52,7 +68,7 @@ Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz
```
-### 1.3. Cookie 类中的方法
+### Cookie 类中的方法
| 方法 | 功能 |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
@@ -69,7 +85,7 @@ Cookie: name=xyz
| public void setComment(String purpose) | 该方法规定了描述 cookie 目的的注释。该注释在浏览器向用户呈现 cookie 时非常有用。 |
| public String getComment() | 该方法返回了描述 cookie 目的的注释,如果 cookie 没有注释则返回 null。 |
-### 1.4. Cookie 的有效期
+### Cookie 的有效期
`Cookie`的`maxAge`决定着 Cookie 的有效期,单位为秒。
@@ -79,7 +95,7 @@ Cookie: name=xyz
Cookie 中提供`getMaxAge()`**和**`setMaxAge(int expiry)`方法来读写`maxAge`属性。
-### 1.5. Cookie 的域名
+### Cookie 的域名
Cookie 是不可以跨域名的。域名 www.google.com 颁发的 Cookie 不会被提交到域名 www.baidu.com 去。这是由 Cookie 的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的 Cookie。
@@ -87,13 +103,13 @@ Cookie 是不可以跨域名的。域名 www.google.com 颁发的 Cookie 不会
Java 中使用`setDomain(Stringdomain)`和`getDomain()`方法来设置、获取 domain。
-### 1.6. Cookie 的路径
+### Cookie 的路径
Path 属性决定允许访问 Cookie 的路径。
Java 中使用`setPath(Stringuri)`和`getPath()`方法来设置、获取 path。
-### 1.7. Cookie 的安全属性
+### Cookie 的安全属性
HTTP 协议不仅是无状态的,而且是不安全的。
@@ -101,9 +117,9 @@ HTTP 协议不仅是无状态的,而且是不安全的。
Java 中使用`setSecure(booleanflag)`和`getSecure ()`方法来设置、获取 Secure。
-### 1.8. Cookie 实例
+### Cookie 实例
-#### 1.8.1. 添加 Cookie
+#### 添加 Cookie
通过 Servlet 添加 Cookies 包括三个步骤:
@@ -200,7 +216,7 @@ addCookies.jsp
```
-#### 1.8.2. 显示 Cookie
+#### 显示 Cookie
要读取 Cookies,您需要通过调用 `HttpServletRequest` 的 `getCookies()` 方法创建一个 `javax.servlet.http.Cookie` 对象的数组。然后循环遍历数组,并使用 `getName()` 和 `getValue()` 方法来访问每个 cookie 和关联的值。
@@ -277,7 +293,7 @@ public class ReadCookies extends HttpServlet {
}
```
-#### 1.8.3. 删除 Cookie
+#### 删除 Cookie
Java 中并没有提供直接删除 Cookie 的方法,如果想要删除一个 Cookie,直接将这个 Cookie 的有效期设为 0 就可以了。步骤如下:
@@ -359,9 +375,9 @@ public class DeleteCookies extends HttpServlet {
}
```
-## 2. Session
+## Session
-### 2.1. Session 是什么
+### Session 是什么
不同于 Cookie 保存在客户端浏览器中,Session 保存在服务器上。
@@ -369,7 +385,7 @@ public class DeleteCookies extends HttpServlet {
Session 对应的类为 `javax.servlet.http.HttpSession` 类。Session 对象是在客户第一次请求服务器时创建的。
-### 2.2. Session 类中的方法
+### Session 类中的方法
`javax.servlet.http.HttpSession` 类中的方法:
@@ -387,7 +403,7 @@ Session 对应的类为 `javax.servlet.http.HttpSession` 类。Session 对象是
| public void setAttribute(String name, Object value) | 该方法使用指定的名称绑定一个对象到该 session 会话。 |
| public void setMaxInactiveInterval(int interval) | 该方法在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。 |
-### 2.3. Session 的有效期
+### Session 的有效期
由于会有越来越多的用户访问服务器,因此 Session 也会越来越多。为防止内存溢出,服务器会把长时间没有活跃的 Session 从内存中删除。
@@ -403,19 +419,19 @@ Tomcat 中 Session 的默认超时时间为 20 分钟。可以修改 web.xml 改
```
-### 2.4. Session 对浏览器的要求
+### Session 对浏览器的要求
HTTP 协议是无状态的,Session 不能依据 HTTP 连接来判断是否为同一客户。因此服务器向客户端浏览器发送一个名为 JESSIONID 的 Cookie,他的值为该 Session 的 id(也就是 HttpSession.getId()的返回值)。Session 依据该 Cookie 来识别是否为同一用户。
该 Cookie 为服务器自动生成的,它的`maxAge`属性一般为-1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。
-### 2.5. URL 地址重写
+### URL 地址重写
URL 地址重写的原理是将该用户 Session 的 id 信息重写到 URL 地址中。服务器能够解析重写后的 URL 获取 Session 的 id。这样即使客户端不支持 Cookie,也可以使用 Session 来记录用户状态。
`HttpServletResponse`类提供了`encodeURL(Stringurl)`实现 URL 地址重写。
-### 2.6. Session 中禁用 Cookie
+### Session 中禁用 Cookie
在`META-INF/context.xml`中编辑如下:
@@ -426,9 +442,9 @@ URL 地址重写的原理是将该用户 Session 的 id 信息重写到 URL 地
部署后,TOMCAT 便不会自动生成名 JESSIONID 的 Cookie,Session 也不会以 Cookie 为识别标志,而仅仅以重写后的 URL 地址为识别标志了。
-### 2.7. Session 实例
+### Session 实例
-#### 2.7.1. Session 跟踪
+#### Session 跟踪
SessionTrackServlet.java
@@ -510,7 +526,7 @@ web.xml
```
-#### 2.7.2. 删除 Session 会话数据
+#### 删除 Session 会话数据
当您完成了一个用户的 session 会话数据,您有以下几种选择:
@@ -534,33 +550,33 @@ web.xml
在一个 Servlet 中的 `getMaxInactiveInterval()` 方法会返回 session 会话的超时时间,以秒为单位。所以,如果在 web.xml 中配置 session 会话超时时间为 15 分钟,那么`getMaxInactiveInterval()` 会返回 900。
-## 3. Cookie vs Session
+## Cookie vs Session
-### 3.1. 存取方式
+### 存取方式
Cookie 只能保存`ASCII`字符串,如果需要存取 Unicode 字符或二进制数据,需要进行`UTF-8`、`GBK`或`BASE64`等方式的编码。
Session 可以存取任何类型的数据,甚至是任何 Java 类。可以将 Session 看成是一个 Java 容器类。
-### 3.2. 隐私安全
+### 隐私安全
Cookie 存于客户端浏览器,一些客户端的程序可能会窥探、复制或修改 Cookie 内容。
Session 存于服务器,对客户端是透明的,不存在敏感信息泄露的危险。
-### 3.3. 有效期
+### 有效期
使用 Cookie 可以保证长时间登录有效,只要设置 Cookie 的`maxAge`属性为一个很大的数字。
而 Session 虽然理论上也可以通过设置很大的数值来保持长时间登录有效,但是,由于 Session 依赖于名为`JESSIONID`的 Cookie,而 Cookie `JESSIONID`的`maxAge`默认为-1,只要关闭了浏览器该 Session 就会失效,因此,Session 不能实现信息永久有效的效果。使用 URL 地址重写也不能实现。
-### 3.4. 服务器的开销
+### 服务器的开销
由于 Session 是保存在服务器的,每个用户都会产生一个 Session,如果并发访问的用户非常多,会产生很多的 Session,消耗大量的内存。
而 Cookie 由于保存在客户端浏览器上,所以不占用服务器资源。
-### 3.5. 浏览器的支持
+### 浏览器的支持
Cookie 需要浏览器支持才能使用。
@@ -568,7 +584,7 @@ Cookie 需要浏览器支持才能使用。
需要注意的事所有的用到 Session 程序的 URL 都要使用`response.encodeURL(StringURL)` 或`response.encodeRediretURL(String URL)`进行 URL 地址重写,否则导致 Session 会话跟踪失效。
-### 3.6. 跨域名
+### 跨域名
-* Cookie 支持跨域名。
-* Session 不支持跨域名。
+- Cookie 支持跨域名。
+- Session 不支持跨域名。
\ No newline at end of file
diff --git a/docs/javaee/javaee-interview.md "b/docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
similarity index 92%
rename from docs/javaee/javaee-interview.md
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
index 0f1be619..8e803b40 100644
--- a/docs/javaee/javaee-interview.md
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
@@ -1,8 +1,23 @@
-# JavaEE 面经
-
-## 1. Servlet
-
-### 1.1. 什么是 Servlet
+---
+title: JavaWeb 面经
+date: 2020-02-07 23:04:47
+order: 99
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - Java
+ - JavaWeb
+ - Servlet
+permalink: /pages/e175ce/
+---
+
+# JavaWeb 面经
+
+## Servlet
+
+### 什么是 Servlet
Servlet(Server Applet),即小服务程序或服务连接器。Servlet 是 Java 编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态 Web 内容。
@@ -11,14 +26,14 @@ Servlet(Server Applet),即小服务程序或服务连接器。Servlet 是
Servlet 运行于支持 Java 的应用服务器中。从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下 Servlet 只用来扩展基于 HTTP 协议的 Web 服务器。
-### 1.2. Servlet 和 CGI 的区别
+### Servlet 和 CGI 的区别
Servlet 技术出现之前,Web 主要使用 CGI 技术。它们的区别如下:
- Servlet 是基于 Java 编写的,处于服务器进程中,他能够通过多线程方式运行 service() 方法,一个实例可以服务于多个请求,而且一般不会销毁;
- CGI(Common Gateway Interface),即通用网关接口。它会为每个请求产生新的进程,服务完成后销毁,所以效率上低于 Servlet。
-### 1.3. Servlet 版本以及主要特性
+### Servlet 版本以及主要特性
| 版本 | 日期 | JAVA EE/JDK 版本 | 特性 |
| ----------- | ------------- | ------------------ | --------------------------------------------------------------------- |
@@ -33,14 +48,14 @@ Servlet 技术出现之前,Web 主要使用 CGI 技术。它们的区别如下
| Servlet 2.0 | | JDK 1.1 | Part of Java Servlet Development Kit 2.0 |
| Servlet 1.0 | 1997 年 6 月 | | |
-### 1.4. Servlet 和 JSP 的区别
+### Servlet 和 JSP 的区别
1. Servlet 是一个运行在服务器上的 Java 类,依靠服务器支持向浏览器传输数据。
2. **JSP 本质上就是 Servlet**,每次运行的时候 JSP 都会被编译成 .java 文件,然后再被编译成 .class 文件。
3. 有了 JSP,Servlet 不再负责动态生成页面,转而去负责控制程序逻辑的作用,控制 JSP 与 JavaBean 之间的流转。
4. JSP 侧重于视图,而 Servlet 侧重于控制逻辑,在 MVC 架构模式中,JSP 适合充当视图 View,Servlet 适合充当控制器 Controller。
-### 1.5. 简述 Servlet 生命周期
+### 简述 Servlet 生命周期

@@ -52,19 +67,19 @@ Servlet 生命周期如下:
4. **销毁** - Servlet 通过调用 **destroy()** 方法终止(结束)。
5. **卸载** - Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
-### 1.6. 如何现实 servlet 的单线程模式
+### 如何现实 servlet 的单线程模式
```java
<%@ page isThreadSafe="false" %>
```
-### 1.7. Servlet 中如何获取用户提交的查询参数或者表单数据
+### Servlet 中如何获取用户提交的查询参数或者表单数据
- HttpServletRequest 的 getParameter() 方法。
- HttpServletRequest 的 getParameterValues() 方法。
- HttpServletRequest 的 getParameterMap() 方法。
-### 1.8. request 的主要方法
+### request 的主要方法
- setAttribute(String name,Object):设置名字为 name 的 request 的参数值
- getAttribute(String name):返回由 name 指定的属性值
@@ -90,9 +105,9 @@ Servlet 生命周期如下:
- getServerPort():获取服务器的端口号
- removeAttribute(String name):删除请求中的一个属性
-## 2. JSP
+## JSP
-### 2.1. JSP 的内置对象
+### JSP 的内置对象
1. **request**:包含**客户端请求的信息**;
2. **response**:包含**服务器传回客户端的响应信息**;
@@ -104,14 +119,14 @@ Servlet 生命周期如下:
8. **page**:指**网页本身**;
9. **exception**:处理 JSP 文件执行时发生的错误和异常,只要在**错误页面**里才能使用。
-### 2.2. JSP 的作用域
+### JSP 的作用域
1. **page**:一个页面;
2. **request**:一次请求;
3. **session**:一次会话;
4. **application**:服务器从启动到停止。
-### 2.3. JSP 中 7 个动作指令和作用
+### JSP 中 7 个动作指令和作用
1. **jsp:forward** - 执行页面转向,把请求转发到下一个页面;
2. **jsp:param** - 用于传递参数,必须与其他支持参数的标签一起使用;
@@ -121,14 +136,14 @@ Servlet 生命周期如下:
6. **jsp:setProperty** - 设置 JavaBean 的属性值;
7. **jsp:getProperty** - 获取 JavaBean 的属性值。
-### 2.4. JSP 中动态 INCLUDE 和静态 INCLUDE 有什么区别
+### JSP 中动态 INCLUDE 和静态 INCLUDE 有什么区别
- **静态 INCLUDE**:用 include 伪码实现,**不会检查所含文件的变化**,适用于包含**静态页面<%@ include file="页面名称.html" %>**。**先合并再编译**。
- **动态 INCLUDE**:用 jsp:include 动作实现 **** 它总是**会检查文件中的变化**,适用于包含**动态页面**,并且可以**带参数**。**先编译再合并**。
-## 3. 原理
+## 原理
-### 3.1. 请求转发(forward)和重定向(redirect)的区别
+### 请求转发(forward)和重定向(redirect)的区别
- 效率上
- 转发(forward) > 重定向(redirect)
@@ -142,7 +157,7 @@ Servlet 生命周期如下:
- 重定向(redirect)是两次
- 转发(forward)是一次
-### 3.2. get 请求和 post 请求的区别
+### get 请求和 post 请求的区别

@@ -157,7 +172,7 @@ Servlet 生命周期如下:
- 安全性高
- 请的求的数据内容放置在 HTML HEADER 中
-### 3.3. 用户在浏览器中输入 URL 之后,发什么了什么?写出请求和响应的流程
+### 用户在浏览器中输入 URL 之后,发什么了什么?写出请求和响应的流程
1. 域名解析
2. TCP 三次握手
@@ -169,12 +184,12 @@ Servlet 生命周期如下:
8. 服务器发送数据
9. TCP 连接关闭
-### 3.4. 什么是 Web Service?
+### 什么是 Web Service?
1. WebService 就是一个应用程序,它向外界暴露出一个能够通过 Web 进行调用的 API。
2. 它是基于 HTTP 协议传输数据,这使得运行在不同机上的不同应用程序,无须借助附加的、专门的第三方 软件或硬件,就可以相互交换数据或集成。
-### 3.5. 会话跟踪技术有哪些?
+### 会话跟踪技术有哪些?
由于 HTTP 协议本身是无状态的,服务器为了区分不同的用户,就需要对用户会话进行跟踪,简单的说就是为用户进行登记,为用户分配唯一的 ID,下一次用户在请求中包含此 ID,服务器根据此判断到底是哪一个用户。
@@ -191,7 +206,7 @@ Servlet 生命周期如下:
- 与上面三种方式不同的是,HttpSession 放在服务器的内存中,因此不要将过大的对象放在里面,即使目前的 Servlet 容器可以在内存将满时将 HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。
- 添加到 HttpSession 中 的值可以是任意 Java 对象,这个对象最好实现了 Serializable 接口,这样 Servlet 容器在必要的时候可以将其序列 化到文件中,否则在序列化时就会出现异常。
-### 3.6. 响应结果状态码有哪些,并给出中文含义?
+### 响应结果状态码有哪些,并给出中文含义?
- `1**`:信息性状态码
- `2**`:成功状态码
@@ -211,7 +226,7 @@ Servlet 生命周期如下:
- 500:服务器端在执行请求时发生了错误
- 503:服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
-### 3.7. XML 文档定义有几种形式?它们之间有何本质区别?解析 XML 文档有哪几种方式?
+### XML 文档定义有几种形式?它们之间有何本质区别?解析 XML 文档有哪几种方式?
(1)XML 文档有两种约束方式:
@@ -248,7 +263,7 @@ Servlet 生命周期如下:
- 4)XMLWriter.write("..")-- 写出
- 5)XMLWriter.close()-- 关闭输出流
-## 4. 参考资料
+## 参考资料
- https://blog.csdn.net/YM_IlY/article/details/81266959
-- https://www.jianshu.com/p/f073dde56262
+- https://www.jianshu.com/p/f073dde56262
\ No newline at end of file
diff --git a/docs/01.Java/02.JavaEE/01.JavaWeb/README.md b/docs/01.Java/02.JavaEE/01.JavaWeb/README.md
new file mode 100644
index 00000000..56a9b42a
--- /dev/null
+++ b/docs/01.Java/02.JavaEE/01.JavaWeb/README.md
@@ -0,0 +1,34 @@
+---
+title: JavaWeb
+date: 2020-02-07 23:04:47
+categories:
+ - Java
+ - JavaEE
+ - JavaWeb
+tags:
+ - JavaWeb
+permalink: /pages/50f49f/
+hidden: true
+index: false
+---
+
+# ☕ JavaWeb
+
+## 知识点
+
+- [JavaWeb 之 Servlet 指南](01.JavaWeb之Servlet指南.md)
+- [JavaWeb 之 Jsp 指南](01.JavaWeb之Servlet指南.md)
+- [JavaWeb 之 Filter 和 Listener](03.JavaWeb之Filter和Listener.md)
+- [JavaWeb 之 Cookie 和 Session](04.JavaWeb之Cookie和Session.md)
+- [JavaWeb 面经](99.JavaWeb面经.md)
+
+## 学习资料
+
+- **书籍**
+ - [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+ - [Head First Servlets & JSP](https://book.douban.com/subject/1942934/)
+- **教程**
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [Servlet 教程](https://www.runoob.com/servlet/servlet-tutorial.html)
+ - [博客园孤傲苍狼 JavaWeb 学习总结](https://www.cnblogs.com/xdp-gacl/tag/JavaWeb%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/)
+ - [JSP 教程](https://www.runoob.com/jsp/jsp-tutorial.html)
\ No newline at end of file
diff --git "a/docs/server/Tomcat\345\272\224\347\224\250\346\214\207\345\215\227.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
similarity index 93%
rename from "docs/server/Tomcat\345\272\224\347\224\250\346\214\207\345\215\227.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
index be2edc47..05822b5e 100644
--- "a/docs/server/Tomcat\345\272\224\347\224\250\346\214\207\345\215\227.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
@@ -1,4 +1,21 @@
-# Tomcat 应用指南
+---
+title: Tomcat 快速入门
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+permalink: /pages/4a4c02/
+---
+
+# Tomcat 快速入门
> 🎁 版本说明
>
@@ -6,32 +23,6 @@
>
> 环境要求:JDK7+
-
-
-- [1. Tomcat 简介](#1-tomcat-简介)
- - [1.1. Tomcat 是什么](#11-tomcat-是什么)
- - [1.2. Tomcat 重要目录](#12-tomcat-重要目录)
- - [1.3. web 工程发布目录结构](#13-web-工程发布目录结构)
- - [1.4. Tomcat 功能](#14-tomcat-功能)
-- [2. Tomcat 入门](#2-tomcat-入门)
- - [2.1. 安装](#21-安装)
- - [2.2. 配置](#22-配置)
- - [2.3. 启动](#23-启动)
-- [3. Tomcat 架构](#3-tomcat-架构)
- - [3.1. Service](#31-service)
- - [3.2. 连接器](#32-连接器)
- - [3.3. 容器](#33-容器)
-- [4. Tomcat 生命周期](#4-tomcat-生命周期)
- - [4.1. Tomcat 的启动过程](#41-tomcat-的启动过程)
- - [4.2. Web 应用的部署方式](#42-web-应用的部署方式)
- - [4.3. LifeCycle](#43-lifecycle)
- - [4.4. Connector 流程](#44-connector-流程)
- - [4.5. Comet](#45-comet)
- - [4.6. 异步 Servlet](#46-异步-servlet)
-- [5. 参考资料](#5-参考资料)
-
-
-
## 1. Tomcat 简介
### 1.1. Tomcat 是什么
@@ -121,7 +112,7 @@ tar -zxf apache-tomcat-8.5.24.tar.gz
启动后,访问 `http://localhost:8080` ,可以看到 Tomcat 安装成功的测试页面。
-
+
### 2.2. 配置
@@ -374,7 +365,7 @@ public class SimpleTomcatServer {
- 设置启动应用的端口、JVM 参数、启动浏览器等。
- 成功后,可以访问 `http://localhost:8080/`(当然,你也可以在 url 中设置上下文名称)。
-
+
> **说明**
>
@@ -384,7 +375,7 @@ public class SimpleTomcatServer {
## 3. Tomcat 架构
-
+
Tomcat 要实现 2 个核心功能:
@@ -412,7 +403,7 @@ Tomcat 支持的应用层协议有:
Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个容器可能对接多个连接器。但是,单独的连接器或容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。Tomcat 内可能有多个 Service,通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。
-
+
**一个 Tomcat 实例有一个或多个 Service;一个 Service 有多个 Connector 和 Container**。Connector 和 Container 之间通过标准的 ServletRequest 和 ServletResponse 通信。
@@ -428,19 +419,19 @@ Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个
Tomcat 设计了 3 个组件来实现这 3 个功能,分别是 **`EndPoint`**、**`Processor`** 和 **`Adapter`**。
-
+
组件间通过抽象接口交互。这样做还有一个好处是**封装变化。**这是面向对象设计的精髓,将系统中经常变化的部分和稳定的部分隔离,有助于增加复用性,并降低系统耦合度。网络通信的 I/O 模型是变化的,可能是非阻塞 I/O、异步 I/O 或者 APR。应用层协议也是变化的,可能是 HTTP、HTTPS、AJP。浏览器端发送的请求信息也是变化的。但是整体的处理逻辑是不变的,EndPoint 负责提供字节流给 Processor,Processor 负责提供 Tomcat Request 对象给 Adapter,Adapter 负责提供 ServletRequest 对象给容器。
如果要支持新的 I/O 方案、新的应用层协议,只需要实现相关的具体子类,上层通用的处理逻辑是不变的。由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,设计了一个叫 ProtocolHandler 的接口来封装这两种变化点。各种协议和通信模型的组合有相应的具体实现类。比如:Http11NioProtocol 和 AjpNioProtocol。
-
+
-#### ProtocolHandler 组件
+#### 3.2.1. ProtocolHandler 组件
**连接器用 ProtocolHandler 接口来封装通信协议和 I/O 模型的差异**。ProtocolHandler 内部又分为 EndPoint 和 Processor 模块,EndPoint 负责底层 Socket 通信,Proccesor 负责应用层协议解析。
-##### EndPoint
+##### 3.2.1.1. EndPoint
EndPoint 是通信端点,即通信监听的接口,是具体的 Socket 接收和发送处理器,是对传输层的抽象,因此 EndPoint 是用来实现 TCP/IP 协议的。
@@ -448,17 +439,17 @@ EndPoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 Ab
其中 Acceptor 用于监听 Socket 连接请求。SocketProcessor 用于处理接收到的 Socket 请求,它实现 Runnable 接口,在 Run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor)。
-##### Processor
+##### 3.2.1.2. Processor
如果说 EndPoint 是用来实现 TCP/IP 协议的,那么 Processor 用来实现 HTTP 协议,Processor 接收来自 EndPoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,并通过 Adapter 将其提交到容器处理,Processor 是对应用层协议的抽象。
Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AJPProcessor、HTTP11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式。
-
+
从图中我们看到,EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。
-#### Adapter
+#### 3.2.2. Adapter
**连接器通过适配器 Adapter 调用容器**。
@@ -475,13 +466,13 @@ Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。
- **Context** - Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管理所有的 Web 资源;
- **Wrapper** - 最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创 建、执行和销毁。
-#### 请求分发 Servlet 过程
+#### 3.3.1. 请求分发 Servlet 过程
Tomcat 是怎么确定请求是由哪个 Wrapper 容器里的 Servlet 来处理的呢?答案是,Tomcat 是用 Mapper 组件来完成这个任务的。
举例来说,假如有一个网购系统,有面向网站管理人员的后台管理系统,还有面向终端客户的在线购物系统。这两个系统跑在同一个 Tomcat 上,为了隔离它们的访问域名,配置了两个虚拟域名:`manage.shopping.com`和`user.shopping.com`,网站管理人员通过`manage.shopping.com`域名访问 Tomcat 去管理用户和商品,而用户管理和商品管理是两个单独的 Web 应用。终端客户通过`user.shopping.com`域名去搜索商品和下订单,搜索功能和订单管理也是两个独立的 Web 应用。如下所示,演示了 url 应声 Servlet 的处理流程。
-
+
假如有用户访问一个 URL,比如图中的`http://user.shopping.com:8080/order/buy`,Tomcat 如何将这个 URL 定位到一个 Servlet 呢?
@@ -492,7 +483,7 @@ Tomcat 是怎么确定请求是由哪个 Wrapper 容器里的 Servlet 来处理
这个路由分发过程具体是怎么实现的呢?答案是使用 Pipeline-Valve 管道。
-#### Pipeline-Value
+#### 3.3.2. Pipeline-Value
Pipeline 可以理解为现实中的管道,Valve 为管道中的阀门,Request 和 Response 对象在管道中经过各个阀门的处理和控制。
@@ -500,7 +491,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理
先来了解一下 Valve 和 Pipeline 接口的设计:
-
+
- 每一个容器都有一个 Pipeline 对象,只要触发这个 Pipeline 的第一个 Valve,这个容器里 Pipeline 中的 Valve 就都会被调用到。但是,不同容器的 Pipeline 是怎么链式触发的呢,比如 Engine 中 Pipeline 需要调用下层容器 Host 中的 Pipeline。
- 这是因为 Pipeline 中还有个 getBasic 方法。这个 BasicValve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。
@@ -509,7 +500,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理
- 各层容器对应的 basic valve 分别是 `StandardEngineValve`、`StandardHostValve`、 `StandardContextValve`、`StandardWrapperValve`。
- 由于 Valve 是一个处理点,因此 invoke 方法就是来处理请求的。注意到 Valve 中有 getNext 和 setNext 方法,因此我们大概可以猜到有一个链表将 Valve 链起来了。
-
+
整个调用过程由连接器中的 Adapter 触发的,它会调用 Engine 的第一个 Valve:
@@ -521,7 +512,7 @@ connector.getService().getContainer().getPipeline().getFirst().invoke(request, r
### 4.1. Tomcat 的启动过程
-
+
1. Tomcat 是一个 Java 程序,它的运行从执行 `startup.sh` 脚本开始。`startup.sh` 会启动一个 JVM 来运行 Tomcat 的启动类 `Bootstrap`。
2. `Bootstrap` 会初始化 Tomcat 的类加载器并实例化 `Catalina`。
@@ -529,7 +520,7 @@ connector.getService().getContainer().getPipeline().getFirst().invoke(request, r
4. `Server` 负责管理 `Service` 组件,它会调用 `Service` 的 `start` 方法。
5. `Service` 负责管理 `Connector` 和顶层容器 `Engine`,它会调用 `Connector` 和 `Engine` 的 `start` 方法。
-#### Catalina 组件
+#### 4.1.1. Catalina 组件
Catalina 的职责就是解析 server.xml 配置,并据此实例化 Server。接下来,调用 Server 组件的 init 方法和 start 方法,将 Tomcat 启动起来。
@@ -595,7 +586,7 @@ protected class CatalinaShutdownHook extends Thread {
Tomcat 的“关闭钩子”实际上就执行了 `Server` 的 `stop` 方法,`Server` 的 `stop` 方法会释放和清理所有的资源。
-#### Server 组件
+#### 4.1.2. Server 组件
Server 组件的具体实现类是 StandardServer,Server 继承了 LifeCycleBase,它的生命周期被统一管理,并且它的子组件是 Service,因此它还需要管理 Service 的生命周期,也就是说在启动时调用 Service 组件的启动方法,在停止时调用它们的停止方法。Server 在内部维护了若干 Service 组件,它是以数组来保存的。
@@ -636,7 +627,7 @@ Server 并没有一开始就分配一个很长的数组,而是在添加的过
在 await 方法里会创建一个 Socket 监听 8005 端口,并在一个死循环里接收 Socket 上的连接请求,如果有新的连接到来就建立连接,然后从 Socket 中读取数据;如果读到的数据是停止命令“SHUTDOWN”,就退出循环,进入 stop 流程。
-#### Service 组件
+#### 4.1.3. Service 组件
Service 组件的具体实现类是 StandardService。
@@ -700,7 +691,7 @@ protected void startInternal() throws LifecycleException {
从启动方法可以看到,Service 先启动了 Engine 组件,再启动 Mapper 监听器,最后才是启动连接器。这很好理解,因为内层组件启动好了才能对外提供服务,才能启动外层的连接器组件。而 Mapper 也依赖容器组件,容器组件启动好了才能监听它们的变化,因此 Mapper 和 MapperListener 在容器组件之后启动。组件停止的顺序跟启动顺序正好相反的,也是基于它们的依赖关系。
-#### Engine 组件
+#### 4.1.4. Engine 组件
Engine 本质是一个容器,因此它继承了 ContainerBase 基类,并且实现了 Engine 接口。
@@ -741,12 +732,12 @@ ContextConfig 解析 web.xml 顺序:
### 4.3. LifeCycle
-
+
-#### 4.2.3. 请求处理过程
+#### 4.3.1. 请求处理过程
-

+
1. 根据 server.xml 配置的指定的 connector 以及端口监听 http、或者 ajp 请求
@@ -757,35 +748,35 @@ ContextConfig 解析 web.xml 顺序:
### 4.4. Connector 流程
-

+
-#### 4.3.1. 阻塞 IO
+#### 4.4.1. 阻塞 IO
-

+
-#### 4.3.2. 非阻塞 IO
+#### 4.4.2. 非阻塞 IO
-

+
-#### 4.3.3. IO 多路复用
+#### 4.4.3. IO 多路复用
-

+
阻塞与非阻塞的区别在于进行读操作和写操作的系统调用时,如果此时内核态没有数据可读或者没有缓冲空间可写时,是否阻塞。
IO 多路复用的好处在于可同时监听多个 socket 的可读和可写事件,这样就能使得应用可以同时监听多个 socket,释放了应用线程资源。
-#### 4.3.4. Tomcat 各类 Connector 对比
+#### 4.4.4. Tomcat 各类 Connector 对比
-

+
- JIO:用 java.io 编写的 TCP 模块,阻塞 IO
@@ -806,7 +797,7 @@ Apache Portable Runtime 是一个高度可移植的库,它是 Apache HTTP Serv
**NIO 处理相关类**
-

+
Poller 线程从 EventQueue 获取 PollerEvent,并执行 PollerEvent 的 run 方法,调用 Selector 的 select 方法,如果有可读的 Socket 则创建 Http11NioProcessor,放入到线程池中执行;
@@ -839,7 +830,7 @@ Note:
### 4.6. 异步 Servlet
-

+
传统流程:
@@ -849,7 +840,7 @@ Note:
- 最后,根据处理的结果提交响应,Servlet 线程结束
-

+
异步处理流程:
@@ -892,4 +883,4 @@ onComplete 执行后,就不可再操作 request 和 response
- [Creating a Web App with Bootstrap and Tomcat Embedded](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/basic_app_embedded_tomcat/basic_app-tomcat-embedded.html)
- [Tomcat 组成与工作原理](https://juejin.im/post/58eb5fdda0bb9f00692a78fc)
- [Tomcat 工作原理](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/index.html)
- - [Tomcat 设计模式分析](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/index.html?ca=drs-)
+ - [Tomcat 设计模式分析](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/index.html?ca=drs-)
\ No newline at end of file
diff --git "a/docs/server/Tomcat\350\277\236\346\216\245\345\231\250.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
similarity index 95%
rename from "docs/server/Tomcat\350\277\236\346\216\245\345\231\250.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
index c90c3845..fbf9fe8e 100644
--- "a/docs/server/Tomcat\350\277\236\346\216\245\345\231\250.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
@@ -1,33 +1,27 @@
-# Tomcat 连接器
+---
+title: Tomcat连接器
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+permalink: /pages/13f070/
+---
-
-
-- [1. NioEndpoint 组件](#1-nioendpoint-组件)
- - [1.1. LimitLatch](#11-limitlatch)
- - [1.2. Acceptor](#12-acceptor)
- - [1.3. Poller](#13-poller)
- - [1.4. SocketProcessor](#14-socketprocessor)
-- [2. Nio2Endpoint 组件](#2-nio2endpoint-组件)
- - [2.1. Nio2Acceptor](#21-nio2acceptor)
- - [2.2. Nio2SocketWrapper](#22-nio2socketwrapper)
-- [3. AprEndpoint 组件](#3-aprendpoint-组件)
- - [3.1. AprEndpoint 工作流程](#31-aprendpoint-工作流程)
- - [3.2. APR 提升性能的秘密](#32-apr-提升性能的秘密)
-- [4. Executor 组件](#4-executor-组件)
- - [4.1. Tomcat 定制线程池](#41-tomcat-定制线程池)
- - [4.2. Tomcat 定制任务队列](#42-tomcat-定制任务队列)
-- [5. WebSocket 组件](#5-websocket-组件)
- - [5.1. WebSocket 加载](#51-websocket-加载)
- - [5.2. WebSocket 请求处理](#52-websocket-请求处理)
-- [6. 参考资料](#6-参考资料)
-
-
+# Tomcat 连接器
## 1. NioEndpoint 组件
Tomcat 的 NioEndPoint 组件利用 Java NIO 实现了 I/O 多路复用模型。
-
+
NioEndPoint 子组件功能简介:
@@ -130,7 +124,7 @@ private final SynchronizedQueue events = new SynchronizedQueue<>();
Nio2Endpoint 工作流程跟 NioEndpoint 较为相似。
-
+
Nio2Endpoint 子组件功能说明:
@@ -225,9 +219,9 @@ Tomcat 本身是 Java 编写的,为了调用 C 语言编写的 APR,需要通
### 3.1. AprEndpoint 工作流程
-
+
-#### Acceptor
+#### 3.1.1. Acceptor
Accpetor 的功能就是监听连接,接收并建立连接。它的本质就是调用了四个操作系统 API:socket、bind、listen 和 accept。那 Java 语言如何直接调用 C 语言 API 呢?答案就是通过 JNI。具体来说就是两步:先封装一个 Java 类,在里面定义一堆用**native 关键字**修饰的方法,像下面这样。
@@ -265,7 +259,7 @@ Java_org_apache_tomcat_jni_Socket_bind(JNIEnv *e, jlong sock,jlong sa)
专栏里我就不展开 JNI 的细节了,你可以[扩展阅读](http://jnicookbook.owsiak.org/contents/)获得更多信息和例子。我们要注意的是函数名字要符合 JNI 的规范,以及 Java 和 C 语言如何互相传递参数,比如在 C 语言有指针,Java 没有指针的概念,所以在 Java 中用 long 类型来表示指针。AprEndpoint 的 Acceptor 组件就是调用了 APR 实现的四个 API。
-#### Poller
+#### 3.1.2. Poller
Acceptor 接收到一个新的 Socket 连接后,按照 NioEndpoint 的实现,它会把这个 Socket 交给 Poller 去查询 I/O 事件。AprEndpoint 也是这样做的,不过 AprEndpoint 的 Poller 并不是调用 Java NIO 里的 Selector 来查询 Socket 的状态,而是通过 JNI 调用 APR 中的 poll 方法,而 APR 又是调用了操作系统的 epoll API 来实现的。
@@ -289,7 +283,7 @@ java my.class
这个命令行中的`java`其实是**一个可执行程序,这个程序会创建 JVM 来加载和运行你的 Java 类**。操作系统会创建一个进程来执行这个`java`可执行程序,而每个进程都有自己的虚拟地址空间,JVM 用到的内存(包括堆、栈和方法区)就是从进程的虚拟地址空间上分配的。请你注意的是,JVM 内存只是进程空间的一部分,除此之外进程空间内还有代码段、数据段、内存映射区、内核空间等。从 JVM 的角度看,JVM 内存之外的部分叫作本地内存,C 程序代码在运行过程中用到的内存就是本地内存中分配的。下面我们通过一张图来理解一下。
-
+
Tomcat 的 Endpoint 组件在接收网络数据时需要预先分配好一块 Buffer,所谓的 Buffer 就是字节数组`byte[]`,Java 通过 JNI 调用把这块 Buffer 的地址传给 C 代码,C 代码通过操作系统 API 读取 Socket 并把数据填充到这块 Buffer。Java NIO API 提供了两种 Buffer 来接收数据:HeapByteBuffer 和 DirectByteBuffer,下面的代码演示了如何创建两种 Buffer。
@@ -314,7 +308,7 @@ int bytesRead = socketChannel.read(buf);
Tomcat 中的 AprEndpoint 就是通过 DirectByteBuffer 来接收数据的,而 NioEndpoint 和 Nio2Endpoint 是通过 HeapByteBuffer 来接收数据的。你可能会问,NioEndpoint 和 Nio2Endpoint 为什么不用 DirectByteBuffer 呢?这是因为本地内存不好管理,发生内存泄漏难以定位,从稳定性考虑,NioEndpoint 和 Nio2Endpoint 没有去冒这个险。
-#### sendfile
+#### 3.2.1. sendfile
我们再来考虑另一个网络通信的场景,也就是静态文件的处理。浏览器通过 Tomcat 来获取一个 HTML 文件,而 Tomcat 的处理逻辑无非是两步:
@@ -330,7 +324,7 @@ Tomcat 中的 AprEndpoint 就是通过 DirectByteBuffer 来接收数据的,而
从下面的图你会发现这个过程有 6 次内存拷贝,并且 read 和 write 等系统调用将导致进程从用户态到内核态的切换,会耗费大量的 CPU 和内存资源。
-
+
而 Tomcat 的 AprEndpoint 通过操作系统层面的 sendfile 特性解决了这个问题,sendfile 系统调用方式非常简洁。
@@ -344,7 +338,7 @@ sendfile(socket, file, len);
第二步:数据并没有从内核缓冲区复制到 Socket 关联的缓冲区,只有记录数据位置和长度的描述符被添加到 Socket 缓冲区中;接着把数据直接从内核缓冲区传递给网卡。这个过程你可以看下面的图。
-
+
## 4. Executor 组件
@@ -515,7 +509,7 @@ Tomcat 用 ProtocolHandler 组件屏蔽应用层协议的差异,其中 Protoco
WebSocket 是通过 HTTP 协议来进行握手的,因此当 WebSocket 的握手请求到来时,HttpProtocolHandler 首先接收到这个请求,在处理这个 HTTP 请求时,Tomcat 通过一个特殊的 Filter 判断该当前 HTTP 请求是否是一个 WebSocket Upgrade 请求(即包含`Upgrade: websocket`的 HTTP 头信息),如果是,则在 HTTP 响应里添加 WebSocket 相关的响应头信息,并进行协议升级。具体来说就是用 UpgradeProtocolHandler 替换当前的 HttpProtocolHandler,相应的,把当前 Socket 的 Processor 替换成 UpgradeProcessor,同时 Tomcat 会创建 WebSocket Session 实例和 Endpoint 实例,并跟当前的 WebSocket 连接一一对应起来。这个 WebSocket 连接不会立即关闭,并且在请求处理中,不再使用原有的 HttpProcessor,而是用专门的 UpgradeProcessor,UpgradeProcessor 最终会调用相应的 Endpoint 实例来处理请求。
-
+
你可以看到,Tomcat 对 WebSocket 请求的处理没有经过 Servlet 容器,而是通过 UpgradeProcessor 组件直接把请求发到 ServerEndpoint 实例,并且 Tomcat 的 WebSocket 实现不需要关注具体 I/O 模型的细节,从而实现了与具体 I/O 方式的解耦。
@@ -526,4 +520,4 @@ WebSocket 是通过 HTTP 协议来进行握手的,因此当 WebSocket 的握
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git "a/docs/server/Tomcat\345\256\271\345\231\250.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
similarity index 95%
rename from "docs/server/Tomcat\345\256\271\345\231\250.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
index f572bb6c..0f71d9ce 100644
--- "a/docs/server/Tomcat\345\256\271\345\231\250.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
@@ -1,28 +1,23 @@
+---
+title: Tomcat容器
+date: 2022-02-17 22:34:30
+order: 03
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+permalink: /pages/d5076a/
+---
+
# Tomcat 容器
-
-
-- [1. Tomcat 实现热部署和热加载](#1-tomcat-实现热部署和热加载)
- - [1.1. ContainerBackgroundProcessor 实现](#11-containerbackgroundprocessor-实现)
- - [1.2. backgroundProcess 方法](#12-backgroundprocess-方法)
- - [1.3. Tomcat 热加载](#13-tomcat-热加载)
- - [1.4. Tomcat 热部署](#14-tomcat-热部署)
-- [2. Tomcat 的类加载机制](#2-tomcat-的类加载机制)
- - [2.1. findClass 方法](#21-findclass-方法)
- - [2.2. loadClass 方法](#22-loadclass-方法)
- - [2.3. Tomcat 实现应用隔离](#23-tomcat-实现应用隔离)
-- [3. Tomcat 实现 Servlet 规范](#3-tomcat-实现-servlet-规范)
- - [3.1. Servlet 管理](#31-servlet-管理)
- - [3.2. Filter 管理](#32-filter-管理)
- - [3.3. Listener 管理](#33-listener-管理)
-- [4. Tomcat 支持异步 Servlet](#4-tomcat-支持异步servlet)
- - [4.1. 异步示例](#41-异步示例)
- - [4.2. 异步 Servlet 原理](#42-异步-servlet-原理)
-- [5. 参考资料](#5-参考资料)
-
-
-
-## 1. Tomcat 实现热部署和热加载
+## Tomcat 实现热部署和热加载
- 热加载的实现方式是 Web 容器启动一个后台线程,定期检测类文件的变化,如果有变化,就重新加载类,在这个过程中不会清空 Session ,一般用在开发环境。
- 热部署原理类似,也是由后台线程定时检测 Web 应用的变化,但它会重新加载整个 Web 应用。这种方式会清空 Session,比热加载更加干净、彻底,一般用在生产环境。
@@ -39,7 +34,7 @@ bgFuture = exec.scheduleWithFixedDelay(
第一个参数就是要周期性执行的任务类 ContainerBackgroundProcessor,它是一个 Runnable,同时也是 ContainerBase 的内部类,ContainerBase 是所有容器组件的基类,我们来回忆一下容器组件有哪些,有 Engine、Host、Context 和 Wrapper 等,它们具有父子关系。
-### 1.1. ContainerBackgroundProcessor 实现
+### ContainerBackgroundProcessor 实现
我们接来看 ContainerBackgroundProcessor 具体是如何实现的。
@@ -75,7 +70,7 @@ protected class ContainerBackgroundProcessor implements Runnable {
这样的设计意味着什么呢?我们只需要在顶层容器,也就是 Engine 容器中启动一个后台线程,那么这个线程**不但会执行 Engine 容器的周期性任务,它还会执行所有子容器的周期性任务**。
-### 1.2. backgroundProcess 方法
+### backgroundProcess 方法
上述代码都是在基类 ContainerBase 中实现的,那具体容器类需要做什么呢?其实很简单,如果有周期性任务要执行,就实现 backgroundProcess 方法;如果没有,就重用基类 ContainerBase 的方法。ContainerBase 的 backgroundProcess 方法实现如下:
@@ -116,7 +111,7 @@ public void backgroundProcess() {
总之,有了 ContainerBase 中的后台线程和 backgroundProcess 方法,各种子容器和通用组件不需要各自弄一个后台线程来处理周期性任务,这样的设计显得优雅和整洁。
-### 1.3. Tomcat 热加载
+### Tomcat 热加载
有了 ContainerBase 的周期性任务处理“框架”,作为具体容器子类,只需要实现自己的周期性任务就行。而 Tomcat 的热加载,就是在 Context 容器中实现的。Context 容器的 backgroundProcess 方法是这样实现的:
@@ -164,7 +159,7 @@ public void backgroundProcess() {
```
-### 1.4. Tomcat 热部署
+### Tomcat 热部署
我们再来看看热部署,热部署跟热加载的本质区别是,热部署会重新部署 Web 应用,原来的 Context 对象会整个被销毁掉,因此这个 Context 所关联的一切资源都会被销毁,包括 Session。
@@ -209,11 +204,11 @@ protected void check() {
因此 HostConfig 做的事情都是比较“宏观”的,它不会去检查具体类文件或者资源文件是否有变化,而是检查 Web 应用目录级别的变化。
-## 2. Tomcat 的类加载机制
+## Tomcat 的类加载机制
Tomcat 的自定义类加载器 `WebAppClassLoader` 打破了双亲委派机制,它**首先自己尝试去加载某个类,如果找不到再代理给父类加载器**,其目的是优先加载 Web 应用自己定义的类。具体实现就是重写 ClassLoader 的两个方法:findClass 和 loadClass。
-### 2.1. findClass 方法
+### findClass 方法
我们先来看看 findClass 方法的实现,为了方便理解和阅读,我去掉了一些细节:
@@ -252,7 +247,7 @@ public Class> findClass(String name) throws ClassNotFoundException {
2. 如果没有找到,交给父加载器去查找,它的父加载器就是上面提到的系统类加载器 AppClassLoader。
3. 如何父加载器也没找到这个类,抛出 ClassNotFound 异常。
-### 2.2. loadClass 方法
+### loadClass 方法
接着我们再来看 Tomcat 类加载器的 loadClass 方法的实现,同样我也去掉了一些细节:
@@ -333,7 +328,7 @@ loadClass 方法稍微复杂一点,主要有六个步骤:
从上面的过程我们可以看到,Tomcat 的类加载器打破了双亲委派机制,没有一上来就直接委托给父加载器,而是先在本地目录下加载,为了避免本地目录下的类覆盖 JRE 的核心类,先尝试用 JVM 扩展类加载器 ExtClassLoader 去加载。那为什么不先用系统类加载器 AppClassLoader 去加载?很显然,如果是这样的话,那就变成双亲委派机制了,这就是 Tomcat 类加载器的巧妙之处。
-### 2.3. Tomcat 实现应用隔离
+### Tomcat 实现应用隔离
Tomcat 作为 Web 容器,需要解决以下问题:
@@ -341,7 +336,7 @@ Tomcat 作为 Web 容器,需要解决以下问题:
2. 两个 Web 应用都依赖同一个第三方的 JAR 包,比如 Spring,那 Spring 的 JAR 包被加载到内存后,Tomcat 要保证这两个 Web 应用能够共享,也就是说 Spring 的 JAR 包只被加载一次,否则随着依赖的第三方 JAR 包增多,JVM 的内存会膨胀。
3. 需要隔离 Tomcat 本身的类和 Web 应用的类。
-
+
#### WebAppClassLoader
@@ -367,7 +362,7 @@ Tomcat 的解决方案是自定义一个类加载器 WebAppClassLoader, 并且
老办法,还是再增加一个 CommonClassLoader,作为 CatalinaClassloader 和 SharedClassLoader 的父加载器。CommonClassLoader 能加载的类都可以被 CatalinaClassLoader 和 SharedClassLoader 使用,而 CatalinaClassLoader 和 SharedClassLoader 能加载的类则与对方相互隔离。WebAppClassLoader 可以使用 SharedClassLoader 加载到的类,但各个 WebAppClassLoader 实例之间相互隔离。
-## 3. Tomcat 实现 Servlet 规范
+## Tomcat 实现 Servlet 规范
Servlet 容器最重要的任务就是创建 Servlet 的实例并且调用 Servlet。
@@ -377,7 +372,7 @@ Servlet 容器最重要的任务就是创建 Servlet 的实例并且调用 Servl
除此以外,Servlet 规范中还有两个重要特性:Listener 和 Filter,Tomcat 也需要创建它们的实例,并在合适的时机去调用它们的方法。
-### 3.1. Servlet 管理
+### Servlet 管理
Tomcat 是用 Wrapper 容器来管理 Servlet 的,那 Wrapper 容器具体长什么样子呢?我们先来看看它里面有哪些关键的成员变量:
@@ -439,7 +434,7 @@ StandardWrapperValve 的 invoke 方法比较复杂,去掉其他异常处理的
接下来我们来看 Filter 的实现原理。
-### 3.2. Filter 管理
+### Filter 管理
我们知道,跟 Servlet 一样,Filter 也可以在`web.xml`文件里进行配置,不同的是,Filter 的作用域是整个 Web 应用,因此 Filter 的实例是在 Context 容器中进行管理的,Context 容器用 Map 集合来保存 Filter。
@@ -512,7 +507,7 @@ public void doFilter(ServletRequest request, ServletResponse response,
Filter 链跟 Tomcat 的 Pipeline-Valve 本质都是责任链模式,但是在具体实现上稍有不同,你可以细细体会一下。
-### 3.3. Listener 管理
+### Listener 管理
我们接着聊 Servlet 规范里 Listener。跟 Filter 一样,Listener 也是一种扩展机制,你可以监听容器内部发生的事件,主要有两类事件:
@@ -550,9 +545,9 @@ for (int i = 0; i < instances.length; i++) {
需要注意的是,这里的 ServletContextListener 接口是一种留给用户的扩展机制,用户可以实现这个接口来定义自己的监听器,监听 Context 容器的启停事件。Spring 就是这么做的。ServletContextListener 跟 Tomcat 自己的生命周期事件 LifecycleListener 是不同的。LifecycleListener 定义在生命周期管理组件中,由基类 LifeCycleBase 统一管理。
-## 4. Tomcat 支持异步 Servlet
+## Tomcat 支持异步 Servlet
-### 4.1. 异步示例
+### 异步示例
```java
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
@@ -593,7 +588,7 @@ public class AsyncServlet extends HttpServlet {
这里请你注意,虽然异步 Servlet 允许用更长的时间来处理请求,但是也有超时限制的,默认是 30 秒,如果 30 秒内请求还没处理完,Tomcat 会触发超时机制,向浏览器返回超时错误,如果这个时候你的 Web 应用再调用`ctx.complete`方法,会得到一个 IllegalStateException 异常。
-### 4.2. 异步 Servlet 原理
+### 异步 Servlet 原理
通过上面的例子,相信你对 Servlet 的异步实现有了基本的理解。要理解 Tomcat 在这个过程都做了什么事情,关键就是要弄清楚`req.startAsync`方法和`ctx.complete`方法都做了什么。
@@ -723,11 +718,11 @@ public boolean processSocket(SocketWrapperBase socketWrapper,
请你注意 createSocketProcessor 函数的第二个参数是 SocketEvent,这里我们传入的是 OPEN_READ。通过这个参数,我们就能控制 SocketProcessor 的行为,因为我们不需要再把请求发送到容器进行处理,只需要向浏览器端发送数据,并且重新在这个 Socket 上监听新的请求就行了。
-## 5. 参考资料
+## 参考资料
- **官方**
- [Tomcat 官方网站](http://tomcat.apache.org/)
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git "a/docs/server/Tomcat\344\274\230\345\214\226.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
similarity index 88%
rename from "docs/server/Tomcat\344\274\230\345\214\226.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
index 259ef5e4..3beb96e8 100644
--- "a/docs/server/Tomcat\344\274\230\345\214\226.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
@@ -1,32 +1,34 @@
-# Tomcat 优化
-
-
+---
+title: Tomcat优化
+date: 2022-02-17 22:34:30
+order: 04
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+permalink: /pages/f9e1e6/
+---
-- [1. Tomcat 启动优化](#1-tomcat-启动优化)
- - [1.1. 清理 Tomcat](#11-清理-tomcat)
- - [1.2. 禁止 Tomcat TLD 扫描](#12-禁止-tomcat-tld-扫描)
- - [1.3. 关闭 WebSocket 支持](#13-关闭-websocket-支持)
- - [1.4. 关闭 JSP 支持](#14-关闭-jsp-支持)
- - [1.5. 禁止扫描 Servlet 注解](#15-禁止扫描-servlet-注解)
- - [1.6. 配置 Web-Fragment 扫描](#16-配置-web-fragment-扫描)
- - [1.7. 随机数熵源优化](#17-随机数熵源优化)
- - [1.8. 并行启动多个 Web 应用](#18-并行启动多个-web-应用)
-- [2. 参考资料](#2-参考资料)
-
-
+# Tomcat 优化
-## 1. Tomcat 启动优化
+## Tomcat 启动优化
如果 Tomcat 启动比较慢,可以考虑一些优化点
-### 1.1. 清理 Tomcat
+### 清理 Tomcat
- **清理不必要的 Web 应用**:首先我们要做的是删除掉 webapps 文件夹下不需要的工程,一般是 host-manager、example、doc 等这些默认的工程,可能还有以前添加的但现在用不着的工程,最好把这些全都删除掉。
- **清理 XML 配置文件**:Tomcat 在启动时会解析所有的 XML 配置文件,解析 XML 较为耗时,所以应该尽量保持配置文件的简洁。
- **清理 JAR 文件**:JVM 的类加载器在加载类时,需要查找每一个 JAR 文件,去找到所需要的类。如果删除了不需要的 JAR 文件,查找的速度就会快一些。这里请注意:**Web 应用中的 lib 目录下不应该出现 Servlet API 或者 Tomcat 自身的 JAR**,这些 JAR 由 Tomcat 负责提供。
- **清理其他文件**:及时清理日志,删除 logs 文件夹下不需要的日志文件。同样还有 work 文件夹下的 catalina 文件夹,它其实是 Tomcat 把 JSP 转换为 Class 文件的工作目录。有时候我们也许会遇到修改了代码,重启了 Tomcat,但是仍没效果,这时候便可以删除掉这个文件夹,Tomcat 下次启动的时候会重新生成。
-### 1.2. 禁止 Tomcat TLD 扫描
+### 禁止 Tomcat TLD 扫描
Tomcat 为了支持 JSP,在应用启动的时候会扫描 JAR 包里面的 TLD 文件,加载里面定义的标签库。所以在 Tomcat 的启动日志里,你可能会碰到这种提示:
@@ -52,7 +54,7 @@ Tomcat 的意思是,我扫描了你 Web 应用下的 JAR 包,发现 JAR 包
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=xxx.jar
```
-### 1.3. 关闭 WebSocket 支持
+### 关闭 WebSocket 支持
Tomcat 会扫描 WebSocket 注解的 API 实现,比如 `@ServerEndpoint` 注解的类。如果不需要使用 WebSockets 就可以关闭它。具体方法是,找到 Tomcat 的 `conf/` 目录下的 `context.xml` 文件,给 `Context` 标签加一个 **`containerSciFilter`** 的属性:
@@ -64,7 +66,7 @@ Tomcat 会扫描 WebSocket 注解的 API 实现,比如 `@ServerEndpoint` 注
更进一步,如果你不需要 WebSockets 这个功能,你可以把 Tomcat `lib` 目录下的 `websocket-api.jar` 和 `tomcat-websocket.jar` 这两个 JAR 文件删除掉,进一步提高性能。
-### 1.4. 关闭 JSP 支持
+### 关闭 JSP 支持
如果不需要使用 JSP,可以关闭 JSP 功能:
@@ -82,7 +84,7 @@ Tomcat 会扫描 WebSocket 注解的 API 实现,比如 `@ServerEndpoint` 注
```
-### 1.5. 禁止扫描 Servlet 注解
+### 禁止扫描 Servlet 注解
Servlet 3.0 引入了注解 Servlet,Tomcat 为了支持这个特性,会在 Web 应用启动时扫描你的类文件,因此如果你没有使用 Servlet 注解这个功能,可以告诉 Tomcat 不要去扫描 Servlet 注解。具体配置方法是,在你的 Web 应用的`web.xml`文件中,设置``元素的属性`metadata-complete="true"`,像下面这样。
@@ -93,7 +95,7 @@ Servlet 3.0 引入了注解 Servlet,Tomcat 为了支持这个特性,会在 W
`metadata-complete` 的意思是,`web.xml` 里配置的 Servlet 是完整的,不需要再去库类中找 Servlet 的定义。
-### 1.6. 配置 Web-Fragment 扫描
+### 配置 Web-Fragment 扫描
Servlet 3.0 还引入了“Web 模块部署描述符片段”的 `web-fragment.xml`,这是一个部署描述文件,可以完成 `web.xml` 的配置功能。而这个 `web-fragment.xml` 文件必须存放在 JAR 文件的 `META-INF` 目录下,而 JAR 包通常放在 `WEB-INF/lib` 目录下,因此 Tomcat 需要对 JAR 文件进行扫描才能支持这个功能。
@@ -107,7 +109,7 @@ Servlet 3.0 还引入了“Web 模块部署描述符片段”的 `web-fragment.x
```
-### 1.7. 随机数熵源优化
+### 随机数熵源优化
Tomcat 7 以上的版本依赖 Java 的 SecureRandom 类来生成随机数,比如 Session ID。而 JVM 默认使用阻塞式熵源(`/dev/random`), 在某些情况下就会导致 Tomcat 启动变慢。当阻塞时间较长时, 你会看到这样一条警告日志:
@@ -128,7 +130,7 @@ INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRN
这里请你注意,`/dev/./urandom` 中间有个 `./` 的原因是 Oracle JRE 中的 Bug,Java 8 里面的 SecureRandom 类已经修正这个 Bug。 阻塞式的熵源(`/dev/random`)安全性较高, 非阻塞式的熵源(`/dev/./urandom`)安全性会低一些,因为如果你对随机数的要求比较高, 可以考虑使用硬件方式生成熵源。
-### 1.8. 并行启动多个 Web 应用
+### 并行启动多个 Web 应用
Tomcat 启动的时候,默认情况下 Web 应用都是一个一个启动的,等所有 Web 应用全部启动完成,Tomcat 才算启动完毕。如果在一个 Tomcat 下有多个 Web 应用,为了优化启动速度,你可以配置多个应用程序并行启动,可以通过修改 `server.xml` 中 Host 元素的 `startStopThreads` 属性来完成。`startStopThreads` 的值表示你想用多少个线程来启动你的 Web 应用,如果设成 0 表示你要并行启动 Web 应用,像下面这样的配置。
@@ -144,11 +146,11 @@ Tomcat 启动的时候,默认情况下 Web 应用都是一个一个启动的
需要注意的是,Engine 元素里也配置了这个参数,这意味着如果你的 Tomcat 配置了多个 Host(虚拟主机),Tomcat 会以并行的方式启动多个 Host。
-## 2. 参考资料
+## 参考资料
- **官方**
- [Tomcat 官方网站](http://tomcat.apache.org/)
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git a/docs/server/tomcat-and-jetty.md "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
similarity index 80%
rename from docs/server/tomcat-and-jetty.md
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
index b7ca24d8..a841530f 100644
--- a/docs/server/tomcat-and-jetty.md
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
@@ -1,6 +1,24 @@
+---
+title: Tomcat 和 Jetty
+date: 2022-02-17 22:34:30
+order: 05
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+ - Jetty
+permalink: /pages/f37326/
+---
+
## Tomcat 和 Jetty
-Web容器Tomcat或Jetty,作为重要的系统中间件,连接着浏览器和你的Web应用,并且支撑着Web程序的运行,可以说,**弄懂了Tomcat和Jetty的原理,Java Web开发对你来说就毫无秘密可言**。
+Web 容器 Tomcat 或 Jetty,作为重要的系统中间件,连接着浏览器和你的 Web 应用,并且支撑着 Web 程序的运行,可以说,**弄懂了 Tomcat 和 Jetty 的原理,Java Web 开发对你来说就毫无秘密可言**。
## Web 容器
diff --git "a/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
new file mode 100644
index 00000000..6204b0c8
--- /dev/null
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
@@ -0,0 +1,36 @@
+---
+title: Tomcat 教程
+date: 2022-02-18 08:53:11
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+ - Tomcat
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Tomcat
+permalink: /pages/33e817/
+hidden: true
+index: false
+---
+
+# Tomcat 教程
+
+## 📖 内容
+
+- [Tomcat 快速入门](01.Tomcat快速入门.md)
+- [Tomcat 连接器](02.Tomcat连接器.md)
+- [Tomcat 容器](03.Tomcat容器.md)
+- [Tomcat 优化](04.Tomcat优化.md)
+- [Tomcat 和 Jetty](05.Tomcat和Jetty.md)
+
+## 📚 资料
+
+- [Tomcat 官网](http://tomcat.apache.org/)
+- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+
+## 🚪 传送
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/server/jetty.md "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
similarity index 98%
rename from docs/server/jetty.md
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
index b884d07f..db02b55c 100644
--- a/docs/server/jetty.md
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
@@ -1,24 +1,22 @@
-# Jetty 应用指南
-
-
-
-- [1. Jetty 简介](#1-jetty-简介)
-- [2. Jetty 的使用](#2-jetty-的使用)
- - [2.1. API 方式](#21-api-方式)
- - [2.2. Maven 插件方式](#22-maven-插件方式)
-- [3. Jetty 的架构](#3-jetty-的架构)
- - [3.1. Jetty 架构简介](#31-jetty-架构简介)
- - [3.2. Jetty 和 Tomcat 架构区别](#32-jetty-和-tomcat-架构区别)
- - [3.3. Connector 组件](#33-connector-组件)
- - [3.4. Handler 组件](#34-handler-组件)
-- [4. Jetty 的线程策略](#4-jetty-的线程策略)
- - [4.1. 传统 Selector 编程模型](#41-传统-selector-编程模型)
- - [4.2. Jetty 的 Selector 编程模型](#42-jetty-的-selector-编程模型)
-- [5. 参考资料](#5-参考资料)
-
-
-
-## 1. Jetty 简介
+---
+title: Jetty 快速入门
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+ - Jetty
+permalink: /pages/ec364e/
+---
+
+# Jetty 快速入门
+
+## Jetty 简介
**jetty 是什么?**
@@ -42,7 +40,7 @@ jetty 是轻量级的 web 服务器和 servlet 引擎。
jetty 非常适用于项目的开发、测试,因为非常快捷。如果想用于生产环境,则需要谨慎考虑,它不一定能像成熟的 Tomcat、Resin 等服务器一样支持企业级 Java EE 的需要。
-## 2. Jetty 的使用
+## Jetty 的使用
我觉得嵌入式启动方式的一个好处在于:可以直接运行项目,无需每次部署都得再配置服务器。
@@ -52,7 +50,7 @@ API 方式
maven 插件方式
-### 2.1. API 方式
+### API 方式
添加 maven 依赖
@@ -143,7 +141,7 @@ public class SplitFileServer
[完整参考代码](https://github.com/dunwu/spring-notes)
-### 2.2. Maven 插件方式
+### Maven 插件方式
如果你熟悉 maven,那么实在太简单了
@@ -252,11 +250,11 @@ mvn jetty:run
```
-## 3. Jetty 的架构
+## Jetty 的架构
-### 3.1. Jetty 架构简介
+### Jetty 架构简介
-
+
Jetty Server 就是由多个 Connector(连接器)、多个 Handler(处理器),以及一个线程池组成。
@@ -266,13 +264,13 @@ Jetty Server 可以有多个 Connector 在不同的端口上监听客户请求
为了启动和协调上面的核心组件工作,Jetty 提供了一个 Server 类来做这个事情,它负责创建并初始化 Connector、Handler、ThreadPool 组件,然后调用 start 方法启动它们。
-### 3.2. Jetty 和 Tomcat 架构区别
+### Jetty 和 Tomcat 架构区别
对比一下 Tomcat 的整体架构图,你会发现 Tomcat 在整体上跟 Jetty 很相似,它们的第一个区别是 Jetty 中没有 Service 的概念,Tomcat 中的 Service 包装了多个连接器和一个容器组件,一个 Tomcat 实例可以配置多个 Service,不同的 Service 通过不同的连接器监听不同的端口;而 Jetty 中 Connector 是被所有 Handler 共享的。
第二个区别是,在 Tomcat 中每个连接器都有自己的线程池,而在 Jetty 中所有的 Connector 共享一个全局的线程池。
-### 3.3. Connector 组件
+### Connector 组件
跟 Tomcat 一样,Connector 的主要功能是对 I/O 模型和应用层协议的封装。I/O 模型方面,最新的 Jetty 9 版本只支持 NIO,因此 Jetty 的 Connector 设计有明显的 Java NIO 通信模型的痕迹。至于应用层协议方面,跟 Tomcat 的 Processor 一样,Jetty 抽象出了 Connection 组件来封装应用层协议的差异。
@@ -381,7 +379,7 @@ getEndPoint().fillInterested(_readCallback);
到此你应该了解了 Connector 的工作原理,下面我画张图再来回顾一下 Connector 的工作流程。
-
+
1. Acceptor 监听连接请求,当有连接请求到达时就接受连接,一个连接对应一个 Channel,Acceptor 将 Channel 交给 ManagedSelector 来处理。
@@ -397,7 +395,7 @@ getEndPoint().fillInterested(_readCallback);
7. Connection 解析读到的数据,生成请求对象并交给 Handler 组件去处理。
-### 3.4. Handler 组件
+### Handler 组件
Jetty 的 Handler 设计是它的一大特色,Jetty 本质就是一个 Handler 管理器,Jetty 本身就提供了一些默认 Handler 来实现 Servlet 容器的功能,你也可以定义自己的 Handler 来添加到 Jetty 中,这体现了“**微内核 + 插件**”的设计思想。
@@ -429,7 +427,7 @@ public interface Handler extends LifeCycle, Destroyable
Handler 只是一个接口,完成具体功能的还是它的子类。那么 Handler 有哪些子类呢?它们的继承关系又是怎样的?这些子类是如何实现 Servlet 容器功能的呢?
-
+
在 AbstractHandler 之下有 AbstractHandlerContainer,为什么需要这个类呢?这其实是个过渡,为了实现链式调用,一个 Handler 内部必然要有其他 Handler 的引用,所以这个类的名字里才有 Container,意思就是这样的 Handler 里包含了其他 Handler 的引用。
@@ -462,9 +460,9 @@ SessionHandler 用来管理 Session。除此之外 WebAppContext 还有一些通
WebAppContext 会将这些 Handler 构建成一个执行链,通过这个链会最终调用到我们的业务 Servlet。
-## 4. Jetty 的线程策略
+## Jetty 的线程策略
-### 4.1. 传统 Selector 编程模型
+### 传统 Selector 编程模型
常规的 NIO 编程思路是,将 I/O 事件的侦测和请求的处理分别用不同的线程处理。具体过程是:
@@ -472,7 +470,7 @@ WebAppContext 会将这些 Handler 构建成一个执行链,通过这个链会
在这个过程中按照职责划分,有两个线程在干活,一个是 I/O 事件检测线程,另一个是 I/O 事件处理线程。这样的好处是它们互不干扰和阻塞对方。
-### 4.2. Jetty 的 Selector 编程模型
+### Jetty 的 Selector 编程模型
将 I/O 事件检测和业务处理这两种工作分开的思路也有缺点:当 Selector 检测读就绪事件时,数据已经被拷贝到内核中的缓存了,同时 CPU 的缓存中也有这些数据了,我们知道 CPU 本身的缓存比内存快多了,这时当应用程序去读取这些数据时,如果用另一个线程去读,很有可能这个读线程使用另一个 CPU 核,而不是之前那个检测数据就绪的 CPU 核,这样 CPU 缓存中的数据就用不上了,并且线程切换也需要开销。
@@ -672,8 +670,8 @@ SelectorProducer 是 ManagedSelector 的内部类,SelectorProducer 实现了 E
2. 如果没有 I/O 事件就绪,就干点杂活,看看有没有客户提交了更新 Selector 上事件注册的任务,也就是上面提到的 SelectorUpdate 任务类。
3. 干完杂活继续执行 select 方法,侦测 I/O 就绪事件。
-## 5. 参考资料
+## 参考资料
- [Jetty 官方网址](http://www.eclipse.org/jetty/index.html)
- [Jetty Github](https://github.com/eclipse/jetty.project)
-- [Jetty wiki](http://wiki.eclipse.org/Jetty/Reference/jetty-env.xml)
+- [Jetty wiki](http://wiki.eclipse.org/Jetty/Reference/jetty-env.xml)
\ No newline at end of file
diff --git "a/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
new file mode 100644
index 00000000..9e9a4473
--- /dev/null
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
@@ -0,0 +1,39 @@
+---
+title: Java 服务器
+date: 2022-02-17 22:34:30
+categories:
+ - Java
+ - JavaEE
+ - 服务器
+tags:
+ - Java
+ - JavaWeb
+ - 服务器
+permalink: /pages/e3f3f3/
+hidden: true
+index: false
+---
+
+# Java 服务器
+
+## 📖 内容
+
+- [Tomcat 快速入门](01.Tomcat/01.Tomcat快速入门.md)
+- [Tomcat 连接器](01.Tomcat/02.Tomcat连接器.md)
+- [Tomcat 容器](01.Tomcat/03.Tomcat容器.md)
+- [Tomcat 优化](01.Tomcat/04.Tomcat优化.md)
+- [Tomcat 和 Jetty](01.Tomcat/05.Tomcat和Jetty.md)
+- [Jetty](02.Jetty.md)
+
+## 📚 资料
+
+- [Tomcat 官网](http://tomcat.apache.org/)
+- [Jetty 官网](http://www.eclipse.org/jetty/index.html)
+- [Jetty Github](https://github.com/eclipse/jetty.project)
+- [Nginx 官网](https://www.nginx.com/)
+- [Nginx 的中文维基](http://tool.oschina.net/apidocs/apidoc?api=nginx-zh)
+- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+
+## 🚪 传送
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/01.Java/02.JavaEE/README.md b/docs/01.Java/02.JavaEE/README.md
new file mode 100644
index 00000000..846c3677
--- /dev/null
+++ b/docs/01.Java/02.JavaEE/README.md
@@ -0,0 +1,61 @@
+---
+title: JavaEE
+date: 2022-02-18 08:53:11
+categories:
+ - Java
+ - JavaEE
+tags:
+ - Java
+ - JavaEE
+permalink: /pages/80a822/
+hidden: true
+index: false
+---
+
+# JavaEE
+
+## 📖 内容
+
+### JavaWeb
+
+- [JavaWeb 面经](01.JavaWeb/99.JavaWeb面经.md)
+- [JavaWeb 之 Servlet 指南](01.JavaWeb/01.JavaWeb之Servlet指南.md)
+- [JavaWeb 之 Jsp 指南](01.JavaWeb/02.JavaWeb之Jsp指南.md)
+- [JavaWeb 之 Filter 和 Listener](01.JavaWeb/03.JavaWeb之Filter和Listener.md)
+- [JavaWeb 之 Cookie 和 Session](01.JavaWeb/04.JavaWeb之Cookie和Session.md)
+
+### Java 服务器
+
+> Tomcat 和 Jetty 都是 Java 比较流行的轻量级服务器。
+>
+> Nginx 是目前最流行的反向代理服务器,也常用于负载均衡。
+
+- [Tomcat 快速入门](02.服务器/01.Tomcat/01.Tomcat快速入门.md)
+- [Tomcat 连接器](02.服务器/01.Tomcat/02.Tomcat连接器.md)
+- [Tomcat 容器](02.服务器/01.Tomcat/03.Tomcat容器.md)
+- [Tomcat 优化](02.服务器/01.Tomcat/04.Tomcat优化.md)
+- [Tomcat 和 Jetty](02.服务器/01.Tomcat/05.Tomcat和Jetty.md)
+- [Jetty](02.服务器/02.Jetty.md)
+
+## 📚 资料
+
+- **JavaWeb**
+ - **书籍**
+ - [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+ - [Head First Servlets & JSP](https://book.douban.com/subject/1942934/)
+ - **教程**
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [Servlet 教程](https://www.runoob.com/servlet/servlet-tutorial.html)
+ - [博客园孤傲苍狼 JavaWeb 学习总结](https://www.cnblogs.com/xdp-gacl/tag/JavaWeb%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/)
+ - [JSP 教程](https://www.runoob.com/jsp/jsp-tutorial.html)
+- **服务器**
+ - [Tomcat 官网](http://tomcat.apache.org/)
+ - [Jetty 官网](http://www.eclipse.org/jetty/index.html)
+ - [Jetty Github](https://github.com/eclipse/jetty.project)
+ - [Nginx 官网](https://www.nginx.com/)
+ - [Nginx 的中文维基](http://tool.oschina.net/apidocs/apidoc?api=nginx-zh)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+
+## 🚪 传送
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-quickstart.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
similarity index 92%
rename from docs/tool/build/maven/maven-quickstart.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
index 8e455d21..b2efbdda 100644
--- a/docs/tool/build/maven/maven-quickstart.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
@@ -1,37 +1,22 @@
-# Maven 教程之入门指南
-
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
-
-
-
-- [一、Maven 简介](#一maven-简介)
- - [Maven 是什么](#maven-是什么)
- - [Maven 的生命周期](#maven-的生命周期)
- - [Maven 的标准工程结构](#maven-的标准工程结构)
- - [Maven 的"约定优于配置"](#maven-的约定优于配置)
- - [Maven 的版本规范](#maven-的版本规范)
-- [二、Maven 安装](#二maven-安装)
- - [环境准备](#环境准备)
- - [下载解压](#下载解压)
- - [环境变量](#环境变量)
- - [检测安装成功](#检测安装成功)
- - [Maven 配置文件](#maven-配置文件)
-- [三、快速入门](#三快速入门)
- - [创建 Maven 工程](#创建-maven-工程)
- - [在 Intellij 中创建 Maven 工程](#在-intellij-中创建-maven-工程)
- - [在 Eclipse 中创建 Maven 工程](#在-eclipse-中创建-maven-工程)
-- [四、使用说明](#四使用说明)
- - [如何添加依赖](#如何添加依赖)
- - [如何寻找 jar 包](#如何寻找-jar-包)
- - [如何使用 Maven 插件(Plugin)](#如何使用-maven-插件plugin)
- - [如何一次编译多个工程](#如何一次编译多个工程)
- - [常用 Maven 插件](#常用-maven-插件)
- - [Maven 命令](#maven-命令)
-- [参考资料](#参考资料)
-
-
-
-## 一、Maven 简介
+---
+title: Maven 快速入门
+date: 2020-02-07 23:04:47
+order: 01
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/e5b79f/
+---
+
+# Maven 快速入门
+
+## Maven 简介
### Maven 是什么
@@ -103,7 +88,7 @@ maven 在版本管理时候可以使用几个特殊的字符串 SNAPSHOT,LATES
- **LATEST** - 指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个 snapshot 版,具体看哪个时间最后。
- **RELEASE** - 指最后一个发布版。
-## 二、Maven 安装
+## Maven 安装
> Linux 环境安装可以使用我写一键安装脚本:https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/ops/service/maven
@@ -150,9 +135,9 @@ export PATH=$MAVEN_HOME/bin:$PATH
右键 "计算机",选择 "属性",之后点击 "高级系统设置",点击"环境变量",来设置环境变量,有以下系统变量需要配置:
-
+
-
+
### 检测安装成功
@@ -183,7 +168,7 @@ OS name: "linux", version: "3.10.0-327.el7.x86_64", arch: "amd64", family: "unix
```
-## 三、快速入门
+## 快速入门
### 创建 Maven 工程
@@ -280,15 +265,15 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
依次点击 File -> New -> Project 打开创建工程对话框,选择 Maven 工程。
-
+
(2)输入项目信息
-
+
(3)点击 Intellij 侧边栏中的 Maven 工具界面,有几个可以直接使用的 maven 命令,可以帮助你进行构建。
-
+
### 在 Eclipse 中创建 Maven 工程
@@ -300,7 +285,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
点击 Help -> Eclipse Marketplace,搜索 maven 关键字,选择安装红框对应的 Maven 插件。
-
+
(2)Maven 环境配置
@@ -308,7 +293,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
如下图所示,配置 settings.xml 文件的位置
-
+
(3)创建 Maven 工程
@@ -316,7 +301,7 @@ File -> New -> Maven Project -> Next,在接下来的窗口中会看到一大
接下来设置项目的参数,如下:
-
+
**groupId**是项目组织唯一的标识符,实际对应 JAVA 的包的结构,是 main 目录里 java 的目录结构。
@@ -330,11 +315,11 @@ Eclipse 中构建方式:
在 Elipse 项目上右击 -> Run As 就能看到很多 Maven 操作。这些操作和 maven 命令是等效的。例如 Maven clean,等同于 mvn clean 命令。
-
+
你也可以点击 Maven build,输入组合命令,并保存下来。如下图:
-
+
Maven 命令构建方式:
@@ -342,9 +327,9 @@ Maven 命令构建方式:
进入工程所在目录,输入 maven 命令就可以了。
-
+
-## 四、使用说明
+## 使用说明
### 如何添加依赖
@@ -569,4 +554,4 @@ mvn clean install -Dmaven.test.skip=true -B -U
- [Maven in 5 Minutes](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html)
- [Maven Getting Started Guide](https://maven.apache.org/guides/getting-started/index.html)
- [maven 常见问题问答](http://www.oschina.net/question/158170_29368)
-- [常用 Maven 插件介绍](https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html)
+- [常用 Maven 插件介绍](https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html)
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-pom.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
similarity index 95%
rename from docs/tool/build/maven/maven-pom.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
index 02d34f99..d19300f4 100644
--- a/docs/tool/build/maven/maven-pom.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
@@ -1,39 +1,22 @@
+---
+title: Maven 教程之 pom.xml 详解
+date: 2019-05-14 14:57:33
+order: 02
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/d893c2/
+---
+
# Maven 教程之 pom.xml 详解
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
-
-
-
-- [一、pom.xml 简介](#一pomxml-简介)
- - [什么是 pom](#什么是-pom)
- - [pom 配置一览](#pom-配置一览)
-- [二、基本配置](#二基本配置)
- - [maven 坐标](#maven-坐标)
-- [三、依赖配置](#三依赖配置)
- - [dependencies](#dependencies)
- - [parent](#parent)
- - [dependencyManagement](#dependencymanagement)
- - [modules](#modules)
- - [properties](#properties)
-- [四、构建配置](#四构建配置)
- - [build](#build)
- - [reporting](#reporting)
-- [五、项目信息](#五项目信息)
-- [六、环境配置](#六环境配置)
- - [issueManagement](#issuemanagement)
- - [ciManagement](#cimanagement)
- - [mailingLists](#mailinglists)
- - [scm](#scm)
- - [prerequisites](#prerequisites)
- - [repositories](#repositories)
- - [pluginRepositories](#pluginrepositories)
- - [distributionManagement](#distributionmanagement)
- - [profiles](#profiles)
-- [参考资料](#参考资料)
-
-
-
-## 一、pom.xml 简介
+## pom.xml 简介
### 什么是 pom
@@ -88,7 +71,7 @@ pom.xml 就是 maven 的配置文件,用以描述项目的各种信息。
```
-## 二、基本配置
+## 基本配置
- **project** - `project` 是 pom.xml 中描述符的根。
- **modelVersion** - `modelVersion` 指定 pom.xml 符合哪个版本的描述符。maven 2 和 3 只能为 4.0.0。
@@ -123,7 +106,7 @@ pom.xml 就是 maven 的配置文件,用以描述项目的各种信息。
- **RELEASE** :指最后一个发布版。
- **packaging** - 项目的类型,描述了项目打包后的输出,默认是 jar。常见的输出类型为:pom, jar, maven-plugin, ejb, war, ear, rar, par。
-## 三、依赖配置
+## 依赖配置
### dependencies
@@ -239,7 +222,7 @@ maven 支持继承功能。子 POM 可以使用 `parent` 指定父 POM ,然后
```
-## 四、构建配置
+## 构建配置
### build
@@ -493,7 +476,7 @@ build 可以分为 "project build" 和 "profile build"。
```
-## 五、项目信息
+## 项目信息
项目信息相关的这部分标签**都不是必要的**,也就是说完全可以不填写。
@@ -587,7 +570,7 @@ build 可以分为 "project build" 和 "profile build"。
- **contributors** - 项目贡献者列表,`` 的子标签和 `` 的完全相同。
-## 六、环境配置
+## 环境配置
### issueManagement
@@ -816,4 +799,4 @@ POM 执行的预设条件。
## 参考资料
-- [maven 官方文档之 pom](https://maven.apache.org/pom.html)
+- [maven 官方文档之 pom](https://maven.apache.org/pom.html)
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-settings.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
similarity index 95%
rename from docs/tool/build/maven/maven-settings.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
index 8df72ab9..9fce2931 100644
--- a/docs/tool/build/maven/maven-settings.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
@@ -1,30 +1,22 @@
-# Maven 教程之 settings.xml 详解
-
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
-
-
+---
+title: Maven 教程之 settings.xml 详解
+date: 2019-05-14 14:57:33
+order: 03
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/1d58f1/
+---
-- [一、settings.xml 简介](#一settingsxml-简介)
- - [settings.xml 有什么用](#settingsxml-有什么用)
- - [settings.xml 文件位置](#settingsxml-文件位置)
- - [配置优先级](#配置优先级)
-- [二、settings.xml 元素详解](#二settingsxml-元素详解)
- - [顶级元素概览](#顶级元素概览)
- - [LocalRepository](#localrepository)
- - [InteractiveMode](#interactivemode)
- - [UsePluginRegistry](#usepluginregistry)
- - [Offline](#offline)
- - [PluginGroups](#plugingroups)
- - [Servers](#servers)
- - [Mirrors](#mirrors)
- - [Proxies](#proxies)
- - [Profiles](#profiles)
- - [ActiveProfiles](#activeprofiles)
-- [参考资料](#参考资料)
-
-
+# Maven 教程之 settings.xml 详解
-## 一、settings.xml 简介
+## settings.xml 简介
### settings.xml 有什么用
@@ -50,7 +42,7 @@ settings.xml 文件一般存在于两个位置:
如果这些文件同时存在,在应用配置时,会合并它们的内容,如果有重复的配置,优先级高的配置会覆盖优先级低的。
-## 二、settings.xml 元素详解
+## settings.xml 元素详解
### 顶级元素概览
@@ -414,4 +406,4 @@ maven 插件是一种特殊类型的构件。由于这个原因,插件仓库
## 参考资料
-- [maven 官方文档之 settings](https://maven.apache.org/settings.html)
+- [maven 官方文档之 settings](https://maven.apache.org/settings.html)
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-action.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
similarity index 83%
rename from docs/tool/build/maven/maven-action.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
index 82d16c3b..af20c6e4 100644
--- a/docs/tool/build/maven/maven-action.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
@@ -1,27 +1,22 @@
-# Maven 实战问题和最佳实践
-
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
-
-
+---
+title: Maven 实战问题和最佳实践
+date: 2018-11-28 09:29:22
+order: 04
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/198618/
+---
-- [常见问题](#常见问题)
- - [dependencies 和 dependencyManagement,plugins 和 pluginManagement 有什么区别](#dependencies-和-dependencymanagementplugins-和-pluginmanagement-有什么区别)
- - [IDEA 修改 JDK 版本后编译报错](#idea-修改-jdk-版本后编译报错)
- - [重复引入依赖](#重复引入依赖)
- - [如何打包一个可以直接运行的 Spring Boot jar 包](#如何打包一个可以直接运行的-spring-boot-jar-包)
- - [去哪儿找 maven dependency](#去哪儿找-maven-dependency)
- - [如何指定编码](#如何指定编码)
- - [如何指定 JDK 版本](#如何指定-jdk-版本)
- - [如何避免将 dependency 打包到构件中](#如何避免将-dependency-打包到构件中)
- - [如何跳过单元测试](#如何跳过单元测试)
- - [如何引入本地 jar](#如何引入本地-jar)
- - [如何排除依赖](#如何排除依赖)
-- [最佳实践](#最佳实践)
- - [通过 bom 统一管理版本](#通过-bom-统一管理版本)
-
-
+# Maven 实战问题和最佳实践
-## 一、Maven 常见问题
+## Maven 常见问题
### dependencies 和 dependencyManagement,plugins 和 pluginManagement 有什么区别
@@ -53,21 +48,21 @@ maven 的 JDK 源与指定的 JDK 编译版本不符。
Project SDK 是否正确
-
+
SDK 路径是否正确
-
+
- **查看 Settings > Maven 的配置**
JDK for importer 是否正确
-
+
Runner 是否正确
-
+
### 重复引入依赖
@@ -246,7 +241,7 @@ Runner 是否正确
```
-## 二、Maven 最佳实践
+## Maven 最佳实践
### 通过 bom 统一管理版本
@@ -297,4 +292,4 @@ spring-boot-dependencies 的 pom.xml 形式:
-```
+```
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-deploy.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
similarity index 94%
rename from docs/tool/build/maven/maven-deploy.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
index e4fece0e..2f29b940 100644
--- a/docs/tool/build/maven/maven-deploy.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
@@ -1,21 +1,20 @@
-# Maven 教程之发布 jar 到私服或中央仓库
-
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
-
-
+---
+title: Maven 教程之发布 jar 到私服或中央仓库
+date: 2019-05-14 14:57:33
+order: 05
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/7bdaf9/
+---
-- [发布 jar 包到中央仓库](#发布-jar-包到中央仓库)
- - [在 Sonatype 创建 Issue](#在-sonatype-创建-issue)
- - [使用 GPG 生成公私钥对](#使用-gpg-生成公私钥对)
- - [Maven 配置](#maven-配置)
- - [部署和发布](#部署和发布)
-- [部署 maven 私服](#部署-maven-私服)
- - [下载安装 Nexus](#下载安装-nexus)
- - [启动停止 Nexus](#启动停止-nexus)
- - [使用 Nexus](#使用-nexus)
-- [参考资料](#参考资料)
-
-
+# Maven 教程之发布 jar 到私服或中央仓库
## 发布 jar 包到中央仓库
@@ -33,7 +32,7 @@
注册账号成功后,根据你 Java 包的功能分别写上`Summary`、`Description`、`Group Id`、`SCM url`以及`Project URL`等必要信息,可以参见我之前创建的 Issue:[OSSRH-36187](https://issues.sonatype.org/browse/OSSRH-36187)。
-
+
创建完之后需要等待 Sonatype 的工作人员审核处理,审核时间还是很快的,我的审核差不多等待了两小时。当 Issue 的 Status 变为`RESOLVED`后,就可以进行下一步操作了。
@@ -309,7 +308,7 @@ gpg: unchanged: 1
进入[官方下载地址](https://www.sonatype.com/download-oss-sonatype),选择合适版本下载。
-
+
本人希望将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。
@@ -341,13 +340,13 @@ Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}
启动成功后,在浏览器中访问 `http://:8081`,欢迎页面如下图所示:
-
+
点击右上角 Sign in 登录,默认用户名/密码为:admin/admin123。
有必要提一下的是,在 Nexus 的 Repositories 管理页面,展示了可用的 maven 仓库,如下图所示:
-
+
> 说明:
>
@@ -477,4 +476,4 @@ $ mvn clean deploy -Dmaven.skip.test=true -P zp
- http://www.ruanyifeng.com/blog/2013/07/gpg.html
- https://www.cnblogs.com/hoobey/p/6102382.html
- https://blog.csdn.net/wzygis/article/details/49276779
-- https://blog.csdn.net/clj198606061111/article/details/52200928
+- https://blog.csdn.net/clj198606061111/article/details/52200928
\ No newline at end of file
diff --git a/docs/tool/build/maven/maven-checkstyle-plugin.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
similarity index 97%
rename from docs/tool/build/maven/maven-checkstyle-plugin.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
index 9699ad59..561aa81a 100644
--- a/docs/tool/build/maven/maven-checkstyle-plugin.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
@@ -1,15 +1,20 @@
-# Maven 插件之代码检查
-
-> **📦 本文已归档在 [java-tutorial](https://dunwu.github.io/java-tutorial/#/)**
->
-
+---
+title: Maven 插件之代码检查
+date: 2019-12-16 17:09:26
+order: 06
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/370f1d/
+---
-- [maven-checkstyle-plugin](#maven-checkstyle-plugin)
- - [定义 checkstyle.xml](#定义-checkstylexml)
-- [maven-pmd-plugin](#maven-pmd-plugin)
-- [参考资料](#参考资料)
-
-
+# Maven 插件之代码检查
## maven-checkstyle-plugin
@@ -84,7 +89,7 @@
scope: 可以检查的方法的范围,例如:public只能检查public修饰的方法,private可以检查所有的方法
allowMissingParamTags: 是否忽略对参数注释的检查
allowMissingThrowsTags: 是否忽略对throws注释的检查
- allowMissingReturnTag: 是否忽略对return注释的检查 -->
+ allowMissingReturntags: 是否忽略对return注释的检查 -->
@@ -422,4 +427,4 @@
- https://www.jianshu.com/p/557b975ae40d
- 阿里巴巴编程规范
- https://github.com/alibaba/p3c
- - https://github.com/alibaba/p3c/blob/master/p3c-pmd/pom.xml
+ - https://github.com/alibaba/p3c/blob/master/p3c-pmd/pom.xml
\ No newline at end of file
diff --git a/docs/tool/build/maven/README.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
similarity index 64%
rename from docs/tool/build/maven/README.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
index 0a2d0869..179cb604 100644
--- a/docs/tool/build/maven/README.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
@@ -1,3 +1,20 @@
+---
+title: Maven 教程
+date: 2020-08-04 15:20:54
+categories:
+ - Java
+ - 软件
+ - 构建
+ - Maven
+tags:
+ - Java
+ - 构建
+ - Maven
+permalink: /pages/85f27a/
+hidden: true
+index: false
+---
+
# Maven 教程
> [Maven](https://github.com/apache/maven) 是一个项目管理工具。它负责管理项目开发过程中的几乎所有的东西。
@@ -12,12 +29,12 @@
## 📖 内容
-- [Maven 入门指南](maven-quickstart.md)
-- [Maven 教程之 pom.xml 详解](maven-pom.md)
-- [Maven 教程之 settings.xml 详解](maven-settings.md)
-- [Maven 实战问题和最佳实践](maven-action.md)
-- [Maven 教程之发布 jar 到私服或中央仓库](maven-deploy.md)
-- [Maven 插件之代码检查](maven-checkstyle-plugin.md)
+- [Maven 快速入门](01.Maven快速入门.md)
+- [Maven 教程之 pom.xml 详解](02.Maven教程之pom.xml详解.md)
+- [Maven 教程之 settings.xml 详解](03.Maven教程之settings.xml详解.md)
+- [Maven 实战问题和最佳实践](04.Maven实战问题和最佳实践.md)
+- [Maven 教程之发布 jar 到私服或中央仓库](05.Maven教程之发布jar到私服或中央仓库.md)
+- [Maven 插件之代码检查](06.Maven插件之代码检查.md)
## 📚 资料
@@ -29,4 +46,4 @@
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/tool/build/ant.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
similarity index 96%
rename from docs/tool/build/ant.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
index f808f4dc..d0b8d139 100644
--- a/docs/tool/build/ant.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
@@ -1,22 +1,19 @@
-# Ant 简易教程
-
-
+---
+title: Ant 简易教程
+date: 2017-12-06 09:46:28
+order: 02
+categories:
+ - Java
+ - 软件
+ - 构建
+tags:
+ - Java
+ - 构建
+ - Ant
+permalink: /pages/0bafae/
+---
-- [简介](#简介)
-- [下载和安装](#下载和安装)
- - [下载](#下载)
- - [配置环境变量](#配置环境变量)
- - [验证](#验证)
-- [例子](#例子)
-- [关键元素](#关键元素)
- - [Project 元素](#project-元素)
- - [Target 元素](#target-元素)
- - [Task 元素](#task-元素)
- - [Property 元素](#property-元素)
- - [extension-point 元素](#extension-point-元素)
-- [参考资料](#参考资料)
-
-
+# Ant 简易教程
## 简介
@@ -380,4 +377,4 @@ _——Ant1.8.0 新增特性。_
## 参考资料
- [ant 官方手册](http://ant.apache.org/manual/index.html)
-- [http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html](http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html)
+- [http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html](http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html)
\ No newline at end of file
diff --git a/docs/tool/build/README.md "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
similarity index 50%
rename from docs/tool/build/README.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
index a1be1ce3..08c9c99a 100644
--- a/docs/tool/build/README.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
@@ -1,4 +1,19 @@
-# 构建工具
+---
+title: Java 构建
+date: 2020-08-04 15:20:54
+categories:
+ - Java
+ - 软件
+ - 构建
+tags:
+ - Java
+ - 构建
+permalink: /pages/d1859b/
+hidden: true
+index: false
+---
+
+# Java 构建
> Java 项目需要通过 **构建工具** 来管理项目依赖,完成编译、打包、发布、生成 JavaDoc 等任务。
>
@@ -10,16 +25,16 @@
### Maven
-- [Maven 入门指南](maven/maven-quickstart.md)
-- [Maven 教程之 pom.xml 详解](maven/maven-pom.md)
-- [Maven 教程之 settings.xml 详解](maven/maven-settings.md)
-- [Maven 实战问题和最佳实践](maven/maven-action.md)
-- [Maven 教程之发布 jar 到私服或中央仓库](maven/maven-deploy.md)
-- [Maven 插件之代码检查](maven/maven-checkstyle-plugin.md)
+- [Maven 快速入门](01.Maven/01.Maven快速入门.md)
+- [Maven 教程之 pom.xml 详解](01.Maven/02.Maven教程之pom.xml详解.md)
+- [Maven 教程之 settings.xml 详解](01.Maven/03.Maven教程之settings.xml详解.md)
+- [Maven 实战问题和最佳实践](01.Maven/04.Maven实战问题和最佳实践.md)
+- [Maven 教程之发布 jar 到私服或中央仓库](01.Maven/05.Maven教程之发布jar到私服或中央仓库.md)
+- [Maven 插件之代码检查](01.Maven/06.Maven插件之代码检查.md)
### Ant
-- [Ant 简易教程](ant.md)
+- [Ant 简易教程](02.Ant.md)
## 📚 资料
@@ -32,4 +47,4 @@
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/tool/ide/intellij-idea.md "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
similarity index 94%
rename from docs/tool/ide/intellij-idea.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
index e1bac2d4..85b4f254 100644
--- a/docs/tool/ide/intellij-idea.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
@@ -1,4 +1,19 @@
-# Intellij IDEA 应用指南
+---
+title: Intellij IDEA 快速入门
+date: 2019-11-29 18:10:14
+order: 01
+categories:
+ - Java
+ - 软件
+ - IDE
+tags:
+ - Java
+ - IDE
+ - Intellij
+permalink: /pages/ac5c6a/
+---
+
+# Intellij IDEA 快速入门
## 快捷键
@@ -241,29 +256,23 @@ IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建
[下载地址](https://github.com/altercation/solarized)
-## 破解
+## FAQ
-Intellij 是一个收费的 IDE,坦白说有点小贵,买不起。
+(1)运行时报错
-所以,很惭愧,只好用下破解方法了。网上有很多使用注册码的网文,但是注册码不稳定,随时可能被封。还是自行搭建一个注册服务器比较稳定。我使用了 [ilanyu](http://blog.lanyus.com/) 博文 [IntelliJ IDEA License Server 本地搭建教程](http://blog.lanyus.com/archives/174.html) 的方法,亲测十分有效。
+> Error running XXX. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun
-我的备用地址:[百度云盘](https://yun.baidu.com/disk/home?#list/vmode=list&path=%2F%E8%BD%AF%E4%BB%B6%2F%E5%BC%80%E5%8F%91%E8%BD%AF%E4%BB%B6%2FIDE)
+解决方案:
-下载并解压文中的压缩包到本地,选择适合操作系统的版本运行。
+找到 `.idea/libraies/workspace.xml` 中的 ``
-如果是在 Linux 上运行,推荐创建一个脚本,代码如下:
+添加一行配置:
-```bash
-# 使用 nohup 创建守护进程,运行 IntelliJIDEALicenseServer_linux_amd64
-# 如果运行在其他 Linux 发行版本,替换执行的脚本即可
-nohup sh IntelliJIDEALicenseServer_linux_amd64 2>&1
+```xml
+
```
-这样做是因为:大部分人使用 linux 是使用仿真器连接虚拟机,如果断开连接,进程也会被 kill,每次启动这个注册服务器很麻烦不是吗?而启动了守护进程,则不会出现这种情况,只有你主动 kill 进程才能将其干掉。
-
-Windows 版本是 exe 程序,将其设为开机自动启动即可,别告诉我你不知道怎么设置开机自动启动。
-
## 参考资料
- [IntelliJ-IDEA-Tutorial](https://github.com/judasn/IntelliJ-IDEA-Tutorial)
-- [极客学院 - Intellij IDEA 使用教程](http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/)
+- [极客学院 - Intellij IDEA 使用教程](http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/)
\ No newline at end of file
diff --git a/docs/tool/ide/eclipse.md "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
similarity index 99%
rename from docs/tool/ide/eclipse.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
index 15a6ca98..d8f3730d 100644
--- a/docs/tool/ide/eclipse.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
@@ -1,4 +1,18 @@
-# Eclipse 应用指南
+---
+title: Eclipse 快速入门
+date: 2018-07-01 11:27:47
+order: 02
+categories:
+ - Java
+ - 软件
+ - IDE
+tags:
+ - Java
+ - IDE
+permalink: /pages/2257c7/
+---
+
+# Eclipse 快速入门
## 代码智能提示
@@ -230,4 +244,4 @@ http://tomcat.apache.org/download-70.cgi这里有Tomcat的安装包和源码包
| Ctrl+T | 快速显示当前类的继承结构 |
| Ctrl+W | 关闭当前 Editer |
| Ctrl+L | 文本编辑器 转至行 |
-| F2 | 显示工具提示描述 |
+| F2 | 显示工具提示描述 |
\ No newline at end of file
diff --git a/docs/tool/ide/vscode.md "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
similarity index 78%
rename from docs/tool/ide/vscode.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
index 3e0b7ac0..909e80c5 100644
--- a/docs/tool/ide/vscode.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
@@ -1,4 +1,18 @@
-# vscode 应用指南
+---
+title: Vscode 快速入门
+date: 2019-05-14 14:57:33
+order: 03
+categories:
+ - Java
+ - 软件
+ - IDE
+tags:
+ - Java
+ - IDE
+permalink: /pages/0f7153/
+---
+
+# Vscode 快速入门
## 快捷键
@@ -44,4 +58,4 @@
- https://github.com/Microsoft/vscode-docs
- https://github.com/Microsoft/vscode-tips-and-tricks
- 更多资源
- - https://github.com/viatsko/awesome-vscode
+ - https://github.com/viatsko/awesome-vscode
\ No newline at end of file
diff --git "a/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md"
new file mode 100644
index 00000000..e487ace7
--- /dev/null
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md"
@@ -0,0 +1,26 @@
+---
+title: Java IDE
+date: 2022-02-18 08:53:11
+categories:
+ - Java
+ - 软件
+ - IDE
+tags:
+ - Java
+ - IDE
+permalink: /pages/8695a7/
+hidden: true
+index: false
+---
+
+# Java IDE
+
+> 自从有了 **IDE**,写代码从此就告别了刀耕火种的蛮荒时代。
+>
+> - [Eclipse](02.Eclipse.md) 是久负盛名的开源 Java IDE,我的学生时代一直使用它写 Java。
+> - 曾经抗拒从转 [Intellij Idea](01.Intellij.md) ,但后来发现真香,不得不说,确实是目前最优秀的 Java IDE。
+> - 你可以在 [vscode](03.VsCode.md) 中写各种语言,只要安装相应插件即可。如果你的项目中使用了很多种编程语言,又懒得在多个 IDE 之间切换,那么就用 vscode 来一网打尽吧。
+
+- [Intellij IDEA 快速入门](01.Intellij.md)
+- [Eclipse 快速入门](02.Eclipse.md)
+- [Vscode 快速入门](03.VsCode.md)
\ No newline at end of file
diff --git "a/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
new file mode 100644
index 00000000..7ccdb465
--- /dev/null
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
@@ -0,0 +1,41 @@
+---
+title: 监控工具对比
+date: 2020-02-11 17:48:32
+order: 01
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 监控
+permalink: /pages/16563a/
+---
+
+# 监控工具对比
+
+## 监控工具发展史
+
+
+
+## 监控工具比对
+
+### 特性对比
+
+
+
+### 生态对比
+
+
+
+## 技术选型
+
+- Zipkin 欠缺 APM 报表能力,不推荐。
+- 企业级,推荐 CAT
+- 关注和试点 SkyWalking。
+
+用好调用链监控,需要订制化、自研能力。
+
+## 参考资料
+
+[CAT、Zipkin 和 SkyWalking 该如何选型?](https://time.geekbang.org/dailylesson/detail/100028416)
\ No newline at end of file
diff --git a/docs/tool/monitor/cat.md "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
similarity index 88%
rename from docs/tool/monitor/cat.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
index 59a129e1..ee099d36 100644
--- a/docs/tool/monitor/cat.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
@@ -1,4 +1,19 @@
-# Cat
+---
+title: CAT 快速入门
+date: 2020-02-11 17:48:32
+order: 02
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 监控
+ - CAT
+permalink: /pages/821ca3/
+---
+
+# CAT 快速入门
## CAT 简介
@@ -15,14 +30,14 @@ CAT(Central Application Tracking),是基于 Java 开发的分布式实时
### 支持的消息类型
-CAT监控系统将每次URL、Service的请求内部执行情况都封装为一个完整的消息树、消息树可能包括Transaction、Event、Heartbeat、Metric等信息。
+CAT 监控系统将每次 URL、Service 的请求内部执行情况都封装为一个完整的消息树、消息树可能包括 Transaction、Event、Heartbeat、Metric 等信息。
- **Transaction** 适合记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控,Transaction 用来记录一段代码的执行时间和次数
- **Event** 用来记录一件事发生的次数,比如记录系统异常,它和 transaction 相比缺少了时间的统计,开销比 transaction 要小
- **Heartbeat** 表示程序内定期产生的统计信息, 如 CPU 利用率, 内存利用率, 连接池状态, 系统负载等
- **Metric** 用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为 1 分钟
-
+
## CAT 部署
@@ -57,7 +72,7 @@ CAT 主要分为三个模块:
在实际开发和部署中,cat-consumer 和 cat-home 是部署在一个 jvm 内部,每个 CAT 服务端都可以作为 consumer 也可以作为 home,这样既能减少整个 CAT 层级结构,也可以增加整个系统稳定性。
-
+
上图是 CAT 目前多机房的整体结构图:
@@ -68,4 +83,4 @@ CAT 主要分为三个模块:
## 参考资料
-- [CAT Github](https://github.com/dianping/cat)
+- [CAT Github](https://github.com/dianping/cat)
\ No newline at end of file
diff --git a/docs/tool/monitor/zipkin.md "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
similarity index 95%
rename from docs/tool/monitor/zipkin.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
index 0b9792b2..e665495d 100644
--- a/docs/tool/monitor/zipkin.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
@@ -1,4 +1,19 @@
-# Zipkin 应用指南
+---
+title: Zipkin 快速入门
+date: 2020-03-23 22:56:45
+order: 03
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 监控
+ - Zipkin
+permalink: /pages/0a8826/
+---
+
+# Zipkin 快速入门
**Zipkin 是一个基于 Java 开发的、开源的、分布式实时数据跟踪系统(Distributed Tracking System)**。它采集有助于解决服务架构中延迟问题的实时数据。
@@ -14,7 +29,7 @@ Zipkin 基于 Google Dapper 的论文设计而来,由 Twitter 公司开发贡
Zipkin UI 还提供了一个依赖关系图,该关系图显示了每个应用程序中跟踪了多少个请求。这对于识别聚合行为(包括错误路径或对不赞成使用的服务的调用)很有帮助。
-
+
### 多平台
@@ -32,7 +47,7 @@ Zipkin 服务器捆绑了用于采集和存储数据的扩展。
数据以 json 形式存储,可以参考:[Zipkin 官方的 Swagger API](https://zipkin.io/zipkin-api/#/default/post_spans)
-
+
## 二、Zipkin 安装
@@ -78,7 +93,7 @@ ZipKin 可以分为两部分,
架构如下:
-
+
### Zipkin Server
@@ -154,4 +169,4 @@ Instrumented client 和 server 是分别使用了 ZipKin Client 的服务,Zipk
- [Zipkin 官网](https://zipkin.io/)
- [Zipkin Github](https://github.com/openzipkin/zipkin)
-- [brave](https://github.com/openzipkin/brave)
+- [brave](https://github.com/openzipkin/brave)
\ No newline at end of file
diff --git a/docs/tool/monitor/skywalking.md "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
similarity index 81%
rename from docs/tool/monitor/skywalking.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
index f8012e0b..e3573437 100644
--- a/docs/tool/monitor/skywalking.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
@@ -1,4 +1,19 @@
-# SkyWalking
+---
+title: SkyWalking 快速入门
+date: 2020-02-07 23:04:47
+order: 04
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 监控
+ - SkyWalking
+permalink: /pages/df7dec/
+---
+
+# SkyWalking 快速入门
SkyWalking 是一个基于 Java 开发的分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。
@@ -8,7 +23,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。
-
+
### SkyWalking 特性
@@ -29,9 +44,9 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
从逻辑上讲,SkyWalking 分为四个部分:探针(Probes),平台后端,存储和 UI。
-
+
-- **探针(Probes)** - 探针是指集成到目标系统中的代理或SDK库。它们负责收集数据(包括跟踪数据和统计数据)并将其按照 SkyWalking 的要求重新格式化为。
+- **探针(Probes)** - 探针是指集成到目标系统中的代理或 SDK 库。它们负责收集数据(包括跟踪数据和统计数据)并将其按照 SkyWalking 的要求重新格式化为。
- **平台后端** - 平台后端是一个提供后端服务的集群。它用于聚合、分析和驱动从探针到 UI 的流程。它还为传入格式(如 Zipkin 的格式),存储实现程序和集群管理提供可插入功能。 您甚至可以使用 Observability Analysis Language 自定义聚合和分析。
- **存储** - 您可以选择一个 SkyWalking 已实现的存储,如由 Sharding-Sphere 管理的 ElasticSearch,H2 或 MySQL 集群,也可以自行实现一个存储。
- **UI** - 用户界面很酷,对于 SkyWalking 最终用户而言非常强大。它也可以自定义以匹配您的自定义后端。
@@ -40,7 +55,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
进入 [Apache SkyWalking 官方下载页面](http://skywalking.apache.org/downloads/),选择安装版本,下载解压到本地。
-
+
安装分为三个部分:
@@ -50,4 +65,4 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
## 参考资料
-- [SkyWalking Github](https://github.com/apache/skywalking)
+- [SkyWalking Github](https://github.com/apache/skywalking)
\ No newline at end of file
diff --git a/docs/tool/monitor/arthas.md "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
similarity index 89%
rename from docs/tool/monitor/arthas.md
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
index a205242b..7e5726c9 100644
--- a/docs/tool/monitor/arthas.md
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
@@ -1,4 +1,19 @@
-# Arthas 应用指南
+---
+title: Arthas 快速入门
+date: 2020-02-07 23:04:47
+order: 05
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 诊断
+ - Arthas
+permalink: /pages/c689d1/
+---
+
+# Arthas 快速入门
> `Arthas` 是 Alibaba 开源的 Java 诊断工具 。
@@ -315,8 +330,8 @@ ts=2018-11-28 19:22:35; [cost=29.969732ms] result=@ArrayList[
### 基础命令
- help——查看命令帮助信息
-- [cat](https://alibaba.github.io/arthas/cat.html)——打印文件内容,和linux里的cat命令类似
-- [pwd](https://alibaba.github.io/arthas/pwd.html)——返回当前的工作目录,和linux命令类似
+- [cat](https://alibaba.github.io/arthas/cat.html)——打印文件内容,和 linux 里的 cat 命令类似
+- [pwd](https://alibaba.github.io/arthas/pwd.html)——返回当前的工作目录,和 linux 命令类似
- cls——清空当前屏幕区域
- session——查看当前会话的信息
- [reset](https://alibaba.github.io/arthas/reset.html)——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
@@ -324,33 +339,33 @@ ts=2018-11-28 19:22:35; [cost=29.969732ms] result=@ArrayList[
- history——打印命令历史
- quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
- shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
-- [keymap](https://alibaba.github.io/arthas/keymap.html)——Arthas快捷键列表及自定义快捷键
+- [keymap](https://alibaba.github.io/arthas/keymap.html)——Arthas 快捷键列表及自定义快捷键
-### jvm相关
+### jvm 相关
- [dashboard](https://alibaba.github.io/arthas/dashboard.html)——当前系统的实时数据面板
- [thread](https://alibaba.github.io/arthas/thread.html)——查看当前 JVM 的线程堆栈信息
- [jvm](https://alibaba.github.io/arthas/jvm.html)——查看当前 JVM 的信息
-- [sysprop](https://alibaba.github.io/arthas/sysprop.html)——查看和修改JVM的系统属性
-- [sysenv](https://alibaba.github.io/arthas/sysenv.html)——查看JVM的环境变量
-- [vmoption](https://alibaba.github.io/arthas/vmoption.html)——查看和修改JVM里诊断相关的option
-- [logger](https://alibaba.github.io/arthas/logger.html)——查看和修改logger
+- [sysprop](https://alibaba.github.io/arthas/sysprop.html)——查看和修改 JVM 的系统属性
+- [sysenv](https://alibaba.github.io/arthas/sysenv.html)——查看 JVM 的环境变量
+- [vmoption](https://alibaba.github.io/arthas/vmoption.html)——查看和修改 JVM 里诊断相关的 option
+- [logger](https://alibaba.github.io/arthas/logger.html)——查看和修改 logger
- [getstatic](https://alibaba.github.io/arthas/getstatic.html)——查看类的静态属性
-- [ognl](https://alibaba.github.io/arthas/ognl.html)——执行ognl表达式
+- [ognl](https://alibaba.github.io/arthas/ognl.html)——执行 ognl 表达式
- [mbean](https://alibaba.github.io/arthas/mbean.html)——查看 Mbean 的信息
-- [heapdump](https://alibaba.github.io/arthas/heapdump.html)——dump java heap, 类似jmap命令的heap dump功能
+- [heapdump](https://alibaba.github.io/arthas/heapdump.html)——dump java heap, 类似 jmap 命令的 heap dump 功能
-### class/classloader相关
+### class/classloader 相关
-- [sc](https://alibaba.github.io/arthas/sc.html)——查看JVM已加载的类信息
+- [sc](https://alibaba.github.io/arthas/sc.html)——查看 JVM 已加载的类信息
- [sm](https://alibaba.github.io/arthas/sm.html)——查看已加载类的方法信息
- [jad](https://alibaba.github.io/arthas/jad.html)——反编译指定已加载类的源码
- [mc](https://alibaba.github.io/arthas/mc.html)——内存编绎器,内存编绎`.java`文件为`.class`文件
-- [redefine](https://alibaba.github.io/arthas/redefine.html)——加载外部的`.class`文件,redefine到JVM里
+- [redefine](https://alibaba.github.io/arthas/redefine.html)——加载外部的`.class`文件,redefine 到 JVM 里
- [dump](https://alibaba.github.io/arthas/dump.html)——dump 已加载类的 byte code 到特定目录
-- [classloader](https://alibaba.github.io/arthas/classloader.html)——查看classloader的继承树,urls,类加载信息,使用classloader去getResource
+- [classloader](https://alibaba.github.io/arthas/classloader.html)——查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource
-### monitor/watch/trace相关
+### monitor/watch/trace 相关
> 请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 `shutdown` 或将增强过的类执行 `reset` 命令。
@@ -362,29 +377,29 @@ ts=2018-11-28 19:22:35; [cost=29.969732ms] result=@ArrayList[
### options
-- [options](https://alibaba.github.io/arthas/options.html)——查看或设置Arthas全局开关
+- [options](https://alibaba.github.io/arthas/options.html)——查看或设置 Arthas 全局开关
### 管道
-Arthas支持使用管道对上述命令的结果进行进一步的处理,如`sm java.lang.String * | grep 'index'`
+Arthas 支持使用管道对上述命令的结果进行进一步的处理,如`sm java.lang.String * | grep 'index'`
-- grep——搜索满足条件的结果
-- plaintext——将命令的结果去除ANSI颜色
+- grep——搜索满足条件的 结果
+- plaintext——将 命令的结果去除 ANSI 颜色
- wc——按行统计输出结果
### 后台异步任务
-当线上出现偶发的问题,比如需要watch某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了,详情请参考[这里](https://alibaba.github.io/arthas/async.html)
+当线上出现偶发的问题,比如需要 watch 某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了,详情请参考[这里](https://alibaba.github.io/arthas/async.html)
-- 使用 > 将结果重写向到日志文件,使用 & 指定命令是后台运行,session断开不影响任务执行(生命周期默认为1天)
-- jobs——列出所有job
+- 使用 > 将结果重写向到日志文件,使用 & 指定命令是后台运行,session 断开不影响任务执行(生命周期默认为 1 天)
+- jobs——列出所有 job
- kill——强制终止任务
- fg——将暂停的任务拉到前台执行
- bg——将暂停的任务放到后台执行
### Web Console
-通过websocket连接Arthas。
+通过 websocket 连接 Arthas。
- [Web Console](https://alibaba.github.io/arthas/web-console.html)
@@ -394,7 +409,7 @@ Arthas支持使用管道对上述命令的结果进行进一步的处理,如`s
在启动时,指定`stat-url`,就会回报执行的每一行命令,比如: `./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'`
-在tunnel server里有一个示例的回报代码,用户可以自己在服务器上实现。
+在 tunnel server 里有一个示例的回报代码,用户可以自己在服务器上实现。
[StatController.java](https://github.com/alibaba/arthas/blob/master/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/web/StatController.java)
@@ -403,10 +418,10 @@ Arthas支持使用管道对上述命令的结果进行进一步的处理,如`s
- [异步命令支持](https://alibaba.github.io/arthas/async.html)
- [执行结果存日志](https://alibaba.github.io/arthas/save-log.html)
- [批处理的支持](https://alibaba.github.io/arthas/batch-support.html)
-- [ognl表达式的用法说明](https://github.com/alibaba/arthas/issues/11)
+- [ognl 表达式的用法说明](https://github.com/alibaba/arthas/issues/11)
## 参考资料
- [Arthas Github](https://github.com/alibaba/arthas)
- [Arthas 用户文档](https://alibaba.github.io/arthas/index.html)
-- [arthas源码分析](https://www.jianshu.com/p/4e34d0ab47d1)
+- [arthas 源码分析](https://www.jianshu.com/p/4e34d0ab47d1)
\ No newline at end of file
diff --git "a/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
new file mode 100644
index 00000000..a2caaea0
--- /dev/null
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
@@ -0,0 +1,33 @@
+---
+title: Java 监控诊断
+date: 2020-02-11 17:48:32
+categories:
+ - Java
+ - 软件
+ - 监控诊断
+tags:
+ - Java
+ - 监控
+ - 诊断
+permalink: /pages/3d16d3/
+hidden: true
+index: false
+---
+
+# Java 监控诊断
+
+## 内容
+
+- [监控工具对比](01.监控工具对比.md)
+- [CAT](02.CAT.md)
+- [Zipkin](03.Zipkin.md)
+- [SkyWalking](04.Skywalking.md)
+- [Arthas](05.Arthas.md)
+
+## 资料
+
+- [CAT Github](https://github.com/dianping/cat)
+- [Zipkin Github](https://github.com/openzipkin/zipkin)
+- [SkyWalking Github](https://github.com/apache/skywalking)
+- [PinPoint Github](https://github.com/naver/pinpoint)
+- [Arthas Github](https://github.com/alibaba/arthas)
\ No newline at end of file
diff --git "a/docs/01.Java/11.\350\275\257\344\273\266/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/README.md"
new file mode 100644
index 00000000..d44fbe38
--- /dev/null
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/README.md"
@@ -0,0 +1,70 @@
+---
+title: Java 软件
+date: 2022-02-18 08:53:11
+categories:
+ - Java
+ - 软件
+tags:
+ - Java
+permalink: /pages/2cb045/
+hidden: true
+index: false
+---
+
+# Java 软件
+
+> 本部分内容主要是 Java 开发领域使用的一些 Java 软件,如构建工具、IDE、服务器、日志中心等等。
+
+## 📖 内容
+
+### 构建
+
+> Java 项目需要通过 [**构建工具**](01.构建) 来管理项目依赖,完成编译、打包、发布、生成 JavaDoc 等任务。
+>
+> - 目前最主流的构建工具是 Maven,它的功能非常强大。
+> - Gradle 号称是要替代 Maven 等构件工具,它的版本管理确实简洁,但是需要学习 Groovy,学习成本比 Maven 高。
+> - Ant 功能比 Maven 和 Gradle 要弱,现代 Java 项目基本不用了,但也有一些传统的 Java 项目还在使用。
+
+- [Maven](01.构建/01.Maven) 📚
+ - [Maven 快速入门](01.构建/01.Maven/01.Maven快速入门.md)
+ - [Maven 教程之 pom.xml 详解](01.构建/01.Maven/02.Maven教程之pom.xml详解.md)
+ - [Maven 教程之 settings.xml 详解](01.构建/01.Maven/03.Maven教程之settings.xml详解.md)
+ - [Maven 实战问题和最佳实践](01.构建/01.Maven/04.Maven实战问题和最佳实践.md)
+ - [Maven 教程之发布 jar 到私服或中央仓库](01.构建/01.Maven/05.Maven教程之发布jar到私服或中央仓库.md)
+ - [Maven 插件之代码检查](01.构建/01.Maven/06.Maven插件之代码检查.md)
+- [Ant 简易教程](01.构建/02.Ant.md)
+
+### IDE
+
+> 自从有了 [**IDE**](02.IDE),写代码从此就告别了刀耕火种的蛮荒时代。
+>
+> - [Eclipse](02.IDE/02.Eclipse.md) 是久负盛名的开源 Java IDE,我的学生时代一直使用它写 Java。
+> - 曾经抗拒从转 [Intellij Idea](02.IDE/01.Intellij.md) ,但后来发现真香,不得不说,确实是目前最优秀的 Java IDE。
+> - 你可以在 [vscode](02.IDE/03.VsCode.md) 中写各种语言,只要安装相应插件即可。如果你的项目中使用了很多种编程语言,又懒得在多个 IDE 之间切换,那么就用 vscode 来一网打尽吧。
+
+- [Intellij Idea](02.IDE/01.Intellij.md)
+- [Eclipse](02.IDE/02.Eclipse.md)
+- [vscode](02.IDE/03.VsCode.md)
+
+### 监控诊断
+
+> [监控/诊断](03.监控诊断) 工具主要用于 Java 应用的运维。通过采集、分析、存储、可视化应用的有效数据,帮助开发者、使用者快速定位问题,找到性能瓶颈。
+
+- [监控工具对比](03.监控诊断/01.监控工具对比.md)
+- [CAT](03.监控诊断/02.CAT.md)
+- [Zipkin](03.监控诊断/03.Zipkin.md)
+- [SkyWalking](03.监控诊断/04.Skywalking.md)
+- [Arthas](03.监控诊断/05.Arthas.md)
+
+## 📚 资料
+
+- **官网**
+ - [Maven Github](https://github.com/apache/maven)
+ - [Maven 官方文档](https://maven.apache.org/ref/current)
+ - [Ant 官方手册](http://ant.apache.org/manual/index.html)
+- **书籍**
+ - [《Maven 实战》](https://book.douban.com/subject/5345682/)
+
+## 🚪 传送
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/lib/serialized/javalib-json.md "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
similarity index 90%
rename from docs/lib/serialized/javalib-json.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
index 12145b5a..2e3cfea8 100644
--- a/docs/lib/serialized/javalib-json.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
@@ -1,38 +1,28 @@
+---
+title: Java 和 JSON 序列化
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - 工具
+ - IO
+tags:
+ - Java
+ - IO
+ - 序列化
+ - JSON
+permalink: /pages/4622a6/
+---
+
# Java 和 JSON 序列化
> JSON(JavaScript Object Notation)是一种基于文本的数据交换格式。几乎所有的编程语言都有很好的库或第三方工具来提供基于 JSON 的 API 支持,因此你可以非常方便地使用任何自己喜欢的编程语言来处理 JSON 数据。
>
> 本文主要从 Java 语言的角度来讲解 JSON 的应用。
-
-
-- [1. JSON 简介](#1-json-简介)
- - [1.1. JSON 是什么](#11-json-是什么)
- - [1.2. JSON 标准](#12-json-标准)
- - [1.3. JSON 优缺点](#13-json-优缺点)
- - [1.4. JSON 工具](#14-json工具)
- - [1.5. Java JSON 库](#15-java-json-库)
- - [1.6. JSON 编码指南](#16-json-编码指南)
-- [2. Fastjson 应用](#2-fastjson-应用)
- - [2.1. 添加 maven 依赖](#21-添加-maven-依赖)
- - [2.2. Fastjson API](#22-fastjson-api)
- - [2.3. Fastjson 注解](#23-fastjson-注解)
-- [3. Jackson 应用](#3-jackson-应用)
- - [3.1. 添加 maven 依赖](#31-添加-maven-依赖)
- - [3.2. Jackson API](#32-jackson-api)
- - [3.3. Jackson 注解](#33-jackson-注解)
-- [4. Gson 应用](#4-gson-应用)
- - [4.1. 添加 maven 依赖](#41-添加-maven-依赖)
- - [4.2. Gson API](#42-gson-api)
- - [4.3. Gson 注解](#43-gson-注解)
-- [5. 示例源码](#5-示例源码)
-- [6. 参考资料](#6-参考资料)
-
-
-
-## 1. JSON 简介
-
-### 1.1. JSON 是什么
+## JSON 简介
+
+### JSON 是什么
JSON 起源于 1999 年的 [JS 语言规范 ECMA262 的一个子集](http://javascript.crockford.com/)(即 15.12 章节描述了格式与解析),后来 2003 年作为一个数据格式[ECMA404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf)(很囧的序号有不有?)发布。
2006 年,作为 [rfc4627](http://www.ietf.org/rfc/rfc4627.txt) 发布,这时规范增加到 18 页,去掉没用的部分,十页不到。
@@ -41,7 +31,7 @@ JSON 的应用很广泛,这里有超过 100 种语言下的 JSON 库:[json.o
更多的可以参考这里,[关于 json 的一切](https://github.com/burningtree/awesome-json)。
-### 1.2. JSON 标准
+### JSON 标准
这估计是最简单标准规范之一:
@@ -72,7 +62,7 @@ JSON 的应用很广泛,这里有超过 100 种语言下的 JSON 库:[json.o
>
> - [json 的 RFC 文档](http://tools.ietf.org/html/rfc4627)
-### 1.3. JSON 优缺点
+### JSON 优缺点
优点:
@@ -85,7 +75,7 @@ JSON 的应用很广泛,这里有超过 100 种语言下的 JSON 库:[json.o
- 性能一般,文本表示的数据一般来说比二进制大得多,在数据传输上和解析处理上都要更影响性能。
- 缺乏 schema,跟同是文本数据格式的 XML 比,在类型的严格性和丰富性上要差很多。XML 可以借由 XSD 或 DTD 来定义复杂的格式,并由此来验证 XML 文档是否符合格式要求,甚至进一步的,可以基于 XSD 来生成具体语言的操作代码,例如 apache xmlbeans。并且这些工具组合到一起,形成一套庞大的生态,例如基于 XML 可以实现 SOAP 和 WSDL,一系列的 ws-\*规范。但是我们也可以看到 JSON 在缺乏规范的情况下,实际上有更大一些的灵活性,特别是近年来 REST 的快速发展,已经有一些 schema 相关的发展(例如[理解 JSON Schema](https://spacetelescope.github.io/understanding-json-schema/index.html),[使用 JSON Schema](http://usingjsonschema.com/downloads/), [在线 schema 测试](http://azimi.me/json-schema-view/demo/demo.html)),也有类似于 WSDL 的[WADL](https://www.w3.org/Submission/wadl/)出现。
-### 1.4. JSON 工具
+### JSON 工具
- 使用 JSON 实现 RPC(类似 XML-RPC):[JSON-RPC](http://www.jsonrpc.org/)
- 使用 JSON 实现 path 查询操作(类似 XML-PATH):[JsonPATH](https://github.com/json-path/JsonPath)
@@ -96,7 +86,7 @@ JSON 的应用很广泛,这里有超过 100 种语言下的 JSON 库:[json.o
- 在线 Mock: [在线 mock](https://www.easy-mock.com/)
- 其他 Mock:[SoapUI](https://www.soapui.org/rest-testing-mocking/rest-service-mocking.html)可以支持,SwaggerUI 也可以,[RestMock](https://github.com/andrzejchm/RESTMock)也可以。
-### 1.5. Java JSON 库
+### Java JSON 库
Java 中比较流行的 JSON 库有:
@@ -106,7 +96,7 @@ Java 中比较流行的 JSON 库有:
从性能上来看,一般情况下:Fastjson > Jackson > Gson
-### 1.6. JSON 编码指南
+### JSON 编码指南
> 遵循好的设计与编码风格,能提前解决 80%的问题,个人推荐 Google JSON 风格指南。
>
@@ -133,9 +123,9 @@ Java 中比较流行的 JSON 库有:
JSON API 设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。在高效实现的同时,无需牺牲可读性、灵活性和可发现性。
-## 2. Fastjson 应用
+## Fastjson 应用
-### 2.1. 添加 maven 依赖
+### 添加 maven 依赖
```xml
@@ -145,7 +135,7 @@ JSON API 设计用来最小化请求的数量,以及客户端与服务器间
```
-### 2.2. Fastjson API
+### Fastjson API
#### 定义 Bean
@@ -202,7 +192,7 @@ System.out.println(jsonString);
Group bean = JSON.parseObject(jsonString, Group.class);
```
-### 2.3. Fastjson 注解
+### Fastjson 注解
#### `@JSONField`
@@ -250,11 +240,11 @@ public static class B {
}
```
-## 3. Jackson 应用
+## Jackson 应用
> 扩展阅读:更多 API 使用细节可以参考 [jackson-databind 官方说明](https://github.com/FasterXML/jackson-databind)
-### 3.1. 添加 maven 依赖
+### 添加 maven 依赖
```xml
@@ -264,7 +254,7 @@ public static class B {
```
-### 3.2. Jackson API
+### Jackson API
#### 序列化
@@ -313,7 +303,7 @@ try {
}
```
-### 3.3. Jackson 注解
+### Jackson 注解
> 扩展阅读:更多注解使用细节可以参考 [jackson-annotations 官方说明](https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations)
@@ -381,11 +371,11 @@ alphabetic 设为 true 表示,json 字段按自然顺序排列,默认为 fal
public class JacksonAnnotationBean {}
```
-## 4. Gson 应用
+## Gson 应用
> 详细内容可以参考官方文档:[Gson 用户指南](https://github.com/google/gson/blob/master/UserGuide.md)
-### 4.1. 添加 maven 依赖
+### 添加 maven 依赖
```xml
@@ -395,7 +385,7 @@ public class JacksonAnnotationBean {}
```
-### 4.2. Gson API
+### Gson API
#### 序列化
@@ -431,7 +421,7 @@ Gson gson = new GsonBuilder()
.create();
```
-### 4.3. Gson 注解
+### Gson 注解
#### `@Since`
@@ -477,11 +467,11 @@ private class SomeObject {
}
```
-## 5. 示例源码
+## 示例源码
> 示例源码:[javalib-io-json](https://github.com/dunwu/java-tutorial/tree/master/javalib-io-json)
-## 6. 参考资料
+## 参考资料
- **官方**
- [Fastjson Github](https://github.com/alibaba/fastjson)
@@ -492,4 +482,4 @@ private class SomeObject {
-
- [json 的 RFC 文档](http://tools.ietf.org/html/rfc4627)
- [JSON 最佳实践](https://kimmking.github.io/2017/06/06/json-best-practice/)
- - [【简明教程】JSON](https://www.jianshu.com/p/8b428e1d1564)
+ - [【简明教程】JSON](https://www.jianshu.com/p/8b428e1d1564)
\ No newline at end of file
diff --git a/docs/lib/serialized/javalib-binary.md "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
similarity index 81%
rename from docs/lib/serialized/javalib-binary.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
index 60d762d0..631a5fcb 100644
--- a/docs/lib/serialized/javalib-binary.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
@@ -1,4 +1,20 @@
-# Java 二进制序列化库
+---
+title: Java 二进制序列化
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - 工具
+ - IO
+tags:
+ - Java
+ - IO
+ - 序列化
+ - 二进制
+permalink: /pages/08d872/
+---
+
+# Java 二进制序列化
## 简介
@@ -6,7 +22,7 @@
原因很简单,就是 Java 默认的序列化机制(`ObjectInputStream` 和 `ObjectOutputStream`)具有很多缺点。
-> 不了解 Java 默认的序列化机制,可以参考:[Java 序列化](https://github.com/dunwu/javacore/blob/master/docs/io/Java序列化.md)
+> 不了解 Java 默认的序列化机制,可以参考:[Java 序列化](https://dunwu.github.io/waterdrop/pages/2b2f0f/)
Java 自身的序列化方式具有以下缺点:
@@ -21,15 +37,23 @@ Java 自身的序列化方式具有以下缺点:
#### Protobuf
-[Protobuf](https://developers.google.com/protocol-buffers/) 是 Google 开发的结构序列化库。
+[Protobuf](https://developers.google.com/protocol-buffers/) 是 Google 公司内部的混合语言数据标准,是一种轻便、高效的结构化数据存储
+格式,可以用于结构化数据序列化,支持 Java、Python、C++、Go 等语言。Protobuf
+使用的时候需要定义 IDL(Interface description language),然后使用不同语言的 IDL
+编译器,生成序列化工具类。
-它具有以下特性:
+优点:
-- 结构化数据存储格式(xml,json 等)
-- 高性能编解码技术
-- 语言和平台无关,扩展性好
+- 序列化后体积相比 JSON、Hessian 小很多
+- 序列化反序列化速度很快,不需要通过反射获取类型
+- 语言和平台无关(基于 IDL),IDL 能清晰地描述语义,所以足以帮助并保证应用程序之间的类型不会丢失,无需类似 XML 解析器
+- 消息格式升级和兼容性不错,可以做到后向兼容
- 支持 Java, C++, Python 三种语言
+缺点:
+
+- Protobuf 对于具有反射和动态能力的语言来说,用起来很费劲。
+
#### Thrift
> [Thrift](https://github.com/apache/thrift) 是 apache 开源项目,是一个点对点的 RPC 实现。
@@ -42,15 +66,23 @@ Java 自身的序列化方式具有以下缺点:
#### Hessian
-> [Hessian](http://hessian.caucho.com/) 是一种二进制传输协议。
->
-> RPC 框架 Dubbo 就支持 Thrift 和 Hession。
+[Hessian](http://hessian.caucho.com/) 是动态类型、二进制、紧凑的,并且可跨语言移植的一种序列化框架。Hessian 协
+议要比 JDK、JSON 更加紧凑,性能上要比 JDK、JSON 序列化高效很多,而且生成的字节
+数也更小。
+
+RPC 框架 Dubbo 就支持 Thrift 和 Hession。
它具有以下特性:
- 支持多种语言。如:Java、Python、C++、C#、PHP、Ruby 等。
- 相对其他二进制序列化库较慢。
+Hessian 本身也有问题,官方版本对 Java 里面一些常见对象的类型不支持:
+
+- Linked 系列,LinkedHashMap、LinkedHashSet 等,但是可以通过扩展 CollectionDeserializer 类修复;
+- Locale 类,可以通过扩展 ContextSerializerFactory 类修复;
+- Byte/Short 反序列化的时候变成 Integer。
+
#### Kryo
> [Kryo](https://github.com/EsotericSoftware/kryo) 是用于 Java 的快速高效的二进制对象图序列化框架。Kryo 还可以执行自动的深拷贝和浅拷贝。 这是从对象到对象的直接复制,而不是从对象到字节的复制。
@@ -325,6 +357,27 @@ long end = System.currentTimeMillis();
System.out.printf("Kryo 序列化/反序列化耗时:%s", (end - begin));
```
+Hessian 应用
+
+```java
+Student student = new Student();
+student.setNo(101);
+student.setName("HESSIAN");
+//把student对象转化为byte数组
+ByteArrayOutputStream bos = new ByteArrayOutputStream();
+Hessian2Output output = new Hessian2Output(bos);
+output.writeObject(student);
+output.flushBuffer();
+byte[] data = bos.toByteArray();
+bos.close();
+//把刚才序列化出来的byte数组转化为student对象
+ByteArrayInputStream bis = new ByteArrayInputStream(data);
+Hessian2Input input = new Hessian2Input(bis);
+Student deStudent = (Student) input.readObject();
+input.close();
+System.out.println(deStudent);
+```
+
## 参考资料
- **官方**
@@ -335,4 +388,4 @@ System.out.printf("Kryo 序列化/反序列化耗时:%s", (end - begin));
- [Hessian 官网](http://hessian.caucho.com/)
- [FST Github](https://github.com/RuedigerMoeller/fast-serialization)
- **文章**
- - [java 序列化框架对比](https://www.jianshu.com/p/937883b6b2e5)
+ - [java 序列化框架对比](https://www.jianshu.com/p/937883b6b2e5)
\ No newline at end of file
diff --git a/docs/lib/serialized/README.md "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
similarity index 69%
rename from docs/lib/serialized/README.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
index 2552c5dd..1cd5ba95 100644
--- a/docs/lib/serialized/README.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
@@ -1,6 +1,22 @@
-# Java 序列化库
+---
+title: Java 序列化工具
+date: 2022-02-17 22:34:30
+categories:
+ - Java
+ - 工具
+ - IO
+tags:
+ - Java
+ - IO
+ - 序列化
+permalink: /pages/08b504/
+hidden: true
+index: false
+---
-Java 官方的序列化存在许多问题,因此,很多人更愿意使用优秀的第三方序列化工具来替代 Java 自身的序列化机制。 如果想详细了解 Java 自身序列化方式,可以参考:[深入理解 Java 序列化](https://github.com/dunwu/javacore/blob/master/docs/io/java-serialization.md)
+# Java 序列化工具
+
+Java 官方的序列化存在许多问题,因此,很多人更愿意使用优秀的第三方序列化工具来替代 Java 自身的序列化机制。 如果想详细了解 Java 自身序列化方式,可以参考:[Java 序列化](https://dunwu.github.io/waterdrop/pages/2b2f0f/)
序列化库技术选型:
@@ -10,8 +26,8 @@ Java 官方的序列化存在许多问题,因此,很多人更愿意使用优
## 内容
-- [JSON](javalib-json.md) - Fastjson、Jackson、Gson
-- [二进制](javalib-binary.md) - Protobuf、Thrift、Hessian、Kryo、FST
+- [JSON](01.JSON序列化.md) - Fastjson、Jackson、Gson
+- [二进制](02.二进制序列化.md) - Protobuf、Thrift、Hessian、Kryo、FST
## 资料
@@ -20,4 +36,4 @@ Java 官方的序列化存在许多问题,因此,很多人更愿意使用优
- [Hessian 官网](http://hessian.caucho.com/doc/hessian-overview.xtp)
- [Fastjson Github](https://github.com/alibaba/fastjson)
- [Jackson Github](https://github.com/FasterXML/jackson)
-- [Gson Github](https://github.com/google/gson)
+- [Gson Github](https://github.com/google/gson)
\ No newline at end of file
diff --git a/docs/lib/bean/lombok.md "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
similarity index 92%
rename from docs/lib/bean/lombok.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
index a36b5487..39b1df3a 100644
--- a/docs/lib/bean/lombok.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
@@ -1,31 +1,25 @@
-# Lombok 应用指南
-
-
-
-- [1. Lombok 简介](#1-lombok-简介)
-- [2. Lombok 安装](#2-lombok-安装)
-- [3. Lombok 使用](#3-lombok-使用)
- - [3.1. @Getter and @Setter](#31-getter-and-setter)
- - [3.2. @NonNull](#32-nonnull)
- - [3.3. @ToString](#33-tostring)
- - [3.4. @EqualsAndHashCode](#34-equalsandhashcode)
- - [3.5. @Data](#35-data)
- - [3.6. @Cleanup](#36-cleanup)
- - [3.7. @Synchronized](#37-synchronized)
- - [3.8. @SneakyThrows](#38-sneakythrows)
- - [3.9. 示例源码](#39-示例源码)
-- [4. Lombok 使用注意点](#4-lombok-使用注意点)
- - [4.1. 谨慎使用 `@Builder`](#41-谨慎使用-builder)
- - [4.2. `@Data` 注解和继承](#42-data-注解和继承)
-- [5. 参考资料](#5-参考资料)
-
-
-
-## 1. Lombok 简介
+---
+title: Lombok 快速入门
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - 工具
+ - JavaBean
+tags:
+ - Java
+ - JavaBean
+ - Lombok
+permalink: /pages/eb1d46/
+---
+
+# Lombok 快速入门
+
+## Lombok 简介
Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现 Lombok,开发人员可以节省构建诸如 `hashCode()` 和 `equals()` 、`getter / setter` 这样的方法以及以往用来分类各种 accessor 和 mutator 的大量时间。
-## 2. Lombok 安装
+## Lombok 安装
由于 Lombok 仅在编译阶段生成代码,所以使用 Lombok 注解的源代码,在 IDE 中会被高亮显示错误,针对这个问题可以通过安装 IDE 对应的插件来解决。具体的安装方式可以参考:[Setting up Lombok with Eclipse and Intellij](https://www.baeldung.com/lombok-ide)
@@ -48,11 +42,11 @@ Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的
```
-## 3. Lombok 使用
+## Lombok 使用
Lombok 提供注解 API 来修饰指定的类:
-### 3.1. @Getter and @Setter
+### @Getter and @Setter
[@Getter and @Setter](http://jnb.ociweb.com/jnb/jnbJan2010.html#gettersetter) Lombok 代码:
@@ -80,7 +74,7 @@ protected void setName(final String name) {
}
```
-### 3.2. @NonNull
+### @NonNull
[@NonNull](http://jnb.ociweb.com/jnb/jnbJan2010.html#nonnull) Lombok 代码:
@@ -111,7 +105,7 @@ public void setMembers(@NonNull final List members) {
}
```
-### 3.3. @ToString
+### @ToString
[@ToString](http://jnb.ociweb.com/jnb/jnbJan2010.html#tostring) Lombok 代码:
@@ -141,7 +135,7 @@ public class Foo extends Bar {
}
```
-### 3.4. @EqualsAndHashCode
+### @EqualsAndHashCode
[@EqualsAndHashCode](http://jnb.ociweb.com/jnb/jnbJan2010.html#equals) Lombok 代码:
@@ -206,7 +200,7 @@ public class Person extends SentientBeing {
}
```
-### 3.5. @Data
+### @Data
[@Data](http://jnb.ociweb.com/jnb/jnbJan2010.html#data) Lombok 代码:
@@ -284,7 +278,7 @@ public class Company {
}
```
-### 3.6. @Cleanup
+### @Cleanup
[@Cleanup](http://jnb.ociweb.com/jnb/jnbJan2010.html#cleanup) Lombok 代码:
@@ -318,7 +312,7 @@ public void testCleanUp() {
}
```
-### 3.7. @Synchronized
+### @Synchronized
[@Synchronized](http://jnb.ociweb.com/jnb/jnbJan2010.html#synchronized) Lombok 代码:
@@ -344,7 +338,7 @@ public String synchronizedFormat(Date date) {
}
```
-### 3.8. @SneakyThrows
+### @SneakyThrows
[@SneakyThrows](http://jnb.ociweb.com/jnb/jnbJan2010.html#sneaky) Lombok 代码:
@@ -367,13 +361,13 @@ public void testSneakyThrows() {
}
```
-### 3.9. 示例源码
+### 示例源码
> 示例源码:[javalib-bean](https://github.com/dunwu/java-tutorial/tree/master/javalib-bean)
-## 4. Lombok 使用注意点
+## Lombok 使用注意点
-### 4.1. 谨慎使用 `@Builder`
+### 谨慎使用 `@Builder`
在类上标注了 `@Data` 和 `@Builder` 注解的时候,编译时,lombok 优化后的 Class 中会没有默认的构造方法。在反序列化的时候,没有默认构造方法就可能会报错。
@@ -436,7 +430,7 @@ public class BuilderDemo02 {
}
```
-### 4.2. `@Data` 注解和继承
+### `@Data` 注解和继承
使用 `@Data` 注解时,则有了 `@EqualsAndHashCode` 注解,那么就会在此类中存在 `equals(Object other)` 和 `hashCode()` 方法,且不会使用父类的属性,这就导致了可能的问题。比如,有多个类有相同的部分属性,把它们定义到父类中,恰好 id(数据库主键)也在父类中,那么就会存在部分对象在比较时,它们并不相等,这是因为:lombok 自动生成的 `equals(Object other)` 和 `hashCode()` 方法判定为相等,从而导致和预期不符。
@@ -535,8 +529,8 @@ public void testEqualsAndHashCodeDemo() {
上面的单元测试可以通过,但如果将 `@EqualsAndHashCode(callSuper = true, exclude = { "address", "city", "state", "zip" })` 注掉就会报错。
-## 5. 参考资料
+## 参考资料
- [Lombok 官网](https://projectlombok.org/)
- [Lombok Github](https://github.com/rzwitserloot/lombok)
-- [IntelliJ IDEA - Lombok Plugin](http://plugins.jetbrains.com/plugin/6317-lombok-plugin)
+- [IntelliJ IDEA - Lombok Plugin](http://plugins.jetbrains.com/plugin/6317-lombok-plugin)
\ No newline at end of file
diff --git a/docs/lib/bean/dozer.md "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
similarity index 95%
rename from docs/lib/bean/dozer.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
index da9f89aa..e9a7c230 100644
--- a/docs/lib/bean/dozer.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
@@ -1,28 +1,24 @@
-# Dozer 应用指南
+---
+title: Dozer 快速入门
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - 工具
+ - JavaBean
+tags:
+ - Java
+ - JavaBean
+ - Dozer
+permalink: /pages/45e21b/
+---
+
+# Dozer 快速入门
这篇文章是本人在阅读 Dozer 官方文档(5.5.1 版本,官网已经一年多没更新了)的过程中,整理下来我认为比较基础的应用场景。
本文中提到的例子应该能覆盖 JavaBean 映射的大部分场景,希望对你有所帮助。
-
-
-- [简介](#简介)
-- [安装](#安装)
- - [引入 jar 包](#引入-jar-包)
- - [Eclipse 插件](#eclipse-插件)
-- [使用](#使用)
- - [准备](#准备)
- - [Dozer 的配置](#dozer-的配置)
- - [与 Spring 整合](#与-spring-整合)
-- [Dozer 支持的数据类型转换](#dozer-支持的数据类型转换)
-- [Dozer 的映射配置](#dozer-的映射配置)
- - [用注解来配置映射](#用注解来配置映射)
- - [用 API 来配置映射](#用-api-来配置映射)
- - [用 XML 来配置映射](#用-xml-来配置映射)
-- [参考](#参考)
-
-
-
## 简介
**Dozer 是什么?**
@@ -120,7 +116,7 @@ DestinationObject destObject =
所以,你需要一些配置来告诉 Dozer 应该转换什么,怎么转换。
-***注:官网着重建议:在现实应用中,最好不要每次映射对象时都创建一个`Mapper`实例来工作,这样会产生不必要的开销。如果你不使用 IoC 容器(如:spring)来管理你的项目,那么,最好将`Mapper`定义为单例模式。***
+**_注:官网着重建议:在现实应用中,最好不要每次映射对象时都创建一个`Mapper`实例来工作,这样会产生不必要的开销。如果你不使用 IoC 容器(如:spring)来管理你的项目,那么,最好将`Mapper`定义为单例模式。_**
#### 映射配置文件
@@ -567,7 +563,7 @@ field-exclude 可以排除不需要映射的属性。
#### 单向映射(One-Way Mapping)
-***注:本文的映射方式,无特殊说明,都是双向映射的。***
+**_注:本文的映射方式,无特殊说明,都是双向映射的。_**
有的场景可能希望转换过程不可逆,即单向转换。
@@ -790,4 +786,4 @@ superAttribute 和 superAttr 的映射规则会被子类所继承,所以不必
## 参考
-[Dozer 官方文档](http://dozer.sourceforge.net/documentation/gettingstarted.html) | [Dozer 源码地址](https://github.com/DozerMapper/dozer)
+[Dozer 官方文档](http://dozer.sourceforge.net/documentation/gettingstarted.html) | [Dozer 源码地址](https://github.com/DozerMapper/dozer)
\ No newline at end of file
diff --git a/docs/lib/template/freemark.md "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
similarity index 96%
rename from docs/lib/template/freemark.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
index 8eff5f72..8de94dbc 100644
--- a/docs/lib/template/freemark.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
@@ -1,4 +1,19 @@
-# Freemark Cheat Sheet
+---
+title: Freemark 快速入门
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - 工具
+ - 模板引擎
+tags:
+ - Java
+ - 模板引擎
+ - Freemark
+permalink: /pages/a60ccf/
+---
+
+# Freemark 快速入门
> FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML 网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个 Java 类库,是一款程序员可以嵌入他们所开发产品的组件。
@@ -19,7 +34,7 @@ Freemark 模板一句话概括就是:**_`模板 + 数据模型 = 输出`_**
- **FTL 标签**:FTL 标签和 HTML 标签很相似,但是它们却是给 FreeMarker 的指示, 而且不会打印在输出内容中。
- **注释**:注释和 HTML 的注释也很相似,但它们是由 `<#--` 和 `-->`来分隔的。注释会被 FreeMarker 直接忽略, 更不会在输出内容中显示。
-
+
> 🔔 注意:
>
@@ -157,4 +172,4 @@ FTL 支持的所有转义字符:
- [Freemark Github](https://github.com/apache/freemarker)
- [Freemark 中文教程](http://freemarker.foofun.cn/)
-- [在线 Freemark 工具](https://try.freemarker.apache.org/)
+- [在线 Freemark 工具](https://try.freemarker.apache.org/)
\ No newline at end of file
diff --git a/docs/lib/template/thymeleaf.md "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
similarity index 97%
rename from docs/lib/template/thymeleaf.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
index 7c6b46bf..df2e8fc4 100644
--- a/docs/lib/template/thymeleaf.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
@@ -1,4 +1,19 @@
-# Thymeleaf Cheat Sheet
+---
+title: Thymeleaf 快速入门
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - 工具
+ - 模板引擎
+tags:
+ - Java
+ - 模板引擎
+ - Thymeleaf
+permalink: /pages/e7d2ad/
+---
+
+# Thymeleaf 快速入门
## 标准方言
@@ -27,7 +42,7 @@ ${session.user.name}
它们作为属性值或作为它们的一部分,取决于属性:
```html
-
+
```
上面的表达式与下面是相同的(在 OGNL 和 SpringEL 中):
@@ -39,7 +54,7 @@ ${session.user.name}
但是不仅在涉及输出的场景中找到变量表达式,而且还可以使用更复杂的处理方式,如:条件,迭代…等等。
```html
-
+
```
这里`${books}`从上下文中选择名为`books`的变量,并在`th:each`中使用循环将其评估为迭代器。
@@ -98,8 +113,7 @@ ${session.user.name}
请注意,如果希望消息键由上下文变量的值确定,或者希望将变量指定为参数,则可以在消息表达式中使用变量表达式:
```html
-#{${config.adminWelcomeKey}(${session.user.name})}
-Jsp
+#{${config.adminWelcomeKey}(${session.user.name})} Jsp
```
#### 链接(URL)表达式
@@ -176,7 +190,7 @@ Jsp
```html
```
@@ -466,4 +480,4 @@ TODO
- [Thymeleaf 官网](https://www.thymeleaf.org/)
- [Thymeleaf Github](https://github.com/thymeleaf/thymeleaf/)
-- [Thymeleaf 教程](https://fanlychie.github.io/post/thymeleaf.html)
+- [Thymeleaf 教程](https://fanlychie.github.io/post/thymeleaf.html)
\ No newline at end of file
diff --git a/docs/lib/template/velocity.md "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
similarity index 96%
rename from docs/lib/template/velocity.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
index d4d3a621..ccb6514f 100644
--- a/docs/lib/template/velocity.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
@@ -1,4 +1,19 @@
-# Velocity Cheat Sheet
+---
+title: Velocity 快速入门
+date: 2022-02-17 22:34:30
+order: 03
+categories:
+ - Java
+ - 工具
+ - 模板引擎
+tags:
+ - Java
+ - 模板引擎
+ - Velocity
+permalink: /pages/3ba0ff/
+---
+
+# Velocity 快速入门
**Velocity (简称 VTL)是一个基于 Java 的模版引擎**。它允许 web 页面设计者引用 JAVA 代码预定义的方法。Web 设计者可以根据 MVC 模式和 JAVA 程序员并行工作,这意味着 Web 设计者可以单独专注于设计良好的站点,而程序员则可单独专注于编写底层代码。Velocity 将 Java 代码从 web 页面中分离出来,使站点在长时间运行后仍然具有很好的可维护性,并提供了一个除 JSP 和 PHP 之外的可行的被选方案。
@@ -313,4 +328,4 @@ Send me
- [Velocity Github](https://github.com/apache/velocity-engine/)
- [Velocity 官网](https://velocity.apache.org/)
- [Velocity 中文文档](https://wizardforcel.gitbooks.io/velocity-doc/content/)
-- [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
+- [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
\ No newline at end of file
diff --git a/docs/lib/template/README.md "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
similarity index 74%
rename from docs/lib/template/README.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
index 4cad92b7..ffd80ba3 100644
--- a/docs/lib/template/README.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
@@ -1,8 +1,23 @@
-# 模板引擎
+---
+title: Java 模板引擎
+date: 2022-02-17 22:34:30
+categories:
+ - Java
+ - 工具
+ - 模板引擎
+tags:
+ - Java
+ - 模板引擎
+permalink: /pages/9d37fa/
+hidden: true
+index: false
+---
+
+# Java 模板引擎
模板引擎不属于特定技术领域,它是跨领域跨平台的概念。 模板引擎的作用就是分离业务数据和最终呈现内容,它可以生成特定格式的文档(模板) 。
-模板引擎简单来说,就是:***`模板 + 数据模型 = 输出`***
+模板引擎简单来说,就是:**_`模板 + 数据模型 = 输出`_**
较早,也比较经典的模板引擎是 JavaEE 的标准技术 JSP。
@@ -10,8 +25,8 @@
- **性能差**
- JSP 本质上是 Servlet,第一次请求 JSP 页面,必须要在 web 服务器中编译成 servlet,所以第一次响应较慢。
- - 每次请求 JSP 都是访问servlet再用输出流输出的html页面。
- - JSP中的内容很多,页面响应会很慢,因为是同步加载。
+ - 每次请求 JSP 都是访问 servlet 再用输出流输出的 html 页面。
+ - JSP 中的内容很多,页面响应会很慢,因为是同步加载。
- **无法前后端分离**
- 动态资源和静态资源全部耦合在一起,无法做到前后端分离。一旦服务器出现状况,前后台一起玩完。
- 而且 Java 工程师既当爹又当妈,又要维护 Java 代码,又要维护 JSP 代码,痛苦。
@@ -26,9 +41,9 @@
## 内容
-- [Freemark](freemark.md)
-- [Thymeleaf](thymeleaf.md)
-- [Velocity](velocity.md)
+- [Freemark](01.Freemark.md)
+- [Thymeleaf](02.Thymeleaf.md)
+- [Velocity](03.Velocity.md)
## 资源
@@ -40,4 +55,4 @@
- [Velocity Github](https://github.com/apache/velocity-engine/)
- [Velocity 官网](https://velocity.apache.org/)
- [Velocity 中文文档](https://wizardforcel.gitbooks.io/velocity-doc/content/)
- - [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
+ - [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
\ No newline at end of file
diff --git a/docs/test/junit.md "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
similarity index 90%
rename from docs/test/junit.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
index f8750cf5..b1d02cb9 100644
--- a/docs/test/junit.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
@@ -1,26 +1,35 @@
-# JUnit5 应用指南
+---
+title: JUnit5 快速入门
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+ - JUnit
+permalink: /pages/b39f47/
+---
-> version: junit5
+# JUnit5 快速入门
-
+## JUnit5 简介
-- [1. 安装](#1-安装)
-- [2. JUnit 注解](#2-junit-注解)
-- [3. 编写单元测试](#3-编写单元测试)
- - [3.1. 基本的单元测试类和方法](#31-基本的单元测试类和方法)
- - [3.2. 定制测试类和方法的显示名称](#32-定制测试类和方法的显示名称)
- - [3.3. 断言(Assertions)](#33-断言assertions)
- - [3.4. 假想(Assumptions)](#34-假想assumptions)
- - [3.5. 禁用](#35-禁用)
- - [3.6. 测试条件](#36-测试条件)
- - [3.7. 嵌套测试](#37-嵌套测试)
- - [3.8. 重复测试](#38-重复测试)
- - [3.9. 参数化测试](#39-参数化测试)
-- [4. 引用和引申](#4-引用和引申)
+与以前的 JUnit 版本不同,JUnit 5 由来自三个不同子项目的几个不同模块组成。
-
+JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
-## 1. 安装
+JUnit Platform 是在 JVM 上启动测试框架的基础。它还定义了用于开发在平台上运行的测试框架的 TestEngine API。此外,该平台还提供了一个控制台启动器,用于从命令行启动平台,并提供 JUnit 平台套件引擎,用于使用平台上的一个或多个测试引擎运行自定义测试套件。
+
+JUnit Jupiter 是编程模型和扩展模型的组合,用于在 JUnit 5 中编写测试和扩展。Jupiter 子项目提供了一个 测试引擎(`TestEngine` )用于在平台上运行基于 Jupiter 的测试。
+
+JUnit Vintage 提供了一个测试引擎(`TestEngine` ),用于在平台上运行基于 JUnit 3 和 JUnit 4 的测试。它要求 JUnit 4.12 或更高版本。
+
+JUnit 5 在运行时需要 Java 8(或更高版本)。
+
+## JUnit5 安装
在 pom 中添加依赖
@@ -53,9 +62,9 @@
组件间依赖关系:
-
+
-## 2. JUnit 注解
+## JUnit5 注解
| Annotation | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -75,9 +84,13 @@
| `@Disabled` | Used to _disable_ a test class or test method; analogous to JUnit 4’s `@Ignore`. Such annotations are not _inherited_. |
| `@ExtendWith` | Used to register custom [extensions](https://junit.org/junit5/docs/current/user-guide/#extensions). Such annotations are _inherited_. |
-## 3. 编写单元测试
+## JUnit5 示例
+
+> 我将一部分官方示例放在了我的个人项目中,可以直接下载测试。
+>
+> 示例源码路径:https://github.com/dunwu/java-tutorial/tree/master/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5
-### 3.1. 基本的单元测试类和方法
+### 基本的单元测试类和方法
```java
import org.junit.jupiter.api.*;
@@ -128,7 +141,7 @@ class Junit5StandardTests {
}
```
-### 3.2. 定制测试类和方法的显示名称
+### 定制测试类和方法的显示名称
支持普通字符、特殊符号、emoji
@@ -153,7 +166,7 @@ class JunitDisplayNameDemo {
}
```
-### 3.3. 断言(Assertions)
+### 断言(Assertions)
```java
import org.junit.jupiter.api.BeforeAll;
@@ -270,7 +283,7 @@ class AssertionsDemo {
}
```
-### 3.4. 假想(Assumptions)
+### 假想(Assumptions)
```java
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -309,7 +322,7 @@ class AssumptionsDemo {
}
```
-### 3.5. 禁用
+### 禁用
禁用单元测试类示例:
@@ -344,7 +357,7 @@ class DisabledTestsDemo {
}
```
-### 3.6. 测试条件
+### 测试条件
#### 操作系统条件
@@ -418,7 +431,7 @@ void notOnCiServer() {
}
```
-### 3.7. 嵌套测试
+### 嵌套测试
```java
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -507,7 +520,7 @@ class TestingAStackDemo {
}
```
-### 3.8. 重复测试
+### 重复测试
```java
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -563,7 +576,7 @@ class RepeatedTestsDemo {
}
```
-### 3.9. 参数化测试
+### 参数化测试
```java
@ParameterizedTest
@@ -573,10 +586,9 @@ void palindromes(String candidate) {
}
```
-## 4. 引用和引申
+## 参考资料
-- [Github](https://github.com/junit-team/junit5)
-- [官方用户手册](https://junit.org/junit5/docs/current/user-guide/)
-- [Javadoc](https://junit.org/junit5/docs/current/api/)
-- [版本声明](https://junit.org/junit5/docs/current/release-notes/)
-- [官方示例](https://github.com/junit-team/junit5-samples)
+- [Junit5 Github](https://github.com/junit-team/junit5)
+- [Junit5 官方用户手册](https://junit.org/junit5/docs/current/user-guide/)
+- [Junit5 Javadoc](https://junit.org/junit5/docs/current/api/)
+- [Junit5 官方示例](https://github.com/junit-team/junit5-samples)
\ No newline at end of file
diff --git a/docs/test/mockito.md "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
similarity index 98%
rename from docs/test/mockito.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
index 74551215..e33ffaa4 100644
--- a/docs/test/mockito.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
@@ -1,4 +1,19 @@
-# Mockito 应用指南
+---
+title: Mockito 快速入门
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+ - Mockito
+permalink: /pages/f2c6f5/
+---
+
+# Mockito 快速入门
> Mockito 是一个针对 Java 的 mock 框架。
@@ -37,7 +52,7 @@ Mock 对象可以被提供来进行测试。因此,我们测试的类应该避
### 使用 Mockito 生成 Mock 对象
-*Mockito* 是一个流行 mock 框架,可以和 JUnit 结合起来使用。Mockito 允许你创建和配置 mock 对象。使用 Mockito 可以明显的简化对外部依赖的测试类的开发。
+_Mockito_ 是一个流行 mock 框架,可以和 JUnit 结合起来使用。Mockito 允许你创建和配置 mock 对象。使用 Mockito 可以明显的简化对外部依赖的测试类的开发。
一般使用 Mockito 需要执行下面三步
@@ -228,7 +243,7 @@ public void testVerify() {
### 使用 Spy 封装 java 对象
-@Spy 或者`spy()`方法可以被用来封装 java 对象。被封装后,除非特殊声明(打桩 *stub*),否则都会真正的调用对象里面的每一个方法
+@Spy 或者`spy()`方法可以被用来封装 java 对象。被封装后,除非特殊声明(打桩 _stub_),否则都会真正的调用对象里面的每一个方法
```java
import static org.mockito.Mockito.*;
@@ -559,4 +574,4 @@ class FooWraper {
- [官网](https://site.mockito.org/)
- [Github](https://github.com/mockito/mockito)
-- [使用强大的 Mockito 测试框架来测试你的代码](https://github.com/xitu/gold-miner/blob/master/TODO/Unit-tests-with-Mockito.md)
+- [使用强大的 Mockito 测试框架来测试你的代码](https://github.com/xitu/gold-miner/blob/master/TODO/Unit-tests-with-Mockito.md)
\ No newline at end of file
diff --git a/docs/test/jmeter.md "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
similarity index 81%
rename from docs/test/jmeter.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
index 028c260f..7378e09f 100644
--- a/docs/test/jmeter.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
@@ -1,14 +1,29 @@
-# JMeter 应用指南
+---
+title: JMeter 快速入门
+date: 2022-02-17 22:34:30
+order: 03
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+ - JMeter
+permalink: /pages/0e5ab1/
+---
+
+# JMeter 快速入门
> [Jmeter](https://github.com/apache/jmeter) 是一款基于 Java 开发的功能和性能测试软件。
>
> 🎁 本文编辑时的最新版本为:5.1.1
-## 1. 简介
+## 简介
[Jmeter](https://github.com/apache/jmeter) 是一款使用 Java 开发的功能和性能测试软件。
-### 1.1. 特性
+### 特性
Jmeter 能够加载和性能测试许多不同的应用程序/服务器/协议类型:
@@ -23,15 +38,15 @@ Jmeter 能够加载和性能测试许多不同的应用程序/服务器/协议
- TCP 协议
- Java 对象
-### 1.2. 工作流
+### 工作流
Jmeter 的工作原理是仿真用户向服务器发送请求,并收集服务器应答信息并计算统计信息。
Jmeter 的工作流如下图所示:
-
+
-### 1.3. 主要元素
+### 主要元素
Jmeter 的主要元素如下:
@@ -49,7 +64,7 @@ Jmeter 的主要元素如下:
- **`预处理器元素(Pre-Processor Elements)`** - 预处理器元素在采样器发出请求之前执行,如果预处理器附加到采样器元素,那么它将在该采样器元素运行之前执行。预处理器元素用于在运行之前准备环境及参数。
- **`后处理器元素(Post-Processor Elements)`** - 后处理器元素是在发送采样器请求之后执行的元素,常用于处理响应数据。
-
+
> 📌 提示:
>
@@ -60,9 +75,9 @@ Jmeter 的主要元素如下:
> 3. 线程组中至少要有一个取样器。
> 4. 线程组中至少要有一个监听器。
-## 2. 安装
+## 安装
-### 2.1. 环境要求
+### 环境要求
- 必要的。Jmeter 基于 JDK8 开发,所以必须运行在 JDK8 环境。
@@ -73,21 +88,21 @@ Jmeter 的主要元素如下:
- JMS
- [Bouncy Castle](http://www.bouncycastle.org/test_releases.html)
-### 2.2. 下载
+### 下载
进入 [**Jmeter 官网下载地址**](https://jmeter.apache.org/download_jmeter.cgi) 选择需要版本进行下载。
-### 2.3. 启动
+### 启动
解压 Jmeter 压缩包,进入 bin 目录
Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
-
+
-## 3. 使用
+## 使用
-### 3.1. 创建测试计划
+### 创建测试计划
> 🔔 注意:
>
@@ -95,23 +110,23 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
>
> - JMeter 的测试计划以 `.jmx` 扩展文件的形式保存。
-#### 3.1.1. 创建线程组
+#### 创建线程组
- 在“测试计划”上右键 【添加】=>【线程(用户)】=>【线程组】。
- 设置线程数和循环次数
-
+
-#### 3.1.2. 配置原件
+#### 配置原件
- 在新建的线程组上右键 【添加】=>【配置元件】=>【HTTP 请求默认值】。
- 填写协议、服务器名称或 IP、端口号
-
+
-#### 3.1.3. 构造 HTTP 请求
+#### 构造 HTTP 请求
- 在“线程组”上右键 【添加-】=>【取样器】=>【HTTP 请求】。
@@ -119,41 +134,41 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
- 填写方法、路径
- 填写参数、消息体数据、文件上传
-
+
-#### 3.1.4. 添加 HTTP 请求头
+#### 添加 HTTP 请求头
- 在“线程组”上右键 【添加】=>【配置元件】=>【HTTP 信息头管理器】
- 由于我的测试例中传输的数据为 json 形式,所以设置键值对 `Content-Type`:`application/json`
-
+
-#### 3.1.5. 添加断言
+#### 添加断言
- 在“线程组”上右键 【添加】=>【断言】=>【 响应断言 】
- 在我的案例中,以 HTTP 应答状态码为 200 来判断请求是否成功
-
+
-#### 3.1.6. 添加察看结果树
+#### 添加察看结果树
- 在“线程组”上右键 【添加】=>【监听器】=>【察看结果树】
- 直接点击运行,就可以查看测试结果
-
+
-#### 3.1.7. 添加汇总报告
+#### 添加汇总报告
- 在“线程组”上右键 【添加】=>【监听器】=>【汇总报告】
- 直接点击运行,就可以查看测试结果
-
+
-#### 3.1.8. 保存测试计划
+#### 保存测试计划
执行测试计划前,GUI 会提示先保存配置为 `jmx` 文件。
-### 3.2. 执行测试计划
+### 执行测试计划
官方建议不要直接使用 GUI 来执行测试计划,这种模式指适用于创建测试计划和 debug。
@@ -165,11 +180,11 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
执行测试计划后,在 `-e -o` 参数后指定的 web 报告目录下,可以找到测试报告内容。在浏览器中打开 `index.html` 文件,可以看到如下报告:
-
+
-## 4. 问题
+## 问题
-### 4.1. 如何读取本地 txt/csv 文件作为请求参数
+### 如何读取本地 txt/csv 文件作为请求参数
参考:[Jmeter 读取本地 txt/csv 文件作为请求参数,实现接口自动化](https://www.jianshu.com/p/3b2d3b643415)
@@ -177,7 +192,7 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
配置如下所示:
-
+
重要配置说明(其他配置根据实际情况填):
@@ -191,14 +206,14 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
[{"a":"${a}","b":"${b}"}]
```
-### 4.2. 如何有序发送数据
+### 如何有序发送数据
依次点击【添加】=>【逻辑控制器】=>【事务控制器】
-## 5. 参考资料
+## 参考资料
- [Jmeter 官网](https://jmeter.apache.org/)
- [Jmeter Github](https://github.com/apache/jmeter)
- [Jmeter 性能测试入门](https://www.cnblogs.com/TankXiao/p/4045439.html)
- [易百教程 - Jmeter 教程](https://www.yiibai.com/jmeter)
-- [Jmeter 读取本地 txt/csv 文件作为请求参数,实现接口自动化](https://www.jianshu.com/p/3b2d3b643415)
+- [Jmeter 读取本地 txt/csv 文件作为请求参数,实现接口自动化](https://www.jianshu.com/p/3b2d3b643415)
\ No newline at end of file
diff --git a/docs/test/jmh.md "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
similarity index 96%
rename from docs/test/jmh.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
index a14f54a9..e5707faf 100644
--- a/docs/test/jmh.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
@@ -1,4 +1,19 @@
-# JMH 应用指南
+---
+title: JMH 快速入门
+date: 2022-02-17 22:34:30
+order: 04
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+ - JUnit
+permalink: /pages/9c6402/
+---
+
+# JMH 快速入门
## 基准测试简介
@@ -8,7 +23,7 @@
现代软件常常都把高性能作为目标。那么,何为高性能,性能就是快,更快吗?显然,如果没有一个量化的标准,难以衡量性能的好坏。
-不同的基准测试其具体内容和范围也存在很大的不同。如果是专业的性能工程师,更加熟悉的可能是类似SPEC提供的工业标准的系统级测试;而对于大多数 Java 开发者,更熟悉的则是范围相对较小、关注点更加细节的微基准测试(Micro-Benchmark)。何谓 Micro Benchmark 呢? 简单地说就是在 method 层面上的 benchmark,精度可以精确到 **微秒级**。
+不同的基准测试其具体内容和范围也存在很大的不同。如果是专业的性能工程师,更加熟悉的可能是类似 SPEC 提供的工业标准的系统级测试;而对于大多数 Java 开发者,更熟悉的则是范围相对较小、关注点更加细节的微基准测试(Micro-Benchmark)。何谓 Micro Benchmark 呢? 简单地说就是在 method 层面上的 benchmark,精度可以精确到 **微秒级**。
### 何时需要微基准测试
@@ -337,4 +352,4 @@ State 用于声明某个类是一个“状态”,然后接受一个 Scope 参
- [jmh 官方示例](http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/)
- [Java 微基准测试框架 JMH](https://www.xncoding.com/2018/01/07/java/jmh.html)
-- [JAVA 拾遗 — JMH 与 8 个测试陷阱](https://www.cnkirito.moe/java-jmh/)
+- [JAVA 拾遗 — JMH 与 8 个测试陷阱](https://www.cnkirito.moe/java-jmh/)
\ No newline at end of file
diff --git "a/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md"
new file mode 100644
index 00000000..ab247b86
--- /dev/null
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md"
@@ -0,0 +1,23 @@
+---
+title: Java 测试
+date: 2022-02-17 22:34:30
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+permalink: /pages/2cecc3/
+hidden: true
+index: false
+---
+
+# Java 测试
+
+## 内容
+
+- [Junit](01.Junit.md)
+- [Mockito](02.Mockito.md)
+- [Jmeter](03.Jmeter.md)
+- [JMH](04.JMH.md)
\ No newline at end of file
diff --git a/docs/lib/javalib-log.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
similarity index 93%
rename from docs/lib/javalib-log.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
index caab593c..efdc23d6 100644
--- a/docs/lib/javalib-log.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
@@ -1,3 +1,17 @@
+---
+title: javalib-log
+date: 2022-02-17 22:34:30
+order: 01
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 日志
+permalink: /pages/fcc1c4/
+---
+
# 细说 Java 主流日志工具库
> 在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息。
@@ -5,37 +19,6 @@
> 在 Java 世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子。
>
> 我们先来逐一了解一下主流日志工具。
->
-> 📦 本文已归档到:「[blog](https://github.com/dunwu/blog)」
-
-
-
-- [日志框架](#日志框架)
- - [java.util.logging (JUL)](#javautillogging-jul)
- - [Log4j](#log4j)
- - [Logback](#logback)
- - [Log4j2](#log4j2)
- - [Log4j vs Logback vs Log4j2](#log4j-vs-logback-vs-log4j2)
-- [日志门面](#日志门面)
- - [common-logging](#common-logging)
- - [slf4j](#slf4j)
- - [common-logging vs slf4j](#common-logging-vs-slf4j)
- - [总结](#总结)
-- [实施日志解决方案](#实施日志解决方案)
- - [引入 jar 包](#引入-jar-包)
- - [使用 API](#使用-api)
-- [log4j2 配置](#log4j2-配置)
-- [logback 配置](#logback-配置)
- - [``](#configuration)
- - [``](#appender)
- - [``](#logger)
- - [``](#root)
- - [完整的 logback.xml 参考示例](#完整的-logbackxml-参考示例)
-- [log4j 配置](#log4j-配置)
- - [完整的 log4j.xml 参考示例](#完整的-log4jxml-参考示例)
-- [参考](#参考)
-
-
## 日志框架
@@ -81,7 +64,7 @@ logback 当前分成三个模块:`logback-core`、`logback-classic` 和 `logba
Log4j2 架构:
-
+
### Log4j vs Logback vs Log4j2
@@ -125,7 +108,7 @@ common-logging 的功能是提供日志功能的 API 接口,本身并不提供
[官网地址](http://www.slf4j.org/)
-
+
### common-logging vs slf4j
@@ -219,7 +202,7 @@ _slf4j-jdk14-1.7.21.jar_ 会自动将 _slf4j-api-1.7.21.jar_ 也添加到你的
假如你正在开发应用程序所调用的组件当中已经使用了 common-logging,这时你需要 jcl-over-slf4j.jar 把日志信息输出重定向到 slf4j-api,slf4j-api 再去调用 slf4j 实际依赖的日志组件。这个过程称为桥接。下图是官方的 slf4j 桥接策略图:
-
+
从图中应该可以看出,无论你的老项目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用对应的桥接 jar 包来解决兼容问题。
@@ -435,7 +418,7 @@ log4j2 基本配置形式如下:
- 要点
- 它有 ``、``、`` 三个子元素。
-
+
### ``
@@ -473,7 +456,7 @@ log4j2 基本配置形式如下:
- 属性
- class:设置具体的实例化类。
-
+
### ``
@@ -759,4 +742,4 @@ log4j 的配置文件一般有 xml 格式或 properties 格式。这里为了和
- [logback 官方文档](http://logback.qos.ch/)
- [log4j 官方文档](http://logging.apache.org/log4j/1.2/)
- [commons-logging 官方文档](http://commons.apache.org/proper/commons-logging/)
--
+-
\ No newline at end of file
diff --git a/docs/lib/javalib-util.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
similarity index 53%
rename from docs/lib/javalib-util.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
index 005aec39..192f3c42 100644
--- a/docs/lib/javalib-util.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
@@ -1,7 +1,21 @@
+---
+title: javalib-util
+date: 2022-02-17 22:34:30
+order: 02
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 工具包
+permalink: /pages/27ad42/
+---
+
# 细说 Java 主流工具包
- apache.commons
- [commons-lang](https://github.com/apache/commons-lang)
- [commons-collections](https://github.com/apache/commons-collections)
- [common-io](https://github.com/apache/commons-io)
-- [guava](https://github.com/google/guava)
+- [guava](https://github.com/google/guava)
\ No newline at end of file
diff --git a/docs/lib/reflections.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
similarity index 92%
rename from docs/lib/reflections.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
index e24c081d..6200ebea 100644
--- a/docs/lib/reflections.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
@@ -1,13 +1,21 @@
-# Reflections 应用指南
-
-
-
-- [使用](#使用)
-- [ReflectionUtils](#reflectionutils)
-
-
-
-引入
+---
+title: Reflections 快速入门
+date: 2022-02-17 22:34:30
+order: 03
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 反射
+ - Reflections
+permalink: /pages/ce6195/
+---
+
+# Reflections 快速入门
+
+引入 pom
```xml
@@ -97,4 +105,4 @@ Set listMethodsFromCollectionToBoolean =
withParametersAssignableTo(Collection.class), withReturnType(boolean.class));
Set fields = getAllFields(SomeClass.class, withAnnotation(annotation), withTypeAssignableTo(type));
-```
+```
\ No newline at end of file
diff --git a/docs/lib/javamail.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
similarity index 93%
rename from docs/lib/javamail.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
index 89c351d6..dc623bbf 100644
--- a/docs/lib/javamail.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
@@ -1,28 +1,18 @@
-# JavaMail 应用指南
-
-
-
-- [简介](#简介)
- - [邮件相关的标准](#邮件相关的标准)
- - [JavaMail 简介](#javamail-简介)
- - [邮件传输过程](#邮件传输过程)
- - [Message 结构](#message-结构)
-- [JavaMail 的核心类](#javamail-的核心类)
- - [java.util.Properties 类(属性对象)](#javautilproperties-类属性对象)
- - [javax.mail.Session 类(会话对象)](#javaxmailsession-类会话对象)
- - [javax.mail.Transport 类(邮件传输)](#javaxmailtransport-类邮件传输)
- - [javax.mail.Store 类(邮件存储 )](#javaxmailstore-类邮件存储-)
- - [javax.mail.Message 类(消息对象)](#javaxmailmessage-类消息对象)
- - [javax.mail.Address 类(地址)](#javaxmailaddress-类地址)
- - [Authenticator 类(认证者)](#authenticator-类认证者)
-- [实例](#实例)
- - [发送文本邮件](#发送文本邮件)
- - [发送 HTML 格式的邮件](#发送-html-格式的邮件)
- - [发送带附件的邮件](#发送带附件的邮件)
- - [获取邮箱中的邮件](#获取邮箱中的邮件)
- - [转发邮件](#转发邮件)
-
-
+---
+title: JavaMail 快速入门
+date: 2022-02-17 22:34:30
+order: 04
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 邮件
+permalink: /pages/cd38ec/
+---
+
+# JavaMail 快速入门
## 简介
@@ -463,4 +453,4 @@ public static void main(String[] args) throws Exception {
ts.close();
System.out.println("message forwarded successfully....");
}
-```
+```
\ No newline at end of file
diff --git a/docs/lib/jsoup.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
similarity index 93%
rename from docs/lib/jsoup.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
index 936dba8c..04f0cbd5 100644
--- a/docs/lib/jsoup.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
@@ -1,27 +1,19 @@
-# Jsoup 应用指南
-
-
-
-- [简介](#简介)
-- [加载](#加载)
- - [从 HTML 字符串加载一个文档](#从-html-字符串加载一个文档)
- - [解析一个 body 片断](#解析一个-body-片断)
- - [从 URL 加载一个文档](#从-url-加载一个文档)
- - [从一个文件加载一个文档](#从一个文件加载一个文档)
-- [解析](#解析)
- - [使用 DOM 方法来遍历一个文档](#使用-dom-方法来遍历一个文档)
- - [使用选择器语法来查找元素](#使用选择器语法来查找元素)
- - [从元素抽取属性,文本和 HTML](#从元素抽取属性文本和-html)
- - [处理 URLs](#处理-urls)
-- [数据修改](#数据修改)
- - [设置属性的值](#设置属性的值)
- - [设置一个元素的 HTML 内容](#设置一个元素的-html-内容)
- - [设置元素的文本内容](#设置元素的文本内容)
-- [HTML 清理](#html-清理)
- - [消除不受信任的 HTML (来防止 XSS 攻击)](#消除不受信任的-html-来防止-xss-攻击)
-- [参考](#参考)
-
-
+---
+title: Jsoup 快速入门
+date: 2022-02-17 22:34:30
+order: 05
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - Html
+ - Jsoup
+permalink: /pages/5dd78d/
+---
+
+# Jsoup 快速入门
## 简介
@@ -238,7 +230,7 @@ Elements resultLinks = doc.select("h3.r > a"); //在h3元素之后的a元素
#### 伪选择器 selectors
- `:lt(n)`: 查找哪些元素的同级索引值(它的位置在 DOM 树中是相对于它的父节点)小于 n,比如:`td:lt(3)` 表示小于三列的元素
-- `:gt(n)`:查找哪些元素的同级索引值大于`n``,比如`: `div p:gt(2)`表示哪些 div 中有包含 2 个以上的 p 元素
+- `:gt(n)`:查找哪些元素的同级索引值大于` n``,比如 `: `div p:gt(2)`表示哪些 div 中有包含 2 个以上的 p 元素
- `:eq(n)`: 查找哪些元素的同级索引值与`n`相等,比如:`form input:eq(1)`表示包含一个 input 标签的 Form 元素
- `:has(seletor)`: 查找匹配选择器包含元素的元素,比如:`div:has(p)`表示哪些 div 包含了 p 元素
- `:not(selector)`: 查找与选择器不匹配的元素,比如: `div:not(.logo)` 表示不包含 class=logo 元素的所有 div 列表
@@ -453,9 +445,6 @@ jsoup 提供了一系列的 `Whitelist` 基本配置,能够满足大多数要
## 参考
- [jsoup github 托管代码](https://github.com/jhy/jsoup)
-
- [jsoup Cookbook](https://jsoup.org/cookbook/)
-
- [jsoup Cookbook(中文版)](http://www.open-open.com/jsoup/)
-
-- [不错的 jsoup 学习笔记](https://github.com/code4craft/jsoup-learning)
+- [不错的 jsoup 学习笔记](https://github.com/code4craft/jsoup-learning)
\ No newline at end of file
diff --git a/docs/lib/thumbnailator.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
similarity index 93%
rename from docs/lib/thumbnailator.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
index 1f9dfc94..71151154 100644
--- a/docs/lib/thumbnailator.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
@@ -1,21 +1,19 @@
-# Thumbnailator 应用指南
-
-
-
-- [简介](#简介)
-- [核心 API](#核心-api)
- - [Thumbnails](#thumbnails)
- - [Thumbnails.Builder](#thumbnailsbuilder)
- - [工作流](#工作流)
-- [实战](#实战)
- - [安装](#安装)
- - [图片缩放](#图片缩放)
- - [图片旋转](#图片旋转)
- - [加水印](#加水印)
- - [批量处理图片](#批量处理图片)
-- [参考](#参考)
-
-
+---
+title: Thumbnailator 快速入门
+date: 2022-02-17 22:34:30
+order: 06
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 图形处理
+ - Thumbnailator
+permalink: /pages/adacc5/
+---
+
+# Thumbnailator 快速入门
## 简介
@@ -67,7 +65,7 @@ public static Builder fromImages(Iterable images)
`Thumbnails.Builder` 是 `Thumbnails` 的内部静态类。它用于设置生成缩略图任务的相关参数。
-***注:`Thumbnails.Builder` 的构造函数是私有函数。所以,它只允许通过 `Thumbnails` 的实例化函数来进行初始化。***
+**_注:`Thumbnails.Builder` 的构造函数是私有函数。所以,它只允许通过 `Thumbnails` 的实例化函数来进行初始化。_**
#### 设置参数的函数
@@ -241,4 +239,4 @@ Thumbnails.of("oldFile.png", "oldFile2.png")
## 参考
-[Thumbnailator 官方示例文档](https://github.com/coobird/thumbnailator/wiki/Examples)
+[Thumbnailator 官方示例文档](https://github.com/coobird/thumbnailator/wiki/Examples)
\ No newline at end of file
diff --git a/docs/lib/zxing.md "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
similarity index 87%
rename from docs/lib/zxing.md
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
index 62a7ae77..d5f691bb 100644
--- a/docs/lib/zxing.md
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
@@ -1,15 +1,19 @@
-# ZXing 应用指南
-
-
-
-- [简介](#简介)
-- [实战](#实战)
- - [安装](#安装)
- - [生成二维码图片](#生成二维码图片)
- - [解析二维码图片](#解析二维码图片)
-- [参考](#参考)
-
-
+---
+title: ZXing 快速入门
+date: 2022-02-17 22:34:30
+order: 07
+categories:
+ - Java
+ - 工具
+ - 其他
+tags:
+ - Java
+ - 条形码
+ - ZXing
+permalink: /pages/b563af/
+---
+
+# ZXing 快速入门
## 简介
@@ -19,7 +23,7 @@
## 实战
-***本例演示如何在一个非 android 的 Java 项目中使用 ZXing 来生成、解析二维码图片。***
+**_本例演示如何在一个非 android 的 Java 项目中使用 ZXing 来生成、解析二维码图片。_**
### 安装
@@ -90,4 +94,4 @@ public String decode(String filepath) throws IOException, NotFoundException {
## 参考
-[ZXing github 仓库](https://github.com/zxing/zxing)
+[ZXing github 仓库](https://github.com/zxing/zxing)
\ No newline at end of file
diff --git "a/docs/01.Java/12.\345\267\245\345\205\267/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/README.md"
new file mode 100644
index 00000000..dbd1c924
--- /dev/null
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/README.md"
@@ -0,0 +1,56 @@
+---
+title: Java 工具
+date: 2022-02-18 08:53:11
+categories:
+ - Java
+ - 工具
+tags:
+ - Java
+ - 工具
+permalink: /pages/1123e1/
+hidden: true
+index: false
+---
+
+# Java 工具
+
+## 📖 内容
+
+### Java IO
+
+- [JSON 序列化](01.IO/01.JSON序列化.md) - [fastjson](https://github.com/alibaba/fastjson)、[Jackson](https://github.com/FasterXML/jackson)、[Gson](https://github.com/google/gson)
+- [二进制序列化](01.IO/02.二进制序列化.md) - [Protobuf](https://developers.google.com/protocol-buffers)、[Thrift](https://thrift.apache.org/)、[Hessian](http://hessian.caucho.com/)、[Kryo](https://github.com/EsotericSoftware/kryo)、[FST](https://github.com/RuedigerMoeller/fast-serialization)
+
+### JavaBean 工具
+
+- [Lombok](02.JavaBean/01.Lombok.md)
+- [Dozer](02.JavaBean/02.Dozer.md)
+
+### Java 模板引擎
+
+- [Freemark](03.模板引擎/01.Freemark.md)
+- [Velocity](03.模板引擎/02.Thymeleaf.md)
+- [Thymeleaf](03.模板引擎/03.Velocity.md)
+
+### Java 测试工具
+
+- [Junit](04.测试/01.Junit.md)
+- [Mockito](04.测试/02.Mockito.md)
+- [Jmeter](04.测试/03.Jmeter.md)
+- [JMH](04.测试/04.JMH.md)
+
+### 其他
+
+- [Java 日志](99.其他/01.Java日志.md)
+- [Java 工具包](99.其他/02.Java工具包.md)
+- [Reflections](99.其他/03.Reflections.md)
+- [JavaMail](99.其他/04.JavaMail.md)
+- [Jsoup](99.其他/05.Jsoup.md)
+- [Thumbnailator](99.其他/06.Thumbnailator.md)
+- [Zxing](99.其他/07.Zxing.md)
+
+## 📚 资料
+
+## 🚪 传送
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md" "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md"
new file mode 100644
index 00000000..3a202241
--- /dev/null
+++ "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md"
@@ -0,0 +1,188 @@
+---
+title: Spring Framework 综述
+date: 2019-11-22 10:46:02
+order: 01
+categories:
+ - Java
+ - 框架
+ - Spring
+ - Spring综合
+tags:
+ - Java
+ - 框架
+ - Spring
+permalink: /pages/9d3091/
+---
+
+# Spring Framework 综述
+
+## Spring Framework 简介
+
+Spring Framework 是最受欢迎的企业级 Java 应用程序开发框架。用于构建企业级应用的轻量级、一站式解决方案。
+
+当谈论到大小和透明度时, Spring 是轻量级的。 Spring 框架的基础版本是在 2 MB 左右的。
+
+Spring 框架的核心特性可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。
+
+Spring Framework 设计理念如下:
+
+- 力争让选择无处不在
+- 体现海纳百川的精神
+- 保持后向兼容性
+- 专注 API 设计
+- 追求严苛的代码质量
+
+## 为什么使用 Spring
+
+下面列出的是使用 Spring 框架主要的好处:
+
+- Spring 可以使开发人员使用 POJOs 开发企业级的应用程序。只使用 POJOs 的好处是你不需要一个 EJB 容器产品,比如一个应用程序服务器,但是你可以选择使用一个健壮的 servlet 容器,比如 Tomcat 或者一些商业产品。
+- Spring 在一个单元模式中是有组织的。即使包和类的数量非常大,你只需要选择你需要的部分,而忽略剩余的那部分。
+- Spring 不会让你白费力气做重复工作,它真正的利用了一些现有的技术,像几个 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,其他视图技术。
+- 测试一个用 Spring 编写的应用程序很容易,因为 environment-dependent 代码被放进了这个框架中。此外,通过使用 JavaBean-style POJOs,它在使用依赖注入注入测试数据时变得更容易。
+- Spring 的 web 框架是一个设计良好的 web MVC 框架,它为 web 框架,比如 Structs 或者其他工程上的或者很少受欢迎的 web 框架,提供了一个很好的供替代的选择。
+- 为将特定技术的异常(例如,由 JDBC、Hibernate,或者 JDO 抛出的异常)翻译成一致的, Spring 提供了一个方便的 API,而这些都是未经检验的异常。
+- 轻量级的 IOC 容器往往是轻量级的,例如,特别是当与 EJB 容器相比的时候。这有利于在内存和 CPU 资源有限的计算机上开发和部署应用程序。
+- Spring 提供了一个一致的事务管理界面,该界面可以缩小成一个本地事务(例如,使用一个单一的数据库)和扩展成一个全局事务(例如,使用 JTA)。
+
+## 核心思想
+
+Spring 最核心的两个技术思想是:IoC 和 Aop
+
+### IoC
+
+`IoC` 即 `Inversion of Control` ,意为控制反转。
+
+Spring 最认同的技术是控制反转的**依赖注入(DI)**模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
+
+当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。
+
+到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。
+
+依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。
+
+### Aop
+
+Spring 框架的一个关键组件是**面向方面的程序设计(AOP)**框架。一个程序中跨越多个点的功能被称为**横切关注点**,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。
+
+在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。
+
+Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。
+
+## Spring 体系结构
+
+Spring 当前框架有**20**个 jar 包,大致可以分为**6**大模块:
+
+- 1. 为什么使用 Spring
+- 2. 核心思想
+ - 2.1. IoC
+ - 2.2. Aop
+- 3. Spring 体系结构
+ - 3.1. Core Container
+ - 3.1.1. BeanFactory
+ - 3.1.2. ApplicationContext
+ - 3.2. AOP and Instrumentation
+ - 3.3. Messaging
+ - 3.4. Data Access / Integaration
+ - 3.5. Web
+ - 3.6. Test
+- 4. 术语
+
+Spring 框架提供了非常丰富的功能,因此整个架构也很庞大。
+在我们实际的应用开发中,并不一定要使用所有的功能,而是可以根据需要选择合适的 Spring 模块。
+
+
+
+### Core Container
+
+IoC 容器是 Spring 框架的核心。spring 容器使用依赖注入管理构成应用的组件,它会创建相互协作的组件之间的关联。毫无疑问,这些对象更简单干净,更容易理解,也更容易重用和测试。
+Spring 自带了几种容器的实现,可归纳为两种类型:
+
+#### BeanFactory
+
+由 org.springframework.beans.factory.BeanFactory 接口定义。
+它是最简单的容器,提供基本的 DI 支持。
+
+#### ApplicationContext
+
+由 org.springframework.context.ApplicationContext 接口定义。
+它是基于 BeanFactory 之上构建,并提供面向应用的服务,例如从属性文件解析文本信息的能力,以及发布应用事件给感兴趣的事件监听者的能力。
+**_注:Bean 工厂对于大多数应用来说往往太低级了,所以应用上下文使用更广泛。推荐在开发中使用应用上下文容器。_**
+
+Spring 自带了多种应用上下文,最可能遇到的有以下几种:
+`ClassPathXmlApplicationContext`:从类路径下的 XML 配置文件中加载上下文定义,把应用上下文定义文件当做类资源。
+`FileSystemXmlApplicationContext`:读取文件系统下的 XML 配置文件并加载上下文定义。
+`XmlWebApplicationContext`:读取 Web 应用下的 XML 配置文件并装载上下文定义。
+
+**_范例_**
+
+```java
+ApplicationContext context = new FileSystemXmlApplicationContext("D:\Temp\build.xml");
+ApplicationContext context2 = new ClassPathXmlApplicationContext("build.xml");
+```
+
+可以看到,加载 `FileSystemXmlApplicationContext` 和 `ClassPathXmlApplicationContext` 十分相似。
+差异在于:前者在指定文件系统路径下查找 build.xml 文件;而后在所有类路径(包含 JAR 文件)下查找 build.xml 文件。
+通过引用应用上下文,可以很方便的调用 getBean() 方法从 Spring 容器中获取 Bean。
+
+**相关 jar 包**
+
+- `spring-core`, `spring-beans`, 提供框架的基础部分,包括 IoC 和依赖注入特性。
+
+- `spring-context`, 在`spring-core`, `spring-beans`基础上构建。它提供一种框架式的访问对象的方法。它也支持类似 Java EE 特性,例如:EJB,JMX 和基本 remoting。ApplicationContext 接口是它的聚焦点。
+- `springcontext-support`, 集成第三方库到 Spring application context。
+- `spring-expression`,提供一种强有力的表达语言在运行时来查询和操纵一个对象图。
+
+### AOP and Instrumentation
+
+**相关 jar 包**
+
+- `spring-aop`,提供了对面向切面编程的丰富支持。
+- `spring-aspects`,提供了对 AspectJ 的集成。
+- `spring-instrument`,提供了对类 instrumentation 的支持和类加载器。
+- `spring-instrument-tomcat`,包含了 Spring 对 Tomcat 的 instrumentation 代理。
+
+### Messaging
+
+**相关 jar 包**
+
+- `spring-messaging`,包含 spring 的消息处理功能,如 Message,MessageChannel,MessageHandler。
+
+### Data Access / Integaration
+
+Data Access/Integration 层包含了 JDBC / ORM / OXM / JMS 和 Transaction 模块。
+
+**相关 jar 包**
+
+- `spring-jdbc`,提供了一个 JDBC 抽象层。
+
+- `spring-tx`,支持编程和声明式事务管理类。
+- `spring-orm`,提供了流行的对象关系型映射 API 集,如 JPA,JDO,Hibernate。
+- `spring-oxm`,提供了一个抽象层以支持对象/XML 映射的实现,如 JAXB,Castor,XMLBeans,JiBX 和 XStream.
+- `spring-jms`,包含了生产和消费消息的功能。
+
+### Web
+
+**相关 jar 包**
+
+- `spring-web`,提供了基本的面向 web 的功能,如多文件上传、使用 Servlet 监听器的 Ioc 容器的初始化。一个面向 web 的应用层上下文。
+
+- `spring-webmvc`,包括 MVC 和 REST web 服务实现。
+- `spring-webmvc-portlet`,提供在 Protlet 环境的 MVC 实现和`spring-webmvc`功能的镜像。
+
+### Test
+
+**相关 jar 包**
+
+- `spring-test`,以 Junit 和 TestNG 来支持 spring 组件的单元测试和集成测试。
+
+## 术语
+
+- **应用程序**:是能完成我们所需要功能的成品,比如购物网站、OA 系统。
+- **框架**:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
+- **非侵入式设计**:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
+- **轻量级及重量级**:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
+- **POJO**:POJO(Plain Old Java Objects)简单的 Java 对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它 Java 框架的类或接口。
+- **容器**:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
+- **控制反转:**即 Inversion of Control,缩写为 IoC,控制反转还有一个名字叫做依赖注入(Dependency Injection),就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。
+- **JavaBean**:一般指容器管理对象,在 Spring 中指 Spring IoC 容器管理对象。
\ No newline at end of file
diff --git "a/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md" "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md"
new file mode 100644
index 00000000..3a5733b4
--- /dev/null
+++ "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md"
@@ -0,0 +1,951 @@
+---
+title: SpringBoot 知识图谱
+date: 2020-08-12 07:01:26
+order: 21
+categories:
+ - Java
+ - 框架
+ - Spring
+ - Spring综合
+tags:
+ - Java
+ - 框架
+ - Spring
+ - SpringBoot
+permalink: /pages/430f53/
+---
+
+# SpringBoot 知识图谱
+
+> 1. 预警:本文非常长,建议先 mark 后看,也许是最后一次写这么长的文章
+> 2. 说明:前面有 4 个小节关于 Spring 的基础知识,分别是:IOC 容器、JavaConfig、事件监听、SpringFactoriesLoader 详解,它们占据了本文的大部分内容,虽然它们之间可能没有太多的联系,但这些知识对于理解 Spring Boot 的核心原理至关重要,如果你对 Spring 框架烂熟于心,完全可以跳过这 4 个小节。正是因为这个系列的文章是由这些看似不相关的知识点组成,因此取名知识清单。
+
+在过去两三年的 Spring 生态圈,最让人兴奋的莫过于 Spring Boot 框架。或许从命名上就能看出这个框架的设计初衷:快速的启动 Spring 应用。因而 Spring Boot 应用本质上就是一个基于 Spring 框架的应用,它是 Spring 对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于 Spring 生态圈的应用。
+
+那 Spring Boot 有何魔法?**自动配置**、**起步依赖**、**Actuator**、**命令行界面(CLI)** 是 Spring Boot 最重要的 4 大核心特性,其中 CLI 是 Spring Boot 的可选特性,虽然它功能强大,但也引入了一套不太常规的开发模型,因而这个系列的文章仅关注其它 3 种特性。如文章标题,本文是这个系列的第一部分,将为你打开 Spring Boot 的大门,重点为你剖析其启动流程以及自动配置实现原理。要掌握这部分核心内容,理解一些 Spring 框架的基础知识,将会让你事半功倍。
+
+## 一、抛砖引玉:探索 Spring IoC 容器
+
+如果有看过`SpringApplication.run()`方法的源码,Spring Boot 冗长无比的启动流程一定会让你抓狂,透过现象看本质,SpringApplication 只是将一个典型的 Spring 应用的启动流程进行了扩展,因此,透彻理解 Spring 容器是打开 Spring Boot 大门的一把钥匙。
+
+### 1.1、Spring IoC 容器
+
+可以把 Spring IoC 容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。IoC 容器也是一样,你只需要告诉它需要某个 bean,它就把对应的实例(instance)扔给你,至于这个 bean 是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。
+
+作为餐馆,想要做出菜肴,得知道菜的原料和菜谱,同样地,IoC 容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。`BeanDefinition`对象就承担了这个责任:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例,该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的 bean 实例。
+
+原材料已经准备好(把 BeanDefinition 看着原料),开始做菜吧,等等,你还需要一份菜谱,`BeanDefinitionRegistry`和`BeanFactory`就是这份菜谱,BeanDefinitionRegistry 抽象出 bean 的注册逻辑,而 BeanFactory 则抽象出了 bean 的管理逻辑,而各个 BeanFactory 的实现类就具体承担了 bean 的注册以及管理工作。它们之间的关系就如下图:
+
+ _BeanFactory、BeanDefinitionRegistry 关系图(来自:Spring 揭秘)_
+
+`DefaultListableBeanFactory`作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 Bean 的注册管理工作。从图中也可以看出,BeanFactory 接口中主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法,而 BeanDefinitionRegistry 接口则包含 registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。
+
+下面通过一段简单的代码来模拟 BeanFactory 底层是如何工作的:
+
+```
+// 默认容器实现
+DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
+// 根据业务对象构造相应的BeanDefinition
+AbstractBeanDefinition definition = new RootBeanDefinition(Business.class,true);
+// 将bean定义注册到容器中
+beanRegistry.registerBeanDefinition("beanName",definition);
+// 如果有多个bean,还可以指定各个bean之间的依赖关系
+// ........
+
+// 然后可以从容器中获取这个bean的实例
+// 注意:这里的beanRegistry其实实现了BeanFactory接口,所以可以强转,
+// 单纯的BeanDefinitionRegistry是无法强制转换到BeanFactory类型的
+BeanFactory container = (BeanFactory)beanRegistry;
+Business business = (Business)container.getBean("beanName");
+```
+
+这段代码仅为了说明 BeanFactory 底层的大致工作流程,实际情况会更加复杂,比如 bean 之间的依赖关系可能定义在外部配置文件(XML/Properties)中、也可能是注解方式。Spring IoC 容器的整个工作流程大致可以分为两个阶段:
+
+①、容器启动阶段
+
+容器启动时,会通过某种途径加载`Configuration MetaData`。除了代码方式比较直接外,在大部分情况下,容器需要依赖某些工具类,比如:`BeanDefinitionReader`,BeanDefinitionReader 会对加载的`Configuration MetaData`进行解析和分析,并将分析后的信息组装为相应的 BeanDefinition,最后把这些保存了 bean 定义的 BeanDefinition,注册到相应的 BeanDefinitionRegistry,这样容器的启动工作就完成了。这个阶段主要完成一些准备性工作,更侧重于 bean 对象管理信息的收集,当然一些验证性或者辅助性的工作也在这一阶段完成。
+
+来看一个简单的例子吧,过往,所有的 bean 都定义在 XML 配置文件中,下面的代码将模拟 BeanFactory 如何从配置文件中加载 bean 的定义以及依赖关系:
+
+```
+// 通常为BeanDefinitionRegistry的实现类,这里以DeFaultListabeBeanFactory为例
+BeanDefinitionRegistry beanRegistry = new DefaultListableBeanFactory();
+// XmlBeanDefinitionReader实现了BeanDefinitionReader接口,用于解析XML文件
+XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReaderImpl(beanRegistry);
+// 加载配置文件
+beanDefinitionReader.loadBeanDefinitions("classpath:spring-bean.xml");
+
+// 从容器中获取bean实例
+BeanFactory container = (BeanFactory)beanRegistry;
+Business business = (Business)container.getBean("beanName");
+```
+
+②、Bean 的实例化阶段
+
+经过第一阶段,所有 bean 定义都通过 BeanDefinition 的方式注册到 BeanDefinitionRegistry 中,当某个请求通过容器的 getBean 方法请求某个对象,或者因为依赖关系容器需要隐式的调用 getBean 时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的 BeanDefinition 所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。
+
+BeanFactory 只是 Spring IoC 容器的一种实现,如果没有特殊指定,它采用采用延迟初始化策略:只有当访问容器中的某个对象时,才对该对象进行初始化和依赖注入操作。而在实际场景下,我们更多的使用另外一种类型的容器:`ApplicationContext`,它构建在 BeanFactory 之上,属于更高级的容器,除了具有 BeanFactory 的所有能力之外,还提供对事件监听机制以及国际化的支持等。它管理的 bean,在容器启动时全部完成初始化和依赖注入操作。
+
+### 1.2、Spring 容器扩展机制
+
+IoC 容器负责管理容器中所有 bean 的生命周期,而在 bean 生命周期的不同阶段,Spring 提供了不同的扩展点来改变 bean 的命运。在容器的启动阶段,`BeanFactoryPostProcessor`允许我们在容器实例化相应对象之前,对注册到容器的 BeanDefinition 所保存的信息做一些额外的操作,比如修改 bean 定义的某些属性或者增加其他信息等。
+
+如果要自定义扩展类,通常需要实现`org.springframework.beans.factory.config.BeanFactoryPostProcessor`接口,与此同时,因为容器中可能有多个 BeanFactoryPostProcessor,可能还需要实现`org.springframework.core.Ordered`接口,以保证 BeanFactoryPostProcessor 按照顺序执行。Spring 提供了为数不多的 BeanFactoryPostProcessor 实现,我们以`PropertyPlaceholderConfigurer`来说明其大致的工作流程。
+
+在 Spring 项目的 XML 配置文件中,经常可以看到许多配置项的值使用占位符,而将占位符所代表的值单独配置到独立的 properties 文件,这样可以将散落在不同 XML 文件中的配置集中管理,而且也方便运维根据不同的环境进行配置不同的值。这个非常实用的功能就是由 PropertyPlaceholderConfigurer 负责实现的。
+
+根据前文,当 BeanFactory 在第一阶段加载完所有配置信息时,BeanFactory 中保存的对象的属性还是以占位符方式存在的,比如`${jdbc.mysql.url}`。当 PropertyPlaceholderConfigurer 作为 BeanFactoryPostProcessor 被应用时,它会使用 properties 配置文件中的值来替换相应的 BeanDefinition 中占位符所表示的属性值。当需要实例化 bean 时,bean 定义中的属性值就已经被替换成我们配置的值。当然其实现比上面描述的要复杂一些,这里仅说明其大致工作原理,更详细的实现可以参考其源码。
+
+与之相似的,还有`BeanPostProcessor`,其存在于对象实例化阶段。跟 BeanFactoryPostProcessor 类似,它会处理容器内所有符合条件并且已经实例化后的对象。简单的对比,BeanFactoryPostProcessor 处理 bean 的定义,而 BeanPostProcessor 则处理 bean 完成实例化后的对象。BeanPostProcessor 定义了两个接口:
+
+```
+public interface BeanPostProcessor {
+ // 前置处理
+ Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
+ // 后置处理
+ Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
+}
+```
+
+为了理解这两个方法执行的时机,简单的了解下 bean 的整个生命周期:
+
+`postProcessBeforeInitialization()`方法与`postProcessAfterInitialization()`分别对应图中前置处理和后置处理两个步骤将执行的方法。这两个方法中都传入了 bean 对象实例的引用,为扩展容器的对象实例化过程提供了很大便利,在这儿几乎可以对传入的实例执行任何操作。注解、AOP 等功能的实现均大量使用了`BeanPostProcessor`,比如有一个自定义注解,你完全可以实现 BeanPostProcessor 的接口,在其中判断 bean 对象的脑袋上是否有该注解,如果有,你可以对这个 bean 实例执行任何操作,想想是不是非常的简单?
+
+再来看一个更常见的例子,在 Spring 中经常能够看到各种各样的 Aware 接口,其作用就是在对象实例化完成以后将 Aware 接口定义中规定的依赖注入到当前实例中。比如最常见的`ApplicationContextAware`接口,实现了这个接口的类都可以获取到一个 ApplicationContext 对象。当容器中每个对象的实例化过程走到 BeanPostProcessor 前置处理这一步时,容器会检测到之前注册到容器的 ApplicationContextAwareProcessor,然后就会调用其 postProcessBeforeInitialization()方法,检查并设置 Aware 相关依赖。看看代码吧,是不是很简单:
+
+```
+// 代码来自:org.springframework.context.support.ApplicationContextAwareProcessor
+// 其postProcessBeforeInitialization方法调用了invokeAwareInterfaces方法
+private void invokeAwareInterfaces(Object bean) {
+ if (bean instanceof EnvironmentAware) {
+ ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
+ }
+ if (bean instanceof ApplicationContextAware) {
+ ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
+ }
+ // ......
+}
+```
+
+最后总结一下,本小节内容和你一起回顾了 Spring 容器的部分核心内容,限于篇幅不能写更多,但理解这部分内容,足以让您轻松理解 Spring Boot 的启动原理,如果在后续的学习过程中遇到一些晦涩难懂的知识,再回过头来看看 Spring 的核心知识,也许有意想不到的效果。也许 Spring Boot 的中文资料很少,但 Spring 的中文资料和书籍有太多太多,总有东西能给你启发。
+
+## 二、夯实基础:JavaConfig 与常见 Annotation
+
+### 2.1、JavaConfig
+
+我们知道`bean`是 Spring IOC 中非常核心的概念,Spring 容器负责 bean 的生命周期的管理。在最初,Spring 使用 XML 配置文件的方式来描述 bean 的定义以及相互间的依赖关系,但随着 Spring 的发展,越来越多的人对这种方式表示不满,因为 Spring 项目的所有业务类均以 bean 的形式配置在 XML 文件中,造成了大量的 XML 文件,使项目变得复杂且难以管理。
+
+后来,基于纯 Java Annotation 依赖注入框架`Guice`出世,其性能明显优于采用 XML 方式的 Spring,甚至有部分人认为,`Guice`可以完全取代 Spring(`Guice`仅是一个轻量级 IOC 框架,取代 Spring 还差的挺远)。正是这样的危机感,促使 Spring 及社区推出并持续完善了`JavaConfig`子项目,它基于 Java 代码和 Annotation 注解来描述 bean 之间的依赖绑定关系。比如,下面是使用 XML 配置方式来描述 bean 的定义:
+
+```
+
+```
+
+而基于 JavaConfig 的配置形式是这样的:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+
+ // 任何标志了@Bean的方法,其返回值将作为一个bean注册到Spring的IOC容器中
+ // 方法名默认成为该bean定义的id
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl();
+ }
+}
+```
+
+如果两个 bean 之间有依赖关系的话,在 XML 配置中应该是这样:
+
+```
+
+
+
+
+
+
+
+
+
+```
+
+而在 JavaConfig 中则是这样:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+
+ // 如果一个bean依赖另一个bean,则直接调用对应JavaConfig类中依赖bean的创建方法即可
+ // 这里直接调用dependencyService()
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl(dependencyService());
+ }
+
+ @Bean
+ public OtherService otherService() {
+ return new OtherServiceImpl(dependencyService());
+ }
+
+ @Bean
+ public DependencyService dependencyService() {
+ return new DependencyServiceImpl();
+ }
+}
+```
+
+你可能注意到这个示例中,有两个 bean 都依赖于 dependencyService,也就是说当初始化 bookService 时会调用`dependencyService()`,在初始化 otherService 时也会调用`dependencyService()`,那么问题来了?这时候 IOC 容器中是有一个 dependencyService 实例还是两个?这个问题留着大家思考吧,这里不再赘述。
+
+### 2.2、@ComponentScan
+
+`@ComponentScan`注解对应 XML 配置形式中的``元素,表示启用组件扫描,Spring 会自动扫描所有通过注解配置的 bean,然后将其注册到 IOC 容器中。我们可以通过`basePackages`等属性来指定`@ComponentScan`自动扫描的范围,如果不指定,默认从声明`@ComponentScan`所在类的`package`进行扫描。正因为如此,SpringBoot 的启动类都默认在`src/main/java`下。
+
+### 2.3、@Import
+
+`@Import`注解用于导入配置类,举个简单的例子:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl();
+ }
+}
+```
+
+现在有另外一个配置类,比如:`MoonUserConfiguration`,这个配置类中有一个 bean 依赖于`MoonBookConfiguration`中的 bookService,如何将这两个 bean 组合在一起?借助`@Import`即可:
+
+```
+@Configuration
+// 可以同时导入多个配置类,比如:@Import({A.class,B.class})
+@Import(MoonBookConfiguration.class)
+public class MoonUserConfiguration {
+ @Bean
+ public UserService userService(BookService bookService) {
+ return new BookServiceImpl(bookService);
+ }
+}
+```
+
+需要注意的是,在 4.2 之前,`@Import`注解只支持导入配置类,但是在 4.2 之后,它支持导入普通类,并将这个类作为一个 bean 的定义注册到 IOC 容器中。
+
+### 2.4、@Conditional
+
+`@Conditional`注解表示在满足某种条件后才初始化一个 bean 或者启用某些配置。它一般用在由`@Component`、`@Service`、`@Configuration`等注解标识的类上面,或者由`@Bean`标记的方法上。如果一个`@Configuration`类标记了`@Conditional`,则该类中所有标识了`@Bean`的方法和`@Import`注解导入的相关类将遵从这些条件。
+
+在 Spring 里可以很方便的编写你自己的条件类,所要做的就是实现`Condition`接口,并覆盖它的`matches()`方法。举个例子,下面的简单条件类表示只有在`Classpath`里存在`JdbcTemplate`类时才生效:
+
+```
+public class JdbcTemplateCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
+ try {
+ conditionContext.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate");
+ return true;
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+}
+```
+
+当你用 Java 来声明 bean 的时候,可以使用这个自定义条件类:
+
+```
+@Conditional(JdbcTemplateCondition.class)
+@Service
+public MyService service() {
+ ......
+}
+```
+
+这个例子中只有当`JdbcTemplateCondition`类的条件成立时才会创建 MyService 这个 bean。也就是说 MyService 这 bean 的创建条件是`classpath`里面包含`JdbcTemplate`,否则这个 bean 的声明就会被忽略掉。
+
+`Spring Boot`定义了很多有趣的条件,并把他们运用到了配置类上,这些配置类构成了`Spring Boot`的自动配置的基础。`Spring Boot`运用条件化配置的方法是:定义多个特殊的条件化注解,并将它们用到配置类上。下面列出了`Spring Boot`提供的部分条件化注解:
+
+| 条件化注解 | 配置生效条件 |
+| ------------------------------- | ------------------------------------------------------- |
+| @ConditionalOnBean | 配置了某个特定 bean |
+| @ConditionalOnMissingBean | 没有配置特定的 bean |
+| @ConditionalOnClass | Classpath 里有指定的类 |
+| @ConditionalOnMissingClass | Classpath 里没有指定的类 |
+| @ConditionalOnExpression | 给定的 Spring Expression Language 表达式计算结果为 true |
+| @ConditionalOnJava | Java 的版本匹配特定指或者一个范围值 |
+| @ConditionalOnProperty | 指定的配置属性要有一个明确的值 |
+| @ConditionalOnResource | Classpath 里有指定的资源 |
+| @ConditionalOnWebApplication | 这是一个 Web 应用程序 |
+| @ConditionalOnNotWebApplication | 这不是一个 Web 应用程序 |
+
+### 2.5、@ConfigurationProperties 与@EnableConfigurationProperties
+
+当某些属性的值需要配置的时候,我们一般会在`application.properties`文件中新建配置项,然后在 bean 中使用`@Value`注解来获取配置的值,比如下面配置数据源的代码。
+
+```
+// jdbc config
+jdbc.mysql.url=jdbc:mysql://localhost:3306/sampledb
+jdbc.mysql.username=root
+jdbc.mysql.password=123456
+......
+
+// 配置数据源
+@Configuration
+public class HikariDataSourceConfiguration {
+
+ @Value("jdbc.mysql.url")
+ public String url;
+ @Value("jdbc.mysql.username")
+ public String user;
+ @Value("jdbc.mysql.password")
+ public String password;
+
+ @Bean
+ public HikariDataSource dataSource() {
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setJdbcUrl(url);
+ hikariConfig.setUsername(user);
+ hikariConfig.setPassword(password);
+ // 省略部分代码
+ return new HikariDataSource(hikariConfig);
+ }
+}
+```
+
+使用`@Value`注解注入的属性通常都比较简单,如果同一个配置在多个地方使用,也存在不方便维护的问题(考虑下,如果有几十个地方在使用某个配置,而现在你想改下名字,你改怎么做?)。对于更为复杂的配置,Spring Boot 提供了更优雅的实现方式,那就是`@ConfigurationProperties`注解。我们可以通过下面的方式来改写上面的代码:
+
+```
+@Component
+// 还可以通过@PropertySource("classpath:jdbc.properties")来指定配置文件
+@ConfigurationProperties("jdbc.mysql")
+// 前缀=jdbc.mysql,会在配置文件中寻找jdbc.mysql.*的配置项
+pulic class JdbcConfig {
+ public String url;
+ public String username;
+ public String password;
+}
+
+@Configuration
+public class HikariDataSourceConfiguration {
+
+ @AutoWired
+ public JdbcConfig config;
+
+ @Bean
+ public HikariDataSource dataSource() {
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setJdbcUrl(config.url);
+ hikariConfig.setUsername(config.username);
+ hikariConfig.setPassword(config.password);
+ // 省略部分代码
+ return new HikariDataSource(hikariConfig);
+ }
+}
+```
+
+`@ConfigurationProperties`对于更为复杂的配置,处理起来也是得心应手,比如有如下配置文件:
+
+```
+#App
+app.menus[0].title=Home
+app.menus[0].name=Home
+app.menus[0].path=/
+app.menus[1].title=Login
+app.menus[1].name=Login
+app.menus[1].path=/login
+
+app.compiler.timeout=5
+app.compiler.output-folder=/temp/
+
+app.error=/error/
+```
+
+可以定义如下配置类来接收这些属性
+
+```
+@Component
+@ConfigurationProperties("app")
+public class AppProperties {
+
+ public String error;
+ public List