From c881767bd754f675e89965dfa2aaa53506ad747c Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 24 Jun 2022 17:12:54 +0800 Subject: [PATCH 01/83] leetcode: 2022-06-24 LeetCode515_FindLargeValueInEachTreeRow --- ...etCode515_FindLargeValueInEachTreeRow.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java new file mode 100644 index 0000000..141a534 --- /dev/null +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java @@ -0,0 +1,76 @@ +package com.wdbyte.leetcode; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode.cn/problems/find-largest-value-in-each-tree-row/ + * + * 515. 在每个树行中找最大值 + * + * @author niulang + * @date 2022/06/24 + */ +public class LeetCode515_FindLargeValueInEachTreeRow { + + public static void main(String[] args) { + LeetCode515_FindLargeValueInEachTreeRow code515 = new LeetCode515_FindLargeValueInEachTreeRow(); + TreeNode tree3_5 = new TreeNode(5); + TreeNode tree3_3 = new TreeNode(3); + TreeNode tree3_9 = new TreeNode(9); + TreeNode tree2_3 = new TreeNode(3, tree3_5, tree3_3); + TreeNode tree2_2 = new TreeNode(2, null, tree3_9); + TreeNode tree1_1 = new TreeNode(1, tree2_3, tree2_2); + List integers = code515.largestValues(tree1_1); + System.out.println(integers); + } + + public List largestValues(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + List nodeList = new ArrayList<>(); + nodeList.add(root); + while (!nodeList.isEmpty()) { + List nodeListTemp = new ArrayList<>(); + Integer max = null; + for (TreeNode treeNode : nodeList) { + if (treeNode == null) { + continue; + } + if (max == null) { + max = treeNode.val; + } + if (max < treeNode.val) { + max = treeNode.val; + } + if (treeNode.left != null) { + nodeListTemp.add(treeNode.left); + } + if (treeNode.right != null) { + nodeListTemp.add(treeNode.right); + } + } + result.add(max); + nodeList = nodeListTemp; + } + return result; + } +} + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode() {} + + TreeNode(int val) {this.val = val;} + + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } +} \ No newline at end of file From 276700c3f3b81b5e52b2998e993cebcc9aed80f2 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sun, 10 Jul 2022 23:29:51 +0800 Subject: [PATCH 02/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0Java=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=AF=B9=E8=B1=A1=E6=B1=A0=E5=8C=96=20(https?= =?UTF-8?q?://www.wdbyte.com/java/object-pool.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + tool-java-object-pool/pom.xml | 41 +++++++++ .../wdbyet/tool/objectpool/JedisPoolTest.java | 22 +++++ .../apachekeyedpool/ApacheKeyedPool.java | 64 ++++++++++++++ .../objectpool/apachepool/ApachePool.java | 88 +++++++++++++++++++ .../tool/objectpool/mypool/MyObjectPool.java | 81 +++++++++++++++++ .../objectpool/mypool/MyObjectPoolTest.java | 58 ++++++++++++ 7 files changed, 355 insertions(+) create mode 100644 tool-java-object-pool/pom.xml create mode 100644 tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/JedisPoolTest.java create mode 100644 tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachekeyedpool/ApacheKeyedPool.java create mode 100644 tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachepool/ApachePool.java create mode 100644 tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPool.java create mode 100644 tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPoolTest.java diff --git a/pom.xml b/pom.xml index ff351cb..0decd9c 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ junit5-jupiter-starter apache-httpclient leetcode + tool-java-object-pool parent-modules Parent for all java modules diff --git a/tool-java-object-pool/pom.xml b/tool-java-object-pool/pom.xml new file mode 100644 index 0000000..f8c4630 --- /dev/null +++ b/tool-java-object-pool/pom.xml @@ -0,0 +1,41 @@ + + + + parent-modules + com.wdbyte + 1.0.0-SNAPSHOT + + 4.0.0 + objectpool + + + 8 + 8 + + + + + org.apache.commons + commons-pool2 + 2.11.1 + + + org.openjdk.jmh + jmh-core + 1.33 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.33 + provided + + + redis.clients + jedis + 4.2.0 + + + \ No newline at end of file diff --git a/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/JedisPoolTest.java b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/JedisPoolTest.java new file mode 100644 index 0000000..48b73b1 --- /dev/null +++ b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/JedisPoolTest.java @@ -0,0 +1,22 @@ +package com.wdbyet.tool.objectpool; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/09 + */ +public class JedisPoolTest { + + public static void main(String[] args) { + JedisPool jedisPool = new JedisPool("localhost", 6379); + // 从对象池中借一个对象 + Jedis jedis = jedisPool.getResource(); + String name = jedis.get("name"); + System.out.println("redis get :" + name); + jedis.close(); + // 彻底退出前,关闭 Redis 连接池 + jedisPool.close(); + } +} diff --git a/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachekeyedpool/ApacheKeyedPool.java b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachekeyedpool/ApacheKeyedPool.java new file mode 100644 index 0000000..8eed279 --- /dev/null +++ b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachekeyedpool/ApacheKeyedPool.java @@ -0,0 +1,64 @@ +package com.wdbyet.tool.objectpool.apachekeyedpool; + +import org.apache.commons.pool2.BaseKeyedPooledObjectFactory; +import org.apache.commons.pool2.KeyedPooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.AbandonedConfig; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericKeyedObjectPool; +import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; +import redis.clients.jedis.Jedis; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/07 + */ +public class ApacheKeyedPool { + + public static void main(String[] args) throws Exception { + String key = "local"; + MyGenericKeyedObjectPool objectMyObjectPool = new MyGenericKeyedObjectPool(new MyKeyedPooledObjectFactory()); + Jedis jedis = objectMyObjectPool.borrowObject(key); + String name = jedis.get("name"); + System.out.println("redis get :" + name); + objectMyObjectPool.returnObject(key, jedis); + } +} + +class MyKeyedPooledObjectFactory extends BaseKeyedPooledObjectFactory { + + @Override + public Jedis create(String key) throws Exception { + if ("local".equals(key)) { + return new Jedis("localhost", 6379); + } + if ("remote".equals(key)) { + return new Jedis("192.168.0.105", 6379); + } + return null; + } + + @Override + public PooledObject wrap(Jedis value) { + return new DefaultPooledObject<>(value); + } +} + +class MyGenericKeyedObjectPool extends GenericKeyedObjectPool { + + public MyGenericKeyedObjectPool(KeyedPooledObjectFactory factory) { + super(factory); + } + + public MyGenericKeyedObjectPool(KeyedPooledObjectFactory factory, + GenericKeyedObjectPoolConfig config) { + super(factory, config); + } + + public MyGenericKeyedObjectPool(KeyedPooledObjectFactory factory, + GenericKeyedObjectPoolConfig config, AbandonedConfig abandonedConfig) { + super(factory, config, abandonedConfig); + } +} + + diff --git a/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachepool/ApachePool.java b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachepool/ApachePool.java new file mode 100644 index 0000000..1ce04fd --- /dev/null +++ b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/apachepool/ApachePool.java @@ -0,0 +1,88 @@ +package com.wdbyet.tool.objectpool.apachepool; + +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.PooledObjectFactory; +import org.apache.commons.pool2.impl.AbandonedConfig; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import redis.clients.jedis.Jedis; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/07 + */ +public class ApachePool { + + public static void main(String[] args) throws Exception { + MyGenericObjectPool objectMyObjectPool = new MyGenericObjectPool(new MyPooledObjectFactory()); + Jedis jedis = objectMyObjectPool.borrowObject(); + String name = jedis.get("name"); + System.out.println("redis get:" + name); + objectMyObjectPool.returnObject(jedis); + objectMyObjectPool.close(); + } + +} + +class MyPooledObjectFactory implements PooledObjectFactory { + + @Override + public void activateObject(PooledObject pooledObject) throws Exception { + + } + + @Override + public void destroyObject(PooledObject pooledObject) throws Exception { + Jedis jedis = pooledObject.getObject(); + jedis.close(); + System.out.println("释放连接"); + } + + @Override + public PooledObject makeObject() throws Exception { + return new DefaultPooledObject(new Jedis("localhost", 6379)); + } + + @Override + public void passivateObject(PooledObject pooledObject) throws Exception { + + } + + @Override + public boolean validateObject(PooledObject pooledObject) { + return false; + } +} + +class SimplePooledObjectFactory extends BasePooledObjectFactory { + + @Override + public Jedis create() throws Exception { + return new Jedis("127.0.0.1", 6379); + } + + @Override + public PooledObject wrap(Jedis jedis) { + return new DefaultPooledObject<>(jedis); + } +} + +class MyGenericObjectPool extends GenericObjectPool { + + public MyGenericObjectPool(PooledObjectFactory factory) { + super(factory); + } + + public MyGenericObjectPool(PooledObjectFactory factory, GenericObjectPoolConfig config) { + super(factory, config); + } + + public MyGenericObjectPool(PooledObjectFactory factory, GenericObjectPoolConfig config, + AbandonedConfig abandonedConfig) { + super(factory, config, abandonedConfig); + } +} + + diff --git a/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPool.java b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPool.java new file mode 100644 index 0000000..124c8f2 --- /dev/null +++ b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPool.java @@ -0,0 +1,81 @@ +package com.wdbyet.tool.objectpool.mypool; + +import java.io.Closeable; +import java.io.IOException; +import java.util.HashSet; +import java.util.Stack; + +/** + * @author https://www.wdbyte.com + */ +public class MyObjectPool { + + // 池子大小 + private Integer size = 5; + // 对象池栈。后进先出 + private Stack stackPool = new Stack<>(); + // 借出的对象的 hashCode 集合 + private HashSet borrowHashCodeSet = new HashSet<>(); + + /** + * 增加一个对象 + * + * @param t + */ + public synchronized void addObj(T t) { + if ((stackPool.size() + borrowHashCodeSet.size()) == size) { + throw new RuntimeException("池中对象已经达到最大值"); + } + stackPool.add(t); + System.out.println("添加了对象:" + t.hashCode()); + } + + /** + * 借出一个对象 + * + * @return + */ + public synchronized T borrowObj() { + if (stackPool.isEmpty()) { + System.out.println("没有可以被借出的对象"); + return null; + } + T pop = stackPool.pop(); + borrowHashCodeSet.add(pop.hashCode()); + System.out.println("借出了对象:" + pop.hashCode()); + return pop; + } + + /** + * 归还一个对象 + * + * @param t + */ + public synchronized void returnObj(T t) { + if (borrowHashCodeSet.contains(t.hashCode())) { + stackPool.add(t); + borrowHashCodeSet.remove(t.hashCode()); + System.out.println("归还了对象:" + t.hashCode()); + return; + } + throw new RuntimeException("只能归还从池中借出的对象"); + } + + /** + * 销毁池中对象 + */ + public synchronized void destory() { + if (!borrowHashCodeSet.isEmpty()) { + throw new RuntimeException("尚有未归还的对象,不能关闭所有对象"); + } + while (!stackPool.isEmpty()) { + T pop = stackPool.pop(); + try { + pop.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + System.out.println("已经销毁了所有对象"); + } +} diff --git a/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPoolTest.java b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPoolTest.java new file mode 100644 index 0000000..3b29104 --- /dev/null +++ b/tool-java-object-pool/src/main/java/com/wdbyet/tool/objectpool/mypool/MyObjectPoolTest.java @@ -0,0 +1,58 @@ +package com.wdbyet.tool.objectpool.mypool; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import redis.clients.jedis.Jedis; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/02 + */ +@State(Scope.Benchmark) +@Warmup(iterations = 1, time = 3) +@Measurement(iterations = 3, time = 3) +public class MyObjectPoolTest { + private static MyObjectPool objectPool = new MyObjectPool<>(); + + static { + //objectPool.addObj(new Jedis("192.168.0.105", 6379)); + } + + public static void main(String[] args) { + MyObjectPool objectPool = new MyObjectPool<>(); + // 增加一个 jedis 连接对象 + objectPool.addObj(new Jedis("127.0.0.1", 6379)); + objectPool.addObj(new Jedis("127.0.0.1", 6379)); + // 从对象池中借出一个 jedis 对象 + Jedis jedis = objectPool.borrowObj(); + // 一次 redis 查询 + String name = jedis.get("name"); + System.out.println(String.format("redis get:" + name)); + // 归还 redis 连接对象 + objectPool.returnObj(jedis); + // 销毁对象池中的所有对象 + objectPool.destory(); + // 再次借用对象 + objectPool.borrowObj(); + } + + @Benchmark + public void testPool(Blackhole bh) { + Jedis jedis = objectPool.borrowObj(); + String name = jedis.get("name"); + objectPool.returnObj(jedis); + bh.consume(name); + } + + @Benchmark + public void test(Blackhole bh) { + Jedis jedis = new Jedis("localhost", 6379); + String name = jedis.get("name"); + jedis.close(); + bh.consume(name); + } +} From edc67f84c8e897885568f6cce2fe4a3d2966230d Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sun, 10 Jul 2022 23:44:39 +0800 Subject: [PATCH 03/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0Java=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=AF=B9=E8=B1=A1=E6=B1=A0=E5=8C=96=20(https?= =?UTF-8?q?://www.wdbyte.com/java/object-pool.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index ead8918..c70dec4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ > **原创文章每周更新**。技术文字在写的过程中难免会有纰漏,或者细节不够完善。大家发现问题,可以及时给我 PR 反馈,也可以去 [公众号](https://github.com/niumoo/JavaNotes#%E5%85%AC%E4%BC%97%E5%8F%B7) 给我留言,或者加我 [微信](https://github.com/niumoo/JavaNotes#联系我) 直接说明,我都会及时更正,哪怕是一个错别字。加油!奥利给! - -

Java Notes

wechat @@ -19,6 +17,7 @@ ## ⏳ Java 开发 +- [Java 中的对象池化](https://www.wdbyte.com/java/object-pool.html) - [5种限流算法,7种限流方式,挡住突发流量?](https://www.wdbyte.com/java/rate-limiter.html) - [Java 中拼接 String 的 N 种方式](https://www.wdbyte.com/java/string-concat.html) - [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) From 63a6b60be82b57b903a46ceddcde98370d62e329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=8C=BF=E9=98=BF=E6=9C=97?= Date: Thu, 14 Jul 2022 23:17:26 +0800 Subject: [PATCH 04/83] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c70dec4..4906a79 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ ## ⏳ Java 开发 +- [必应壁纸,我的第一个 400 Star 开源项目](https://www.wdbyte.com/bing-wallpaper-400.html) - [Java 中的对象池化](https://www.wdbyte.com/java/object-pool.html) - [5种限流算法,7种限流方式,挡住突发流量?](https://www.wdbyte.com/java/rate-limiter.html) - [Java 中拼接 String 的 N 种方式](https://www.wdbyte.com/java/string-concat.html) From 7b1415ceebdf917c8027be9687b626d88572a452 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 21 Jul 2022 00:01:07 +0800 Subject: [PATCH 05/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Jackson=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=93=8D=E4=BD=9C(https://www.wdbyte.com/too?= =?UTF-8?q?l/jackson.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool-java-jackson/README.md | 4 + tool-java-jackson/pom.xml | 42 ++++++++ tool-java-jackson/src/EmployeeList.json | 18 ++++ tool-java-jackson/src/Person.json | 8 ++ .../src/main/java/com/wdbyte/jackson/Cat.java | 24 +++++ .../main/java/com/wdbyte/jackson/Order.java | 57 ++++++++++ .../main/java/com/wdbyte/jackson/Person.java | 17 +++ .../main/java/com/wdbyte/jackson/Student.java | 48 +++++++++ .../test/java/com/wdbyte/jackson/CatTest.java | 47 ++++++++ .../java/com/wdbyte/jackson/OrderTest.java | 44 ++++++++ .../java/com/wdbyte/jackson/PersonTest.java | 100 ++++++++++++++++++ .../java/com/wdbyte/jackson/PersonTest2.java | 24 +++++ .../java/com/wdbyte/jackson/StudentTest.java | 46 ++++++++ 13 files changed, 479 insertions(+) create mode 100644 tool-java-jackson/README.md create mode 100644 tool-java-jackson/pom.xml create mode 100644 tool-java-jackson/src/EmployeeList.json create mode 100644 tool-java-jackson/src/Person.json create mode 100644 tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java create mode 100644 tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java create mode 100644 tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java create mode 100644 tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java create mode 100644 tool-java-jackson/src/test/java/com/wdbyte/jackson/CatTest.java create mode 100644 tool-java-jackson/src/test/java/com/wdbyte/jackson/OrderTest.java create mode 100644 tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest.java create mode 100644 tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest2.java create mode 100644 tool-java-jackson/src/test/java/com/wdbyte/jackson/StudentTest.java diff --git a/tool-java-jackson/README.md b/tool-java-jackson/README.md new file mode 100644 index 0000000..0b9e3f0 --- /dev/null +++ b/tool-java-jackson/README.md @@ -0,0 +1,4 @@ +## tool-java-jackson + +### 相关文章 +- [Jackson 解析 JSON 教程](https://www.wdbyte.com/tool/jackson.html) diff --git a/tool-java-jackson/pom.xml b/tool-java-jackson/pom.xml new file mode 100644 index 0000000..51e295d --- /dev/null +++ b/tool-java-jackson/pom.xml @@ -0,0 +1,42 @@ + + + + parent-modules + com.wdbyte + 1.0.0-SNAPSHOT + + 4.0.0 + + com.wdbyte.jackson + tool-java-jackson + + + 8 + 8 + + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.3 + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.13.3 + + + + org.junit.jupiter + junit-jupiter + 5.8.2 + test + + + + + \ No newline at end of file diff --git a/tool-java-jackson/src/EmployeeList.json b/tool-java-jackson/src/EmployeeList.json new file mode 100644 index 0000000..ab00d44 --- /dev/null +++ b/tool-java-jackson/src/EmployeeList.json @@ -0,0 +1,18 @@ +[ + { + "name": "aLang", + "age": 27, + "skillList": [ + "java", + "c++" + ] + }, + { + "name": "darcy", + "age": 26, + "skillList": [ + "go", + "rust" + ] + } +] \ No newline at end of file diff --git a/tool-java-jackson/src/Person.json b/tool-java-jackson/src/Person.json new file mode 100644 index 0000000..2d2e72b --- /dev/null +++ b/tool-java-jackson/src/Person.json @@ -0,0 +1,8 @@ +{ + "name": "aLang", + "age": 27, + "skillList": [ + "java", + "c++" + ] +} \ No newline at end of file diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java new file mode 100644 index 0000000..5492a46 --- /dev/null +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java @@ -0,0 +1,24 @@ +package com.wdbyte.jackson; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.Data; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +@Data +public class Cat { + + @JsonSetter(value = "catName") + private String name; + + private Integer age; + + @JsonGetter(value = "catName") + public String getName() { + return name; + } +} diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java new file mode 100644 index 0000000..6318eb3 --- /dev/null +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java @@ -0,0 +1,57 @@ +package com.wdbyte.jackson; + +import java.time.LocalDateTime; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +//@Data +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class Order { + + @JsonSetter(value = "orderId") + private Integer id; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date createTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private LocalDateTime updateTime; + + //@JsonGetter(value = "orderId") + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } +} diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java new file mode 100644 index 0000000..3bc1210 --- /dev/null +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java @@ -0,0 +1,17 @@ +package com.wdbyte.jackson; + +import java.util.List; + +import lombok.Data; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/16 + */ +@Data +public class Person { + private String name; + private Integer age; + private List skillList; +} + diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java new file mode 100644 index 0000000..377253d --- /dev/null +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java @@ -0,0 +1,48 @@ +package com.wdbyte.jackson; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.google.common.collect.Maps; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class Student { + @Getter + @Setter + private String name; + + @Getter + @Setter + private Integer age; + + @Getter + @Setter + private Map diyMap = new HashMap<>(); + + @JsonAnyGetter + private Map initMap = new HashMap() {{ + put("a", 111); + put("b", 222); + put("c", 333); + }}; + + @JsonAnySetter + public void otherField(String key, String value) { + this.diyMap.put(key, value); + } + +} diff --git a/tool-java-jackson/src/test/java/com/wdbyte/jackson/CatTest.java b/tool-java-jackson/src/test/java/com/wdbyte/jackson/CatTest.java new file mode 100644 index 0000000..d2b82ba --- /dev/null +++ b/tool-java-jackson/src/test/java/com/wdbyte/jackson/CatTest.java @@ -0,0 +1,47 @@ +package com.wdbyte.jackson; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +class CatTest { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testPojoToJson() throws JsonProcessingException { + Cat cat = new Cat(); + cat.setName("Tom"); + cat.setAge(2); + String json = objectMapper.writeValueAsString(cat); + System.out.println(json); + + Assertions.assertEquals(json, "{\"name\":\"Tom\"}"); + + cat = objectMapper.readValue(json, Cat.class); + Assertions.assertEquals(cat.getName(), "Tom"); + Assertions.assertEquals(cat.getAge(), null); + } + + @Test + void testJsonToPojo() throws JsonProcessingException { + String json = "{\"name\":\"tom\"}"; + Cat cat = objectMapper.readValue(json, Cat.class); + Assertions.assertEquals(cat.getName(), "Tom"); + Assertions.assertEquals(cat.getAge(), null); + } + + @Test + void testPojoToJson2() throws JsonProcessingException { + String json = "{\"age\":2,\"catName\":\"Tom\"}"; + Cat cat = objectMapper.readValue(json, Cat.class); + System.out.println(cat.toString()); + Assertions.assertEquals(cat.getName(), "Tom"); + } + +} \ No newline at end of file diff --git a/tool-java-jackson/src/test/java/com/wdbyte/jackson/OrderTest.java b/tool-java-jackson/src/test/java/com/wdbyte/jackson/OrderTest.java new file mode 100644 index 0000000..8cd5a11 --- /dev/null +++ b/tool-java-jackson/src/test/java/com/wdbyte/jackson/OrderTest.java @@ -0,0 +1,44 @@ +package com.wdbyte.jackson; + +import java.time.LocalDateTime; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +class OrderTest { + + ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); + //ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testPojoToJson() throws JsonProcessingException { + Order order = new Order(1, new Date(), LocalDateTime.now()); + String json = objectMapper.writeValueAsString(order); + System.out.println(json); + + order = objectMapper.readValue(json, Order.class); + System.out.println(order.toString()); + + Assertions.assertEquals(order.getId(), 1); + } + + @Test + void testPojoToJson0() throws JsonProcessingException { + Order order = new Order(1, new Date(), null); + String json = objectMapper.writeValueAsString(order); + System.out.println(json); + + order = objectMapper.readValue(json, Order.class); + System.out.println( order.toString()); + + Assertions.assertEquals(order.getId(), 1); + } + +} \ No newline at end of file diff --git a/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest.java b/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest.java new file mode 100644 index 0000000..dcfff39 --- /dev/null +++ b/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest.java @@ -0,0 +1,100 @@ +package com.wdbyte.jackson; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/16 + */ +class PersonTest { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void pojoToJsonString() throws JsonProcessingException { + Person person = new Person(); + person.setName("aLng"); + person.setAge(27); + person.setSkillList(Arrays.asList("java", "c++")); + + String json = objectMapper.writeValueAsString(person); + System.out.println(json); + String expectedJson = "{\"name\":\"aLng\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + Assertions.assertEquals(json, expectedJson); + } + + @Test + void jsonStringToPojo() throws JsonProcessingException { + String expectedJson = "{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + Person person = objectMapper.readValue(expectedJson, Person.class); + System.out.println(person); + Assertions.assertEquals(person.getName(), "aLang"); + Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]"); + } + + @Test + void testJsonFilePojo() throws IOException { + File file = new File("src/Person.json"); + Person person = objectMapper.readValue(file, Person.class); + System.out.println(person); + Assertions.assertEquals(person.getName(), "aLang"); + Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]"); + } + + @Test + void jsonBytesToPojo() throws IOException { + String expectedJson = "{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + Person person = objectMapper.readValue(expectedJson.getBytes(), Person.class); + System.out.println(person); + Assertions.assertEquals(person.getName(), "aLang"); + Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]"); + } + + @Test + void fileToPojoList() throws IOException { + File file = new File("src/EmployeeList.json"); + List personList = objectMapper.readValue(file, new TypeReference>() {}); + for (Person person : personList) { + System.out.println(person); + } + Assertions.assertEquals(personList.size(), 2); + Assertions.assertEquals(personList.get(0).getName(), "aLang"); + Assertions.assertEquals(personList.get(1).getName(), "darcy"); + } + + @Test + void jsonStringToMap() throws IOException { + String expectedJson = "{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + Map employeeMap = objectMapper.readValue(expectedJson, new TypeReference() {}); + System.out.println(employeeMap.getClass()); + for (Entry entry : employeeMap.entrySet()) { + System.out.println(entry.getKey() + ":" + entry.getValue()); + } + Assertions.assertEquals(employeeMap.get("name"), "aLang"); + } + + + @Test + void jsonStringToPojoIgnoreProperties() throws IOException { + // UnrecognizedPropertyException + String json = "{\"yyy\":\"xxx\",\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + Person person = objectMapper.readValue(json, Person.class); + System.out.printf(person.toString()); + Assertions.assertEquals(person.getName(), "aLang"); + Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]"); + } + +} \ No newline at end of file diff --git a/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest2.java b/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest2.java new file mode 100644 index 0000000..a89200e --- /dev/null +++ b/tool-java-jackson/src/test/java/com/wdbyte/jackson/PersonTest2.java @@ -0,0 +1,24 @@ +package com.wdbyte.jackson; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/16 + */ +class PersonTest2 { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void jsonStringToPojo() throws JsonProcessingException { + String expectedJson = "{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}"; + Person person = objectMapper.readValue(expectedJson, Person.class); + System.out.println(person); + Assertions.assertEquals(person.getName(), "aLang"); + Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]"); + } +} \ No newline at end of file diff --git a/tool-java-jackson/src/test/java/com/wdbyte/jackson/StudentTest.java b/tool-java-jackson/src/test/java/com/wdbyte/jackson/StudentTest.java new file mode 100644 index 0000000..3c4d327 --- /dev/null +++ b/tool-java-jackson/src/test/java/com/wdbyte/jackson/StudentTest.java @@ -0,0 +1,46 @@ +package com.wdbyte.jackson; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author https://www.wdbyte.com + * @date 2022/07/17 + */ +class StudentTest { + + private ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testJsonToPojo() throws JsonProcessingException { + Map map = new HashMap<>(); + map.put("name", "aLang"); + map.put("age", 18); + map.put("skill", "java"); + + String json = objectMapper.writeValueAsString(map); + System.out.println(json); + + Student student = objectMapper.readValue(json, Student.class); + System.out.println(student); + + Assertions.assertEquals(student.getDiyMap().get("skill"), "java"); + } + + @Test + void testPojoToJsonTest() throws JsonProcessingException { + Student student = new Student(); + student.setName("aLang"); + student.setAge(20); + String json = objectMapper.writeValueAsString(student); + System.out.println(json); + + Assertions.assertEquals(json,"{\"name\":\"aLang\",\"age\":20,\"diyMap\":{},\"a\":111,\"b\":222,\"c\":333}"); + } + +} \ No newline at end of file From 156336cd51243410052529324523764164934add Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 21 Jul 2022 00:02:20 +0800 Subject: [PATCH 06/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Jackson=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=93=8D=E4=BD=9C(https://www.wdbyte.com/too?= =?UTF-8?q?l/jackson.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- pom.xml | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4906a79..c74a0ed 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 一款好用的工具,不仅可以装X,更可以让你事半功倍,准时下班。 - +- [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) - [Java 反编译工具的使用与对比分析](https://www.wdbyte.com/2021/05/java-decompiler/) - [可以Postman,也可以cURL.进来领略下cURL的独门绝技](https://www.wdbyte.com/2020/06/tool/curl/) - [抛弃Eclipse,投入IDEA 的独孤求败江湖](https://www.wdbyte.com/2019/10/develop/idea-skill/) diff --git a/pom.xml b/pom.xml index 0decd9c..f2874bf 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ apache-httpclient leetcode tool-java-object-pool + tool-java-jackson parent-modules Parent for all java modules @@ -23,6 +24,7 @@ 1.8 31.0.1-jre 3.12.0 + 1.18.22 @@ -37,5 +39,10 @@ commons-lang3 ${commons-lang3.version} + + org.projectlombok + lombok + ${lombok.version} + From 4b7a76c02c220fc9c648c0a88a9449b74bf876ff Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 5 Aug 2022 15:33:53 +0800 Subject: [PATCH 07/83] build: add apache-httpclient --- pom.xml | 2 +- .../.gitignore | 0 .../pom.xml | 13 ++++--------- 3 files changed, 5 insertions(+), 10 deletions(-) rename {apache-httpclient => tool-java-apache-httpclient}/.gitignore (100%) rename {apache-httpclient => tool-java-apache-httpclient}/pom.xml (82%) diff --git a/pom.xml b/pom.xml index f2874bf..0fe1bcd 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,8 @@ core-java-modules core-java-rate-limiter junit5-jupiter-starter - apache-httpclient leetcode + tool-java-apache-httpclient tool-java-object-pool tool-java-jackson diff --git a/apache-httpclient/.gitignore b/tool-java-apache-httpclient/.gitignore similarity index 100% rename from apache-httpclient/.gitignore rename to tool-java-apache-httpclient/.gitignore diff --git a/apache-httpclient/pom.xml b/tool-java-apache-httpclient/pom.xml similarity index 82% rename from apache-httpclient/pom.xml rename to tool-java-apache-httpclient/pom.xml index 36e0086..c78012a 100644 --- a/apache-httpclient/pom.xml +++ b/tool-java-apache-httpclient/pom.xml @@ -10,27 +10,22 @@ 4.0.0 com.wdbyte.httpclient - apache-httpclient + tool-java-apache-httpclient - 17 - 17 + 1.8 + 1.8 + org.apache.httpcomponents.client5 httpclient5 5.1.3 - - org.junit.jupiter - junit-jupiter - test - - org.apache.httpcomponents.client5 From 4dee6b0ba27165531d72ddfe8155b86e9d759617 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 5 Aug 2022 15:35:09 +0800 Subject: [PATCH 08/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20HttpClient5?= =?UTF-8?q?=20GET=20=E8=AF=B7=E6=B1=82(https://www.wdbyte.com/httpclient5/?= =?UTF-8?q?get.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wdbyte/httpclient/HttpClient5Get.java | 43 ++++++++++++ .../httpclient/HttpClient5GetFluent.java | 28 ++++++++ .../httpclient/HttpClient5GetParams.java | 65 +++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Get.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetFluent.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetParams.java diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Get.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Get.java new file mode 100644 index 0000000..136b61b --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Get.java @@ -0,0 +1,43 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** +* @author https://www.wdbyte.com + * @date 2022/04/01 + */ +public class HttpClient5Get { + + public static void main(String[] args) { + String result = get("http://httpbin.org/get"); + System.out.println(result); + } + + public static String get(String url) { + String resultContent = null; + HttpGet httpGet = new HttpGet(url); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + try (CloseableHttpResponse response = httpclient.execute(httpGet)) { + // 获取状态码 + System.out.println(response.getVersion()); // HTTP/1.1 + System.out.println(response.getCode()); // 200 + System.out.println(response.getReasonPhrase()); // OK + HttpEntity entity = response.getEntity(); + // 获取响应信息 + resultContent = EntityUtils.toString(entity); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return resultContent; + } + +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetFluent.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetFluent.java new file mode 100644 index 0000000..76b1077 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetFluent.java @@ -0,0 +1,28 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; + +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.client5.http.fluent.Response; + +/** +* @author https://www.wdbyte.com + */ +public class HttpClient5GetFluent { + + public static void main(String[] args) { + System.out.println(get("http://httpbin.org/get")); + } + + public static String get(String url) { + String result = null; + try { + Response response = Request.get(url).execute(); + result = response.returnContent().asString(); + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetParams.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetParams.java new file mode 100644 index 0000000..868f149 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetParams.java @@ -0,0 +1,65 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.net.URIBuilder; + +/** +* @author https://www.wdbyte.com + * @date 2022/04/01 + */ +public class HttpClient5GetParams { + + public static void main(String[] args) { + String result = get("http://httpbin.org/get"); + System.out.println(result); + } + + public static String get(String url) { + String resultContent = null; + HttpGet httpGet = new HttpGet(url); + // 表单参数 + List nvps = new ArrayList<>(); + // GET 请求参数 + nvps.add(new BasicNameValuePair("username", "wdbyte.com")); + nvps.add(new BasicNameValuePair("password", "secret")); + // 增加到请求 URL 中 + try { + URI uri = new URIBuilder(new URI(url)) + .addParameters(nvps) + .build(); + httpGet.setUri(uri); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + try (CloseableHttpResponse response = httpclient.execute(httpGet)) { + // 获取状态码 + System.out.println(response.getVersion()); // HTTP/1.1 + System.out.println(response.getCode()); // 200 + System.out.println(response.getReasonPhrase()); // OK + HttpEntity entity = response.getEntity(); + // 获取响应信息 + resultContent = EntityUtils.toString(entity); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return resultContent; + } + +} From f0d82dcf4f21492ccaec303a55006dffff0b91da Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 5 Aug 2022 15:35:30 +0800 Subject: [PATCH 09/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20HttpClient5?= =?UTF-8?q?=20POST=20=E8=AF=B7=E6=B1=82(https://www.wdbyte.com/httpclient5?= =?UTF-8?q?/post.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wdbyte/httpclient/HttpClient5Post.java | 77 +++++++++++++++++++ .../httpclient/HttpClient5PostFluent.java | 33 ++++++++ .../httpclient/HttpClient5PostWithJson.java | 68 ++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Post.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostFluent.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostWithJson.java diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Post.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Post.java new file mode 100644 index 0000000..713b191 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Post.java @@ -0,0 +1,77 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.BasicNameValuePair; + +/** +* @author https://www.wdbyte.com + */ +public class HttpClient5Post { + + public static void main(String[] args) { + String result = post("http://httpbin.org/post"); + System.out.println(result); + } + + /** + * { + * "args": {}, + * "data": "", + * "files": {}, + * "form": { + * "password": "secret", + * "username": "wdbyte.com" + * }, + * "headers": { + * "Accept-Encoding": "gzip, x-gzip, deflate", + * "Content-Length": "31", + * "Content-Type": "application/x-www-form-urlencoded; charset=ISO-8859-1", + * "Host": "httpbin.org", + * "User-Agent": "Apache-HttpClient/5.1.3 (Java/17)", + * "X-Amzn-Trace-Id": "Root=1-62ab2708-4425003d3641a0a75cfeda74" + * }, + * "json": null, + * "origin": "47.251.4.198", + * "url": "http://httpbin.org/post" + * } + */ + public static String post(String url) { + String result = null; + HttpPost httpPost = new HttpPost(url); + // 表单参数 + List nvps = new ArrayList<>(); + // POST 请求参数 + nvps.add(new BasicNameValuePair("username", "wdbyte.com")); + nvps.add(new BasicNameValuePair("password", "secret")); + httpPost.setEntity(new UrlEncodedFormEntity(nvps)); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + System.out.println(response.getVersion()); // HTTP/1.1 + System.out.println(response.getCode()); // 200 + System.out.println(response.getReasonPhrase()); // OK + + HttpEntity entity = response.getEntity(); + // 获取响应信息 + result = EntityUtils.toString(entity); + // 确保流被完全消费 + EntityUtils.consume(entity); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return result; + } + +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostFluent.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostFluent.java new file mode 100644 index 0000000..4053cc8 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostFluent.java @@ -0,0 +1,33 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; + +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.message.BasicNameValuePair; + +/** +* @author https://www.wdbyte.com + */ +public class HttpClient5PostFluent { + + public static void main(String[] args) { + String result = post("http://httpbin.org/post"); + System.out.println(result); + } + + public static String post(String url) { + String result = null; + Request request = Request.post(url); + // POST 请求参数 + request.bodyForm( + new BasicNameValuePair("username", "wdbyte.com"), + new BasicNameValuePair("password", "secret")); + try { + result = request.execute().returnContent().asString(); + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostWithJson.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostWithJson.java new file mode 100644 index 0000000..921c64f --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PostWithJson.java @@ -0,0 +1,68 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; + +/** + * @author https://www.wdbyte.com + */ +public class HttpClient5PostWithJson { + + /** + * { + * "args": {}, + * "data": "{ \"password\": \"secret\", \"username\": \"wdbyte.com\"}", + * "files": {}, + * "form": {}, + * "headers": { + * "Accept-Encoding": "gzip, x-gzip, deflate", + * "Content-Length": "55", + * "Content-Type": "text/plain; charset=ISO-8859-1", + * "Host": "httpbin.org", + * "User-Agent": "Apache-HttpClient/5.1.3 (Java/17)", + * "X-Amzn-Trace-Id": "Root=1-62b6ab18-2aec3a5731e325620f1f5717" + * }, + * "json": { + * "password": "secret", + * "username": "wdbyte.com" + * }, + * "origin": "42.120.74.8", + * "url": "http://httpbin.org/post" + * } + * + * @param args + */ + public static void main(String[] args) { + String json = "{" + + " \"password\": \"secret\"," + + " \"username\": \"wdbyte.com\"" + + "}"; + String result = post("http://httpbin.org/post", json); + System.out.println(result); + } + + public static String post(String url, String jsonBody) { + String result = null; + HttpPost httpPost = new HttpPost(url); + httpPost.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON)); + + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + // 获取响应信息 + result = EntityUtils.toString(response.getEntity()); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return result; + } + +} From 3092e34c436c86ce9c7bf08680c72dbe75f3e468 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 17 Aug 2022 09:22:34 +0800 Subject: [PATCH 10/83] =?UTF-8?q?feat:=20Apache=20HttpClient=205=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=AF=A6=E7=BB=86=E6=95=99=E7=A8=8B(https://?= =?UTF-8?q?www.wdbyte.com/tool/httpclient5.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- tool-java-apache-httpclient/README.md | 5 + .../wdbyte/httpclient/HttpClient5Async.java | 172 ++++++++++++++++++ .../HttpClient5BasicAuthentication.java | 72 ++++++++ .../httpclient/HttpClient5CancleMethod.java | 27 +++ .../HttpClient5ChunkEncodedPost.java | 42 +++++ .../httpclient/HttpClient5CustomSSL.java | 76 ++++++++ .../httpclient/HttpClient5ExecuteProxy.java | 46 +++++ .../httpclient/HttpClient5FormLogin.java | 58 ++++++ .../HttpClient5GetWithBasicAuth.java | 51 ++++++ .../httpclient/HttpClient5GetWithTimeout.java | 54 ++++++ .../httpclient/HttpClient5Interceptors.java | 81 +++++++++ ...pClient5PreemptiveBasicAuthentication.java | 59 ++++++ ...Client5PreemptiveDigestAuthentication.java | 104 +++++++++++ .../HttpClient5ProxyAuthentication.java | 48 +++++ .../HttpClient5ProxyTunnelDemo.java | 42 +++++ .../httpclient/HttpClient5WithCookie.java | 53 ++++++ 17 files changed, 991 insertions(+), 1 deletion(-) create mode 100644 tool-java-apache-httpclient/README.md create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Async.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5BasicAuthentication.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CancleMethod.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ChunkEncodedPost.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CustomSSL.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ExecuteProxy.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5FormLogin.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithBasicAuth.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithTimeout.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Interceptors.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveBasicAuthentication.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveDigestAuthentication.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyAuthentication.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyTunnelDemo.java create mode 100644 tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5WithCookie.java diff --git a/README.md b/README.md index c74a0ed..26d8a9e 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 >出处:孔子《论语》 一款好用的工具,不仅可以装X,更可以让你事半功倍,准时下班。 - +- [Apache HttpClient 5 使用详细教程](https://www.wdbyte.com/tool/httpclient5.html) - [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) - [Java 反编译工具的使用与对比分析](https://www.wdbyte.com/2021/05/java-decompiler/) - [可以Postman,也可以cURL.进来领略下cURL的独门绝技](https://www.wdbyte.com/2020/06/tool/curl/) diff --git a/tool-java-apache-httpclient/README.md b/tool-java-apache-httpclient/README.md new file mode 100644 index 0000000..cbbdd52 --- /dev/null +++ b/tool-java-apache-httpclient/README.md @@ -0,0 +1,5 @@ +## tool-java-apache-httpclient +当前模块包含 Apache HttpClient 5 相关代码 + +### 相关文章 +- [Apache HttpClient 5 使用详细教程](https://www.wdbyte.com/tool/httpclient5.html) diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Async.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Async.java new file mode 100644 index 0000000..ae325f8 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Async.java @@ -0,0 +1,172 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; +import java.nio.CharBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.async.methods.AbstractCharResponseConsumer; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequests; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.nio.AsyncRequestProducer; +import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder; + +/** + * HttpClient 5 异步请求 +* @author https://www.wdbyte.com + * @date 2022/06/25 + */ +public class HttpClient5Async { + + public static void main(String[] args) { + getAsync1("http://httpbin.org/get"); + getAsync2("http://httpbin.org/get"); + getAsync3("http://httpbin.org/get"); + } + + /** + * 异步请求 + * + * @param url + * @return + */ + public static String getAsync1(String url) { + try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) { + // 开始 http clinet + httpclient.start(); + // 执行请求 + SimpleHttpRequest request1 = SimpleHttpRequests.get(url); + Future future = httpclient.execute(request1, null); + // 等待直到返回完毕 + SimpleHttpResponse response1 = future.get(); + System.out.println("getAsync1:" + request1.getRequestUri() + "->" + response1.getCode()); + } catch (IOException | ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + return null; + } + + /** + * 异步请求,根据响应情况回调 + * + * @param url + * @return + */ + public static String getAsync2(String url) { + try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) { + // 开始 http clinet + httpclient.start(); + // 根据请求响应情况进行回调操作 + CountDownLatch latch = new CountDownLatch(1); + SimpleHttpRequest request = SimpleHttpRequests.get(url); + httpclient.execute(request, new FutureCallback() { + @Override + public void completed(SimpleHttpResponse response2) { + latch.countDown(); + System.out.println("getAsync2:" + request.getRequestUri() + "->" + response2.getCode()); + } + + @Override + public void failed(Exception ex) { + latch.countDown(); + System.out.println("getAsync2:" + request.getRequestUri() + "->" + ex); + } + + @Override + public void cancelled() { + latch.countDown(); + System.out.println("getAsync2:" + request.getRequestUri() + " cancelled"); + } + + }); + latch.await(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + return null; + } + + /** + * 异步请求,对响应流做点什么 + * + * @param url + * @return + */ + public static String getAsync3(String url) { + try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) { + // 开始 http clinet + httpclient.start(); + // 根据请求响应情况进行回调操作 + SimpleHttpRequest request = SimpleHttpRequests.get(url); + + CountDownLatch latch = new CountDownLatch(1); + AsyncRequestProducer producer = AsyncRequestBuilder.get("http://httpbin.org/get").build(); + AbstractCharResponseConsumer consumer3 = new AbstractCharResponseConsumer() { + + HttpResponse response; + + @Override + protected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException { + System.out.println("getAsync3: 开始响应...."); + this.response = response; + } + + @Override + protected int capacityIncrement() { + return Integer.MAX_VALUE; + } + + @Override + protected void data(CharBuffer data, boolean endOfStream) throws IOException { + System.out.println("getAsync3: 收到数据...."); + // Do something useful + } + + @Override + protected HttpResponse buildResult() throws IOException { + System.out.println("getAsync3: 接收完毕..."); + return response; + } + + @Override + public void releaseResources() { + } + + }; + httpclient.execute(producer, consumer3, new FutureCallback() { + + @Override + public void completed(HttpResponse response) { + latch.countDown(); + System.out.println("getAsync3: "+request.getRequestUri() + "->" + response.getCode()); + } + + @Override + public void failed(Exception ex) { + latch.countDown(); + System.out.println("getAsync3: "+request.getRequestUri() + "->" + ex); + } + + @Override + public void cancelled() { + latch.countDown(); + System.out.println("getAsync3: "+request.getRequestUri() + " cancelled"); + } + + }); + latch.await(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + return null; + + } +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5BasicAuthentication.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5BasicAuthentication.java new file mode 100644 index 0000000..0ccf076 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5BasicAuthentication.java @@ -0,0 +1,72 @@ +package com.wdbyte.httpclient; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * 一个简单的示例,它使用HttpClient执行HTTP请求; + * 一个需要进行用户身份验证的目标站点。 + * Basic Authorization + * + * GET /basic-auth/user/passwd HTTP/1.1 + * Accept-Encoding: gzip, x-gzip, deflate + * Host: httpbin.org + * Connection: keep-alive + * User-Agent: Apache-HttpClient/5.1.3 (Java/1.8.0_151) + * + * HTTP/1.1 401 UNAUTHORIZED + * Date: Sat, 06 Aug 2022 08:25:33 GMT + * Content-Length: 0 + * Connection: keep-alive + * Server: gunicorn/19.9.0 + * WWW-Authenticate: Basic realm="Fake Realm" + * Access-Control-Allow-Origin: * + * Access-Control-Allow-Credentials: true + * + * GET /basic-auth/user/passwd HTTP/1.1 + * Host: httpbin.org + * Connection: keep-alive + * User-Agent: Apache-HttpClient/5.1.3 (Java/1.8.0_151) + * Authorization: Basic dXNlcjpwYXNzd2Q= + * + * HTTP/1.1 200 OK + * Date: Sat, 06 Aug 2022 08:25:33 GMT + * Content-Type: application/json + * Content-Length: 47 + * Connection: keep-alive + * Server: gunicorn/19.9.0 + * Access-Control-Allow-Origin: * + * Access-Control-Allow-Credentials: true + * + * { + * "authenticated": true, + * "user": "user" + * } + */ +public class HttpClient5BasicAuthentication { + + public static void main(final String[] args) throws Exception { + final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( + new AuthScope("httpbin.org", 80), + new UsernamePasswordCredentials("admin", "123456".toCharArray())); + try (final CloseableHttpClient httpclient = HttpClients.custom() + .setDefaultCredentialsProvider(credsProvider) + .build()) { + final HttpGet httpget = new HttpGet("http://httpbin.org/basic-auth/admin/123456"); + + System.out.println("执行请求" + httpget.getMethod() + " " + httpget.getUri()); + try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } + } +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CancleMethod.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CancleMethod.java new file mode 100644 index 0000000..11ed77b --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CancleMethod.java @@ -0,0 +1,27 @@ +package com.wdbyte.httpclient; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; + +/** + * 这个案例展示了如何中止一个HTTP方法之前正常完成。; + */ +public class HttpClient5CancleMethod { + + public static void main(final String[] args) throws Exception { + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + final HttpGet httpget = new HttpGet("http://httpbin.org/get"); + + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + // 不像读取结果,直接中止 + httpget.cancel(); + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ChunkEncodedPost.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ChunkEncodedPost.java new file mode 100644 index 0000000..e587844 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ChunkEncodedPost.java @@ -0,0 +1,42 @@ +package com.wdbyte.httpclient; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.FileEntity; +import org.apache.hc.core5.http.io.entity.InputStreamEntity; + +/** + * 加载数据流作为 POST 请求参数 + */ +public class HttpClient5ChunkEncodedPost { + + public static void main(final String[] args) throws Exception { + String params = "/Users/darcy/params.json"; + + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + final HttpPost httppost = new HttpPost("http://httpbin.org/post"); + + final InputStreamEntity reqEntity = new InputStreamEntity(new FileInputStream(params), -1, + ContentType.APPLICATION_JSON); + // 也可以使用 FileEntity 的形式 + // FileEntity reqEntity = new FileEntity(new File(params), ContentType.APPLICATION_JSON); + + httppost.setEntity(reqEntity); + + System.out.println("执行请求 " + httppost.getMethod() + " " + httppost.getUri()); + try (final CloseableHttpResponse response = httpclient.execute(httppost)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CustomSSL.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CustomSSL.java new file mode 100644 index 0000000..90064b6 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5CustomSSL.java @@ -0,0 +1,76 @@ +package com.wdbyte.httpclient; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.ssl.TrustStrategy; + +/** + * This example demonstrates how to create secure connections with a custom SSL + * context. + */ +public class HttpClient5CustomSSL { + + public final static void main(final String[] args) throws Exception { + // 标准CA信任,信任我们的自定义策略; + final SSLContext sslcontext = SSLContexts.custom() + .loadTrustMaterial(new TrustStrategy() { + + @Override + public boolean isTrusted( + final X509Certificate[] chain, + final String authType) throws CertificateException { + final X509Certificate cert = chain[0]; + return "CN=httpbin.org".equalsIgnoreCase(cert.getSubjectDN().getName()); + } + + }) + .build(); + // 只允许 TLSv1.2 协议 + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() + .setSslContext(sslcontext) + .setTlsVersions(TLS.V_1_2) + .build(); + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory) + .build(); + + try (CloseableHttpClient httpclient = HttpClients.custom() + .setConnectionManager(cm) + .build()) { + + final HttpGet httpget = new HttpGet("https://httpbin.org/get"); + + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + + final HttpClientContext clientContext = HttpClientContext.create(); + try (CloseableHttpResponse response = httpclient.execute(httpget, clientContext)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + + final SSLSession sslSession = clientContext.getSSLSession(); + if (sslSession != null) { + System.out.println("SSL 协议 " + sslSession.getProtocol()); + System.out.println("SSL cipher suite " + sslSession.getCipherSuite()); + } + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ExecuteProxy.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ExecuteProxy.java new file mode 100644 index 0000000..b5312b1 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ExecuteProxy.java @@ -0,0 +1,46 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * 如何通过代理发送请求。 + * +* @author https://www.wdbyte.com + * @date 2022/06/26 + */ +public class HttpClient5ExecuteProxy { + + public static void main(String[] args) { + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + final HttpHost target = new HttpHost("https", "httpbin.org", 443); + final HttpHost proxy = new HttpHost("http", "127.0.0.1", 8080); + + final RequestConfig config = RequestConfig.custom() + .setProxy(proxy) + .build(); + final HttpGet request = new HttpGet("/get"); + request.setConfig(config); + + System.out.println("执行请求 " + request.getMethod() + " " + request.getUri() + " via " + proxy); + + try (final CloseableHttpResponse response = httpclient.execute(target, request)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } catch (IOException | ParseException | URISyntaxException e) { + throw new RuntimeException(e); + } + } +} + diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5FormLogin.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5FormLogin.java new file mode 100644 index 0000000..fed0fda --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5FormLogin.java @@ -0,0 +1,58 @@ +package com.wdbyte.httpclient; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.Cookie; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.BasicNameValuePair; + +/** + * 演示基于表单的登录 + * + * @author https://www.wdbyte.com + */ +public class HttpClient5FormLogin { + + public static void main(final String[] args) throws Exception { + final BasicCookieStore cookieStore = new BasicCookieStore(); + try (final CloseableHttpClient httpclient = HttpClients.custom() + .setDefaultCookieStore(cookieStore) + .build()) { + + // 本应该使用 POST 请求发送表单参数,但是在 httpbin.org 中没有对应的接口用于测试,所以这里换成了 GET 请求 + // HttpPost httpPost = new HttpPost("http://httpbin.org/cookies/set/username/wdbyte.com"); + HttpGet httpPost = new HttpGet("http://httpbin.org/cookies/set/username/wdbyte.com"); + // POST 表单请求参数 + List nvps = new ArrayList<>(); + nvps.add(new BasicNameValuePair("username", "wdbyte.com")); + nvps.add(new BasicNameValuePair("password", "secret")); + httpPost.setEntity(new UrlEncodedFormEntity(nvps)); + + try (final CloseableHttpResponse response2 = httpclient.execute(httpPost)) { + final HttpEntity entity = response2.getEntity(); + + System.out.println("Login form get: " + response2.getCode() + " " + response2.getReasonPhrase()); + System.out.println("当前响应信息 "+EntityUtils.toString(entity));; + + System.out.println("Post 登录 Cookie:"); + final List cookies = cookieStore.getCookies(); + if (cookies.isEmpty()) { + System.out.println("None"); + } else { + for (int i = 0; i < cookies.size(); i++) { + System.out.println("- " + cookies.get(i)); + } + } + } + } + } +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithBasicAuth.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithBasicAuth.java new file mode 100644 index 0000000..9c6bb80 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithBasicAuth.java @@ -0,0 +1,51 @@ +//package com.wdbyte.httpclient.get; +// +//import org.apache.hc.client5.http.auth.AuthScope; +//import org.apache.hc.client5.http.auth.CredentialsProvider; +//import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +//import org.apache.hc.client5.http.classic.methods.HttpGet; +//import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +//import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +//import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +//import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +//import org.apache.hc.core5.http.HttpEntity; +//import org.apache.hc.core5.http.io.entity.EntityUtils; +// +///** +//* @author https://www.wdbyte.com +// * @date 2022/06/25 +// */ +//public class HttpClient5GetWithBasicAuth { +// +// public static void main(String[] args) { +// +// } +// +// public static String get(String url, String username, String password) { +// HttpGet request = new HttpGet(url); +// BasicCredentialsProvider provider = new BasicCredentialsProvider(); +// provider.setCredentials(AuthScope.); +// +// provider.setCredentials( +// AuthScope.ANY, +// new UsernamePasswordCredentials("user", "password") +// ); +// +// try (CloseableHttpClient httpClient = HttpClientBuilder.create() +// .setDefaultCredentialsProvider(provider) +// .build(); +// CloseableHttpResponse response = httpClient.execute(request)) { +// +// // 401 if wrong user/password +// System.out.println(response.getStatusLine().getStatusCode()); +// +// HttpEntity entity = response.getEntity(); +// if (entity != null) { +// // return it as a String +// String result = EntityUtils.toString(entity); +// System.out.println(result); +// } +// +// } +// } +//} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithTimeout.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithTimeout.java new file mode 100644 index 0000000..c199ca7 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5GetWithTimeout.java @@ -0,0 +1,54 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.util.Timeout; + +/** +* @author https://www.wdbyte.com + */ +public class HttpClient5GetWithTimeout { + + public static void main(String[] args) { + String result = get("http://httpbin.org/get"); + System.out.println(result); + } + + public static String get(String url) { + String resultContent = null; + // 设置超时时间 + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(Timeout.ofMilliseconds(5000L)) + .setConnectionRequestTimeout(Timeout.ofMilliseconds(5000L)) + .setResponseTimeout(Timeout.ofMilliseconds(5000L)) + .build(); + // 请求级别的超时 + HttpGet httpGet = new HttpGet(url); + //httpGet.setConfig(config); + //try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + // 客户端级别的超时 + try (CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(config).build()) { + try (CloseableHttpResponse response = httpclient.execute(httpGet)) { + // 获取状态码 + System.out.println(response.getVersion()); // HTTP/1.1 + System.out.println(response.getCode()); // 200 + System.out.println(response.getReasonPhrase()); // OK + HttpEntity entity = response.getEntity(); + // 获取响应信息 + resultContent = EntityUtils.toString(entity); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return resultContent; + } + +} diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Interceptors.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Interceptors.java new file mode 100644 index 0000000..6a5d6f3 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5Interceptors.java @@ -0,0 +1,81 @@ +package com.wdbyte.httpclient; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.hc.client5.http.classic.ExecChain; +import org.apache.hc.client5.http.classic.ExecChain.Scope; +import org.apache.hc.client5.http.classic.ExecChainHandler; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.ChainElement; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.EntityDetails; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicClassicHttpResponse; +import org.apache.hc.core5.http.protocol.HttpContext; + +/** + * 展示如何在请求和响应时进行拦截进行自定义处理。 + */ +public class HttpClient5Interceptors { + + public static void main(final String[] args) throws Exception { + try (final CloseableHttpClient httpclient = HttpClients.custom() + // 添加一个请求 id 到请求 header + .addRequestInterceptorFirst(new HttpRequestInterceptor() { + private final AtomicLong count = new AtomicLong(0); + @Override + public void process( + final HttpRequest request, + final EntityDetails entity, + final HttpContext context) throws HttpException, IOException { + request.setHeader("request-id", Long.toString(count.incrementAndGet())); + } + }) + .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", new ExecChainHandler() { + // 请求 id 为 2 的,模拟 404 响应,并自定义响应的内容。 + @Override + public ClassicHttpResponse execute( + final ClassicHttpRequest request, + final Scope scope, + final ExecChain chain) throws IOException, HttpException { + + final Header idHeader = request.getFirstHeader("request-id"); + if (idHeader != null && "2".equalsIgnoreCase(idHeader.getValue())) { + final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_NOT_FOUND, + "Oppsie"); + response.setEntity(new StringEntity("bad luck", ContentType.TEXT_PLAIN)); + return response; + } else { + return chain.proceed(request, scope); + } + } + }) + .build()) { + + for (int i = 0; i < 3; i++) { + final HttpGet httpget = new HttpGet("http://httpbin.org/get"); + + try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + System.out.println("----------------------------------------"); + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveBasicAuthentication.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveBasicAuthentication.java new file mode 100644 index 0000000..e0bb8a7 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveBasicAuthentication.java @@ -0,0 +1,59 @@ +package com.wdbyte.httpclient; + +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.CredentialsProvider; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * 抢先式身份认证 + * 注意安全性问题 + */ +public class HttpClient5PreemptiveBasicAuthentication { + + public static void main(final String[] args) throws Exception { + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + + // 生成一个认证信息 + final BasicScheme basicAuth = new BasicScheme(); + basicAuth.initPreemptive(new UsernamePasswordCredentials("admin", "123456".toCharArray())); + // 认证信息的生效域名信息 + final HttpHost target = new HttpHost("http", "httpbin.org", 80); + // 添加认证信息到 HttpClient 请求上下文中 + final HttpClientContext localContext = HttpClientContext.create(); + localContext.resetAuthExchange(target, basicAuth); + + //AuthScope authScope = new AuthScope("httpbin.org", 80); + //BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + //credsProvider.setCredentials(authScope, + // new UsernamePasswordCredentials("admin", "1234556".toCharArray())); + + AuthCache authCache = new BasicAuthCache(); + authCache.put(target, new BasicScheme()); + //localContext.setCredentialsProvider(credsProvider); + localContext.setAuthCache(authCache); + + final HttpGet httpget = new HttpGet("http://httpbin.org/basic-auth/admin/123456"); + + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + for (int i = 0; i < 3; i++) { + try (final CloseableHttpResponse response = httpclient.execute(httpget, localContext)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveDigestAuthentication.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveDigestAuthentication.java new file mode 100644 index 0000000..5e3772b --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5PreemptiveDigestAuthentication.java @@ -0,0 +1,104 @@ +package com.wdbyte.httpclient; + +import org.apache.hc.client5.http.auth.AuthExchange; +import org.apache.hc.client5.http.auth.AuthScheme; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.DigestScheme; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * GET /digest-auth/auth/user/1234567 HTTP/1.1 + * Accept-Encoding: gzip, x-gzip, deflate + * Host: httpbin.org + * Connection: keep-alive + * User-Agent: Apache-HttpClient/5.1.3 (Java/17) + * + * HTTP/1.1 401 UNAUTHORIZED + * Date: Mon, 27 Jun 2022 01:14:33 GMT + * Content-Type: text/html; charset=utf-8 + * Content-Length: 0 + * Connection: keep-alive + * Server: gunicorn/19.9.0 + * WWW-Authenticate: Digest realm="me@kennethreitz.com", nonce="5555b4af2e521ae090278b68bdc0a514", qop="auth", + * opaque="ba9c52e5ba8efb290bbf44404c9df42c", algorithm=MD5, stale=FALSE + * Set-Cookie: stale_after=never; Path=/ + * Set-Cookie: fake=fake_value; Path=/ + * Access-Control-Allow-Origin: * + * Access-Control-Allow-Credentials: true + * + * GET /digest-auth/auth/user/1234567 HTTP/1.1 + * Host: httpbin.org + * Connection: keep-alive + * User-Agent: Apache-HttpClient/5.1.3 (Java/17) + * Cookie: fake=fake_value; stale_after=never + * Authorization: Digest username="user", realm="me@kennethreitz.com", nonce="5555b4af2e521ae090278b68bdc0a514", + * uri="/digest-auth/auth/user/1234567", response="ceef33b582fcbe9b15157d29a75f4781", qop=auth, nc=00000001, + * cnonce="085c5561765f5b9a", algorithm=MD5, opaque="ba9c52e5ba8efb290bbf44404c9df42c" + * + * HTTP/1.1 200 OK + * Date: Mon, 27 Jun 2022 01:14:33 GMT + * Content-Type: application/json + * Content-Length: 47 + * Connection: keep-alive + * Server: gunicorn/19.9.0 + * Set-Cookie: fake=fake_value; Path=/ + * Set-Cookie: stale_after=never; Path=/ + * Access-Control-Allow-Origin: * + * Access-Control-Allow-Credentials: true + * + * { + * "authenticated": true, + * "user": "user" + * } + * + * HttpClient如何验证多个请求的示例 + * 使用相同的摘要方案。在初始请求/响应交换之后 + * 共享相同执行上下文的所有后续请求都可以重用 + * 要向服务器进行身份验证的最后一个摘要nonce值。 + */ +public class HttpClient5PreemptiveDigestAuthentication { + + public static void main(final String[] args) throws Exception { + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + + final HttpHost target = new HttpHost("http", "httpbin.org", 80); + + final HttpClientContext localContext = HttpClientContext.create(); + final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials( + new AuthScope(target), + new UsernamePasswordCredentials("admin", "123456".toCharArray())); + localContext.setCredentialsProvider(credentialsProvider); + + final HttpGet httpget = new HttpGet("http://httpbin.org/digest-auth/auth/admin/123456"); + + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + for (int i = 0; i < 2; i++) { + try (final CloseableHttpResponse response = httpclient.execute(target, httpget, localContext)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + EntityUtils.consume(response.getEntity()); + + final AuthExchange authExchange = localContext.getAuthExchange(target); + if (authExchange != null) { + final AuthScheme authScheme = authExchange.getAuthScheme(); + if (authScheme instanceof DigestScheme) { + final DigestScheme digestScheme = (DigestScheme) authScheme; + System.out.println("Nonce: " + digestScheme.getNonce() + + "; count: " + digestScheme.getNounceCount()); + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyAuthentication.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyAuthentication.java new file mode 100644 index 0000000..97c115e --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyAuthentication.java @@ -0,0 +1,48 @@ +package com.wdbyte.httpclient; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * A simple example that uses HttpClient to execute an HTTP request + * over a secure connection tunneled through an authenticating proxy. + */ +public class HttpClient5ProxyAuthentication { + + public static void main(final String[] args) throws Exception { + final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( // 代理和认证信息 + new AuthScope("localhost", 8888), + new UsernamePasswordCredentials("squid", "squid".toCharArray())); + credsProvider.setCredentials( // 目标和认证信息 + new AuthScope("httpbin.org", 80), + new UsernamePasswordCredentials("user", "passwd".toCharArray())); + try (final CloseableHttpClient httpclient = HttpClients.custom() + .setDefaultCredentialsProvider(credsProvider).build()) { + final HttpHost target = new HttpHost("http", "httpbin.org", 80); + final HttpHost proxy = new HttpHost("localhost", 8888); + + final RequestConfig config = RequestConfig.custom() + .setProxy(proxy) + .build(); + final HttpGet httpget = new HttpGet("/basic-auth/user/passwd"); + httpget.setConfig(config); + + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri() + " via " + proxy); + + try (final CloseableHttpResponse response = httpclient.execute(target, httpget)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + System.out.println(EntityUtils.toString(response.getEntity())); + } + } + } +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyTunnelDemo.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyTunnelDemo.java new file mode 100644 index 0000000..7a6b491 --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5ProxyTunnelDemo.java @@ -0,0 +1,42 @@ +package com.wdbyte.httpclient; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.impl.classic.ProxyClient; +import org.apache.hc.core5.http.HttpHost; + +/** + * Example code for using {@link ProxyClient} in order to establish a tunnel through an HTTP proxy. + */ +public class HttpClient5ProxyTunnelDemo { + + public final static void main(final String[] args) throws Exception { + + final ProxyClient proxyClient = new ProxyClient(); + final HttpHost target = new HttpHost("www.yahoo.com", 80); + final HttpHost proxy = new HttpHost("127.0.0.1", 9090); + final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("user", "pwd".toCharArray()); + try (final Socket socket = proxyClient.tunnel(proxy, target, credentials)) { + final Writer out = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.ISO_8859_1); + out.write("GET / HTTP/1.1\r\n"); + out.write("Host: " + target.toHostString() + "\r\n"); + out.write("Agent: whatever\r\n"); + out.write("Connection: close\r\n"); + out.write("\r\n"); + out.flush(); + final BufferedReader in = new BufferedReader( + new InputStreamReader(socket.getInputStream(), StandardCharsets.ISO_8859_1)); + String line = null; + while ((line = in.readLine()) != null) { + System.out.println(line); + } + } + } + +} \ No newline at end of file diff --git a/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5WithCookie.java b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5WithCookie.java new file mode 100644 index 0000000..af0eace --- /dev/null +++ b/tool-java-apache-httpclient/src/main/java/com/wdbyte/httpclient/HttpClient5WithCookie.java @@ -0,0 +1,53 @@ +package com.wdbyte.httpclient; + +import java.util.List; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.Cookie; +import org.apache.hc.client5.http.cookie.CookieStore; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +/** + * 这个例子演示了使用本地HTTP上下文填充, 自定义属性 + */ +public class HttpClient5WithCookie { + + public static void main(final String[] args) throws Exception { + try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { + // 创建一个本地的 Cookie 存储 + final CookieStore cookieStore = new BasicCookieStore(); + //BasicClientCookie clientCookie = new BasicClientCookie("name", "www.wdbyte.com"); + //clientCookie.setDomain("http://httpbin.org/cookies"); + // 过期时间 + //clientCookie.setExpiryDate(new Date()); + // 添加到本地 Cookie + //cookieStore.addCookie(clientCookie); + + // 创建本地 HTTP 请求上下文 HttpClientContext + final HttpClientContext localContext = HttpClientContext.create(); + // 绑定 cookieStore 到 localContext + localContext.setCookieStore(cookieStore); + + final HttpGet httpget = new HttpGet("http://httpbin.org/cookies/set/cookieName/www.wdbyte.com"); + System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri()); + + // 获取 Coolie 信息 + try (final CloseableHttpResponse response = httpclient.execute(httpget, localContext)) { + System.out.println("----------------------------------------"); + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + final List cookies = cookieStore.getCookies(); + for (int i = 0; i < cookies.size(); i++) { + System.out.println("Local cookie: " + cookies.get(i)); + } + EntityUtils.consume(response.getEntity()); + } + } + } + +} \ No newline at end of file From 68041649815e956a70b4a6755f5201f2822c64ca Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 2 Nov 2022 00:03:42 +0800 Subject: [PATCH 11/83] =?UTF-8?q?feat:[=E4=BD=BF=E7=94=A8=20StringUtils.sp?= =?UTF-8?q?lit=20=E7=9A=84=E5=9D=91](https://www.wdbyte.com/java/stringuti?= =?UTF-8?q?ls=5Fsplit.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + tool-java-apache-common/pom.xml | 20 ++++++ .../com/wdbyte/string/StringUtilsTest.java | 70 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tool-java-apache-common/pom.xml create mode 100644 tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java diff --git a/pom.xml b/pom.xml index 0fe1bcd..1f62483 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ tool-java-apache-httpclient tool-java-object-pool tool-java-jackson + tool-java-apache-common parent-modules Parent for all java modules diff --git a/tool-java-apache-common/pom.xml b/tool-java-apache-common/pom.xml new file mode 100644 index 0000000..895fe6b --- /dev/null +++ b/tool-java-apache-common/pom.xml @@ -0,0 +1,20 @@ + + + + parent-modules + com.wdbyte + 1.0.0-SNAPSHOT + + 4.0.0 + + tool-java-apache-common + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java b/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java new file mode 100644 index 0000000..fdaedda --- /dev/null +++ b/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java @@ -0,0 +1,70 @@ +package com.wdbyte.string; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; + +/** + * apache common lang StringUtils test + * @author niulang + * @date 2022/11/01 + */ +public class StringUtilsTest { + + public static void testA() { + String str = "aabbccdd"; + String[] resultArray = StringUtils.split(str, "bc"); + for (String s : resultArray) { + System.out.println(s); + } + } + + public static void testB() { + String str = "abc"; + String[] resultArray = StringUtils.split(str, "ac"); + for (String s : resultArray) { + System.out.println(s); + } + } + + public static void testC() { + String str = "abcd"; + String[] resultArray = StringUtils.split(str, "ac"); + for (String s : resultArray) { + System.out.println(s); + } + } + + public static void testD() { + String str = "aabbccdd"; + String[] resultArray = StringUtils.splitByWholeSeparator(str, "bc"); + for (String s : resultArray) { + System.out.println(s); + } + } + + public static void testE() { + //String str = "aabbccdd"; + //Iterable iterable = Splitter.on("bc") + // .omitEmptyStrings() // 忽略空值 + // .trimResults() // 过滤结果中的空白 + // .split(str); + //iterable.forEach(System.out::println); + } + + public static void testF() { + String str = "aabbccdd"; + String[] res = str.split("bc"); + for (String re : res) { + System.out.println(re); + } + + } + + public static void testG() { + String str = ",a,,b,"; + String[] splitArr = str.split(","); + Arrays.stream(splitArr).forEach(System.out::println); + } + +} From e26df19a8d0a1f8e4720a988b10995d26db15c94 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 2 Nov 2022 00:04:02 +0800 Subject: [PATCH 12/83] =?UTF-8?q?feat:[=E4=BD=BF=E7=94=A8=20StringUtils.sp?= =?UTF-8?q?lit=20=E7=9A=84=E5=9D=91](https://www.wdbyte.com/java/stringuti?= =?UTF-8?q?ls=5Fsplit.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 26d8a9e..31fe748 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ ## ⏳ Java 开发 +- [使用 StringUtils.split 的坑](https://www.wdbyte.com/java/stringutils_split.html) - [必应壁纸,我的第一个 400 Star 开源项目](https://www.wdbyte.com/bing-wallpaper-400.html) - [Java 中的对象池化](https://www.wdbyte.com/java/object-pool.html) - [5种限流算法,7种限流方式,挡住突发流量?](https://www.wdbyte.com/java/rate-limiter.html) From f903692fde2ec5c4e94689eb56ff9cf75a1a20f8 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 17 Nov 2022 23:23:47 +0800 Subject: [PATCH 13/83] =?UTF-8?q?feat:[JUnit=205=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=95=99=E7=A8=8B](https://www.wdbyte.com/java/junit5.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- junit5-jupiter-starter/pom.xml | 24 +++------ .../java/com/wdbyte/test/junit5/Person.java | 12 +++++ .../wdbyte/test/junit5/JUnitBeforeAll.java | 54 +++++++++++++++++++ .../wdbyte/test/junit5/JUnitJDKVersion.java | 38 +++++++++++++ .../com/wdbyte/test/junit5/JUnitOrder.java | 35 ++++++++++++ .../com/wdbyte/test/junit5/JUnitOther.java | 37 +++++++++++++ .../com/wdbyte/test/junit5/JUnitParam.java | 21 ++++++++ .../wdbyte/test/junit5/JUnitTestIsDog.java | 29 ++++++++++ .../com/wdbyte/test/junit5/JunitAssert.java | 31 +++++++++++ .../com/wdbyte/test/junit5/PersonTest.java | 20 +++++++ 10 files changed, 284 insertions(+), 17 deletions(-) create mode 100644 junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java create mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java diff --git a/junit5-jupiter-starter/pom.xml b/junit5-jupiter-starter/pom.xml index b41ccff..d100632 100644 --- a/junit5-jupiter-starter/pom.xml +++ b/junit5-jupiter-starter/pom.xml @@ -13,41 +13,31 @@ junit5-jupiter-starter - 17 - 17 + 1.8 + 1.8 UTF-8 ${maven.compiler.source} - - - - org.junit - junit-bom - 5.8.2 - pom - import - - - - org.junit.jupiter junit-jupiter + 5.9.1 test - maven-compiler-plugin - 3.8.1 + maven-surefire-plugin + 2.22.2 - maven-surefire-plugin + maven-failsafe-plugin 2.22.2 + \ No newline at end of file diff --git a/junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java b/junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java new file mode 100644 index 0000000..514c0af --- /dev/null +++ b/junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java @@ -0,0 +1,12 @@ +package com.wdbyte.test.junit5; + +/** + * @author niulang + * @date 2022/11/17 + */ +public class Person { + + public int getLuckyNumber() { + return 7; + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java new file mode 100644 index 0000000..732fb50 --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java @@ -0,0 +1,54 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2022/11/15 + */ +class JUnitBeforeAll { + + @BeforeAll + public static void init() { + System.out.println("初始化,准备测试信息"); + } + + @BeforeEach + public void start() { + System.out.println("开始测试..."); + } + + @DisplayName("是否是狗") + @Disabled("由于xx原因,关闭 testIsDog 测试") + @Test + public void testIsDog() { + String name = "dog"; + Assertions.assertEquals(name, "dog"); + System.out.println("is dog"); + } + + @DisplayName("是否是猫") + @Test + public void testIsCat() { + String name = "cat"; + Assertions.assertEquals(name, "cat"); + System.out.println("is cat"); + } + + @AfterEach + public void end() { + System.out.println("测试完毕..."); + } + + @AfterAll + public static void close() { + System.out.println("结束,准备退出测试"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java new file mode 100644 index 0000000..62230fc --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java @@ -0,0 +1,38 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.condition.EnabledOnJre; + +import static org.junit.jupiter.api.condition.JRE.JAVA_19; + +/** + * @author niulang + * @date 2022/11/17 + */ +@TestMethodOrder(OrderAnnotation.class) +public class JUnitJDKVersion { + + @Test + //@EnabledOnJre(JAVA_19) + @DisplayName("测试是否是狗") + @Order(2) + public void testIsDog() { + String name = "dog"; + Assertions.assertEquals(name, "dog"); + System.out.println("is dog"); + } + + @DisplayName("是否是猫") + @Test + @Order(10) + public void testIsCat() { + String name = "cat"; + Assertions.assertEquals(name, "cat"); + System.out.println("is cat"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java new file mode 100644 index 0000000..eef289a --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java @@ -0,0 +1,35 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +/** + * @author niulang + * @date 2022/11/17 + */ +@TestMethodOrder(OrderAnnotation.class) +public class JUnitOrder { + + @Test + //@EnabledOnJre(JAVA_19) + @DisplayName("测试是否是狗") + @Order(2) + public void testIsDog() { + String name = "dog"; + Assertions.assertEquals(name, "dog"); + System.out.println("is dog"); + } + + @DisplayName("是否是猫") + @Test + @Order(1) + public void testIsCat() { + String name = "cat"; + Assertions.assertEquals(name, "cat"); + System.out.println("is cat"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java new file mode 100644 index 0000000..aebe289 --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java @@ -0,0 +1,37 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +/** + * @author niulang + * @date 2022/11/17 + */ +@TestMethodOrder(OrderAnnotation.class) +public class JUnitOther { + + //@Test + //@EnabledOnJre(JAVA_19) + @DisplayName("测试是否是狗") + @Order(2) + @RepeatedTest(10) + public void testIsDog() { + String name = "dog"; + Assertions.assertEquals(name, "dog"); + System.out.println("is dog"); + } + + @DisplayName("是否是猫") + @Test + @Order(1) + public void testIsCat() { + String name = "cat"; + Assertions.assertEquals(name, "cat"); + System.out.println("is cat"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java new file mode 100644 index 0000000..fe29bbd --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java @@ -0,0 +1,21 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * @author niulang + * @date 2022/11/17 + */ +public class JUnitParam { + + //@Test + @DisplayName("是否是狗") + @ValueSource(strings = {"dog", "cat"}) + @ParameterizedTest(name = "开始测试入参 {0} ") + public void testIsDog(String name) { + Assertions.assertEquals(name, "dog"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java new file mode 100644 index 0000000..5d0cb07 --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java @@ -0,0 +1,29 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2022/11/15 + */ +class JUnitTestIsDog { + + @BeforeAll + public static void init() { + System.out.println("准备测试 Dog 信息"); + } + + @Test + public void testIsDog() { + String name = "cat"; + Assertions.assertEquals(name, "dog"); + } + + @Test + public void testIsDog2() { + String name = "dog"; + Assertions.assertEquals(name, "dog"); + } +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java new file mode 100644 index 0000000..0063739 --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java @@ -0,0 +1,31 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2022/11/17 + */ +public class JunitAssert { + + @DisplayName("是否是狗") + @Test + public void testIsDog() { + String name = "dog"; + Assertions.assertNotNull(name); + Assertions.assertEquals(name, "dog"); + Assertions.assertNotEquals(name, "cat"); + Assertions.assertTrue("dog".equals(name)); + Assertions.assertFalse("cat".equals(name)); + } + + @DisplayName("是否是猫") + @Test + public void testIsCat() { + String name = "cat"; + Assertions.assertNull(name, "name is not null"); + } + +} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java new file mode 100644 index 0000000..0d883ed --- /dev/null +++ b/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java @@ -0,0 +1,20 @@ +package com.wdbyte.test.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2022/11/17 + */ +@DisplayName("测试 Presion") +class PersonTest { + + @DisplayName("测试幸运数字") + @Test + void getLuckyNumber() { + Person person = new Person(); + Assertions.assertEquals(8, person.getLuckyNumber()); + } +} \ No newline at end of file From c1e2e590e35b82506fa770646c20cfa8f2c6b963 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 17 Nov 2022 23:25:07 +0800 Subject: [PATCH 14/83] =?UTF-8?q?feat:[JUnit=205=20=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=95=99=E7=A8=8B](https://www.wdbyte.com/ja?= =?UTF-8?q?va/junit5.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../java/com/wdbyte/junit5/Calculator.java | 32 ------------------- .../com/wdbyte/junit5/CalculatorTest.java | 30 ----------------- tool-java-jackson/README.md | 2 +- 4 files changed, 2 insertions(+), 63 deletions(-) delete mode 100644 junit5-jupiter-starter/src/main/java/com/wdbyte/junit5/Calculator.java delete mode 100644 junit5-jupiter-starter/src/test/java/com/wdbyte/junit5/CalculatorTest.java diff --git a/README.md b/README.md index 31fe748..4bff109 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ ## ⏳ Java 开发 +- [JUnit5 单元测试教程](https://www.wdbyte.com/java/junit5.html) - [使用 StringUtils.split 的坑](https://www.wdbyte.com/java/stringutils_split.html) - [必应壁纸,我的第一个 400 Star 开源项目](https://www.wdbyte.com/bing-wallpaper-400.html) - [Java 中的对象池化](https://www.wdbyte.com/java/object-pool.html) diff --git a/junit5-jupiter-starter/src/main/java/com/wdbyte/junit5/Calculator.java b/junit5-jupiter-starter/src/main/java/com/wdbyte/junit5/Calculator.java deleted file mode 100644 index 56a1037..0000000 --- a/junit5-jupiter-starter/src/main/java/com/wdbyte/junit5/Calculator.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.wdbyte.junit5; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.charset.Charset; - -/** - * @author niulang - * @date 2022/03/16 - */ -public class Calculator { - - public int add(int x, int y) { - return x + y; - } - public static void main(String[] args) throws UnknownHostException { - InetAddress byName = InetAddress.getByName("www.baidu.com"); - System.out.println(byName.getHostAddress()); - //Java使用的默认字符集 - System.out.println("java 默认字符集:"); - System.out.println(Charset.defaultCharset()+"\n"); - //汉字“测”的字节编码 - String str = "测试一下"; - //这里可以手动设置编码字符集,默认使用utf-8编码 - byte[] bytes = str.getBytes(); - System.out.println("汉字\"测\"的编码:"); - for(byte bt: bytes){ - System.out.println(bt); - } - - } -} diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/junit5/CalculatorTest.java b/junit5-jupiter-starter/src/test/java/com/wdbyte/junit5/CalculatorTest.java deleted file mode 100644 index 2005ed6..0000000 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/junit5/CalculatorTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.wdbyte.junit5; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.RepeatedTest; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author niulang - * @date 2022/03/16 - */ -@DisplayName("计算器") -class CalculatorTest { - - private final Calculator calculator = new Calculator(); - - //@Tag("fast") - @Test - //@RepeatedTest(2) - @DisplayName("相加") - //@ParameterizedTest() - //@ValueSource(ints = { -1, -4 }) - void add() { - assertEquals(3, calculator.add(1, 1)); - } -} \ No newline at end of file diff --git a/tool-java-jackson/README.md b/tool-java-jackson/README.md index 0b9e3f0..bd31197 100644 --- a/tool-java-jackson/README.md +++ b/tool-java-jackson/README.md @@ -1,4 +1,4 @@ ## tool-java-jackson ### 相关文章 -- [Jackson 解析 JSON 教程](https://www.wdbyte.com/tool/jackson.html) +- [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) From 36191924707171af075faf13b49d373611c143d5 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 18 Nov 2022 10:01:02 +0800 Subject: [PATCH 15/83] =?UTF-8?q?feat:[JUnit=205=20=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=95=99=E7=A8=8B](https://www.wdbyte.com/ja?= =?UTF-8?q?va/junit5.html)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- junit5-jupiter-starter/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 junit5-jupiter-starter/README.md diff --git a/junit5-jupiter-starter/README.md b/junit5-jupiter-starter/README.md new file mode 100644 index 0000000..6773392 --- /dev/null +++ b/junit5-jupiter-starter/README.md @@ -0,0 +1,3 @@ +## junit5-jupiter-starter + +- [JUnit5 单元测试教程](https://www.wdbyte.com/java/junit5.html) \ No newline at end of file From 17af0f453ccbdbe15895a956de61089ce3227c60 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 21 Feb 2023 21:46:21 +0800 Subject: [PATCH 16/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E7=82=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + tool-java-hotcode/pom.xml | 16 ++ .../main/java/com/wdbyte/hotcode/HotCode.java | 167 ++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 tool-java-hotcode/pom.xml create mode 100644 tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java diff --git a/pom.xml b/pom.xml index 1f62483..3110d06 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ tool-java-object-pool tool-java-jackson tool-java-apache-common + tool-java-hotcode parent-modules Parent for all java modules diff --git a/tool-java-hotcode/pom.xml b/tool-java-hotcode/pom.xml new file mode 100644 index 0000000..8ff3731 --- /dev/null +++ b/tool-java-hotcode/pom.xml @@ -0,0 +1,16 @@ + + + parent-modules + com.wdbyte + 1.0.0-SNAPSHOT + + 4.0.0 + tool-java-hotcode + + + + 17 + 17 + + diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java new file mode 100644 index 0000000..46413c7 --- /dev/null +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -0,0 +1,167 @@ +package com.wdbyte.hotcode; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @author niulang + * @date 2023/02/20 + */ +public class HotCode { + + private static HashSet hashSet = new HashSet(); + /** + * 线程池,大小1 + */ + private static ExecutorService executorService = Executors.newFixedThreadPool(1); + + public static void main(String[] args) { + // 模拟 CPU 过高 + //cpuHigh(); + // 模拟线程阻塞,线程池容量为1,塞入两个线程,会有一个一直等待 + thread(); + // 模拟线程死锁 + deadThread(); + // 不断的向 hashSet 集合增加数据,内存缓慢增长 + addHashSetThread(); + // 生成大长度数组 + allocate(); + } + + private static Object array; + + /** + * 生成大长度数组 + */ + private static void allocate() { + new Thread(() -> { + int index = 1; + while (true) { + Thread.currentThread().setName("memory_allocate_thread"); + array = new int[1 * index * 1000]; + array = new Integer[1 * index * 1000]; + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + index++; + + } + }).start(); + + new Thread(()->{ + List list = new ArrayList<>(); + for (int i = 0; i < 1000000; i++) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + list.add("string" + i); + } + }).start(); + } + + /** + * 不断的向 hashSet 集合添加数据,每秒100个字符串 + */ + public static void addHashSetThread() { + // 初始化常量 + new Thread(() -> { + int count = 0; + while (true) { + Thread.currentThread().setName("add_hash_set_thread"); + try { + hashSet.add("count" + count); + Thread.sleep(10); + count++; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } + + /** + * 极度消耗CPU的线程 + * 死循环 + */ + private static void cpuHigh() { + Thread thread = new Thread(() -> { + double pi = 0; + for (int i = 0; i < Integer.MAX_VALUE; i++) { + pi += Math.pow(-1, i) / (2 * i + 1); + } + System.out.println("Pi: " + pi * 4); + }); + thread.start(); + } + + /** + * 模拟线程阻塞 + * 线程池容量为1,但是向线程池中塞入两个线程 + */ + private static void thread() { + Thread thread = new Thread(() -> { + while (true) { + System.out.println("executorService thread start"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + // 添加到线程 + executorService.submit(thread); + executorService.submit(thread); + } + + /** + * 死锁线程 + * 线程 dead_thread_A 与 线程 dead_thread_B 互相锁死 + */ + private static void deadThread() { + /** 创建资源 */ + Object resourceA = new Object(); + Object resourceB = new Object(); + // 创建线程 + Thread threadA = new Thread(() -> { + Thread.currentThread().setName("dead_thread_A"); + synchronized (resourceA) { + System.out.println(Thread.currentThread() + " get ResourceA"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread() + "waiting get resourceB"); + synchronized (resourceB) { + System.out.println(Thread.currentThread() + " get resourceB"); + } + } + }); + + Thread threadB = new Thread(() -> { + Thread.currentThread().setName("dead_thread_A"); + synchronized (resourceB) { + System.out.println(Thread.currentThread() + " get ResourceB"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread() + "waiting get resourceA"); + synchronized (resourceA) { + System.out.println(Thread.currentThread() + " get resourceA"); + } + } + }); + threadA.start(); + threadB.start(); + } +} From 6ccf78a43945ab72f7ce13e79af3f803bcc01a8e Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 21 Feb 2023 22:11:16 +0800 Subject: [PATCH 17/83] feat: opt hotcode --- .../src/main/java/com/wdbyte/hotcode/HotCode.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index 46413c7..8c867fa 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -20,7 +20,7 @@ public class HotCode { public static void main(String[] args) { // 模拟 CPU 过高 - //cpuHigh(); + cpuHigh(); // 模拟线程阻塞,线程池容量为1,塞入两个线程,会有一个一直等待 thread(); // 模拟线程死锁 @@ -92,11 +92,14 @@ public static void addHashSetThread() { */ private static void cpuHigh() { Thread thread = new Thread(() -> { - double pi = 0; - for (int i = 0; i < Integer.MAX_VALUE; i++) { - pi += Math.pow(-1, i) / (2 * i + 1); + Thread.currentThread().setName("cpu_high_thread"); + while (true){ + double pi = 0; + for (int i = 0; i < Integer.MAX_VALUE; i++) { + pi += Math.pow(-1, i) / (2 * i + 1); + } + System.out.println("Pi: " + pi * 4); } - System.out.println("Pi: " + pi * 4); }); thread.start(); } From 45ef97b4fba79f10c50eecbfcc3d7ffbe3c01189 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sat, 25 Feb 2023 16:24:01 +0800 Subject: [PATCH 18/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E7=82=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/wdbyte/hotcode/HotCode.java | 137 ++++++++++-------- 1 file changed, 74 insertions(+), 63 deletions(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index 8c867fa..db7eb11 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -21,16 +21,33 @@ public class HotCode { public static void main(String[] args) { // 模拟 CPU 过高 cpuHigh(); - // 模拟线程阻塞,线程池容量为1,塞入两个线程,会有一个一直等待 - thread(); + // 生成大长度数组 + allocate(); // 模拟线程死锁 deadThread(); // 不断的向 hashSet 集合增加数据,内存缓慢增长 addHashSetThread(); - // 生成大长度数组 - allocate(); + // 模拟线程阻塞,线程池容量为1,塞入两个线程,会有一个一直等待 + thread(); } + /** + * 消耗CPU的线程 + * 不断循环进行浮点运算 + */ + private static void cpuHigh() { + Thread thread = new Thread(() -> { + Thread.currentThread().setName("cpu_high_thread"); + while (true){ + double pi = 0; + for (int i = 0; i < Integer.MAX_VALUE; i++) { + pi += Math.pow(-1, i) / (2 * i + 1); + } + System.out.println("Pi: " + pi * 4); + } + }); + thread.start(); + } private static Object array; /** @@ -38,9 +55,9 @@ public static void main(String[] args) { */ private static void allocate() { new Thread(() -> { + Thread.currentThread().setName("memory_allocate_thread_1"); int index = 1; while (true) { - Thread.currentThread().setName("memory_allocate_thread"); array = new int[1 * index * 1000]; array = new Integer[1 * index * 1000]; try { @@ -54,6 +71,7 @@ private static void allocate() { }).start(); new Thread(()->{ + Thread.currentThread().setName("memory_allocate_thread_2"); List list = new ArrayList<>(); for (int i = 0; i < 1000000; i++) { try { @@ -66,64 +84,6 @@ private static void allocate() { }).start(); } - /** - * 不断的向 hashSet 集合添加数据,每秒100个字符串 - */ - public static void addHashSetThread() { - // 初始化常量 - new Thread(() -> { - int count = 0; - while (true) { - Thread.currentThread().setName("add_hash_set_thread"); - try { - hashSet.add("count" + count); - Thread.sleep(10); - count++; - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }).start(); - } - - /** - * 极度消耗CPU的线程 - * 死循环 - */ - private static void cpuHigh() { - Thread thread = new Thread(() -> { - Thread.currentThread().setName("cpu_high_thread"); - while (true){ - double pi = 0; - for (int i = 0; i < Integer.MAX_VALUE; i++) { - pi += Math.pow(-1, i) / (2 * i + 1); - } - System.out.println("Pi: " + pi * 4); - } - }); - thread.start(); - } - - /** - * 模拟线程阻塞 - * 线程池容量为1,但是向线程池中塞入两个线程 - */ - private static void thread() { - Thread thread = new Thread(() -> { - while (true) { - System.out.println("executorService thread start"); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }); - // 添加到线程 - executorService.submit(thread); - executorService.submit(thread); - } - /** * 死锁线程 * 线程 dead_thread_A 与 线程 dead_thread_B 互相锁死 @@ -167,4 +127,55 @@ private static void deadThread() { threadA.start(); threadB.start(); } + + + /** + * 不断的向 hashSet 集合添加数据,每秒100个字符串 + */ + public static void addHashSetThread() { + // 初始化常量 + new Thread(() -> { + Thread.currentThread().setName("add_hash_set_thread"); + int count = 0; + while (true) { + try { + hashSet.add("count" + count); + Thread.sleep(10); + count++; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } + + /** + * 模拟线程阻塞 + * 线程池容量为1,但是向线程池中塞入两个线程 + */ + private static void thread() { + Thread thread = new Thread(() -> { + System.out.println("executorService thread start"); + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + // 添加到线程 + executorService.submit(thread); + executorService.submit(thread); + executorService.submit(thread); + executorService.submit(thread); + } + + /** + * 运行缓慢的方法 + */ + public static void runSlowThread(){ + new Thread(() -> { + }).start(); + } } From 4147125fafeb5652fdfbc8f3f06cd20130f478ac Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sat, 25 Feb 2023 21:58:13 +0800 Subject: [PATCH 19/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E7=82=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/wdbyte/hotcode/HotCode.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index db7eb11..a7ffa27 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -1,5 +1,6 @@ package com.wdbyte.hotcode; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -58,15 +59,13 @@ private static void allocate() { Thread.currentThread().setName("memory_allocate_thread_1"); int index = 1; while (true) { - array = new int[1 * index * 1000]; - array = new Integer[1 * index * 1000]; + array = new BigDecimal[1 * index * 1000]; try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } index++; - } }).start(); @@ -140,7 +139,7 @@ public static void addHashSetThread() { while (true) { try { hashSet.add("count" + count); - Thread.sleep(10); + Thread.sleep(5); count++; } catch (InterruptedException e) { e.printStackTrace(); From 080568bffeaca4bc1faeebf498fac985260720bc Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sat, 25 Feb 2023 22:28:28 +0800 Subject: [PATCH 20/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E7=82=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/wdbyte/hotcode/HotCode.java | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index a7ffa27..db3d5d3 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -22,7 +22,7 @@ public class HotCode { public static void main(String[] args) { // 模拟 CPU 过高 cpuHigh(); - // 生成大长度数组 + // 不断新增 BigDecimal 信息到 list allocate(); // 模拟线程死锁 deadThread(); @@ -49,36 +49,21 @@ private static void cpuHigh() { }); thread.start(); } - private static Object array; /** - * 生成大长度数组 + * 不断新增 BigDecimal 信息到 list */ private static void allocate() { - new Thread(() -> { - Thread.currentThread().setName("memory_allocate_thread_1"); - int index = 1; - while (true) { - array = new BigDecimal[1 * index * 1000]; - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - index++; - } - }).start(); - new Thread(()->{ - Thread.currentThread().setName("memory_allocate_thread_2"); - List list = new ArrayList<>(); - for (int i = 0; i < 1000000; i++) { + Thread.currentThread().setName("memory_allocate_thread"); + List list = new ArrayList<>(); + for (int i = 0; i < Integer.MAX_VALUE; i++) { try { Thread.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } - list.add("string" + i); + list.add(new BigDecimal(i)); } }).start(); } From 2ca1c771666de241e1d17067adab138135bef262 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Mon, 6 Mar 2023 20:11:03 +0800 Subject: [PATCH 21/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E7=82=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/wdbyte/hotcode/HotCode.java | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index db3d5d3..0750444 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -8,6 +8,7 @@ import java.util.concurrent.Executors; /** + * * @author niulang * @date 2023/02/20 */ @@ -22,7 +23,7 @@ public class HotCode { public static void main(String[] args) { // 模拟 CPU 过高 cpuHigh(); - // 不断新增 BigDecimal 信息到 list + // 不断新增 BigDecimal 信息到 list,每秒10000个,内存迅速上升 allocate(); // 模拟线程死锁 deadThread(); @@ -30,6 +31,8 @@ public static void main(String[] args) { addHashSetThread(); // 模拟线程阻塞,线程池容量为1,塞入两个线程,会有一个一直等待 thread(); + // 运行缓慢的方法 + runSlowThread(); } /** @@ -51,7 +54,7 @@ private static void cpuHigh() { } /** - * 不断新增 BigDecimal 信息到 list + * 不断新增 BigDecimal 信息到 list,每秒10000个 */ private static void allocate() { new Thread(()->{ @@ -63,7 +66,9 @@ private static void allocate() { } catch (InterruptedException e) { throw new RuntimeException(e); } - list.add(new BigDecimal(i)); + for (int i1 = 0; i1 < 10; i1++) { + list.add(new BigDecimal(i)); + } } }).start(); } @@ -160,6 +165,33 @@ private static void thread() { */ public static void runSlowThread(){ new Thread(() -> { + Thread.currentThread().setName("slow_method"); + while (true){ + try { + slow(); + slow2(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } }).start(); } + + public static void slow() throws InterruptedException { + int count = 0; + for (int i = 0; i < 10000; i++) { + count++; + Thread.sleep(1); + } + System.out.println(count); + } + public static void slow2() throws InterruptedException { + int count = 0; + for (int i = 0; i < 1000; i++) { + count++; + Thread.sleep(1); + } + System.out.println(count); + } + } From a8263f9fa14e6801b875177e7148255cf3801c98 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 30 Mar 2023 23:00:42 +0800 Subject: [PATCH 22/83] feat: add java-base --- core-java-modules/core-java-base/.gitignore | 38 +++++++++ core-java-modules/core-java-base/pom.xml | 12 +++ .../src/main/java/com/wdbyte/JavaArray.java | 77 +++++++++++++++++++ .../src/main/java/com/wdbyte/JavaArray3.java | 25 ++++++ .../main/java/com/wdbyte/JavaDataType.java | 36 +++++++++ .../src/main/java/com/wdbyte/JavaString.java | 68 ++++++++++++++++ .../java/com/wdbyte/JavaStringBuilder.java | 38 +++++++++ core-java-modules/core-java-collect/pom.xml | 20 +++++ core-java-modules/pom.xml | 2 + tool-java-hotcode/.gitignore | 38 +++++++++ 10 files changed, 354 insertions(+) create mode 100644 core-java-modules/core-java-base/.gitignore create mode 100644 core-java-modules/core-java-base/pom.xml create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java create mode 100644 core-java-modules/core-java-collect/pom.xml create mode 100644 tool-java-hotcode/.gitignore diff --git a/core-java-modules/core-java-base/.gitignore b/core-java-modules/core-java-base/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/core-java-modules/core-java-base/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/core-java-modules/core-java-base/pom.xml b/core-java-modules/core-java-base/pom.xml new file mode 100644 index 0000000..da2f162 --- /dev/null +++ b/core-java-modules/core-java-base/pom.xml @@ -0,0 +1,12 @@ + + + core-java-modules + com.wdbyte.core-java-modules + 1.0.0-SNAPSHOT + + 4.0.0 + core-java-base + Archetype - core-java-base + http://maven.apache.org + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java new file mode 100644 index 0000000..f82fd63 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java @@ -0,0 +1,77 @@ +package com.wdbyte; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author niulang + * @date 2023/03/23 + */ +public class JavaArray { + + public static void main(String[] args) { + + // 数组定义 + String[] aaa = new String[11]; + System.out.println(aaa.length); + // 数组访问 + int[] arr = {1, 2, 3}; + System.out.println(arr.toString()); // 数组地址 + arr[0] = 10; + System.out.println(arr[0]); + + for (int a : arr) { + System.out.println(a); + } + for (int i = 0; i < arr.length; i++) { + System.out.println(arr[i]); + } + + // copy + String[] strArr = {"hello", "world", "!"}; + String[] strArrByClone = strArr.clone(); + System.out.println(String.join(" ", strArrByClone)); + // 输出:hello world ! + String[] strAyyByCopy = new String[5]; + System.arraycopy(strArr,1,strAyyByCopy,3,2); + for (String s : strAyyByCopy) { + System.out.println(s); + } + String[] newArr = Arrays.copyOfRange(strArr, 0, 2); + System.out.println(Arrays.toString(newArr)); + // 输出:null + //null + //null + //world + //! + + Person[][] personArr = new Person[2][2]; + personArr[0][0] = new Person("www"); + personArr[1][1] = new Person("wdbyte.com"); + Person[][] personArrByClone = personArr.clone(); + personArrByClone[0][0] = new Person("https://www"); + System.out.println(personArr[0][0].name); + System.out.println(personArrByClone[0][0].name); + + int[] numArr = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10}; + // 对数组进行排序 + Arrays.sort(numArr); + // 将数组转换成字符串输出 + System.out.println(Arrays.toString(numArr)); + // 将数组转换成 List + String[] strArray = new String[3]; + // 将数组的所有元素都赋为指定的值 + Arrays.fill(strArray,"byte"); + System.out.println(Arrays.toString(strArray)); + List stringList = Arrays.asList("a","b","c"); + System.out.println(stringList); + } + static class Person{ + public String name; + public Person(String name) { + this.name = name; + } + } + +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java new file mode 100644 index 0000000..cf6c175 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java @@ -0,0 +1,25 @@ +package com.wdbyte; + +/** + * @author niulang + * @date 2023/03/25 + */ +public class JavaArray3 { + + public static void main(String[] args) { + int[][] myArray1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + int[][] myArray2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + int[][] myArray3 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + int[][][] array3d = {myArray1, myArray2, myArray3}; + for (int i = 0; i < array3d.length; i++) { + for (int j = 0; j < array3d[i].length; j++) { + for (int k = 0; k < array3d[i][j].length; k++) { + System.out.print(array3d[i][j][k] + " "); + } + System.out.println(); + } + System.out.println("-----"); + } + System.out.println(array3d[1][1][1]); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java new file mode 100644 index 0000000..24aa637 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java @@ -0,0 +1,36 @@ +package com.wdbyte; + +/** + * @author niulang + * @date 2023/03/23 + */ +public class JavaDataType { + + public static void main(String[] args) { + boolean result = true; + char capitalC = 'C'; + byte b = 100; + short s = 10000; + int i = 100000; + + // 10 进制的 26 + int decVal = 26; + // 16 进制的 26 + int hexVal = 0x1a; + // 2 进制的 26 + int binVal = 0b11010; + System.out.println(decVal); + System.out.println(hexVal); + System.out.println(binVal); + + long creditCardNumber = 1234_5678_9012_3456L; + long socialSecurityNumber = 999_99_9999L; + float pi = 3.14_15F; + long hexBytes = 0xFF_EC_DE_5E; + long hexWords = 0xCAFE_BABE; + long maxLong = 0x7fff_ffff_ffff_ffffL; + byte nybbles = 0b0010_0101; + long bytes = 0b11010010_01101001_10010100_10010010; + + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java new file mode 100644 index 0000000..31890ee --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java @@ -0,0 +1,68 @@ +package com.wdbyte; + +/** + * @author niulang + * @date 2023/03/22 + */ +public class JavaString { + public static void main(String[] args) { + //String str1 = "Hello world"; + //String str2 = "Hello world"; + //String str3 = new String("Hello world"); + //String str4 = new String("Hello world"); + // + //System.out.println(str1 == str2); + //System.out.println(str3 == str4); + //System.out.println(str1 == str4); + // 比较 + //String str1 = "abc"; + //String str2 = "abz"; + //System.out.println(str1.compareTo(str2)); + //System.out.println(str2.compareTo(str1)); + //// 输出:-23 + //// 输出:23 + //System.out.println("19999".compareTo("2")); + //// 输出:-1 + + // + //// CharSequence + //String str = "Hello, world!"; + //str.chars().forEach(System.out::println); + //str.chars().mapToObj(c -> (char) c).forEach(System.out::print); + + //String str1 = "Hello"; + //String str2 = "world"; + //String str3 = str1 + str2; + //String str4 = str1 + str2; + //String str5 = "Hello" + "world"; + //String str6 = "Hello" + "world"; + //System.out.println(str3 == str4); + //System.out.println(str5 == str6); + + //String str1 = new StringBuilder("计算机").append("软件").toString(); + //System.out.println(str1.intern() == str1); + //String str2 = new StringBuilder("ja").append("va").toString(); + //System.out.println(str2.intern() == str2); + // + //String b = "12"; + //String d = new StringBuilder("计算机").append("软件").toString(); + //String c = new StringBuilder("计算机").append("软件").toString(); + //String a = "计算机软件"; + //System.out.println(a == d); + //System.out.println(a == c); + String str0 = "abc"; + String str1 = new String("abc"); + String str3 = "abc"; + System.out.println(str1 == str0); + System.out.println(str3 == str0); + str1.intern(); + String str2 = new String("Hello,world"); + System.out.println(str1 == str2); + } + + public void test() { + String str1 = "Hello, world!"; + String str2 = "Hello, world!"; + System.out.println(str1 == str2); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java new file mode 100644 index 0000000..b492031 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java @@ -0,0 +1,38 @@ +package com.wdbyte; + +/** + * @author niulang + * @date 2023/03/30 + */ +public class JavaStringBuilder { + + public static void main(String[] args) { + StringBuilder sb1 = new StringBuilder(); + System.out.println(sb1.capacity()); // 容量:16 + StringBuilder sb2 = new StringBuilder("wdbyte.com"); + System.out.println(sb2.capacity()); // 容量:26 + + StringBuilder sb3 = new StringBuilder("www"); + sb3.append(".wdbyte.com"); + System.out.println(sb3.toString()); // + + StringBuilder sb4 = new StringBuilder("wdbyte"); + sb4.insert(0,"www."); + System.out.println(sb4.toString()); // www.wdbyte + sb4.insert(10,".com"); + System.out.println(sb4.toString()); // www.wdbyte.com + + StringBuilder sb5 = new StringBuilder("www.wdbyte.com"); + sb5.delete(0,4); + System.out.println(sb5); // wdbyte.com + + StringBuilder sb6 = new StringBuilder("hello world!"); + sb6.replace(6,11, "java"); // 结果为 "hello java!" + System.out.println(sb6); + + StringBuilder sb7 = new StringBuilder("hello world!"); + sb7.reverse(); + System.out.println(sb7); + + } +} diff --git a/core-java-modules/core-java-collect/pom.xml b/core-java-modules/core-java-collect/pom.xml new file mode 100644 index 0000000..0e0ba53 --- /dev/null +++ b/core-java-modules/core-java-collect/pom.xml @@ -0,0 +1,20 @@ + + + + core-java-modules + com.wdbyte.core-java-modules + 1.0.0-SNAPSHOT + + 4.0.0 + + core-java-collect + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 80bd3fc..55a59a8 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -26,6 +26,8 @@ core-java-io core-java-string core-java-18 + core-java-collect + core-java-base \ No newline at end of file diff --git a/tool-java-hotcode/.gitignore b/tool-java-hotcode/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/tool-java-hotcode/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file From 76fbbc46d40097d748a77807c5b556097fce1a70 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 30 Mar 2023 23:02:13 +0800 Subject: [PATCH 23/83] update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4bff109..61447c1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ 未读代码

-目录中没有链接的部分,后续更新,感谢你的 ​STAR​ ,有问题或者建议可以[一起完善](https://github.com/niumoo/JavaNotes#-%E8%B4%A1%E7%8C%AE%E4%B8%8E%E5%BB%BA%E8%AE%AE)。 +目录中没有链接的部分,后续更新,感谢你的 ​STAR​ ,有问题或者建议可以[一起完善](Accept#-%E8%B4%A1%E7%8C%AE%E4%B8%8E%E5%BB%BA%E8%AE%AE)。 文章内容也都可以访问网站 [https://www.wdbyte.com](https://www.wdbyte.com) 进行阅读。 @@ -31,11 +31,18 @@ - [「1024」专属序猿的快乐,惊奇迷惑代码大赏](https://www.wdbyte.com/2020/10/2020-1024/) - [一篇有趣的负载均衡算法实现](https://www.wdbyte.com/2020/05/algorithm/load-balancing/) - [撸了个多线程断点续传下载器,我从中学习到了这些知识](https://www.wdbyte.com/2020/07/tool/java-download/) - - [Java 开发的编程噩梦,这些坑你没踩过算我输](https://www.wdbyte.com/2020/08/java/java-code-standards/) - [如何使用 Lombok 进行优雅的编码](https://www.wdbyte.com/2018/12/develop/tool-lombok/) - [使用MyBatis Generator自动生成Model、Dao、Mapper相关代码](https://www.wdbyte.com/2017/11/develop/tool-mybatis-generator/) +## 🌿 Java 基础教程 +- [JDK、JRE、JVM 的区别](https://www.wdbyte.com/java/jdk-jre-jvm.html) +- [Java 数据类型](https://www.wdbyte.com/java/data-type.html) +- [Java 流程控制](https://www.wdbyte.com/java/flow-control.html) +- [Java String 字符串](https://www.wdbyte.com/java/java-string.html) +- [Java Array 数组](https://www.wdbyte.com/java/java-array.html) +- [Java 多维数组](https://www.wdbyte.com/java/java-array-mul.html) +- [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder.html) ## 🌿 SpringBoot 2.x 教程 From d5dc3ebd7e3d95bd6ba52ddb8acd5a0be084396a Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 13 Apr 2023 19:23:07 +0800 Subject: [PATCH 24/83] =?UTF-8?q?feat:=20Java=20=E7=BB=A7=E6=89=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 +++-- .../main/java/com/wdbyte/oop/JavaExtends.java | 66 +++++++++++++++++++ 2 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java diff --git a/README.md b/README.md index 61447c1..01c2818 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,14 @@ - [使用MyBatis Generator自动生成Model、Dao、Mapper相关代码](https://www.wdbyte.com/2017/11/develop/tool-mybatis-generator/) ## 🌿 Java 基础教程 -- [JDK、JRE、JVM 的区别](https://www.wdbyte.com/java/jdk-jre-jvm.html) -- [Java 数据类型](https://www.wdbyte.com/java/data-type.html) -- [Java 流程控制](https://www.wdbyte.com/java/flow-control.html) -- [Java String 字符串](https://www.wdbyte.com/java/java-string.html) -- [Java Array 数组](https://www.wdbyte.com/java/java-array.html) -- [Java 多维数组](https://www.wdbyte.com/java/java-array-mul.html) -- [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder.html) +- [JDK、JRE、JVM 的区别](https://www.wdbyte.com/java/jdk-jre-jvm/) +- [Java 数据类型](https://www.wdbyte.com/java/data-type/) +- [Java 流程控制](https://www.wdbyte.com/java/flow-control/) +- [Java String 字符串](https://www.wdbyte.com/java/java-string/) +- [Java Array 数组](https://www.wdbyte.com/java/java-array/) +- [Java 多维数组](https://www.wdbyte.com/java/java-array-mul/) +- [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder/) +- [Java 继承](https://www.wdbyte.com/java/extends/) ## 🌿 SpringBoot 2.x 教程 diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java new file mode 100644 index 0000000..595a36c --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java @@ -0,0 +1,66 @@ +package com.wdbyte.oop; + +/** + * @author niulang + * @date 2023/03/31 + */ +public class JavaExtends { + public static void main(String[] args) { + Student student = new Student(); + printSleep(student); + } + public static void printSleep(Person person){ + person.sleep(); + } +} + +class Person { + public void eat() { + System.out.println("吃饭"); + } + + public void sleep() { + System.out.println("睡觉"); + } +} + +class Student extends Person { + + public Student() { + super(); + } + + public void study() { + System.out.println("学习"); + } + + @Override + public void sleep() { + System.out.println("上课时不能睡觉"); + } +} + +interface One { + public void print_geek(); +} + +interface Two { + public void print_for(); +} + +interface Three extends One, Two { + public void print_geek(); +} + +class Teach implements Three{ + + @Override + public void print_for() { + + } + + @Override + public void print_geek() { + + } +} \ No newline at end of file From 2cc614a32cb73b9d76bb1951a00b4761d9af6f8d Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Sat, 15 Apr 2023 08:41:01 +0800 Subject: [PATCH 25/83] =?UTF-8?q?feat:=20Java=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + core-java-modules/core-java-base/pom.xml | 7 ++ .../com/wdbyte/{ => array}/JavaArray.java | 2 +- .../java/com/wdbyte/array/JavaArray2.java | 32 +++++++++ .../com/wdbyte/{ => array}/JavaArray3.java | 2 +- .../java/com/wdbyte/array/JavaArray4.java | 42 ++++++++++++ .../main/java/com/wdbyte/oop/JavaExtends.java | 5 ++ .../java/com/wdbyte/oop/JavaInterface.java | 53 +++++++++++++++ .../java/com/wdbyte/oop/JavaInterface2.java | 66 +++++++++++++++++++ .../java/com/wdbyte/oop/JavaInterface3.java | 15 +++++ 10 files changed, 223 insertions(+), 2 deletions(-) rename core-java-modules/core-java-base/src/main/java/com/wdbyte/{ => array}/JavaArray.java (98%) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java rename core-java-modules/core-java-base/src/main/java/com/wdbyte/{ => array}/JavaArray3.java (96%) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java diff --git a/README.md b/README.md index 01c2818..eed626f 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ - [Java 多维数组](https://www.wdbyte.com/java/java-array-mul/) - [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder/) - [Java 继承](https://www.wdbyte.com/java/extends/) +- [Java 接口](https://www.wdbyte.com/java/interface/) ## 🌿 SpringBoot 2.x 教程 diff --git a/core-java-modules/core-java-base/pom.xml b/core-java-modules/core-java-base/pom.xml index da2f162..b5a436e 100644 --- a/core-java-modules/core-java-base/pom.xml +++ b/core-java-modules/core-java-base/pom.xml @@ -9,4 +9,11 @@ core-java-base Archetype - core-java-base http://maven.apache.org + + + 17 + 17 + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java similarity index 98% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java index f82fd63..daac4ec 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java @@ -1,4 +1,4 @@ -package com.wdbyte; +package com.wdbyte.array; import java.util.ArrayList; import java.util.Arrays; diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java new file mode 100644 index 0000000..b5a5b66 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java @@ -0,0 +1,32 @@ +package com.wdbyte.array; + +/** + * @author niulang + * @date 2023/03/25 + */ +public class JavaArray2 { + + public static void main(String[] args) { + int[][] myArray = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + for (int i = 0; i < myArray.length; i++) { + for (int j = 0; j < myArray[i].length; j++) { + System.out.print(myArray[i][j] + " "); + } + System.out.println(); + } + System.out.println(myArray[0][0]); // 输出1 + System.out.println(myArray[0][1]); // 输出2 + System.out.println(myArray[1][0]); // 输出4 + + System.out.println("------------"); + + int intArray[][] = { { 1, 2, 3 }, { 4, 5 } }; + int cloneArray[][] = intArray.clone(); + // 输出:false + System.out.println(intArray == cloneArray); + + // 因为是浅拷贝,所以元素引用相同,输出 true + System.out.println(intArray[0] == cloneArray[0]); + System.out.println(intArray[1] == cloneArray[1]); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java similarity index 96% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java index cf6c175..d48cd29 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaArray3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java @@ -1,4 +1,4 @@ -package com.wdbyte; +package com.wdbyte.array; /** * @author niulang diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java new file mode 100644 index 0000000..b1b998c --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java @@ -0,0 +1,42 @@ +package com.wdbyte.array; + +/** + * 锯齿数组 + * @author niulang + * @date 2023/03/25 + */ +public class JavaArray4 { + + public static void main(String[] args) { + int[][] arrName1 = new int[][] { + new int[] {10, 20, 30, 40}, + new int[] {50, 60, 70, 80, 90, 100}, + new int[] {110, 120} + }; + + int[][] arrName2 = { + new int[] {10, 20, 30, 40}, + new int[] {50, 60, 70, 80, 90, 100}, + new int[] {110, 120} + }; + + int[][] arrName3 = { + {10, 20, 30, 40}, + {50, 60, 70, 80, 90, 100}, + {110, 120} + }; + + int[][] jaggedArray = new int[3][]; + jaggedArray[0] = new int[] {1, 2, 3}; + jaggedArray[1] = new int[] {4, 5}; + jaggedArray[2] = new int[] {6, 7, 8, 9}; + + for (int i = 0; i < jaggedArray.length; i++) { + for (int j = 0; j < jaggedArray[i].length; j++) { + System.out.print(jaggedArray[i][j] + " "); + } + System.out.println(); + } + + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java index 595a36c..7811d7f 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java @@ -34,6 +34,11 @@ public void study() { System.out.println("学习"); } + @Override + public void eat() { + System.out.println("吃大米"); + } + @Override public void sleep() { System.out.println("上课时不能睡觉"); diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java new file mode 100644 index 0000000..afcfc2b --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java @@ -0,0 +1,53 @@ +package com.wdbyte.oop; + +/** + * @author niulang + * @date 2023/04/13 + */ +public class JavaInterface { + + public static void main(String[] args) { + MyInterface.staticMethod(); + System.out.println(MyInterface.param); + } +} + +interface MyInterface { + String param = null; + void method1(); + void method2(); + // 默认方法 + default void defaultMethod() { + System.out.println("default method"); + } + // 私有方法 + private void privateMethod() { + System.out.println("private method"); + } + // 静态方法 + static void staticMethod() { + System.out.println("static method"); + } + // 私有静态方法 + private static void privateStaticMethod() { + System.out.println("private static method"); + } +} +interface IMobilePhone{ + void mehtod1(); +} +interface MyInterface2{ + void mehtod2(); +} +class IPhone14 implements IMobilePhone{ + @Override + public void mehtod1() { + } + +} +class Xiaomi14 implements IMobilePhone{ + @Override + public void mehtod1() { + } + +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java new file mode 100644 index 0000000..3326b66 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java @@ -0,0 +1,66 @@ +package com.wdbyte.oop; + +/** + * @author niulang + * @date 2023/04/13 + */ +public class JavaInterface2 { + public static void main(String[] args) { + //XPhone xPhone = new XPhone(); + //xPhone.powerUp(); + //xPhone.call(); + } +} + + + +/** + * 手机系统功能接口 + */ +interface IMobilePhoneSystem{ + // 开机 + void powerUp(); + // 显示 + void display(); + // 声音 + void sound(); +} + +/** + * 手机基本功能 + */ +interface IMobilePhoneBasicFunction extends IMobilePhoneSystem { + // 打电话 + void call(); + // 发短信 + void sendMessage(); +} + + +class XPhone implements IMobilePhoneBasicFunction{ + + @Override + public void powerUp() { + System.out.println("XPhone 开始开机"); + } + + @Override + public void display() { + System.out.println("XPhone 开始显示"); + } + + @Override + public void sound() { + System.out.println("XPhone 发出声音"); + } + + @Override + public void call() { + System.out.println("XPhone 开始拨打电话"); + } + + @Override + public void sendMessage() { + System.out.println("XPhone 开始发送短信"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java new file mode 100644 index 0000000..86282a6 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java @@ -0,0 +1,15 @@ +package com.wdbyte.oop; + +/** + * @author niulang + * @date 2023/04/14 + */ +public class JavaInterface3 { + public static void main(String[] args) { + System.out.println(MyInterface.param); + } + interface MyInterface{ + String param = "https://www.wdbyte.com"; + } +} + From 014a6838f86c4897dc21b1fc4b665f6c5d7c206f Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 18 Apr 2023 14:04:26 +0800 Subject: [PATCH 26/83] =?UTF-8?q?feat:=20Java=20=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E7=B1=BB=EF=BC=8CJava=20=E5=A4=9A=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/wdbyte/oop/abs/AbsPerson.java | 15 ++++++++++ .../java/com/wdbyte/oop/abs/PersonTest.java | 23 +++++++++++++++ .../main/java/com/wdbyte/oop/abs/Student.java | 13 +++++++++ .../main/java/com/wdbyte/oop/abs/Teacher.java | 13 +++++++++ .../oop/{ => interfac}/JavaInterface.java | 2 +- .../oop/{ => interfac}/JavaInterface2.java | 2 +- .../oop/{ => interfac}/JavaInterface3.java | 2 +- .../wdbyte/oop/polymorphism/AliyunOss.java | 17 +++++++++++ .../com/wdbyte/oop/polymorphism/Animal.java | 17 +++++++++++ .../java/com/wdbyte/oop/polymorphism/Cat.java | 8 ++++++ .../java/com/wdbyte/oop/polymorphism/Dog.java | 8 ++++++ .../java/com/wdbyte/oop/polymorphism/Oss.java | 14 ++++++++++ .../com/wdbyte/oop/polymorphism/OssUtil.java | 28 +++++++++++++++++++ .../wdbyte/oop/polymorphism/TencentOss.java | 17 +++++++++++ .../wdbyte/oop/polymorphism/inter/Animal.java | 7 +++++ .../wdbyte/oop/polymorphism/inter/Cat.java | 8 ++++++ .../wdbyte/oop/polymorphism/inter/Dog.java | 8 ++++++ .../wdbyte/oop/polymorphism/inter/Test.java | 23 +++++++++++++++ .../wdbyte/oop/polymorphism/inter/Test2.java | 20 +++++++++++++ 19 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java rename core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/{ => interfac}/JavaInterface.java (96%) rename core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/{ => interfac}/JavaInterface2.java (97%) rename core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/{ => interfac}/JavaInterface3.java (88%) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Animal.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Cat.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Dog.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Animal.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Cat.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Dog.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java new file mode 100644 index 0000000..062bb70 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java @@ -0,0 +1,15 @@ +package com.wdbyte.oop.abs; + +/** + * @author niulang + * @date 2023/04/17 + */ +public abstract class AbsPerson { + public int age = 22; + + public void eat() { + System.out.println("吃饭"); + } + + public abstract void sleep(); +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java new file mode 100644 index 0000000..3c8d06e --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java @@ -0,0 +1,23 @@ +package com.wdbyte.oop.abs; + +/** + * @author niulang + * @date 2023/04/17 + */ +public class PersonTest { + public static void main(String[] args) { + AbsPerson absPerson = new Student(); + System.out.println(absPerson.age); + absPerson.eat(); + absPerson.sleep(); + + Student student = new Student(); + Teacher teacher = new Teacher(); + sleep(student); + sleep(teacher); + } + + public static void sleep(AbsPerson person) { + person.sleep(); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java new file mode 100644 index 0000000..bd9060f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java @@ -0,0 +1,13 @@ +package com.wdbyte.oop.abs; + +/** + * @author niulang + * @date 2023/04/17 + */ +public class Student extends AbsPerson { + + @Override + public void sleep() { + System.out.println("学生上课不能睡觉"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java new file mode 100644 index 0000000..8c790c8 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java @@ -0,0 +1,13 @@ +package com.wdbyte.oop.abs; + +/** + * @author niulang + * @date 2023/04/17 + */ +public class Teacher extends AbsPerson { + + @Override + public void sleep() { + System.out.println("老师教课时不能睡觉"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java similarity index 96% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java index afcfc2b..7359a11 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java @@ -1,4 +1,4 @@ -package com.wdbyte.oop; +package com.wdbyte.oop.interfac; /** * @author niulang diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java similarity index 97% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java index 3326b66..b4bce89 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java @@ -1,4 +1,4 @@ -package com.wdbyte.oop; +package com.wdbyte.oop.interfac; /** * @author niulang diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java similarity index 88% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java index 86282a6..d4a75a9 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaInterface3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java @@ -1,4 +1,4 @@ -package com.wdbyte.oop; +package com.wdbyte.oop.interfac; /** * @author niulang diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java new file mode 100644 index 0000000..d6229c3 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java @@ -0,0 +1,17 @@ +package com.wdbyte.oop.polymorphism; + +/** + * @author niulang + * @date 2023/04/18 + */ +public class AliyunOss implements Oss { + @Override + public void upload(String content) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println("文件已经上传到阿里云 OSS,内容:" + content); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Animal.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Animal.java new file mode 100644 index 0000000..a0d456f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Animal.java @@ -0,0 +1,17 @@ +package com.wdbyte.oop.polymorphism; + +import java.util.Arrays; + +public class Animal { + public void makeSound() { + System.out.println("动物发出叫声"); + } + + public static void main(String[] args) { + Animal cat = new Cat(); + Animal dog = new Dog(); + for (Animal animal : Arrays.asList(cat, dog)) { + animal.makeSound(); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Cat.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Cat.java new file mode 100644 index 0000000..152e261 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Cat.java @@ -0,0 +1,8 @@ +package com.wdbyte.oop.polymorphism; + +public class Cat extends Animal{ + @Override + public void makeSound(){ + System.out.println("喵喵喵"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Dog.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Dog.java new file mode 100644 index 0000000..ec6066a --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Dog.java @@ -0,0 +1,8 @@ +package com.wdbyte.oop.polymorphism; + +public class Dog extends Animal{ + @Override + public void makeSound(){ + System.out.println("汪汪汪"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java new file mode 100644 index 0000000..f7466eb --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java @@ -0,0 +1,14 @@ +package com.wdbyte.oop.polymorphism; + +/** + * @author niulang + * @date 2023/04/18 + */ +public interface Oss { + + /** + * 文件上传 + * @param content + */ + void upload(String content); +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java new file mode 100644 index 0000000..1e9eeef --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java @@ -0,0 +1,28 @@ +package com.wdbyte.oop.polymorphism; + +/** + * @author niulang + * @date 2023/04/18 + */ +public class OssUtil { + /** + * OSS 上传工具类 + * + * @param oss + * @param content + */ + public static void upload(Oss oss, String content) { + long start = System.currentTimeMillis(); + oss.upload(content); + long end = System.currentTimeMillis(); + System.out.println("上传耗时:" + (end - start) + "ms"); + } + + public static void main(String[] args) { + AliyunOss aliyunOss = new AliyunOss(); + TencentOss tencentOss = new TencentOss(); + upload(aliyunOss, "Hello aliyun"); + System.out.println("------------"); + upload(tencentOss, "Hello tencent"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java new file mode 100644 index 0000000..ece1f22 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java @@ -0,0 +1,17 @@ +package com.wdbyte.oop.polymorphism; + +/** + * @author niulang + * @date 2023/04/18 + */ +public class TencentOss implements Oss { + @Override + public void upload(String content) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println("文件已经上传到腾讯云 OSS,内容:" + content); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Animal.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Animal.java new file mode 100644 index 0000000..0353708 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Animal.java @@ -0,0 +1,7 @@ +package com.wdbyte.oop.polymorphism.inter; + +public interface Animal{ + void makeSound(); +} + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Cat.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Cat.java new file mode 100644 index 0000000..1a6e10c --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Cat.java @@ -0,0 +1,8 @@ +package com.wdbyte.oop.polymorphism.inter; + +public class Cat implements Animal{ + @Override + public void makeSound(){ + System.out.println("喵喵喵"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Dog.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Dog.java new file mode 100644 index 0000000..8843325 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Dog.java @@ -0,0 +1,8 @@ +package com.wdbyte.oop.polymorphism.inter; + +public class Dog implements Animal{ + @Override + public void makeSound(){ + System.out.println("汪汪汪"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java new file mode 100644 index 0000000..7565cd6 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java @@ -0,0 +1,23 @@ +package com.wdbyte.oop.polymorphism.inter; + +import java.util.Arrays; + + +/** + * @author niulang + * @date 2023/04/18 + */ +public class Test { + public static void main(String[] args) { + Animal cat = new Cat(); + Animal dog = new Dog(); + for (Animal animal : Arrays.asList(cat, dog)) { + animal.makeSound(); + } + } + + public static void makeSound(Animal animal){ + animal.makeSound(); + } +} + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java new file mode 100644 index 0000000..778c203 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java @@ -0,0 +1,20 @@ +package com.wdbyte.oop.polymorphism.inter; + + +/** + * @author niulang + * @date 2023/04/18 + */ +public class Test2 { + public static void main(String[] args) { + Animal cat = new Cat(); + Animal dog = new Dog(); + makeSound(cat); // 喵喵喵 + makeSound(dog); // 汪汪汪 + } + + public static void makeSound(Animal animal) { + animal.makeSound(); + } +} + From e61accd3ad9398387c8318ce1906481efcd220d3 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 18 Apr 2023 14:05:29 +0800 Subject: [PATCH 27/83] =?UTF-8?q?feat:=20Java=20=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E7=B1=BB=EF=BC=8CJava=20=E5=A4=9A=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index eed626f..70c68c3 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ - [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder/) - [Java 继承](https://www.wdbyte.com/java/extends/) - [Java 接口](https://www.wdbyte.com/java/interface/) +- [Java 抽象类](https://www.wdbyte.com/java/abstract/) +- [Java 多态](https://www.wdbyte.com/java/polymorphism/) ## 🌿 SpringBoot 2.x 教程 From 18b86f3083a16ca56219b59a41f105378ba3baec Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 21 Apr 2023 17:09:12 +0800 Subject: [PATCH 28/83] feat: Java Scanner demo --- .../java/com/wdbyte/scanner/ScannerDemo.java | 13 +++++++++++++ .../java/com/wdbyte/scanner/ScannerDemo2.java | 16 ++++++++++++++++ .../java/com/wdbyte/scanner/ScannerDemo3.java | 15 +++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo3.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo.java new file mode 100644 index 0000000..a2de8cc --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo.java @@ -0,0 +1,13 @@ +package com.wdbyte.scanner; + +import java.util.Scanner; + +public class ScannerDemo { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + scanner.useDelimiter(System.lineSeparator()); + System.out.println("请输入一个字符串:"); + String inputString = scanner.next(); + System.out.println("你输入的字符串是:" + inputString); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo2.java new file mode 100644 index 0000000..dc6337e --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo2.java @@ -0,0 +1,16 @@ +package com.wdbyte.scanner; + +import java.util.Scanner; + +public class ScannerDemo2 { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.println("请输入一个整数:"); + int inputInt = scanner.nextInt(); + System.out.println("你输入的整数是:" + inputInt); + + System.out.println("请输入一个浮点数:"); + double inputDouble = scanner.nextDouble(); + System.out.println("你输入的浮点数是:" + inputDouble); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo3.java new file mode 100644 index 0000000..d701062 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/scanner/ScannerDemo3.java @@ -0,0 +1,15 @@ +package com.wdbyte.scanner; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +public class ScannerDemo3 { + public static void main(String[] args) throws FileNotFoundException { + File inputFile = new File("pom.xml"); + Scanner scanner = new Scanner(inputFile); + while (scanner.hasNextLine()) { + System.out.println(scanner.nextLine()); + } + } +} \ No newline at end of file From ff999a980969d16b60856b1476fdeca79a183231 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Thu, 27 Apr 2023 10:24:04 +0800 Subject: [PATCH 29/83] feat: add java date demo --- README.md | 2 + .../java/com/wdbyte/date/JavaDateCalc.java | 68 +++++++++++++++++++ .../java/com/wdbyte/date/JavaDateCalc2.java | 24 +++++++ .../java/com/wdbyte/date/JavaDateCreate.java | 22 ++++++ .../java/com/wdbyte/date/JavaDateDiff.java | 54 +++++++++++++++ .../java/com/wdbyte/date/JavaDateFormat.java | 32 +++++++++ 6 files changed, 202 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java diff --git a/README.md b/README.md index 70c68c3..ccd4ff3 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ - [Java 接口](https://www.wdbyte.com/java/interface/) - [Java 抽象类](https://www.wdbyte.com/java/abstract/) - [Java 多态](https://www.wdbyte.com/java/polymorphism/) +- [Java Scanner](https://www.wdbyte.com/java/scanner/) +- [Java 日期时间 Date](https://www.wdbyte.com/java/date/) ## 🌿 SpringBoot 2.x 教程 diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java new file mode 100644 index 0000000..e400cdb --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java @@ -0,0 +1,68 @@ +package com.wdbyte.date; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * @author niulang + * @date 2023/04/26 + */ +public class JavaDateCalc { + public static void main(String[] args) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + Date date = new Date(); + System.out.println(String.format("当前时间:%s", sdf.format(date))); + date = new JavaDateCalc().addDay(date, 3); + System.out.println(String.format("增加三天:%s", sdf.format(date))); + date = new JavaDateCalc().minDay(date, 1); + System.out.println(String.format("减去一天:%s", sdf.format(date))); + date = new JavaDateCalc().addMonth(date, 2); + System.out.println(String.format("增加两个月:%s", sdf.format(date))); + } + + /** + * 增加天数 + * + * @param date + * @param addDay + * @return + */ + public Date addDay(Date date, int addDay) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.DATE, addDay); + Date newDate = cal.getTime(); + return newDate; + } + + /** + * 减少天数 + * + * @param date + * @param minDay + * @return + */ + public Date minDay(Date date, int minDay) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.DATE, -minDay); + Date newDate = cal.getTime(); + return newDate; + } + + /** + * 增加月份 + * + * @param date + * @param addMonth + * @return + */ + public Date addMonth(Date date, int addMonth) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.MONTH, addMonth); + Date newDate = cal.getTime(); + return newDate; + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java new file mode 100644 index 0000000..16f0c4a --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java @@ -0,0 +1,24 @@ +package com.wdbyte.date; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * @author niulang + * @date 2023/04/26 + */ +public class JavaDateCalc2 { + public static void main(String[] args) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + Date date = new Date(); + System.out.println(String.format("当前时间:%s", sdf.format(date))); + // 三天的毫秒数:3 * 24 * 3600 * 1000 + date = new Date(date.getTime() + 3 * 24 * 3600 * 1000); + System.out.println(String.format("增加三天:%s", sdf.format(date))); + + date = new Date(date.getTime() - 1 * 60 * 1000); + System.out.println(String.format("减去一分钟:%s", sdf.format(date))); + } + +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java new file mode 100644 index 0000000..2046ffe --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java @@ -0,0 +1,22 @@ +package com.wdbyte.date; + +import java.util.Date; + +/** + * @author niulang + * @date 2023/04/25 + */ +public class JavaDateCreate { + public static void main(String[] args) { + Date date = new Date(); + // 输出时间 + System.out.println(date); // Tue Apr 25 20:28:23 CST 2023 + // 输出毫秒数 + System.out.println(date.getTime()); // 1682425703429 + + // 当前毫秒数创建对象 + //Date date2 = new Date(System.currentTimeMillis()); + Date date2 = new Date(1682425703429L); + System.out.println(date2); // Tue Apr 25 20:28:23 CST 2023 + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java new file mode 100644 index 0000000..2f47ade --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java @@ -0,0 +1,54 @@ +package com.wdbyte.date; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author niulang + * @date 2023/04/25 + */ +public class JavaDateDiff { + + public static void main(String[] args) throws InterruptedException { + // 获取当前时间 + Date date1 = new Date(); + // 休眠 3 秒 + Thread.sleep(3000); + // 再获取一次当前时间 + Date date2 = new Date(); + + // 很明显 date1 在 date2 之前,,所以 true + boolean before = date1.before(date2); + System.out.println(before); // true + + // 很明显 date2 在 date1 之后,所以 true + boolean after = date2.after(date1); + System.out.println(after); // true + + // date2 不在 date1 之前,所以 false + System.out.println(date2.before(date1)); // false + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + System.out.println("date1:"+sdf.format(date1)); + System.out.println("date2:"+sdf.format(date2)); + Long diff = date1.getTime() - date2.getTime(); + if (diff > 0) { + System.out.println("date1 > date2"); + } + if (diff < 0) { + System.out.println("date1 < date2"); + } + if (diff == 0) { + System.out.println("date1 = date2"); + } + exec(); + } + + public static void exec() throws InterruptedException { + long start = System.currentTimeMillis(); + // 做点什么 + Thread.sleep(3000); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + "ms"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java new file mode 100644 index 0000000..47be812 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java @@ -0,0 +1,32 @@ +package com.wdbyte.date; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author niulang + * @date 2023/04/25 + */ +public class JavaDateFormat { + + public static void main(String[] args) throws ParseException { + Date date = new Date(); + + // 时间格式化,yyyy 年份,MM 月份, dd 当月第多少天, hh:mm:ss 分别为时分秒 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + String formatDate = simpleDateFormat.format(date); + System.out.println(formatDate); + + SimpleDateFormat sdf1 = new SimpleDateFormat("当前日期是: yyyy-MM-dd"); + SimpleDateFormat sdf2 = new SimpleDateFormat("当前时间是: hh:mm:ss"); + System.out.println(sdf1.format(date)); + System.out.println(sdf2.format(date)); + + + String strDate = "2023-01-19 10:30:00"; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + Date myDate = sdf.parse(strDate); + System.out.println(sdf.format(myDate)); + } +} From aee250d8c70ee8a9df56d58ab85af0213fe11a38 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 28 Apr 2023 16:20:55 +0800 Subject: [PATCH 30/83] feat: add java exception --- README.md | 1 + .../com/wdbyte/exception/JavaException1.java | 12 +++++ .../com/wdbyte/exception/JavaException2.java | 13 ++++++ .../com/wdbyte/exception/JavaException3.java | 19 ++++++++ .../com/wdbyte/exception/JavaException4.java | 19 ++++++++ .../com/wdbyte/exception/JavaException5.java | 35 +++++++++++++++ .../com/wdbyte/exception/JavaException6.java | 20 +++++++++ .../com/wdbyte/exception/JavaException7.java | 22 +++++++++ .../com/wdbyte/exception/JavaException8.java | 33 ++++++++++++++ .../com/wdbyte/exception/MyException.java | 7 +++ .../java/com/wdbyte/exception/ReadFile.java | 45 +++++++++++++++++++ .../java/com/wdbyte/exception/ReadFile2.java | 25 +++++++++++ 12 files changed, 251 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/MyException.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile2.java diff --git a/README.md b/README.md index ccd4ff3..c873bb5 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ - [Java 多态](https://www.wdbyte.com/java/polymorphism/) - [Java Scanner](https://www.wdbyte.com/java/scanner/) - [Java 日期时间 Date](https://www.wdbyte.com/java/date/) +- [Java 异常处理](https://www.wdbyte.com/java/exception/) ## 🌿 SpringBoot 2.x 教程 diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java new file mode 100644 index 0000000..18b22d1 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java @@ -0,0 +1,12 @@ +package com.wdbyte.exception; + +/** + * @author niulang + */ +public class JavaException1 { + + public static void main(String[] args) { + String str = null; + System.out.println(str.length()); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java new file mode 100644 index 0000000..e680d35 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java @@ -0,0 +1,13 @@ +package com.wdbyte.exception; + +/** + * @author niulang + */ +public class JavaException2 { + + public static void main(String[] args) { + String[] strArr = {"www", "wdbyte", "com"}; + System.out.println(strArr[0]); + System.out.println(strArr[3]); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java new file mode 100644 index 0000000..4395064 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java @@ -0,0 +1,19 @@ +package com.wdbyte.exception; + +/** + * @author niulang + */ +public class JavaException3 { + + public static void main(String[] args) { + String[] strArr = {"www", "wdbyte", "com"}; + try { + System.out.println(strArr[0]); + System.out.println(strArr[3]); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("发生数组访问越界异常,不能访问超过数组长度的元素,数组长度为:" + strArr.length); + System.out.println("异常描述:" + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java new file mode 100644 index 0000000..a88f5e5 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java @@ -0,0 +1,19 @@ +package com.wdbyte.exception; + +/** + * @author niulang + */ +public class JavaException4 { + + public static void main(String[] args) { + String[] strArr = {"www", "wdbyte", "com"}; + try { + System.out.println(strArr[0]); + System.out.println(strArr[3]); + } catch (ArrayIndexOutOfBoundsException e) { + //throw e; + throw new RuntimeException(e); + } + System.out.println("执行完成。"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java new file mode 100644 index 0000000..acbb901 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java @@ -0,0 +1,35 @@ +package com.wdbyte.exception; + +import org.apache.commons.lang3.ObjectUtils.Null; + +/** + * @author niulang + */ +public class JavaException5 { + + public static void main(String[] args) { + String[] strArr = {"www", null, "com"}; + try { + System.out.println(strArr[0].length()); + // 空指针异常 + System.out.println(strArr[1].length()); + System.out.println(strArr[3].length()); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("发生数组访问越界异常,不能访问超过数组长度的元素,数组长度为:" + strArr.length); + } catch (NullPointerException e) { + System.out.println("发现空指针异常"); + } + System.out.println("执行完成。"); + + try { + System.out.println(strArr[0].length()); + // 空指针异常 + System.out.println(strArr[1].length()); + // 越界异常 + System.out.println(strArr[3].length()); + } catch (Exception e) { + System.out.println("发生异常:" + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java new file mode 100644 index 0000000..4cbff20 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java @@ -0,0 +1,20 @@ +package com.wdbyte.exception; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * @author niulang + * @date 2023/04/27 + */ +public class JavaException6 { + + public static void main(String[] args) { + try { + Files.readAllLines(Paths.get("c:/abc.txt")); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java new file mode 100644 index 0000000..9b5483d --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java @@ -0,0 +1,22 @@ +package com.wdbyte.exception; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * @author niulang + * @date 2023/04/27 + */ +public class JavaException7 { + + public static void main(String[] args) { + try { + Files.readAllLines(Paths.get("c:/abc.txt")); + } catch (IOException e) { + e.printStackTrace(); + } finally { + + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java new file mode 100644 index 0000000..905a2ab --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java @@ -0,0 +1,33 @@ +package com.wdbyte.exception; + +/** + * @author niulang + */ +public class JavaException8 { + + public static void main(String[] args) { + int result = 0; + try { + result = calc(4, 2); + System.out.println("4 / 2 = " + result); + } catch (MyException e) { // 不处理异常会报错 + e.printStackTrace(); + } + + try { + result = calc(4, 0); + System.out.println("4 / 0 = " + result); + } catch (MyException e) { // 不处理异常会报错 + e.printStackTrace(); + } + } + + public static int calc(int a, int b) throws MyException { + if (b == 0) { + throw new MyException("除数不能为0"); + } + return a / b; + } +} + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/MyException.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/MyException.java new file mode 100644 index 0000000..a91c4a2 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/MyException.java @@ -0,0 +1,7 @@ +package com.wdbyte.exception; + +public class MyException extends Exception { + public MyException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile.java new file mode 100644 index 0000000..664cfc3 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile.java @@ -0,0 +1,45 @@ +package com.wdbyte.exception; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +public class ReadFile { + + public static void main(String[] args) { + + File file = new File("pom2.xml"); + FileReader fileReader = null; + BufferedReader bufferedReader = null; + try { + fileReader = new FileReader(file); + bufferedReader = new BufferedReader(fileReader); + String line; + while ((line = bufferedReader.readLine()) != null) { + System.out.println(line); + } + bufferedReader.close(); + fileReader.close(); + } catch (FileNotFoundException e) { + System.out.println("文件不存在"); + } catch (IOException e) { + System.out.println("读取文件失败"); + } finally { + try { + System.out.println("开始关闭资源"); + if (bufferedReader != null) { + bufferedReader.close(); + System.out.println("关闭 bufferedReader"); + } + if (fileReader != null) { + fileReader.close(); + System.out.println("关闭 fileReader"); + } + } catch (IOException e) { + System.out.println("关闭文件失败"); + } + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile2.java new file mode 100644 index 0000000..d238afb --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/ReadFile2.java @@ -0,0 +1,25 @@ +package com.wdbyte.exception; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +public class ReadFile2 { + + public static void main(String[] args) { + File file = new File("pom.xml"); + try (FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader( + fileReader);) { + String line; + while ((line = bufferedReader.readLine()) != null) { + System.out.println(line); + } + } catch (FileNotFoundException e) { + System.out.println("文件不存在"); + } catch (IOException e) { + System.out.println("读取文件失败"); + } + } +} From 4ab63d267bc70990522ff0debaec082f595e253d Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 3 May 2023 17:35:36 +0800 Subject: [PATCH 31/83] feat: add java enum demo --- .../src/main/java/com/wdbyte/enum2/Calc.java | 30 ++++++++++++++++++ .../main/java/com/wdbyte/enum2/CalcTest.java | 19 ++++++++++++ .../main/java/com/wdbyte/enum2/Rectangle.java | 28 +++++++++++++++++ .../java/com/wdbyte/enum2/WeekdayTest.java | 31 +++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Calc.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Rectangle.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Calc.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Calc.java new file mode 100644 index 0000000..d42ac62 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Calc.java @@ -0,0 +1,30 @@ +package com.wdbyte.enum2; + +/** + * 计算枚举类 + */ +public enum Calc { + // 加法 + PLUS { + public int apply(int x, int y) { + return x + y; + } + }, + // 减法 + MINUS { + public int apply(int x, int y) { + return x - y; + } + }, + // 乘法 + MULTIPLY { + public int apply(int x, int y) { + return x * y; + } + }; + + public int apply(int x, int y){ + // todo + return x + y; + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java new file mode 100644 index 0000000..b9eeff9 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java @@ -0,0 +1,19 @@ +package com.wdbyte.enum2; + +/** + * @author niulang + * @date 2023/05/01 + */ +public class CalcTest { + public static void main(String[] args) { + // 加法 + int res = Calc.PLUS.apply(2, 3); + System.out.println(res); + // 减法 + res = Calc.MINUS.apply(2, 3); + System.out.println(res); + // 乘法 + res = Calc.MULTIPLY.apply(2, 3); + System.out.println(res); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Rectangle.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Rectangle.java new file mode 100644 index 0000000..43ba0ac --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Rectangle.java @@ -0,0 +1,28 @@ +package com.wdbyte.enum2; + +/** + * 矩形枚举类 + */ +public enum Rectangle implements Shape { + SMALL(3, 4), + MEDIUM(4, 5), + LARGE(5, 6); + + private int length; + private int width; + + Rectangle(int length, int width) { + this.length = length; + this.width = width; + } + + public double getArea() { + return length * width; + } + + public static void main(String[] args) { + Shape shape = Rectangle.LARGE; + double shapeArea = shape.getArea(); + System.out.println(shapeArea); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java new file mode 100644 index 0000000..0478277 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java @@ -0,0 +1,31 @@ +package com.wdbyte.enum2; + +/** + * @author niulang + * @date 2023/05/01 + */ +public class WeekdayTest { + public static void main(String[] args) { + Weekday day = Weekday.MONDAY; + if (day == Weekday.MONDAY) { + System.out.println("Today is Monday."); + } + + + Weekday[] weekdays = Weekday.values(); + for (Weekday weekday : weekdays) { + System.out.println(weekday); + } + + for (Weekday weekday : weekdays) { + System.out.println(weekday.ordinal()); + } + Weekday monday = Weekday.MONDAY; + switch (monday){ + case MONDAY :{System.out.println("周一");break;} + case SUNDAY :{System.out.println("周末");break;} + } + System.out.println(Weekday.valueOf("MONDAY")); + System.out.println(Weekday.valueOf("MONDAY1")); + } +} From 0edacda1747135f2fc35841d4454a87ba4bcab49 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 3 May 2023 17:35:58 +0800 Subject: [PATCH 32/83] feat: add java collection demo --- .../com/wdbyte/collection/CollectionTest.java | 20 ++++++++++ .../wdbyte/collection/CollectionTest2.java | 35 ++++++++++++++++++ .../wdbyte/collection/CollectionTest3.java | 35 ++++++++++++++++++ .../wdbyte/collection/CollectionTest4.java | 37 +++++++++++++++++++ .../wdbyte/collection/CollectionTest5.java | 34 +++++++++++++++++ .../java/com/wdbyte/collection/MapTest.java | 21 +++++++++++ .../java/com/wdbyte/collection/MapTest2.java | 26 +++++++++++++ 7 files changed, 208 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java new file mode 100644 index 0000000..67b150a --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java @@ -0,0 +1,20 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author niulang + */ +public class CollectionTest { + public static void main(String[] args) { + List arrayList = new ArrayList<>(); + // 向 List 中添加元素 + arrayList.add("www"); + arrayList.add("wdbyte"); + arrayList.add("com"); + arrayList.add("com"); + // 输出 + System.out.println(arrayList); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java new file mode 100644 index 0000000..dfab350 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java @@ -0,0 +1,35 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.TreeSet; + +/** + * @author niulang + */ +public class CollectionTest2 { + public static void main(String[] args) { + List arrayList = new ArrayList<>(); + List linkedList = new LinkedList<>(); + Set hashSet = new HashSet<>(); + Set treeSet = new TreeSet<>(); + Stack stack = new Stack<>(); + // 添加元素 + arrayList.add("wdbyte.com"); + linkedList.add("wdbyte.com"); + hashSet.add("wdbyte.com"); + treeSet.add("wdbyte.com"); + stack.add("wdbyte.com"); + // 输出 + System.out.println(arrayList); + System.out.println(linkedList); + System.out.println(hashSet); + System.out.println(treeSet); + System.out.println(stack); + } + +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java new file mode 100644 index 0000000..7f75e07 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java @@ -0,0 +1,35 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * @author niulang + */ +public class CollectionTest3 { + public static void main(String[] args) { + List arrayList = new ArrayList<>(); + // 向 List 中添加元素 + arrayList.add("www"); + arrayList.add("wdbyte"); + arrayList.add("com"); + // 普通遍历 + for (int i = 0; i < arrayList.size(); i++) { + System.out.println(arrayList.get(0)); + } + System.out.println("--------"); + // iterator 迭代器遍历 + Iterator iterator = arrayList.iterator(); + while (iterator.hasNext()) { + System.out.println(iterator.next()); + } + } + + public void printCollection(Collection collection) { + for (Object o : collection) { + System.out.println(o); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java new file mode 100644 index 0000000..990fea2 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java @@ -0,0 +1,37 @@ +package com.wdbyte.collection; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * @author niulang + */ +public class CollectionTest4 { + public static void main(String[] args) { + List arrayList = new ArrayList<>(); + // 向 List 中添加元素 + arrayList.add("www"); + arrayList.add("wdbyte"); + arrayList.add("com"); + + HashSet hashSet = new HashSet<>(); + hashSet.addAll(arrayList); + + printCollection(arrayList.iterator()); + System.out.println("--------------"); + printCollection(hashSet.iterator()); + } + + public static void printCollection(Iterator iterator) { + // 当前日期 + LocalDate now = LocalDate.now(); + while (iterator.hasNext()) { + String obj = iterator.next(); + System.out.println(now + ":" + obj.toString()); + } + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java new file mode 100644 index 0000000..2dc01b0 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java @@ -0,0 +1,34 @@ +package com.wdbyte.collection; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * @author niulang + */ +public class CollectionTest5 { + public static void main(String[] args) { + List arrayList = new ArrayList<>(); + // 向 List 中添加元素 + arrayList.add("www"); + arrayList.add("wdbyte"); + arrayList.add("com"); + HashSet hashSet = new HashSet<>(); + hashSet.addAll(arrayList); + + printCollection(arrayList); + printCollection(hashSet); + } + public static void printCollection(Iterable iterable) { + // 当前日期 + LocalDate now = LocalDate.now(); + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + String obj = iterator.next(); + System.out.println(now + ":" + obj.toString()); + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java new file mode 100644 index 0000000..b19d7b1 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java @@ -0,0 +1,21 @@ +package com.wdbyte.collection; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author niulang + */ +public class MapTest { + public static void main(String[] args) { + Map hashMap = new HashMap<>(); + // 添加元素 + hashMap.put("site","www.wdbyte.com"); + hashMap.put("author","程序猿阿朗"); + hashMap.put("github","github.com/niumoo"); + // 获取元素 + System.out.println(hashMap.get("github")); + // 输出全部元素 + System.out.println(hashMap); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java new file mode 100644 index 0000000..306e313 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java @@ -0,0 +1,26 @@ +package com.wdbyte.collection; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author niulang + */ +public class MapTest2 { + public static void main(String[] args) { + Map hashMap = new HashMap<>(); + Map linkedHashMap = new LinkedHashMap<>(); + // 添加元素 + hashMap.put("site", "www.wdbyte.com"); + hashMap.put("author", "程序猿阿朗"); + hashMap.put("github", "github.com/niumoo"); + linkedHashMap.put("site", "www.wdbyte.com"); + linkedHashMap.put("author", "程序猿阿朗"); + linkedHashMap.put("github", "github.com/niumoo"); + + // 输出全部元素 + System.out.println(hashMap); + System.out.println(linkedHashMap); + } +} From 14ed8961a317722b71127a7d54bd55a754a4e73f Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 3 May 2023 17:37:26 +0800 Subject: [PATCH 33/83] feat: add java collection demo --- README.md | 2 + ...6\345\205\263\347\263\273\345\233\276.uml" | 138 ++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 "core-java-modules/core-java-base/\351\233\206\345\220\210\346\241\206\346\236\266\345\205\263\347\263\273\345\233\276.uml" diff --git a/README.md b/README.md index c873bb5..e39a197 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ - [Java Scanner](https://www.wdbyte.com/java/scanner/) - [Java 日期时间 Date](https://www.wdbyte.com/java/date/) - [Java 异常处理](https://www.wdbyte.com/java/exception/) +- [Java 枚举](https://www.wdbyte.com/java/enum/) +- [Java 集合框架](https://www.wdbyte.com/java/collection/) ## 🌿 SpringBoot 2.x 教程 diff --git "a/core-java-modules/core-java-base/\351\233\206\345\220\210\346\241\206\346\236\266\345\205\263\347\263\273\345\233\276.uml" "b/core-java-modules/core-java-base/\351\233\206\345\220\210\346\241\206\346\236\266\345\205\263\347\263\273\345\233\276.uml" new file mode 100644 index 0000000..1e2c5c9 --- /dev/null +++ "b/core-java-modules/core-java-base/\351\233\206\345\220\210\346\241\206\346\236\266\345\205\263\347\263\273\345\233\276.uml" @@ -0,0 +1,138 @@ + + + JAVA + java.util.ArrayList + + java.util.HashSet + com.sun.jmx.remote.internal.ArrayQueue + java.util.Vector + java.util.Set + java.util.TreeSet + java.util.concurrent.ArrayBlockingQueue + java.util.List + java.util.TreeMap + java.util.concurrent.ConcurrentHashMap + java.util.LinkedHashSet + java.util.Stack + java.util.concurrent.DelayQueue + java.util.Map + java.util.LinkedList + java.lang.Iterable + java.util.AbstractList + java.util.Collection + java.util.HashMap + java.util.Queue + java.util.LinkedHashMap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + All + private + + From 15952a5811b114b270070f0898bac09fd31c2ba7 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 5 May 2023 11:55:52 +0800 Subject: [PATCH 34/83] feat: add java 20 demo --- .../core-java-20/src/JEP433SwitchTest.java | 56 +++++++++++++++++++ .../src/Jep429ScopedValueTest.java | 28 ++++++++++ .../src/Jep432RecordAndInstance.java | 22 ++++++++ .../core-java-20/src/RecordTest.java | 14 +++++ 4 files changed, 120 insertions(+) create mode 100644 core-java-modules/core-java-20/src/JEP433SwitchTest.java create mode 100644 core-java-modules/core-java-20/src/Jep429ScopedValueTest.java create mode 100644 core-java-modules/core-java-20/src/Jep432RecordAndInstance.java create mode 100644 core-java-modules/core-java-20/src/RecordTest.java diff --git a/core-java-modules/core-java-20/src/JEP433SwitchTest.java b/core-java-modules/core-java-20/src/JEP433SwitchTest.java new file mode 100644 index 0000000..8080d37 --- /dev/null +++ b/core-java-modules/core-java-20/src/JEP433SwitchTest.java @@ -0,0 +1,56 @@ +/** + * @author niulang + */ +public class JEP433SwitchTest { + public static void main(String[] args) { + Object obj = 123; + System.out.println(matchOld(obj)); // 是个数字 + System.out.println(matchNew(obj)); // 是个数字 + obj = "wdbyte.com"; + System.out.println(matchOld(obj)); // 是个字符串,长度大于2 + System.out.println(matchNew(obj)); // 是个字符串,长度大于2 + } + + /** + * 老代码 + * + * @param obj + * @return + */ + public static String matchOld(Object obj) { + if (obj == null) { + return "数据为空"; + } + if (obj instanceof String) { + String s = obj.toString(); + if (s.length() > 2) { + return "是个字符串,长度大于2"; + } + if (s.length() <= 2) { + return "是个字符串,长度小于等于2"; + } + } + if (obj instanceof Integer) { + return "是个数字"; + } + throw new IllegalStateException("未知数据:" + obj); + } + + /** + * 新代码 + * + * @param obj + * @return + */ + public static String matchNew(Object obj) { + String res = switch (obj) { + case null -> "数据为空"; + case String s when s.length() > 2 -> "是个字符串,长度大于2"; + case String s when s.length() <= 2 -> "是个字符串,长度小于等于于2"; + case Integer i -> "是个数字"; + default -> throw new IllegalStateException("未知数据:" + obj); + }; + return res; + } + +} diff --git a/core-java-modules/core-java-20/src/Jep429ScopedValueTest.java b/core-java-modules/core-java-20/src/Jep429ScopedValueTest.java new file mode 100644 index 0000000..51d03e1 --- /dev/null +++ b/core-java-modules/core-java-20/src/Jep429ScopedValueTest.java @@ -0,0 +1,28 @@ +import jdk.incubator.concurrent.ScopedValue; + +/** + * --add-modules jdk.incubator.concurrent + * + * @date 2023/05/04 + */ +public class Jep429ScopedValueTest { + final static ScopedValue SCOPED_VALUE = ScopedValue.newInstance(); + + public static void main(String[] args) { + // 创建线程 + Thread thread1 = new Thread(Jep429ScopedValueTest::handle); + Thread thread2 = new Thread(Jep429ScopedValueTest::handle); + String str = "hello wdbyte"; + // 传入线程里使用的字符串信息 + ScopedValue.where(SCOPED_VALUE, str).run(thread1); + ScopedValue.where(SCOPED_VALUE, str).run(thread2); + // 执行完毕自动清空,这里获取不到了。 + System.out.println(SCOPED_VALUE.orElse("没有信息")); + } + + public static void handle() { + String result = SCOPED_VALUE.get(); + System.out.println(result); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java b/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java new file mode 100644 index 0000000..3e732a6 --- /dev/null +++ b/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java @@ -0,0 +1,22 @@ +/** + * @author niulang + */ +public class Jep432RecordAndInstance { + public static void main(String[] args) { + ColoredPoint coloredPoint1 = new ColoredPoint(new Point(0, 0), Color.RED); + ColoredPoint coloredPoint2 = new ColoredPoint(new Point(1, 1), Color.GREEN); + Rectangle rectangle = new Rectangle(coloredPoint1, coloredPoint2); + printUpperLeftColoredPoint(rectangle); + } + + static void printUpperLeftColoredPoint(Rectangle r) { + if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) { + System.out.println(ul.c()); + } + } +} + +record Point(int x, int y) {} +enum Color { RED, GREEN, BLUE } +record ColoredPoint(Point p, Color c) {} +record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {} \ No newline at end of file diff --git a/core-java-modules/core-java-20/src/RecordTest.java b/core-java-modules/core-java-20/src/RecordTest.java new file mode 100644 index 0000000..ef9a7c1 --- /dev/null +++ b/core-java-modules/core-java-20/src/RecordTest.java @@ -0,0 +1,14 @@ +/** + * @author niulang + * @date 2023/05/04 + */ +public class RecordTest { + public static void main(String[] args) { + Dog dog = new Dog("name", 1); + System.out.println(dog.name()); + System.out.println(dog.age()); + } +} + +record Dog(String name, Integer age) { +} \ No newline at end of file From d16518413207182d0279adb30b2234ecdfe8a383 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 5 May 2023 13:19:06 +0800 Subject: [PATCH 35/83] feat: add java 20 demo --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e39a197..9e77cfc 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ ## ☕ Java 新特性 Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错,何况有些新特性是**真香**。 +- [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) +- [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) - [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) - [Java 17 新功能介绍](https://www.wdbyte.com/java/java-17/) - [Java 16 新功能介绍](https://www.wdbyte.com/java/java-16/) From babb6fee5d12772806a0a5f0caf178d5eabb9540 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 10 May 2023 11:07:46 +0800 Subject: [PATCH 36/83] feat: update java 8 local date time --- .../java/com/wdbyte/Jdk8LocalDateTime.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java index 360e967..c41caf0 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java @@ -161,15 +161,29 @@ public void calcTest() { public void timeFunctionTest() { LocalDateTime now = LocalDateTime.now(); System.out.println("当前时间:" + now); - // 第一天 + + // LocalDateTime 本月第一天 + // 方法1 LocalDateTime firstDay = now.withDayOfMonth(1); System.out.println("本月第一天:" + firstDay); - // 当天最后一秒 - LocalDateTime lastSecondOfDay = now.withHour(23).withMinute(59).withSecond(59); - System.out.println("当天最后一秒:" + lastSecondOfDay); - // 最后一天 + // 方法2 + firstDay = now.with(TemporalAdjusters.firstDayOfMonth()); + System.out.println("本月第一天:" + firstDay); + + // LocalDateTime 本月最后一天 LocalDateTime lastDay = now.with(TemporalAdjusters.lastDayOfMonth()); System.out.println("本月最后一天:" + lastDay); + + + // LocalDateTime 当天最后一秒 + // 方法1 + LocalDateTime lastSecondOfDay1 = now.withHour(23).withMinute(59).withSecond(59); + System.out.println("当天最后一秒:" + lastSecondOfDay1); + // 方法2 + LocalDateTime lastSecondOfDay2 = LocalDateTime.now().with(LocalTime.MAX); + System.out.println("当天最后一秒:" + lastSecondOfDay2); + + // 是否闰年 System.out.println("今年是否闰年:" + Year.isLeap(now.getYear())); } From 879a101be4226fbba248d698ab31f90b5ecbe2ef Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 15:57:35 +0800 Subject: [PATCH 37/83] feat: proto buf --- pom.xml | 3 +- tool-java-protobuf/pom.xml | 45 +++++++++ .../wdbyte/tool/protos/AddressBookJava.java | 81 ++++++++++++++++ .../com/wdbyte/tool/protos/ProtobufTest1.java | 37 +++++++ .../com/wdbyte/tool/protos/ProtobufTest2.java | 35 +++++++ .../com/wdbyte/tool/protos/ProtobufTest3.java | 65 +++++++++++++ .../com/wdbyte/tool/protos/ProtobufTest4.java | 97 +++++++++++++++++++ .../com/wdbyte/tool/protos/StudentTest.java | 17 ++++ .../src/main/resources/addressbook.proto | 37 +++++++ .../src/main/resources/student.proto | 14 +++ 10 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 tool-java-protobuf/pom.xml create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookJava.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest1.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest2.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest3.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest4.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentTest.java create mode 100644 tool-java-protobuf/src/main/resources/addressbook.proto create mode 100644 tool-java-protobuf/src/main/resources/student.proto diff --git a/pom.xml b/pom.xml index 3110d06..2452dc4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,13 +10,14 @@ core-java-modules core-java-rate-limiter - junit5-jupiter-starter + tool-java-junit5-jupiter-starter leetcode tool-java-apache-httpclient tool-java-object-pool tool-java-jackson tool-java-apache-common tool-java-hotcode + tool-java-protobuf parent-modules Parent for all java modules diff --git a/tool-java-protobuf/pom.xml b/tool-java-protobuf/pom.xml new file mode 100644 index 0000000..36b0b7f --- /dev/null +++ b/tool-java-protobuf/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.wdbyte + parent-modules + 1.0.0-SNAPSHOT + + + tool-java-protobuf + + + 1.8 + 1.8 + UTF-8 + + + + + com.google.protobuf + protobuf-java + 3.22.3 + + + + com.alibaba + fastjson + 2.0.7 + + + org.openjdk.jmh + jmh-core + 1.33 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.33 + provided + + + + \ No newline at end of file diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookJava.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookJava.java new file mode 100644 index 0000000..5d500c4 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookJava.java @@ -0,0 +1,81 @@ +package com.wdbyte.tool.protos; + +import java.util.List; + +public class AddressBookJava { + List personJavaList; + + public static class PersonJava { + private int id; + private String name; + private String email; + private PhoneNumberJava phones; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public PhoneNumberJava getPhones() { + return phones; + } + + public void setPhones(PhoneNumberJava phones) { + this.phones = phones; + } + } + + public static class PhoneNumberJava { + private String number; + private PhoneTypeJava phoneTypeJava; + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public PhoneTypeJava getPhoneTypeJava() { + return phoneTypeJava; + } + + public void setPhoneTypeJava(PhoneTypeJava phoneTypeJava) { + this.phoneTypeJava = phoneTypeJava; + } + } + + public enum PhoneTypeJava { + MOBILE, + HOME, + WORK; + } + + public List getPersonJavaList() { + return personJavaList; + } + + public void setPersonJavaList(List personJavaList) { + this.personJavaList = personJavaList; + } +} \ No newline at end of file diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest1.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest1.java new file mode 100644 index 0000000..d2f825a --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest1.java @@ -0,0 +1,37 @@ +package com.wdbyte.tool.protos; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.wdbyte.tool.protos.Person.PhoneNumber; +import com.wdbyte.tool.protos.Person.PhoneType; + + +/** + * @author https://www.wdbyte.com + * @date 2023/05/07 + */ +public class ProtobufTest1 { + + public static void main(String[] args) { + // 直接构建 + PhoneNumber phoneNumber1 = PhoneNumber.newBuilder().setNumber("18388888888").setType(PhoneType.HOME).build(); + Person person1 = Person.newBuilder().setId(1).setName("www.wdbyte.com").setEmail("xxx@wdbyte.com").addPhones(phoneNumber1).build(); + AddressBook addressBook1 = AddressBook.newBuilder().addPeople(person1).build(); + System.out.println(addressBook1); + System.out.println("------------------"); + + // 链式构建 + AddressBook addressBook2 = AddressBook + .newBuilder() + .addPeople(Person.newBuilder() + .setId(2) + .setName("www.wdbyte.com") + .setEmail("yyy@126.com") + .addPhones(PhoneNumber.newBuilder() + .setNumber("18388888888") + .setType(PhoneType.HOME) + ) + ) + .build(); + System.out.println(addressBook2); + } +} diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest2.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest2.java new file mode 100644 index 0000000..0b3e236 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest2.java @@ -0,0 +1,35 @@ +package com.wdbyte.tool.protos; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import com.wdbyte.tool.protos.Person.PhoneNumber; +import com.wdbyte.tool.protos.Person.PhoneType; + +/** + * + * @author https://www.wdbyte.com + */ +public class ProtobufTest2 { + + public static void main(String[] args) throws IOException { + PhoneNumber phoneNumber1 = PhoneNumber.newBuilder().setNumber("18388888888").setType(PhoneType.HOME).build(); + Person person1 = Person.newBuilder().setId(1).setName("www.wdbyte.com").setEmail("xxx@wdbyte.com").addPhones(phoneNumber1).build(); + AddressBook addressBook1 = AddressBook.newBuilder().addPeople(person1).build(); + + // 序列化成字节数组 + byte[] byteArray = addressBook1.toByteArray(); + // 反序列化 - 字节数组转对象 + AddressBook addressBook2 = AddressBook.parseFrom(byteArray); + System.out.println("字节数组反序列化:"); + System.out.println(addressBook2); + + // 序列化到文件 + addressBook1.writeTo(new FileOutputStream("AddressBook1.txt")); + // 读取文件反序列化 + AddressBook addressBook3 = AddressBook.parseFrom(new FileInputStream("AddressBook1.txt")); + System.out.println("文件读取反序列化:"); + System.out.println(addressBook3); + } +} diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest3.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest3.java new file mode 100644 index 0000000..6f3857c --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest3.java @@ -0,0 +1,65 @@ +package com.wdbyte.tool.protos; + +import java.io.IOException; +import java.util.ArrayList; + +import com.alibaba.fastjson.JSON; + +import com.wdbyte.tool.protos.AddressBook.Builder; +import com.wdbyte.tool.protos.AddressBookJava.PersonJava; +import com.wdbyte.tool.protos.AddressBookJava.PhoneNumberJava; +import com.wdbyte.tool.protos.AddressBookJava.PhoneTypeJava; +import com.wdbyte.tool.protos.Person.PhoneNumber; +import com.wdbyte.tool.protos.Person.PhoneType; + +/** + * @author https://www.wdbyte.com + */ +public class ProtobufTest3 { + + public static void main(String[] args) throws IOException { + AddressBookJava addressBookJava = createAddressBookJava(1000); + String jsonString = JSON.toJSONString(addressBookJava); + System.out.println("json string size:" + jsonString.length()); + + AddressBook addressBook = createAddressBook(1000); + byte[] addressBookByteArray = addressBook.toByteArray(); + System.out.println("protobuf byte array size:" + addressBookByteArray.length); + } + + public static AddressBook createAddressBook(int personCount) { + Builder builder = AddressBook.newBuilder(); + for (int i = 0; i < personCount; i++) { + builder.addPeople(Person.newBuilder() + .setId(i) + .setName("www.wdbyte.com") + .setEmail("xxx@126.com") + .addPhones(PhoneNumber.newBuilder() + .setNumber("18333333333") + .setType(PhoneType.HOME) + ) + ); + } + return builder.build(); + } + + public static AddressBookJava createAddressBookJava(int personCount) { + AddressBookJava addressBookJava = new AddressBookJava(); + addressBookJava.setPersonJavaList(new ArrayList<>()); + for (int i = 0; i < personCount; i++) { + PersonJava personJava = new PersonJava(); + personJava.setId(i); + personJava.setName("www.wdbyte.com"); + personJava.setEmail("xxx@126.com"); + + PhoneNumberJava numberJava = new PhoneNumberJava(); + numberJava.setNumber("18333333333"); + numberJava.setPhoneTypeJava(PhoneTypeJava.HOME); + + personJava.setPhones(numberJava); + addressBookJava.getPersonJavaList().add(personJava); + } + return addressBookJava; + } +} + diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest4.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest4.java new file mode 100644 index 0000000..1437b42 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/ProtobufTest4.java @@ -0,0 +1,97 @@ +package com.wdbyte.tool.protos; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import com.alibaba.fastjson.JSON; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.wdbyte.tool.protos.AddressBook.Builder; +import com.wdbyte.tool.protos.AddressBookJava.PersonJava; +import com.wdbyte.tool.protos.AddressBookJava.PhoneNumberJava; +import com.wdbyte.tool.protos.AddressBookJava.PhoneTypeJava; +import com.wdbyte.tool.protos.Person.PhoneNumber; +import com.wdbyte.tool.protos.Person.PhoneType; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/** + * @author https://www.wdbyte.com + */ +@State(Scope.Thread) +@Fork(2) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 5, time = 3) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class ProtobufTest4 { + + private AddressBookJava addressBookJava; + private AddressBook addressBook; + + @Setup + public void init() { + addressBookJava = createAddressBookJava(1000); + addressBook = createAddressBook(1000); + } + + @Benchmark + public AddressBookJava testJSON() { + // 转 JSON + String jsonString = JSON.toJSONString(addressBookJava); + // JSON 转对象 + return JSON.parseObject(jsonString, AddressBookJava.class); + } + + @Benchmark + public AddressBook testProtobuf() throws InvalidProtocolBufferException { + // 转 JSON + byte[] addressBookByteArray = addressBook.toByteArray(); + // JSON 转对象 + return AddressBook.parseFrom(addressBookByteArray); + } + + public static AddressBook createAddressBook(int personCount) { + Builder builder = AddressBook.newBuilder(); + for (int i = 0; i < personCount; i++) { + builder.addPeople(Person.newBuilder() + .setId(i) + .setName("www.wdbyte.com") + .setEmail("xxx@126.com") + .addPhones(PhoneNumber.newBuilder() + .setNumber("18333333333") + .setType(PhoneType.HOME) + ) + ); + } + return builder.build(); + } + + public static AddressBookJava createAddressBookJava(int personCount) { + AddressBookJava addressBookJava = new AddressBookJava(); + addressBookJava.setPersonJavaList(new ArrayList<>()); + for (int i = 0; i < personCount; i++) { + PersonJava personJava = new PersonJava(); + personJava.setId(i); + personJava.setName("www.wdbyte.com"); + personJava.setEmail("xxx@126.com"); + + PhoneNumberJava numberJava = new PhoneNumberJava(); + numberJava.setNumber("18333333333"); + numberJava.setPhoneTypeJava(PhoneTypeJava.HOME); + + personJava.setPhones(numberJava); + addressBookJava.getPersonJavaList().add(personJava); + } + return addressBookJava; + } +} + diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentTest.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentTest.java new file mode 100644 index 0000000..041a689 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentTest.java @@ -0,0 +1,17 @@ +package com.wdbyte.tool.protos; + +import java.util.Arrays; + +import com.wdbyte.tool.protos.StudentOuterClass.Student; + +/** + * @author https://www.wdbyte.com + * @date 2023/05/10 + */ +public class StudentTest { + + public static void main(String[] args) { + Student student = Student.newBuilder().setId("1").setName("AB").build(); + System.out.println(Arrays.toString(student.toByteArray())); + } +} diff --git a/tool-java-protobuf/src/main/resources/addressbook.proto b/tool-java-protobuf/src/main/resources/addressbook.proto new file mode 100644 index 0000000..cbe93a9 --- /dev/null +++ b/tool-java-protobuf/src/main/resources/addressbook.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; +// 指定 protobuf 包名,防止有相同类名的 message 定义 +package com.wdbyte.protobuf; +// 是否生成多个文件 +option java_multiple_files = true; +// 生成的文件存放在哪个包下 +option java_package = "com.wdbyte.tool.protos"; +// 生成的类名,如果没有指定,会根据文件名自动转驼峰来命名 +option java_outer_classname = "AddressBookProtos"; +// 可选消息字段类型:bool int32 float double string +// 或者自定义消息类型,如下面的 PhoneNumber +// 修饰符:optional: 可选字段, +// 修饰符:repeated:可重复,如数组。 +// 修饰符:required:必要字段,必须给值,否则会报错 RuntimeException,但是在 protobuf 版本 3 中被移除。 +// 慎用 required,因为一旦被标记 requieds,以后将不能更改,否则可能会出问题。 +message Person { + optional int32 id = 1; + optional string name = 2; + optional string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + optional string number = 1; + optional PhoneType type = 2; + } + + repeated PhoneNumber phones = 4; +} + +message AddressBook { + repeated Person people = 1; +} \ No newline at end of file diff --git a/tool-java-protobuf/src/main/resources/student.proto b/tool-java-protobuf/src/main/resources/student.proto new file mode 100644 index 0000000..d656f75 --- /dev/null +++ b/tool-java-protobuf/src/main/resources/student.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +// 指定 protobuf 包名,防止有相同类名的 message 定义 +package com.wdbyte.protobuf; +// 是否生成多个文件 +option java_multiple_files = false; +// 生成的文件存放在哪个包下 +option java_package = "com.wdbyte.tool.protos"; +// 生成的类名,如果没有指定,会根据文件名自动转驼峰来命名 +//option java_outer_classname = "Student"; + +message Student{ + optional string id = 1; + optional string name = 2; +} \ No newline at end of file From 5c996c689e0149a12b01b1057d67aa7498b385b0 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 15:58:17 +0800 Subject: [PATCH 38/83] feat: junit5 --- .../.gitignore | 0 .../README.md | 0 .../pom.xml | 2 +- .../src/main/java/com/wdbyte/test/junit5/Person.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitOrder.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitOther.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitParam.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/JunitAssert.java | 2 +- .../src/test/java/com/wdbyte/test/junit5/PersonTest.java | 2 +- 12 files changed, 10 insertions(+), 10 deletions(-) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/.gitignore (100%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/README.md (100%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/pom.xml (95%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/main/java/com/wdbyte/test/junit5/Person.java (80%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java (97%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java (96%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java (96%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitOther.java (96%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitParam.java (93%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java (94%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/JunitAssert.java (95%) rename {junit5-jupiter-starter => tool-java-junit5-jupiter-starter}/src/test/java/com/wdbyte/test/junit5/PersonTest.java (92%) diff --git a/junit5-jupiter-starter/.gitignore b/tool-java-junit5-jupiter-starter/.gitignore similarity index 100% rename from junit5-jupiter-starter/.gitignore rename to tool-java-junit5-jupiter-starter/.gitignore diff --git a/junit5-jupiter-starter/README.md b/tool-java-junit5-jupiter-starter/README.md similarity index 100% rename from junit5-jupiter-starter/README.md rename to tool-java-junit5-jupiter-starter/README.md diff --git a/junit5-jupiter-starter/pom.xml b/tool-java-junit5-jupiter-starter/pom.xml similarity index 95% rename from junit5-jupiter-starter/pom.xml rename to tool-java-junit5-jupiter-starter/pom.xml index d100632..554f3de 100644 --- a/junit5-jupiter-starter/pom.xml +++ b/tool-java-junit5-jupiter-starter/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.wdbyte.junit5 - junit5-jupiter-starter + tool-java-junit5-jupiter-starter 1.8 diff --git a/junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java b/tool-java-junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java similarity index 80% rename from junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java rename to tool-java-junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java index 514c0af..975d7c6 100644 --- a/junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java +++ b/tool-java-junit5-jupiter-starter/src/main/java/com/wdbyte/test/junit5/Person.java @@ -1,7 +1,7 @@ package com.wdbyte.test.junit5; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ public class Person { diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java similarity index 97% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java index 732fb50..8c28e80 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitBeforeAll.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/15 */ class JUnitBeforeAll { diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java similarity index 96% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java index 62230fc..d610a96 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitJDKVersion.java @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.condition.JRE.JAVA_19; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ @TestMethodOrder(OrderAnnotation.class) diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java similarity index 96% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java index eef289a..6bd959e 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOrder.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestMethodOrder; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ @TestMethodOrder(OrderAnnotation.class) diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java similarity index 96% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java index aebe289..9951745 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitOther.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.TestMethodOrder; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ @TestMethodOrder(OrderAnnotation.class) diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java similarity index 93% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java index fe29bbd..388a865 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitParam.java @@ -6,7 +6,7 @@ import org.junit.jupiter.params.provider.ValueSource; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ public class JUnitParam { diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java similarity index 94% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java index 5d0cb07..e39c696 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JUnitTestIsDog.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/15 */ class JUnitTestIsDog { diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java similarity index 95% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java index 0063739..34a29e6 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/JunitAssert.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ public class JunitAssert { diff --git a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java similarity index 92% rename from junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java rename to tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java index 0d883ed..d72ef3d 100644 --- a/junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java +++ b/tool-java-junit5-jupiter-starter/src/test/java/com/wdbyte/test/junit5/PersonTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/17 */ @DisplayName("测试 Presion") From efd1d904510fb405041df9ece6fa4716f1ec7102 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 16:08:46 +0800 Subject: [PATCH 39/83] =?UTF-8?q?docs:=20=E4=BF=AE=E6=AD=A3=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core-java-20/src/JEP433SwitchTest.java | 2 +- .../core-java-20/src/Jep432RecordAndInstance.java | 2 +- core-java-modules/core-java-20/src/RecordTest.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Base64.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Function.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Interface.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Lambda.java | 2 +- .../src/main/java/com/wdbyte/Jdk8LocalDateTime.java | 2 +- .../src/main/java/com/wdbyte/Jdk8NashornJs.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Optional.java | 2 +- .../src/main/java/com/wdbyte/Jdk8Stream.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator2.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator3.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator4.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator5.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator6.java | 2 +- .../java/com/wdbyte/comparator/Java8Comparator7.java | 2 +- .../src/main/java/com/wdbyte/JavaDataType.java | 2 +- .../src/main/java/com/wdbyte/array/JavaArray.java | 2 +- .../src/main/java/com/wdbyte/array/JavaArray2.java | 2 +- .../src/main/java/com/wdbyte/array/JavaArray3.java | 2 +- .../src/main/java/com/wdbyte/array/JavaArray4.java | 2 +- .../java/com/wdbyte/collection/CollectionTest.java | 2 +- .../java/com/wdbyte/collection/CollectionTest2.java | 2 +- .../java/com/wdbyte/collection/CollectionTest3.java | 2 +- .../java/com/wdbyte/collection/CollectionTest4.java | 2 +- .../java/com/wdbyte/collection/CollectionTest5.java | 2 +- .../src/main/java/com/wdbyte/collection/MapTest.java | 2 +- .../src/main/java/com/wdbyte/collection/MapTest2.java | 2 +- .../src/main/java/com/wdbyte/date/JavaDateCalc.java | 2 +- .../src/main/java/com/wdbyte/date/JavaDateCalc2.java | 2 +- .../src/main/java/com/wdbyte/date/JavaDateCreate.java | 2 +- .../src/main/java/com/wdbyte/date/JavaDateDiff.java | 2 +- .../src/main/java/com/wdbyte/date/JavaDateFormat.java | 2 +- .../src/main/java/com/wdbyte/enum2/CalcTest.java | 2 +- .../src/main/java/com/wdbyte/enum2/WeekdayTest.java | 2 +- .../main/java/com/wdbyte/exception/JavaException1.java | 2 +- .../main/java/com/wdbyte/exception/JavaException2.java | 2 +- .../main/java/com/wdbyte/exception/JavaException3.java | 2 +- .../main/java/com/wdbyte/exception/JavaException4.java | 2 +- .../main/java/com/wdbyte/exception/JavaException5.java | 2 +- .../main/java/com/wdbyte/exception/JavaException6.java | 2 +- .../main/java/com/wdbyte/exception/JavaException7.java | 2 +- .../main/java/com/wdbyte/exception/JavaException8.java | 2 +- .../src/main/java/com/wdbyte/oop/JavaExtends.java | 2 +- .../src/main/java/com/wdbyte/oop/abs/AbsPerson.java | 2 +- .../src/main/java/com/wdbyte/oop/abs/PersonTest.java | 2 +- .../src/main/java/com/wdbyte/oop/abs/Student.java | 2 +- .../src/main/java/com/wdbyte/oop/abs/Teacher.java | 2 +- .../java/com/wdbyte/oop/interfac/JavaInterface.java | 2 +- .../java/com/wdbyte/oop/interfac/JavaInterface2.java | 2 +- .../java/com/wdbyte/oop/interfac/JavaInterface3.java | 2 +- .../java/com/wdbyte/oop/polymorphism/AliyunOss.java | 2 +- .../src/main/java/com/wdbyte/oop/polymorphism/Oss.java | 2 +- .../main/java/com/wdbyte/oop/polymorphism/OssUtil.java | 2 +- .../java/com/wdbyte/oop/polymorphism/TencentOss.java | 2 +- .../java/com/wdbyte/oop/polymorphism/inter/Test.java | 2 +- .../java/com/wdbyte/oop/polymorphism/inter/Test2.java | 2 +- .../main/java/com/wdbyte/{ => string}/JavaString.java | 4 ++-- .../com/wdbyte/{ => string}/JavaStringBuilder.java | 4 ++-- .../src/main/java/com/wdbyte/HashMapKey.java | 10 +++++++++- 62 files changed, 72 insertions(+), 64 deletions(-) rename core-java-modules/core-java-base/src/main/java/com/wdbyte/{ => string}/JavaString.java (97%) rename core-java-modules/core-java-base/src/main/java/com/wdbyte/{ => string}/JavaStringBuilder.java (94%) diff --git a/core-java-modules/core-java-20/src/JEP433SwitchTest.java b/core-java-modules/core-java-20/src/JEP433SwitchTest.java index 8080d37..39094ad 100644 --- a/core-java-modules/core-java-20/src/JEP433SwitchTest.java +++ b/core-java-modules/core-java-20/src/JEP433SwitchTest.java @@ -1,5 +1,5 @@ /** - * @author niulang + * @author https://www.wdbyte.com */ public class JEP433SwitchTest { public static void main(String[] args) { diff --git a/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java b/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java index 3e732a6..6ca31d5 100644 --- a/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java +++ b/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java @@ -1,5 +1,5 @@ /** - * @author niulang + * @author https://www.wdbyte.com */ public class Jep432RecordAndInstance { public static void main(String[] args) { diff --git a/core-java-modules/core-java-20/src/RecordTest.java b/core-java-modules/core-java-20/src/RecordTest.java index ef9a7c1..2a3b46c 100644 --- a/core-java-modules/core-java-20/src/RecordTest.java +++ b/core-java-modules/core-java-20/src/RecordTest.java @@ -1,5 +1,5 @@ /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/05/04 */ public class RecordTest { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Base64.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Base64.java index f3034f9..c50f47c 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Base64.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Base64.java @@ -7,7 +7,7 @@ *

* JDK8 对 base64 编码的支持 * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/6/12 9:47 */ public class Jdk8Base64 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Function.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Function.java index 78d045b..9d14a98 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Function.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Function.java @@ -14,7 +14,7 @@ * - Consumer: 数据消费器, 接收一个 T类型的对象,无返回值,通常用于设置T对象的值; 单参数无返回值的行为接口;提供了 accept, andThen 方法
* - Predicate: 条件测试器,接收一个 T 类型的对象,返回布尔值,通常用于传递条件函数; 单参数布尔值的条件性接口。提供了 test (条件测试) , and-or- negate(与或非) 方法。 * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/2/18 22:08 */ public class Jdk8Function { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Interface.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Interface.java index 4037c71..790262a 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Interface.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Interface.java @@ -5,7 +5,7 @@ * 接口的静态方法和默认方法 * * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/2/18 22:52 */ public class Jdk8Interface { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java index b2663cb..357f967 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java @@ -23,7 +23,7 @@ * 4. 花括号可选,一个语句可以不用花括号,多个参数则花括号必须。 * 5. 返回值可选,如果只有一个表达式,可以自动返回不需要 return 语句,花括号中需要 return 语法。 * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/2/17 14:48 */ public class Jdk8Lambda { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java index c41caf0..9af6004 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8LocalDateTime.java @@ -19,7 +19,7 @@ * - 实现了大部分常用操作方法 *

* - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/2/19 17:48 */ public class Jdk8LocalDateTime { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8NashornJs.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8NashornJs.java index 6a1a2e7..ac34fd1 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8NashornJs.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8NashornJs.java @@ -15,7 +15,7 @@ * * 这类Script引擎遵循相同的规则,允许Java和JavaScript交互使用,例子代码如下: * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/6/12 9:41 */ public class Jdk8NashornJs { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java index 4288b27..ec3fa57 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java @@ -10,7 +10,7 @@ *

* JDK8 为解决空指针增加的 Optional 方法 * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/2/19 11:40 */ public class Jdk8Optional { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Stream.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Stream.java index aa1a6b5..d78cdb2 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Stream.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Stream.java @@ -13,7 +13,7 @@ *

* JDK 8 steam 流操作 * - * @Author niujinpeng +* @Author https://www.wdbyte.com * @Date 2019/8/12 18:03 */ public class Jdk8Stream { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator.java index 78f7109..b4c5773 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator.java @@ -6,7 +6,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator2.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator2.java index bef75cc..b53e60e 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator2.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator2.java @@ -6,7 +6,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator2 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator3.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator3.java index 70d3a24..4031315 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator3.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator3.java @@ -5,7 +5,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator3 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator4.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator4.java index 250e30a..c02c30d 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator4.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator4.java @@ -5,7 +5,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator4 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator5.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator5.java index d65054b..ca3ae94 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator5.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator5.java @@ -6,7 +6,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator5 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator6.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator6.java index bec0fb7..20ab437 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator6.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator6.java @@ -6,7 +6,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator6 { diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator7.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator7.java index c7c9d25..2918e31 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator7.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/comparator/Java8Comparator7.java @@ -5,7 +5,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/02 */ public class Java8Comparator7 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java index 24aa637..192314b 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaDataType.java @@ -1,7 +1,7 @@ package com.wdbyte; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/23 */ public class JavaDataType { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java index daac4ec..521b1c2 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray.java @@ -5,7 +5,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/23 */ public class JavaArray { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java index b5a5b66..ba92287 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray2.java @@ -1,7 +1,7 @@ package com.wdbyte.array; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/25 */ public class JavaArray2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java index d48cd29..3816c54 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray3.java @@ -1,7 +1,7 @@ package com.wdbyte.array; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/25 */ public class JavaArray3 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java index b1b998c..4665cc6 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/array/JavaArray4.java @@ -2,7 +2,7 @@ /** * 锯齿数组 - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/25 */ public class JavaArray4 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java index 67b150a..fc953ed 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest.java @@ -4,7 +4,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com */ public class CollectionTest { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java index dfab350..3c67874 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest2.java @@ -9,7 +9,7 @@ import java.util.TreeSet; /** - * @author niulang + * @author https://www.wdbyte.com */ public class CollectionTest2 { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java index 7f75e07..2989ef5 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest3.java @@ -6,7 +6,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com */ public class CollectionTest3 { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java index 990fea2..349619b 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest4.java @@ -7,7 +7,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com */ public class CollectionTest4 { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java index 2dc01b0..6d480e8 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/CollectionTest5.java @@ -7,7 +7,7 @@ import java.util.List; /** - * @author niulang + * @author https://www.wdbyte.com */ public class CollectionTest5 { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java index b19d7b1..cd346f9 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest.java @@ -4,7 +4,7 @@ import java.util.Map; /** - * @author niulang + * @author https://www.wdbyte.com */ public class MapTest { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java index 306e313..235c79a 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/MapTest2.java @@ -5,7 +5,7 @@ import java.util.Map; /** - * @author niulang + * @author https://www.wdbyte.com */ public class MapTest2 { public static void main(String[] args) { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java index e400cdb..5c39fa8 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc.java @@ -5,7 +5,7 @@ import java.util.Date; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/26 */ public class JavaDateCalc { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java index 16f0c4a..922030f 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCalc2.java @@ -5,7 +5,7 @@ import java.util.Date; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/26 */ public class JavaDateCalc2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java index 2046ffe..44c6bbb 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateCreate.java @@ -3,7 +3,7 @@ import java.util.Date; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/25 */ public class JavaDateCreate { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java index 2f47ade..09e3363 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateDiff.java @@ -4,7 +4,7 @@ import java.util.Date; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/25 */ public class JavaDateDiff { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java index 47be812..96a3c89 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/date/JavaDateFormat.java @@ -5,7 +5,7 @@ import java.util.Date; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/25 */ public class JavaDateFormat { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java index b9eeff9..56e2465 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/CalcTest.java @@ -1,7 +1,7 @@ package com.wdbyte.enum2; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/05/01 */ public class CalcTest { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java index 0478277..6d83265 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java @@ -1,7 +1,7 @@ package com.wdbyte.enum2; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/05/01 */ public class WeekdayTest { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java index 18b22d1..8fe2506 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException1.java @@ -1,7 +1,7 @@ package com.wdbyte.exception; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException1 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java index e680d35..c5b2386 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException2.java @@ -1,7 +1,7 @@ package com.wdbyte.exception; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java index 4395064..5e37b10 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException3.java @@ -1,7 +1,7 @@ package com.wdbyte.exception; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException3 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java index a88f5e5..0ba0f3d 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException4.java @@ -1,7 +1,7 @@ package com.wdbyte.exception; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException4 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java index acbb901..9366d98 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException5.java @@ -3,7 +3,7 @@ import org.apache.commons.lang3.ObjectUtils.Null; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException5 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java index 4cbff20..2b68230 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException6.java @@ -5,7 +5,7 @@ import java.nio.file.Paths; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/27 */ public class JavaException6 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java index 9b5483d..bdbbc19 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException7.java @@ -5,7 +5,7 @@ import java.nio.file.Paths; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/27 */ public class JavaException7 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java index 905a2ab..1f86646 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/exception/JavaException8.java @@ -1,7 +1,7 @@ package com.wdbyte.exception; /** - * @author niulang + * @author https://www.wdbyte.com */ public class JavaException8 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java index 7811d7f..df818b3 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/JavaExtends.java @@ -1,7 +1,7 @@ package com.wdbyte.oop; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/31 */ public class JavaExtends { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java index 062bb70..c142711 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.abs; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/17 */ public abstract class AbsPerson { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java index 3c8d06e..02144e2 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/PersonTest.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.abs; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/17 */ public class PersonTest { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java index bd9060f..dbfa7b7 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Student.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.abs; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/17 */ public class Student extends AbsPerson { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java index 8c790c8..1db8158 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/Teacher.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.abs; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/17 */ public class Teacher extends AbsPerson { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java index 7359a11..e700d09 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.interfac; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/13 */ public class JavaInterface { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java index b4bce89..db299b1 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface2.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.interfac; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/13 */ public class JavaInterface2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java index d4a75a9..abd9ff9 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/JavaInterface3.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.interfac; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/14 */ public class JavaInterface3 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java index d6229c3..3bedb6c 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/AliyunOss.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.polymorphism; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public class AliyunOss implements Oss { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java index f7466eb..8fd2af8 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/Oss.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.polymorphism; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public interface Oss { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java index 1e9eeef..5a07fc1 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/OssUtil.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.polymorphism; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public class OssUtil { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java index ece1f22..4993abd 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/TencentOss.java @@ -1,7 +1,7 @@ package com.wdbyte.oop.polymorphism; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public class TencentOss implements Oss { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java index 7565cd6..9d15814 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test.java @@ -4,7 +4,7 @@ /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public class Test { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java index 778c203..a1b7e3b 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/polymorphism/inter/Test2.java @@ -2,7 +2,7 @@ /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/04/18 */ public class Test2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaString.java similarity index 97% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaString.java index 31890ee..bc4d4e6 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaString.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaString.java @@ -1,7 +1,7 @@ -package com.wdbyte; +package com.wdbyte.string; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/22 */ public class JavaString { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaStringBuilder.java similarity index 94% rename from core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java rename to core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaStringBuilder.java index b492031..514054b 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/JavaStringBuilder.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/string/JavaStringBuilder.java @@ -1,7 +1,7 @@ -package com.wdbyte; +package com.wdbyte.string; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/03/30 */ public class JavaStringBuilder { diff --git a/core-java-modules/core-java-performance-code/src/main/java/com/wdbyte/HashMapKey.java b/core-java-modules/core-java-performance-code/src/main/java/com/wdbyte/HashMapKey.java index 1fc032e..31e622b 100644 --- a/core-java-modules/core-java-performance-code/src/main/java/com/wdbyte/HashMapKey.java +++ b/core-java-modules/core-java-performance-code/src/main/java/com/wdbyte/HashMapKey.java @@ -3,13 +3,18 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; @@ -20,9 +25,12 @@ * @author https://www.wdbyte.com * @date 2021/12/06 */ -@State(Scope.Benchmark) +@State(Scope.Thread) +@Fork(2) @Warmup(iterations = 3, time = 3) @Measurement(iterations = 5, time = 3) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) public class HashMapKey { private int size = 1024; From da5c648fcee5c8bd065584a7f845222e61dd9304 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 16:11:07 +0800 Subject: [PATCH 40/83] update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9e77cfc..2af0b44 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 >出处:孔子《论语》 一款好用的工具,不仅可以装X,更可以让你事半功倍,准时下班。 +- [Protobuf 教程](https://www.wdbyte.com/tool/protobuf/) - [Apache HttpClient 5 使用详细教程](https://www.wdbyte.com/tool/httpclient5.html) - [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) - [Java 反编译工具的使用与对比分析](https://www.wdbyte.com/2021/05/java-decompiler/) From bdc331c1ac2ae2f0f22e9fdbd2b1ec2714a1f602 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 16:11:33 +0800 Subject: [PATCH 41/83] feat: leetcode --- .../LeetCode388_LengthLongestPath.java | 2 +- .../LeetCode396_MaxRotateFunction.java | 2 +- ...etCode515_FindLargeValueInEachTreeRow.java | 2 +- .../leetcode/LeetCode587_OuterTrees.java | 48 +++++++++++++++++++ .../leetcode/LeetCode824_ToGoatLatin.java | 2 +- 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 leetcode/src/main/java/com/wdbyte/leetcode/LeetCode587_OuterTrees.java diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode388_LengthLongestPath.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode388_LengthLongestPath.java index 8a41422..46a0ea9 100644 --- a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode388_LengthLongestPath.java +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode388_LengthLongestPath.java @@ -6,7 +6,7 @@ * 388. 文件的最长绝对路径 * https://leetcode-cn.com/problems/longest-absolute-file-path/ * - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/20 */ public class LeetCode388_LengthLongestPath { diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode396_MaxRotateFunction.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode396_MaxRotateFunction.java index adbe6e1..2e563ef 100644 --- a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode396_MaxRotateFunction.java +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode396_MaxRotateFunction.java @@ -22,7 +22,7 @@ * F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26 * 所以 F(0), F(1), F(2), F(3) 中的最大值是 F(3) = 26 。 * - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/22 */ public class LeetCode396_MaxRotateFunction { diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java index 141a534..3560d97 100644 --- a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode515_FindLargeValueInEachTreeRow.java @@ -8,7 +8,7 @@ * * 515. 在每个树行中找最大值 * - * @author niulang + * @author https://www.wdbyte.com * @date 2022/06/24 */ public class LeetCode515_FindLargeValueInEachTreeRow { diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode587_OuterTrees.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode587_OuterTrees.java new file mode 100644 index 0000000..ed2a356 --- /dev/null +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode587_OuterTrees.java @@ -0,0 +1,48 @@ +package com.wdbyte.leetcode; + +/** + * https://leetcode-cn.com/problems/erect-the-fence/ + * 587. 安装栅栏 + * 在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起 + * 所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。你需要找到正好位于栅栏边界上的树的坐标。 + * + * @author https://www.wdbyte.com + * @date 2022/04/23 + */ +public class LeetCode587_OuterTrees { + public static void main(String[] args) { + int[][] trees = {{1, 1}, {2, 2}, {2, 0}, {2, 4}, {3, 3}, {4, 2}}; + System.out.println(multi(trees[2], trees[2], trees[4])); + } + + public int[][] outerTrees(int[][] trees) { + // 1. 找到最左边的一个点 + int startX = 0; + int startY = 0; + for (int[] tree : trees) { + int x = tree[0]; + int y = tree[1]; + if (x < startX) { + startX = x; + startY = y; + } + } + // 2. 从最左边的一个点开始,寻找最大角度的点的连线 + return null; + } + + static int[][] sort(int[][] trees) { + return trees; + } + + //计算叉积,p1,p2,p0都为点 + static double multi(int[] p1, int[] p2, int[] p0) { + double x1, y1, x2, y2; + x1 = p1[0] - p0[0]; + y1 = p1[1] - p0[1]; + x2 = p2[0] - p0[0]; + y2 = p2[1] - p0[1]; + return x1 * y2 - x2 * y1; + } + +} diff --git a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode824_ToGoatLatin.java b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode824_ToGoatLatin.java index 43a4c12..dbe5e05 100644 --- a/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode824_ToGoatLatin.java +++ b/leetcode/src/main/java/com/wdbyte/leetcode/LeetCode824_ToGoatLatin.java @@ -4,7 +4,7 @@ * https://leetcode-cn.com/problems/goat-latin/ * 824. 山羊拉丁文 * - * @author niulang + * @author https://www.wdbyte.com * @date 2022/04/21 */ public class LeetCode824_ToGoatLatin { From ddce4729b86b5257a620496a55b0bb610d70f8b9 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 16:11:56 +0800 Subject: [PATCH 42/83] update HotCode.java --- .../main/java/com/wdbyte/hotcode/HotCode.java | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java index 0750444..0838ffb 100644 --- a/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java +++ b/tool-java-hotcode/src/main/java/com/wdbyte/hotcode/HotCode.java @@ -1,6 +1,9 @@ package com.wdbyte.hotcode; +import java.io.IOException; import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -9,7 +12,7 @@ /** * - * @author niulang + * @author https://www.wdbyte.com * @date 2023/02/20 */ public class HotCode { @@ -33,6 +36,10 @@ public static void main(String[] args) { thread(); // 运行缓慢的方法 runSlowThread(); + // 读取文件 + readFile(); + // 抛出异常 + exceMethod(); } /** @@ -104,6 +111,7 @@ private static void deadThread() { System.out.println(Thread.currentThread() + " get ResourceB"); try { Thread.sleep(1000); + } catch (InterruptedException e) { e.printStackTrace(); } @@ -194,4 +202,45 @@ public static void slow2() throws InterruptedException { System.out.println(count); } + /** + * 不断读取文件 + */ + public static void readFile(){ + new Thread(() -> { + Thread.currentThread().setName("read_file_method"); + while (true){ + try { + byte[] bytes = Files.readAllBytes(Paths.get("/Users/darcy/Downloads/info.txt")); + System.out.println(bytes.length); + Thread.sleep(100); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + }).start(); + } + + /** + * 不断抛出异常 + */ + public static void exceMethod() { + new Thread(() -> { + Thread.currentThread().setName("exce_method"); + while (true) { + try { + System.out.println(exce(0)); + Thread.sleep(200); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + + public static int exce(int a){ + return 10/a; + } + } From 9717e5a6c7c0927b5e6c17f0921670753550ab0d Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Tue, 16 May 2023 16:25:04 +0800 Subject: [PATCH 43/83] feat: protobuf code --- tool-java-protobuf/pom.xml | 1 + .../com/wdbyte/tool/protos/AddressBook.java | 725 ++++++ .../tool/protos/AddressBookOrBuilder.java | 33 + .../wdbyte/tool/protos/AddressBookProtos.java | 79 + .../java/com/wdbyte/tool/protos/Person.java | 1942 +++++++++++++++++ .../wdbyte/tool/protos/PersonOrBuilder.java | 78 + .../wdbyte/tool/protos/StudentOuterClass.java | 770 +++++++ 7 files changed, 3628 insertions(+) create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBook.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookOrBuilder.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookProtos.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/Person.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/PersonOrBuilder.java create mode 100644 tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentOuterClass.java diff --git a/tool-java-protobuf/pom.xml b/tool-java-protobuf/pom.xml index 36b0b7f..3c9725c 100644 --- a/tool-java-protobuf/pom.xml +++ b/tool-java-protobuf/pom.xml @@ -7,6 +7,7 @@ com.wdbyte parent-modules 1.0.0-SNAPSHOT + ../pom.xml tool-java-protobuf diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBook.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBook.java new file mode 100644 index 0000000..e8e78be --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBook.java @@ -0,0 +1,725 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/addressbook.proto + +package com.wdbyte.tool.protos; + +/** + * Protobuf type {@code com.wdbyte.protobuf.AddressBook} + */ +public final class AddressBook extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.wdbyte.protobuf.AddressBook) + AddressBookOrBuilder { +private static final long serialVersionUID = 0L; + // Use AddressBook.newBuilder() to construct. + private AddressBook(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private AddressBook() { + people_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new AddressBook(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_AddressBook_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_AddressBook_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.AddressBook.class, com.wdbyte.tool.protos.AddressBook.Builder.class); + } + + public static final int PEOPLE_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List people_; + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + @java.lang.Override + public java.util.List getPeopleList() { + return people_; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + @java.lang.Override + public java.util.List + getPeopleOrBuilderList() { + return people_; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + @java.lang.Override + public int getPeopleCount() { + return people_.size(); + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + @java.lang.Override + public com.wdbyte.tool.protos.Person getPeople(int index) { + return people_.get(index); + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + @java.lang.Override + public com.wdbyte.tool.protos.PersonOrBuilder getPeopleOrBuilder( + int index) { + return people_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < people_.size(); i++) { + output.writeMessage(1, people_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < people_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, people_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.wdbyte.tool.protos.AddressBook)) { + return super.equals(obj); + } + com.wdbyte.tool.protos.AddressBook other = (com.wdbyte.tool.protos.AddressBook) obj; + + if (!getPeopleList() + .equals(other.getPeopleList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getPeopleCount() > 0) { + hash = (37 * hash) + PEOPLE_FIELD_NUMBER; + hash = (53 * hash) + getPeopleList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.wdbyte.tool.protos.AddressBook parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.AddressBook parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.AddressBook parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.AddressBook parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.wdbyte.tool.protos.AddressBook prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.wdbyte.protobuf.AddressBook} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.wdbyte.protobuf.AddressBook) + com.wdbyte.tool.protos.AddressBookOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_AddressBook_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_AddressBook_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.AddressBook.class, com.wdbyte.tool.protos.AddressBook.Builder.class); + } + + // Construct using com.wdbyte.tool.protos.AddressBook.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (peopleBuilder_ == null) { + people_ = java.util.Collections.emptyList(); + } else { + people_ = null; + peopleBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_AddressBook_descriptor; + } + + @java.lang.Override + public com.wdbyte.tool.protos.AddressBook getDefaultInstanceForType() { + return com.wdbyte.tool.protos.AddressBook.getDefaultInstance(); + } + + @java.lang.Override + public com.wdbyte.tool.protos.AddressBook build() { + com.wdbyte.tool.protos.AddressBook result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.wdbyte.tool.protos.AddressBook buildPartial() { + com.wdbyte.tool.protos.AddressBook result = new com.wdbyte.tool.protos.AddressBook(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(com.wdbyte.tool.protos.AddressBook result) { + if (peopleBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + people_ = java.util.Collections.unmodifiableList(people_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.people_ = people_; + } else { + result.people_ = peopleBuilder_.build(); + } + } + + private void buildPartial0(com.wdbyte.tool.protos.AddressBook result) { + int from_bitField0_ = bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.wdbyte.tool.protos.AddressBook) { + return mergeFrom((com.wdbyte.tool.protos.AddressBook)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.wdbyte.tool.protos.AddressBook other) { + if (other == com.wdbyte.tool.protos.AddressBook.getDefaultInstance()) return this; + if (peopleBuilder_ == null) { + if (!other.people_.isEmpty()) { + if (people_.isEmpty()) { + people_ = other.people_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensurePeopleIsMutable(); + people_.addAll(other.people_); + } + onChanged(); + } + } else { + if (!other.people_.isEmpty()) { + if (peopleBuilder_.isEmpty()) { + peopleBuilder_.dispose(); + peopleBuilder_ = null; + people_ = other.people_; + bitField0_ = (bitField0_ & ~0x00000001); + peopleBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getPeopleFieldBuilder() : null; + } else { + peopleBuilder_.addAllMessages(other.people_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.wdbyte.tool.protos.Person m = + input.readMessage( + com.wdbyte.tool.protos.Person.parser(), + extensionRegistry); + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.add(m); + } else { + peopleBuilder_.addMessage(m); + } + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List people_ = + java.util.Collections.emptyList(); + private void ensurePeopleIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + people_ = new java.util.ArrayList(people_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person, com.wdbyte.tool.protos.Person.Builder, com.wdbyte.tool.protos.PersonOrBuilder> peopleBuilder_; + + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public java.util.List getPeopleList() { + if (peopleBuilder_ == null) { + return java.util.Collections.unmodifiableList(people_); + } else { + return peopleBuilder_.getMessageList(); + } + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public int getPeopleCount() { + if (peopleBuilder_ == null) { + return people_.size(); + } else { + return peopleBuilder_.getCount(); + } + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public com.wdbyte.tool.protos.Person getPeople(int index) { + if (peopleBuilder_ == null) { + return people_.get(index); + } else { + return peopleBuilder_.getMessage(index); + } + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder setPeople( + int index, com.wdbyte.tool.protos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.set(index, value); + onChanged(); + } else { + peopleBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder setPeople( + int index, com.wdbyte.tool.protos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.set(index, builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder addPeople(com.wdbyte.tool.protos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.add(value); + onChanged(); + } else { + peopleBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder addPeople( + int index, com.wdbyte.tool.protos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.add(index, value); + onChanged(); + } else { + peopleBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder addPeople( + com.wdbyte.tool.protos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.add(builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder addPeople( + int index, com.wdbyte.tool.protos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.add(index, builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder addAllPeople( + java.lang.Iterable values) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, people_); + onChanged(); + } else { + peopleBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder clearPeople() { + if (peopleBuilder_ == null) { + people_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + peopleBuilder_.clear(); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public Builder removePeople(int index) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.remove(index); + onChanged(); + } else { + peopleBuilder_.remove(index); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public com.wdbyte.tool.protos.Person.Builder getPeopleBuilder( + int index) { + return getPeopleFieldBuilder().getBuilder(index); + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public com.wdbyte.tool.protos.PersonOrBuilder getPeopleOrBuilder( + int index) { + if (peopleBuilder_ == null) { + return people_.get(index); } else { + return peopleBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public java.util.List + getPeopleOrBuilderList() { + if (peopleBuilder_ != null) { + return peopleBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(people_); + } + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public com.wdbyte.tool.protos.Person.Builder addPeopleBuilder() { + return getPeopleFieldBuilder().addBuilder( + com.wdbyte.tool.protos.Person.getDefaultInstance()); + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public com.wdbyte.tool.protos.Person.Builder addPeopleBuilder( + int index) { + return getPeopleFieldBuilder().addBuilder( + index, com.wdbyte.tool.protos.Person.getDefaultInstance()); + } + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + public java.util.List + getPeopleBuilderList() { + return getPeopleFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person, com.wdbyte.tool.protos.Person.Builder, com.wdbyte.tool.protos.PersonOrBuilder> + getPeopleFieldBuilder() { + if (peopleBuilder_ == null) { + peopleBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person, com.wdbyte.tool.protos.Person.Builder, com.wdbyte.tool.protos.PersonOrBuilder>( + people_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + people_ = null; + } + return peopleBuilder_; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.wdbyte.protobuf.AddressBook) + } + + // @@protoc_insertion_point(class_scope:com.wdbyte.protobuf.AddressBook) + private static final com.wdbyte.tool.protos.AddressBook DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.wdbyte.tool.protos.AddressBook(); + } + + public static com.wdbyte.tool.protos.AddressBook getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AddressBook parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.wdbyte.tool.protos.AddressBook getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookOrBuilder.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookOrBuilder.java new file mode 100644 index 0000000..e0b5161 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookOrBuilder.java @@ -0,0 +1,33 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/addressbook.proto + +package com.wdbyte.tool.protos; + +public interface AddressBookOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.wdbyte.protobuf.AddressBook) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + java.util.List + getPeopleList(); + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + com.wdbyte.tool.protos.Person getPeople(int index); + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + int getPeopleCount(); + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + java.util.List + getPeopleOrBuilderList(); + /** + * repeated .com.wdbyte.protobuf.Person people = 1; + */ + com.wdbyte.tool.protos.PersonOrBuilder getPeopleOrBuilder( + int index); +} diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookProtos.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookProtos.java new file mode 100644 index 0000000..e1c6788 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/AddressBookProtos.java @@ -0,0 +1,79 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/addressbook.proto + +package com.wdbyte.tool.protos; + +public final class AddressBookProtos { + private AddressBookProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_wdbyte_protobuf_Person_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_wdbyte_protobuf_Person_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_wdbyte_protobuf_Person_PhoneNumber_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_wdbyte_protobuf_AddressBook_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_wdbyte_protobuf_AddressBook_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\033resources/addressbook.proto\022\023com.wdbyt" + + "e.protobuf\"\262\002\n\006Person\022\017\n\002id\030\001 \001(\005H\000\210\001\001\022\021" + + "\n\004name\030\002 \001(\tH\001\210\001\001\022\022\n\005email\030\003 \001(\tH\002\210\001\001\0227\n" + + "\006phones\030\004 \003(\0132\'.com.wdbyte.protobuf.Pers" + + "on.PhoneNumber\032p\n\013PhoneNumber\022\023\n\006number\030" + + "\001 \001(\tH\000\210\001\001\0228\n\004type\030\002 \001(\0162%.com.wdbyte.pr" + + "otobuf.Person.PhoneTypeH\001\210\001\001B\t\n\007_numberB" + + "\007\n\005_type\"+\n\tPhoneType\022\n\n\006MOBILE\020\000\022\010\n\004HOM" + + "E\020\001\022\010\n\004WORK\020\002B\005\n\003_idB\007\n\005_nameB\010\n\006_email\"" + + ":\n\013AddressBook\022+\n\006people\030\001 \003(\0132\033.com.wdb" + + "yte.protobuf.PersonB-\n\026com.wdbyte.tool.p" + + "rotosB\021AddressBookProtosP\001b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_com_wdbyte_protobuf_Person_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_com_wdbyte_protobuf_Person_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_wdbyte_protobuf_Person_descriptor, + new java.lang.String[] { "Id", "Name", "Email", "Phones", "Id", "Name", "Email", }); + internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor = + internal_static_com_wdbyte_protobuf_Person_descriptor.getNestedTypes().get(0); + internal_static_com_wdbyte_protobuf_Person_PhoneNumber_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor, + new java.lang.String[] { "Number", "Type", "Number", "Type", }); + internal_static_com_wdbyte_protobuf_AddressBook_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_com_wdbyte_protobuf_AddressBook_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_wdbyte_protobuf_AddressBook_descriptor, + new java.lang.String[] { "People", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/Person.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/Person.java new file mode 100644 index 0000000..8ba2d40 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/Person.java @@ -0,0 +1,1942 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/addressbook.proto + +package com.wdbyte.tool.protos; + +/** + *

+ * 可选消息字段类型:bool int32 float double string
+ * 或者自定义消息类型,如下面的 PhoneNumber
+ * 修饰符:optional: 可选字段,
+ * 修饰符:repeated:可重复,如数组。
+ * 修饰符:required:必要字段,必须给值,否则会报错 RuntimeException,但是在 protobuf 版本 3 中被移除。
+ * 慎用 required,因为一旦被标记 requieds,以后将不能更改,否则可能会出问题。
+ * 
+ * + * Protobuf type {@code com.wdbyte.protobuf.Person} + */ +public final class Person extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.wdbyte.protobuf.Person) + PersonOrBuilder { +private static final long serialVersionUID = 0L; + // Use Person.newBuilder() to construct. + private Person(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Person() { + name_ = ""; + email_ = ""; + phones_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new Person(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.Person.class, com.wdbyte.tool.protos.Person.Builder.class); + } + + /** + * Protobuf enum {@code com.wdbyte.protobuf.Person.PhoneType} + */ + public enum PhoneType + implements com.google.protobuf.ProtocolMessageEnum { + /** + * MOBILE = 0; + */ + MOBILE(0), + /** + * HOME = 1; + */ + HOME(1), + /** + * WORK = 2; + */ + WORK(2), + UNRECOGNIZED(-1), + ; + + /** + * MOBILE = 0; + */ + public static final int MOBILE_VALUE = 0; + /** + * HOME = 1; + */ + public static final int HOME_VALUE = 1; + /** + * WORK = 2; + */ + public static final int WORK_VALUE = 2; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PhoneType valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static PhoneType forNumber(int value) { + switch (value) { + case 0: return MOBILE; + case 1: return HOME; + case 2: return WORK; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + PhoneType> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public PhoneType findValueByNumber(int number) { + return PhoneType.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return com.wdbyte.tool.protos.Person.getDescriptor().getEnumTypes().get(0); + } + + private static final PhoneType[] VALUES = values(); + + public static PhoneType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private PhoneType(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:com.wdbyte.protobuf.Person.PhoneType) + } + + public interface PhoneNumberOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.wdbyte.protobuf.Person.PhoneNumber) + com.google.protobuf.MessageOrBuilder { + + /** + * optional string number = 1; + * @return Whether the number field is set. + */ + boolean hasNumber(); + /** + * optional string number = 1; + * @return The number. + */ + java.lang.String getNumber(); + /** + * optional string number = 1; + * @return The bytes for number. + */ + com.google.protobuf.ByteString + getNumberBytes(); + + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return Whether the type field is set. + */ + boolean hasType(); + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The enum numeric value on the wire for type. + */ + int getTypeValue(); + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The type. + */ + com.wdbyte.tool.protos.Person.PhoneType getType(); + } + /** + * Protobuf type {@code com.wdbyte.protobuf.Person.PhoneNumber} + */ + public static final class PhoneNumber extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.wdbyte.protobuf.Person.PhoneNumber) + PhoneNumberOrBuilder { + private static final long serialVersionUID = 0L; + // Use PhoneNumber.newBuilder() to construct. + private PhoneNumber(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PhoneNumber() { + number_ = ""; + type_ = 0; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new PhoneNumber(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_PhoneNumber_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.Person.PhoneNumber.class, com.wdbyte.tool.protos.Person.PhoneNumber.Builder.class); + } + + private int bitField0_; + public static final int NUMBER_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object number_ = ""; + /** + * optional string number = 1; + * @return Whether the number field is set. + */ + @java.lang.Override + public boolean hasNumber() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string number = 1; + * @return The number. + */ + @java.lang.Override + public java.lang.String getNumber() { + java.lang.Object ref = number_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + number_ = s; + return s; + } + } + /** + * optional string number = 1; + * @return The bytes for number. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNumberBytes() { + java.lang.Object ref = number_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + number_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TYPE_FIELD_NUMBER = 2; + private int type_ = 0; + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return Whether the type field is set. + */ + @java.lang.Override public boolean hasType() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The enum numeric value on the wire for type. + */ + @java.lang.Override public int getTypeValue() { + return type_; + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The type. + */ + @java.lang.Override public com.wdbyte.tool.protos.Person.PhoneType getType() { + com.wdbyte.tool.protos.Person.PhoneType result = com.wdbyte.tool.protos.Person.PhoneType.forNumber(type_); + return result == null ? com.wdbyte.tool.protos.Person.PhoneType.UNRECOGNIZED : result; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, number_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeEnum(2, type_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, number_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, type_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.wdbyte.tool.protos.Person.PhoneNumber)) { + return super.equals(obj); + } + com.wdbyte.tool.protos.Person.PhoneNumber other = (com.wdbyte.tool.protos.Person.PhoneNumber) obj; + + if (hasNumber() != other.hasNumber()) return false; + if (hasNumber()) { + if (!getNumber() + .equals(other.getNumber())) return false; + } + if (hasType() != other.hasType()) return false; + if (hasType()) { + if (type_ != other.type_) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasNumber()) { + hash = (37 * hash) + NUMBER_FIELD_NUMBER; + hash = (53 * hash) + getNumber().hashCode(); + } + if (hasType()) { + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + type_; + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person.PhoneNumber parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.wdbyte.tool.protos.Person.PhoneNumber prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.wdbyte.protobuf.Person.PhoneNumber} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.wdbyte.protobuf.Person.PhoneNumber) + com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_PhoneNumber_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.Person.PhoneNumber.class, com.wdbyte.tool.protos.Person.PhoneNumber.Builder.class); + } + + // Construct using com.wdbyte.tool.protos.Person.PhoneNumber.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + number_ = ""; + type_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_PhoneNumber_descriptor; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumber getDefaultInstanceForType() { + return com.wdbyte.tool.protos.Person.PhoneNumber.getDefaultInstance(); + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumber build() { + com.wdbyte.tool.protos.Person.PhoneNumber result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumber buildPartial() { + com.wdbyte.tool.protos.Person.PhoneNumber result = new com.wdbyte.tool.protos.Person.PhoneNumber(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(com.wdbyte.tool.protos.Person.PhoneNumber result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.number_ = number_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.type_ = type_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.wdbyte.tool.protos.Person.PhoneNumber) { + return mergeFrom((com.wdbyte.tool.protos.Person.PhoneNumber)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.wdbyte.tool.protos.Person.PhoneNumber other) { + if (other == com.wdbyte.tool.protos.Person.PhoneNumber.getDefaultInstance()) return this; + if (other.hasNumber()) { + number_ = other.number_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasType()) { + setType(other.getType()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + number_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 16: { + type_ = input.readEnum(); + bitField0_ |= 0x00000002; + break; + } // case 16 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object number_ = ""; + /** + * optional string number = 1; + * @return Whether the number field is set. + */ + public boolean hasNumber() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string number = 1; + * @return The number. + */ + public java.lang.String getNumber() { + java.lang.Object ref = number_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + number_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string number = 1; + * @return The bytes for number. + */ + public com.google.protobuf.ByteString + getNumberBytes() { + java.lang.Object ref = number_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + number_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string number = 1; + * @param value The number to set. + * @return This builder for chaining. + */ + public Builder setNumber( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + number_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * optional string number = 1; + * @return This builder for chaining. + */ + public Builder clearNumber() { + number_ = getDefaultInstance().getNumber(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * optional string number = 1; + * @param value The bytes for number to set. + * @return This builder for chaining. + */ + public Builder setNumberBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + number_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private int type_ = 0; + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return Whether the type field is set. + */ + @java.lang.Override public boolean hasType() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The enum numeric value on the wire for type. + */ + @java.lang.Override public int getTypeValue() { + return type_; + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @param value The enum numeric value on the wire for type to set. + * @return This builder for chaining. + */ + public Builder setTypeValue(int value) { + type_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return The type. + */ + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneType getType() { + com.wdbyte.tool.protos.Person.PhoneType result = com.wdbyte.tool.protos.Person.PhoneType.forNumber(type_); + return result == null ? com.wdbyte.tool.protos.Person.PhoneType.UNRECOGNIZED : result; + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @param value The type to set. + * @return This builder for chaining. + */ + public Builder setType(com.wdbyte.tool.protos.Person.PhoneType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + type_ = value.getNumber(); + onChanged(); + return this; + } + /** + * optional .com.wdbyte.protobuf.Person.PhoneType type = 2; + * @return This builder for chaining. + */ + public Builder clearType() { + bitField0_ = (bitField0_ & ~0x00000002); + type_ = 0; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.wdbyte.protobuf.Person.PhoneNumber) + } + + // @@protoc_insertion_point(class_scope:com.wdbyte.protobuf.Person.PhoneNumber) + private static final com.wdbyte.tool.protos.Person.PhoneNumber DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.wdbyte.tool.protos.Person.PhoneNumber(); + } + + public static com.wdbyte.tool.protos.Person.PhoneNumber getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public PhoneNumber parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumber getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + private int id_ = 0; + /** + * optional int32 id = 1; + * @return Whether the id field is set. + */ + @java.lang.Override + public boolean hasId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + + public static final int NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + @java.lang.Override + public boolean hasName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string name = 2; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + * optional string name = 2; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int EMAIL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object email_ = ""; + /** + * optional string email = 3; + * @return Whether the email field is set. + */ + @java.lang.Override + public boolean hasEmail() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * optional string email = 3; + * @return The email. + */ + @java.lang.Override + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + email_ = s; + return s; + } + } + /** + * optional string email = 3; + * @return The bytes for email. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PHONES_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private java.util.List phones_; + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + @java.lang.Override + public java.util.List getPhonesList() { + return phones_; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + @java.lang.Override + public java.util.List + getPhonesOrBuilderList() { + return phones_; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + @java.lang.Override + public int getPhonesCount() { + return phones_.size(); + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumber getPhones(int index) { + return phones_.get(index); + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + @java.lang.Override + public com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index) { + return phones_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeInt32(1, id_); + } + if (((bitField0_ & 0x00000002) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); + } + if (((bitField0_ & 0x00000004) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); + } + for (int i = 0; i < phones_.size(); i++) { + output.writeMessage(4, phones_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, id_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); + } + for (int i = 0; i < phones_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, phones_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.wdbyte.tool.protos.Person)) { + return super.equals(obj); + } + com.wdbyte.tool.protos.Person other = (com.wdbyte.tool.protos.Person) obj; + + if (hasId() != other.hasId()) return false; + if (hasId()) { + if (getId() + != other.getId()) return false; + } + if (hasName() != other.hasName()) return false; + if (hasName()) { + if (!getName() + .equals(other.getName())) return false; + } + if (hasEmail() != other.hasEmail()) return false; + if (hasEmail()) { + if (!getEmail() + .equals(other.getEmail())) return false; + } + if (!getPhonesList() + .equals(other.getPhonesList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasId()) { + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + } + if (hasName()) { + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + } + if (hasEmail()) { + hash = (37 * hash) + EMAIL_FIELD_NUMBER; + hash = (53 * hash) + getEmail().hashCode(); + } + if (getPhonesCount() > 0) { + hash = (37 * hash) + PHONES_FIELD_NUMBER; + hash = (53 * hash) + getPhonesList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.wdbyte.tool.protos.Person parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.Person parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.Person parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.Person parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.wdbyte.tool.protos.Person prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * 可选消息字段类型:bool int32 float double string
+   * 或者自定义消息类型,如下面的 PhoneNumber
+   * 修饰符:optional: 可选字段,
+   * 修饰符:repeated:可重复,如数组。
+   * 修饰符:required:必要字段,必须给值,否则会报错 RuntimeException,但是在 protobuf 版本 3 中被移除。
+   * 慎用 required,因为一旦被标记 requieds,以后将不能更改,否则可能会出问题。
+   * 
+ * + * Protobuf type {@code com.wdbyte.protobuf.Person} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.wdbyte.protobuf.Person) + com.wdbyte.tool.protos.PersonOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.Person.class, com.wdbyte.tool.protos.Person.Builder.class); + } + + // Construct using com.wdbyte.tool.protos.Person.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = 0; + name_ = ""; + email_ = ""; + if (phonesBuilder_ == null) { + phones_ = java.util.Collections.emptyList(); + } else { + phones_ = null; + phonesBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.wdbyte.tool.protos.AddressBookProtos.internal_static_com_wdbyte_protobuf_Person_descriptor; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person getDefaultInstanceForType() { + return com.wdbyte.tool.protos.Person.getDefaultInstance(); + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person build() { + com.wdbyte.tool.protos.Person result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person buildPartial() { + com.wdbyte.tool.protos.Person result = new com.wdbyte.tool.protos.Person(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(com.wdbyte.tool.protos.Person result) { + if (phonesBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + phones_ = java.util.Collections.unmodifiableList(phones_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.phones_ = phones_; + } else { + result.phones_ = phonesBuilder_.build(); + } + } + + private void buildPartial0(com.wdbyte.tool.protos.Person result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.email_ = email_; + to_bitField0_ |= 0x00000004; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.wdbyte.tool.protos.Person) { + return mergeFrom((com.wdbyte.tool.protos.Person)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.wdbyte.tool.protos.Person other) { + if (other == com.wdbyte.tool.protos.Person.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + if (other.hasName()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasEmail()) { + email_ = other.email_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (phonesBuilder_ == null) { + if (!other.phones_.isEmpty()) { + if (phones_.isEmpty()) { + phones_ = other.phones_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensurePhonesIsMutable(); + phones_.addAll(other.phones_); + } + onChanged(); + } + } else { + if (!other.phones_.isEmpty()) { + if (phonesBuilder_.isEmpty()) { + phonesBuilder_.dispose(); + phonesBuilder_ = null; + phones_ = other.phones_; + bitField0_ = (bitField0_ & ~0x00000008); + phonesBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getPhonesFieldBuilder() : null; + } else { + phonesBuilder_.addAllMessages(other.phones_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + id_ = input.readInt32(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 18: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + email_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + com.wdbyte.tool.protos.Person.PhoneNumber m = + input.readMessage( + com.wdbyte.tool.protos.Person.PhoneNumber.parser(), + extensionRegistry); + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.add(m); + } else { + phonesBuilder_.addMessage(m); + } + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int id_ ; + /** + * optional int32 id = 1; + * @return Whether the id field is set. + */ + @java.lang.Override + public boolean hasId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + /** + * optional int32 id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * optional int32 id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string name = 2; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string name = 2; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string name = 2; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * optional string name = 2; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * optional string name = 2; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object email_ = ""; + /** + * optional string email = 3; + * @return Whether the email field is set. + */ + public boolean hasEmail() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * optional string email = 3; + * @return The email. + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + email_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string email = 3; + * @return The bytes for email. + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string email = 3; + * @param value The email to set. + * @return This builder for chaining. + */ + public Builder setEmail( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + email_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * optional string email = 3; + * @return This builder for chaining. + */ + public Builder clearEmail() { + email_ = getDefaultInstance().getEmail(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * optional string email = 3; + * @param value The bytes for email to set. + * @return This builder for chaining. + */ + public Builder setEmailBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + email_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.util.List phones_ = + java.util.Collections.emptyList(); + private void ensurePhonesIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + phones_ = new java.util.ArrayList(phones_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person.PhoneNumber, com.wdbyte.tool.protos.Person.PhoneNumber.Builder, com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder> phonesBuilder_; + + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List getPhonesList() { + if (phonesBuilder_ == null) { + return java.util.Collections.unmodifiableList(phones_); + } else { + return phonesBuilder_.getMessageList(); + } + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public int getPhonesCount() { + if (phonesBuilder_ == null) { + return phones_.size(); + } else { + return phonesBuilder_.getCount(); + } + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public com.wdbyte.tool.protos.Person.PhoneNumber getPhones(int index) { + if (phonesBuilder_ == null) { + return phones_.get(index); + } else { + return phonesBuilder_.getMessage(index); + } + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder setPhones( + int index, com.wdbyte.tool.protos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.set(index, value); + onChanged(); + } else { + phonesBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder setPhones( + int index, com.wdbyte.tool.protos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.set(index, builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones(com.wdbyte.tool.protos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.add(value); + onChanged(); + } else { + phonesBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + int index, com.wdbyte.tool.protos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.add(index, value); + onChanged(); + } else { + phonesBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + com.wdbyte.tool.protos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.add(builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + int index, com.wdbyte.tool.protos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.add(index, builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addAllPhones( + java.lang.Iterable values) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, phones_); + onChanged(); + } else { + phonesBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder clearPhones() { + if (phonesBuilder_ == null) { + phones_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + phonesBuilder_.clear(); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public Builder removePhones(int index) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.remove(index); + onChanged(); + } else { + phonesBuilder_.remove(index); + } + return this; + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public com.wdbyte.tool.protos.Person.PhoneNumber.Builder getPhonesBuilder( + int index) { + return getPhonesFieldBuilder().getBuilder(index); + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index) { + if (phonesBuilder_ == null) { + return phones_.get(index); } else { + return phonesBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List + getPhonesOrBuilderList() { + if (phonesBuilder_ != null) { + return phonesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(phones_); + } + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public com.wdbyte.tool.protos.Person.PhoneNumber.Builder addPhonesBuilder() { + return getPhonesFieldBuilder().addBuilder( + com.wdbyte.tool.protos.Person.PhoneNumber.getDefaultInstance()); + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public com.wdbyte.tool.protos.Person.PhoneNumber.Builder addPhonesBuilder( + int index) { + return getPhonesFieldBuilder().addBuilder( + index, com.wdbyte.tool.protos.Person.PhoneNumber.getDefaultInstance()); + } + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List + getPhonesBuilderList() { + return getPhonesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person.PhoneNumber, com.wdbyte.tool.protos.Person.PhoneNumber.Builder, com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder> + getPhonesFieldBuilder() { + if (phonesBuilder_ == null) { + phonesBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + com.wdbyte.tool.protos.Person.PhoneNumber, com.wdbyte.tool.protos.Person.PhoneNumber.Builder, com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder>( + phones_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + phones_ = null; + } + return phonesBuilder_; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.wdbyte.protobuf.Person) + } + + // @@protoc_insertion_point(class_scope:com.wdbyte.protobuf.Person) + private static final com.wdbyte.tool.protos.Person DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.wdbyte.tool.protos.Person(); + } + + public static com.wdbyte.tool.protos.Person getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Person parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.wdbyte.tool.protos.Person getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/PersonOrBuilder.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/PersonOrBuilder.java new file mode 100644 index 0000000..6cfb178 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/PersonOrBuilder.java @@ -0,0 +1,78 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/addressbook.proto + +package com.wdbyte.tool.protos; + +public interface PersonOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.wdbyte.protobuf.Person) + com.google.protobuf.MessageOrBuilder { + + /** + * optional int32 id = 1; + * @return Whether the id field is set. + */ + boolean hasId(); + /** + * optional int32 id = 1; + * @return The id. + */ + int getId(); + + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + boolean hasName(); + /** + * optional string name = 2; + * @return The name. + */ + java.lang.String getName(); + /** + * optional string name = 2; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * optional string email = 3; + * @return Whether the email field is set. + */ + boolean hasEmail(); + /** + * optional string email = 3; + * @return The email. + */ + java.lang.String getEmail(); + /** + * optional string email = 3; + * @return The bytes for email. + */ + com.google.protobuf.ByteString + getEmailBytes(); + + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + java.util.List + getPhonesList(); + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + com.wdbyte.tool.protos.Person.PhoneNumber getPhones(int index); + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + int getPhonesCount(); + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + java.util.List + getPhonesOrBuilderList(); + /** + * repeated .com.wdbyte.protobuf.Person.PhoneNumber phones = 4; + */ + com.wdbyte.tool.protos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index); +} diff --git a/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentOuterClass.java b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentOuterClass.java new file mode 100644 index 0000000..c8c29e2 --- /dev/null +++ b/tool-java-protobuf/src/main/java/com/wdbyte/tool/protos/StudentOuterClass.java @@ -0,0 +1,770 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: resources/student.proto + +package com.wdbyte.tool.protos; + +public final class StudentOuterClass { + private StudentOuterClass() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface StudentOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.wdbyte.protobuf.Student) + com.google.protobuf.MessageOrBuilder { + + /** + * optional string id = 1; + * @return Whether the id field is set. + */ + boolean hasId(); + /** + * optional string id = 1; + * @return The id. + */ + java.lang.String getId(); + /** + * optional string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + boolean hasName(); + /** + * optional string name = 2; + * @return The name. + */ + java.lang.String getName(); + /** + * optional string name = 2; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + } + /** + * Protobuf type {@code com.wdbyte.protobuf.Student} + */ + public static final class Student extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.wdbyte.protobuf.Student) + StudentOrBuilder { + private static final long serialVersionUID = 0L; + // Use Student.newBuilder() to construct. + private Student(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Student() { + id_ = ""; + name_ = ""; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new Student(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.StudentOuterClass.internal_static_com_wdbyte_protobuf_Student_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.StudentOuterClass.internal_static_com_wdbyte_protobuf_Student_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.StudentOuterClass.Student.class, com.wdbyte.tool.protos.StudentOuterClass.Student.Builder.class); + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + * optional string id = 1; + * @return Whether the id field is set. + */ + @java.lang.Override + public boolean hasId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string id = 1; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + * optional string id = 1; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + @java.lang.Override + public boolean hasName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string name = 2; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + * optional string name = 2; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, id_); + } + if (((bitField0_ & 0x00000002) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, id_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.wdbyte.tool.protos.StudentOuterClass.Student)) { + return super.equals(obj); + } + com.wdbyte.tool.protos.StudentOuterClass.Student other = (com.wdbyte.tool.protos.StudentOuterClass.Student) obj; + + if (hasId() != other.hasId()) return false; + if (hasId()) { + if (!getId() + .equals(other.getId())) return false; + } + if (hasName() != other.hasName()) return false; + if (hasName()) { + if (!getName() + .equals(other.getName())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasId()) { + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + } + if (hasName()) { + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.wdbyte.tool.protos.StudentOuterClass.Student parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.wdbyte.tool.protos.StudentOuterClass.Student prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.wdbyte.protobuf.Student} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.wdbyte.protobuf.Student) + com.wdbyte.tool.protos.StudentOuterClass.StudentOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.wdbyte.tool.protos.StudentOuterClass.internal_static_com_wdbyte_protobuf_Student_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.wdbyte.tool.protos.StudentOuterClass.internal_static_com_wdbyte_protobuf_Student_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.wdbyte.tool.protos.StudentOuterClass.Student.class, com.wdbyte.tool.protos.StudentOuterClass.Student.Builder.class); + } + + // Construct using com.wdbyte.tool.protos.StudentOuterClass.Student.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.wdbyte.tool.protos.StudentOuterClass.internal_static_com_wdbyte_protobuf_Student_descriptor; + } + + @java.lang.Override + public com.wdbyte.tool.protos.StudentOuterClass.Student getDefaultInstanceForType() { + return com.wdbyte.tool.protos.StudentOuterClass.Student.getDefaultInstance(); + } + + @java.lang.Override + public com.wdbyte.tool.protos.StudentOuterClass.Student build() { + com.wdbyte.tool.protos.StudentOuterClass.Student result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.wdbyte.tool.protos.StudentOuterClass.Student buildPartial() { + com.wdbyte.tool.protos.StudentOuterClass.Student result = new com.wdbyte.tool.protos.StudentOuterClass.Student(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(com.wdbyte.tool.protos.StudentOuterClass.Student result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.wdbyte.tool.protos.StudentOuterClass.Student) { + return mergeFrom((com.wdbyte.tool.protos.StudentOuterClass.Student)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.wdbyte.tool.protos.StudentOuterClass.Student other) { + if (other == com.wdbyte.tool.protos.StudentOuterClass.Student.getDefaultInstance()) return this; + if (other.hasId()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasName()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + * optional string id = 1; + * @return Whether the id field is set. + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string id = 1; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * optional string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * optional string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + * optional string name = 2; + * @return Whether the name field is set. + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string name = 2; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string name = 2; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string name = 2; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * optional string name = 2; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * optional string name = 2; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.wdbyte.protobuf.Student) + } + + // @@protoc_insertion_point(class_scope:com.wdbyte.protobuf.Student) + private static final com.wdbyte.tool.protos.StudentOuterClass.Student DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.wdbyte.tool.protos.StudentOuterClass.Student(); + } + + public static com.wdbyte.tool.protos.StudentOuterClass.Student getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Student parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.wdbyte.tool.protos.StudentOuterClass.Student getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_wdbyte_protobuf_Student_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_wdbyte_protobuf_Student_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\027resources/student.proto\022\023com.wdbyte.pr" + + "otobuf\"=\n\007Student\022\017\n\002id\030\001 \001(\tH\000\210\001\001\022\021\n\004na" + + "me\030\002 \001(\tH\001\210\001\001B\005\n\003_idB\007\n\005_nameB\032\n\026com.wdb" + + "yte.tool.protosP\000b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_com_wdbyte_protobuf_Student_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_com_wdbyte_protobuf_Student_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_wdbyte_protobuf_Student_descriptor, + new java.lang.String[] { "Id", "Name", "Id", "Name", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} From 84bf5cb17fc989942280ef40931ebfe49b5affee Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 7 Jun 2023 19:12:12 +0800 Subject: [PATCH 44/83] =?UTF-8?q?feat:=20-=20[ProcessBuilder=20API=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=95=99=E7=A8=8B](https://www.wdbyte.com/ja?= =?UTF-8?q?va/os/processbuilder/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-java-modules/core-java-os/.gitignore | 38 ++++++++++++++ core-java-modules/core-java-os/README.md | 6 +++ core-java-modules/core-java-os/pom.xml | 28 ++++++++++ .../java/com/wdbyte/os/process/ExecDemo.java | 18 +++++++ .../os/process/ProcessBuilderTest1.java | 52 +++++++++++++++++++ .../os/process/ProcessBuilderTest10.java | 42 +++++++++++++++ .../os/process/ProcessBuilderTest2.java | 32 ++++++++++++ .../os/process/ProcessBuilderTest3.java | 31 +++++++++++ .../os/process/ProcessBuilderTest4.java | 36 +++++++++++++ .../os/process/ProcessBuilderTest5.java | 40 ++++++++++++++ .../os/process/ProcessBuilderTest6.java | 23 ++++++++ .../os/process/ProcessBuilderTest7.java | 30 +++++++++++ .../os/process/ProcessBuilderTest8.java | 40 ++++++++++++++ .../os/process/ProcessBuilderTest9.java | 34 ++++++++++++ 14 files changed, 450 insertions(+) create mode 100644 core-java-modules/core-java-os/.gitignore create mode 100644 core-java-modules/core-java-os/README.md create mode 100644 core-java-modules/core-java-os/pom.xml create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ExecDemo.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest1.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest10.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest2.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest3.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest4.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest5.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest6.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest7.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest8.java create mode 100644 core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest9.java diff --git a/core-java-modules/core-java-os/.gitignore b/core-java-modules/core-java-os/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/core-java-modules/core-java-os/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/core-java-modules/core-java-os/README.md b/core-java-modules/core-java-os/README.md new file mode 100644 index 0000000..bfb1c8a --- /dev/null +++ b/core-java-modules/core-java-os/README.md @@ -0,0 +1,6 @@ +## core-java-os +当前模块包含操作系统操作相关代码 + +### 相关文章 + +- [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) \ No newline at end of file diff --git a/core-java-modules/core-java-os/pom.xml b/core-java-modules/core-java-os/pom.xml new file mode 100644 index 0000000..721644b --- /dev/null +++ b/core-java-modules/core-java-os/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.wdbyte.core-java-modules + core-java-modules + 1.0.0-SNAPSHOT + + + core-java-os + + + 17 + 17 + UTF-8 + + + + + commons-io + commons-io + 2.12.0 + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ExecDemo.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ExecDemo.java new file mode 100644 index 0000000..4b73eb6 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ExecDemo.java @@ -0,0 +1,18 @@ +package com.wdbyte.os.process; + +import java.io.IOException; + +/** + * @author https://www.wdbyte.com + */ +public class ExecDemo { + + public static void main(String[] args) throws InterruptedException { + System.out.println("开始处理数据..."); + for (int i = 0; i < 10; i++) { + Thread.sleep(1000); + System.out.println(i); + } + System.out.println("数据处理完毕"); + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest1.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest1.java new file mode 100644 index 0000000..919fb7f --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest1.java @@ -0,0 +1,52 @@ +package com.wdbyte.os.process; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.apache.commons.io.IOUtils; + +/** + * Process 输出Java 版本号 + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest1 { + + public static void main(String[] args) throws IOException, InterruptedException { + // 构建执行命令 + ProcessBuilder processBuilder = new ProcessBuilder("java","-version"); + // 重定向 ERROR 流(有些 JDK 版本 Java 命令通过 ERROR 流输出) + processBuilder.redirectErrorStream(true); + // 运行命令 java -version + Process process = processBuilder.start(); + // 过去PID + long pid = process.pid(); + // 一次性获取运行结果 + //String result = convertInputStreamToString(process.getInputStream()); + String result = IOUtils.toString(process.getInputStream()); + // 等到运行结束 + int exitCode = process.waitFor(); + + System.out.println("pid:" + pid); + System.out.println("result:" + result); + System.out.println("exitCode:" + exitCode); + } + + public static String convertInputStreamToString(InputStream inputStream) throws IOException { + StringBuilder sb = new StringBuilder(); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { + String line = null; + while ((line = bufferedReader.readLine()) != null) { + sb.append(line); + sb.append(System.lineSeparator()); + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + inputStream.close(); + } + return sb.toString(); + } + +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest10.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest10.java new file mode 100644 index 0000000..6c980d9 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest10.java @@ -0,0 +1,42 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +/** + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest10 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + processBuilder.command("java", "ExecDemo.java"); + // 把子线程 I/O 输出重定向当前进程 + processBuilder.inheritIO(); + + // 创建 CompletableFuture 对象 + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + try { + // 命令执行 + Process process = processBuilder.start(); + // 任务超时时间 + process.waitFor(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return null; + }); + + // 注册回调函数,处理异步等待的结果 + future.thenAccept(result -> { + System.out.println("进程执行结束"); + }); + System.out.println("主进程等待"); + Thread.sleep(20 * 1000); + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest2.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest2.java new file mode 100644 index 0000000..7075784 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest2.java @@ -0,0 +1,32 @@ +package com.wdbyte.os.process; + +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.io.IOUtils; + +/** + * 修改环境变量 + * + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest2 { + + public static void main(String[] args) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + Map environment = processBuilder.environment(); + environment.forEach((k, v) -> System.out.println(k + ":" + v)); + System.out.println("--------------"); + processBuilder.environment().put("my_website", "www.wdbyte.com"); + processBuilder.command("/bin/bash", "-c", "echo $my_website"); + + Process process = processBuilder.start(); + long pid = process.pid(); + String result = IOUtils.toString(process.getInputStream()); + int exitCode = process.waitFor(); + + System.out.println("pid:" + pid); + System.out.println("result:" + result); + System.out.println("exitCode:" + exitCode); + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest3.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest3.java new file mode 100644 index 0000000..3042923 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest3.java @@ -0,0 +1,31 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.IOUtils; + +/** + * 修改工作目录 + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest3 { + + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + processBuilder.command("/bin/bash", "-c", "pwd"); + Process process = processBuilder.start(); + + long pid = process.pid(); + String result = IOUtils.toString(process.getInputStream()); + int exitCode = process.waitFor(); + + System.out.println("pid:" + pid); + System.out.println("result:" + result); + System.out.println("exitCode:" + exitCode); + } + +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest4.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest4.java new file mode 100644 index 0000000..73d91be --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest4.java @@ -0,0 +1,36 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +/** + * 输出日志到指定文件 + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest4 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + processBuilder.command("/bin/bash", "-c", "ls -l"); + + File logFile = new File(BASE_DIR + "/process_log.txt"); + // 输出到日志文件 + processBuilder.redirectOutput(logFile); + // 追加日志到文件 + // processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(logFile)); + // 是否输出ERROR日志到文件 + processBuilder.redirectErrorStream(true); + + Process process = processBuilder.start(); + long pid = process.pid(); + int exitCode = process.waitFor(); + System.out.println("pid:" + pid); + System.out.println("exitCode:" + exitCode); + + // 读取日志 + Files.lines(logFile.toPath()).forEach(System.out::println); + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest5.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest5.java new file mode 100644 index 0000000..54c4752 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest5.java @@ -0,0 +1,40 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +/** + * 输出日志到指定文件 + * + * @author https://www.wdbyte.com + ** + */ +public class ProcessBuilderTest5 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + // 执行命令 xxx,命令不存在,会报 ERROR 日志 + processBuilder.command("/bin/bash", "-c", "xxx"); + + File infoLogFile = new File(BASE_DIR + "/process_log_info.txt"); + File errorLogFile = new File(BASE_DIR + "/process_log_error.txt"); + // 日志输出到文件 + processBuilder.redirectOutput(infoLogFile); + processBuilder.redirectError(errorLogFile); + Process process = processBuilder.start(); + + long pid = process.pid(); + int exitCode = process.waitFor(); + + System.out.println("pid:" + pid); + System.out.println("exitCode:" + exitCode); + + // 读取 ERROR 日志 + Files.lines(errorLogFile.toPath()).forEach(System.out::println); + } + +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest6.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest6.java new file mode 100644 index 0000000..8c71d3b --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest6.java @@ -0,0 +1,23 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; + +/** + * 子线程 I/O 重定向到当前线程 + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest6 { + public static void main(String[] args) throws IOException, InterruptedException { + + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File("./")); + processBuilder.command("/bin/bash", "-c", "ls -l"); + // 把子线程 I/O 输出重定向当前进程 + processBuilder.inheritIO(); + Process process = processBuilder.start(); + int exitCode = process.waitFor(); + System.out.println("exitCode:" + exitCode); + } + +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest7.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest7.java new file mode 100644 index 0000000..bbcf647 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest7.java @@ -0,0 +1,30 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; + +/** + * 运行一个 Java 程序 + * + * @author https://www.wdbyte.com + ** + */ +public class ProcessBuilderTest7 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + processBuilder.command("java", "ExecDemo.java"); + // 把子线程 I/O 输出重定向当前进程 + processBuilder.inheritIO(); + Process process = processBuilder.start(); + + long pid = process.pid(); + int exitCode = process.waitFor(); + + System.out.println("pid:" + pid); + System.out.println("exitCode:" + exitCode); + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest8.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest8.java new file mode 100644 index 0000000..d38fbec --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest8.java @@ -0,0 +1,40 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; +import java.lang.ProcessBuilder.Redirect; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; + +/** + * Java 9 中新增的管道操作 + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest8 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + ProcessBuilder ls = new ProcessBuilder("/bin/bash", "-c", "ls -l"); + ProcessBuilder wc = new ProcessBuilder("wc", "-l"); + // 追加日志到文件 + File pipeLineLogFile = getFile(BASE_DIR + "/pipe_line_log.txt"); + wc.redirectOutput(Redirect.appendTo(pipeLineLogFile)); + + List processes = ProcessBuilder.startPipeline(Arrays.asList(ls, wc)); + Process process = processes.get(processes.size() - 1); + + System.out.println("pid:" + process.pid()); + System.out.println("exitCode:" + process.waitFor()); + + Files.lines(pipeLineLogFile.toPath()).forEach(System.out::println); + } + + public static File getFile(String filePath) throws IOException { + File logFile = new File(filePath); + if (!logFile.exists()) { + logFile.createNewFile(); + } + return logFile; + } +} diff --git a/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest9.java b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest9.java new file mode 100644 index 0000000..6ee7b23 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process/ProcessBuilderTest9.java @@ -0,0 +1,34 @@ +package com.wdbyte.os.process; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * 运行一个 Java 程序 + * 等待一定时间后检查状态,未结束则直接杀死进程。 + * + * @author https://www.wdbyte.com + */ +public class ProcessBuilderTest9 { + private static String BASE_DIR = "/Users/darcy/git/JavaNotes/core-java-modules/core-java-os/src/main/java/com/wdbyte/os/process"; + + public static void main(String[] args) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.directory(new File(BASE_DIR)); + processBuilder.command("java", "ExecDemo.java"); + // 把子线程 I/O 输出重定向当前进程 + processBuilder.inheritIO(); + Process process = processBuilder.start(); + // 等待一定时间 + boolean waitFor = process.waitFor(3, TimeUnit.SECONDS); + System.out.println("waitFor:" + waitFor); + // 若未退出,杀死子进程 + if (!waitFor) { + process.destroyForcibly(); + process.waitFor(); + System.out.println("杀死进程:" + process); + } + + } +} From 2f49ceddbb88073fa747f3a1ba095e5b9629518d Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 7 Jun 2023 19:13:17 +0800 Subject: [PATCH 45/83] =?UTF-8?q?feat:=20-=20[ProcessBuilder=20API=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=95=99=E7=A8=8B](https://www.wdbyte.com/ja?= =?UTF-8?q?va/os/processbuilder/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ core-java-modules/README.md | 4 +++- core-java-modules/pom.xml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2af0b44..543e7f9 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ - [Java 枚举](https://www.wdbyte.com/java/enum/) - [Java 集合框架](https://www.wdbyte.com/java/collection/) +## Java 进阶 +- [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) + ## 🌿 SpringBoot 2.x 教程 使用 **Spring Boot** 可以快速的创建一个基于Spring 的、独立的、生产级的应用程序,并且可以直接运行。Spring Boot 采用习惯性配置,整合大量 Spring 组建和第三方库,让你只需要少量的修改就可以轻松上手。 diff --git a/core-java-modules/README.md b/core-java-modules/README.md index caefe7a..6a78bae 100644 --- a/core-java-modules/README.md +++ b/core-java-modules/README.md @@ -32,4 +32,6 @@ - [Java 中的 5 个代码性能提升技巧](https://www.wdbyte.com/java/code-5-tips.html) - [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) -- [Java 中拼接 String 的 N 种方式](https://www.wdbyte.com/java/string-concat.html) \ No newline at end of file +- [Java 中拼接 String 的 N 种方式](https://www.wdbyte.com/java/string-concat.html) + +- [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) \ No newline at end of file diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 55a59a8..bce3cb7 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -28,6 +28,7 @@ core-java-18 core-java-collect core-java-base + core-java-os \ No newline at end of file From 2fa4fa8cc3c5b1fb1db94998f22eb2386f9ef8c0 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 16 Jun 2023 20:54:11 +0800 Subject: [PATCH 46/83] =?UTF-8?q?feat:=20-=20[=E4=BD=BF=E7=94=A8=20JComman?= =?UTF-8?q?der=20=E8=A7=A3=E6=9E=90=E5=91=BD=E4=BB=A4=E8=A1=8C=E5=8F=82?= =?UTF-8?q?=E6=95=B0](https://www.wdbyte.com/tool/jcommander/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool-java-jcommander/.gitignore | 38 +++++++++++ tool-java-jcommander/README.md | 4 ++ tool-java-jcommander/pom.xml | 61 +++++++++++++++++ .../wdbyte/jcommander/FilePathConverter.java | 25 +++++++ .../java/com/wdbyte/jcommander/GitApp.java | 65 +++++++++++++++++++ .../com/wdbyte/jcommander/GitCommandAdd.java | 24 +++++++ .../wdbyte/jcommander/GitCommandCommit.java | 24 +++++++ .../wdbyte/jcommander/GitCommandOptions.java | 39 +++++++++++ .../java/com/wdbyte/jcommander/v1/GitApp.java | 20 ++++++ .../jcommander/v1/GitCommandOptions.java | 17 +++++ .../java/com/wdbyte/jcommander/v2/GitApp.java | 32 +++++++++ .../jcommander/v2/GitCommandOptions.java | 39 +++++++++++ .../java/com/wdbyte/jcommander/v3/GitApp.java | 32 +++++++++ .../jcommander/v3/GitCommandOptions.java | 40 ++++++++++++ .../jcommander/v3/UrlParameterValidator.java | 22 +++++++ .../java/com/wdbyte/jcommander/v4/GitApp.java | 38 +++++++++++ .../jcommander/v4/GitCommandCommit.java | 24 +++++++ .../jcommander/v4/GitCommandOptions.java | 40 ++++++++++++ .../jcommander/v4/UrlParameterValidator.java | 22 +++++++ .../java/com/wdbyte/jcommander/v5/GitApp.java | 45 +++++++++++++ .../wdbyte/jcommander/v5/GitCommandAdd.java | 23 +++++++ .../jcommander/v5/GitCommandCommit.java | 24 +++++++ .../jcommander/v5/GitCommandOptions.java | 40 ++++++++++++ .../jcommander/v5/UrlParameterValidator.java | 22 +++++++ 24 files changed, 760 insertions(+) create mode 100644 tool-java-jcommander/.gitignore create mode 100644 tool-java-jcommander/README.md create mode 100644 tool-java-jcommander/pom.xml create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java create mode 100644 tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java diff --git a/tool-java-jcommander/.gitignore b/tool-java-jcommander/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/tool-java-jcommander/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/tool-java-jcommander/README.md b/tool-java-jcommander/README.md new file mode 100644 index 0000000..d52fb9b --- /dev/null +++ b/tool-java-jcommander/README.md @@ -0,0 +1,4 @@ +## tool-java-jcommander + +### 相关文章 +- [使用 JCommander 解析命令行参数](https://www.wdbyte.com/tool/jcommander/) diff --git a/tool-java-jcommander/pom.xml b/tool-java-jcommander/pom.xml new file mode 100644 index 0000000..cb92565 --- /dev/null +++ b/tool-java-jcommander/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + com.wdbyte + parent-modules + 1.0.0-SNAPSHOT + + + tool-java-jcommander + + + 1.8 + 1.8 + UTF-8 + + + + + com.beust + jcommander + 1.82 + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + + + com.wdbyte.jcommander.GitApp + + + + + jar-with-dependencies + + + git-app + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java new file mode 100644 index 0000000..a451995 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java @@ -0,0 +1,25 @@ +package com.wdbyte.jcommander; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.ParameterException; + +/** + * + * @author niulang + * @date 2023/06/15 + */ +public class FilePathConverter implements IStringConverter { + + @Override + public Path convert(String filePath) { + Path path = Paths.get(filePath); + if (Files.exists(path)) { + return path; + } + throw new ParameterException(String.format("文件不存在,path:%s", filePath)); + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java new file mode 100644 index 0000000..a9ca569 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java @@ -0,0 +1,65 @@ +package com.wdbyte.jcommander; + +import java.nio.file.Path; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; +import org.apache.commons.lang3.StringUtils; + +/** + * Git APP + * + * @author niulang + * @date 2023/06/07 + */ +public class GitApp { + private static GitCommandOptions commandOptions = new GitCommandOptions(); + private static GitCommandCommit commandCommit = new GitCommandCommit(); + private static GitCommandAdd commandAdd = new GitCommandAdd(); + private static JCommander commander; + + static { + commander = JCommander.newBuilder() + .programName("GitApp") + .addObject(commandOptions) + .addCommand(commandAdd) + .addCommand(commandCommit) + .build(); + } + + public static void main(String[] args) { + if (args.length == 0) { + commander.usage(); + return; + } + try { + commander.parse(args); + if (commandOptions.isHelp()) { + commander.usage(); + return; + } + if (commandOptions.isVersion()) { + System.out.println("git version 2.24.3 (Apple Git-128)"); + } + if (commandOptions.getCloneUrl() != null) { + System.out.printf("开始克隆远程仓库数据:%s%n", commandOptions.getCloneUrl()); + return; + } + String parsedCommand = commander.getParsedCommand(); + if (GitCommandCommit.COMMAND.equals(parsedCommand)) { + System.out.printf("提交暂存的文件并注释:%s%n", commandCommit.getComment()); + return; + } + if (GitCommandAdd.COMMAND.equals(parsedCommand)) { + for (Path file : commandAdd.getFiles()) { + System.out.printf("暂存文件:%s%n", file); + } + return; + } + } catch (ParameterException e) { + System.err.println(e.getMessage()); + commander.usage(); + } + } + +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java new file mode 100644 index 0000000..92d733e --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java @@ -0,0 +1,24 @@ +package com.wdbyte.jcommander; + +import java.nio.file.Path; +import java.util.List; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; + +/** + * git add file1 file2 + * + * @author niulang + * @date 2023/06/07 + */ +@Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ") +public class GitCommandAdd { + public static final String COMMAND = "add"; + @Parameter(description = "暂存文件列表", converter = FilePathConverter.class) + private List files; + + public List getFiles() { + return files; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java new file mode 100644 index 0000000..7758197 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java @@ -0,0 +1,24 @@ +package com.wdbyte.jcommander; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; + +/** + * git commit -m "desc" + * @author niulang + * @date 2023/06/07 + */ +@Parameters(commandDescription = "提交文件", commandNames = "commit") +public class GitCommandCommit { + public static final String COMMAND = "commit"; + + @Parameter(names = {"-comment", "-m"}, + description = "请输入注释", + arity = 1, + required = true) + private String comment; + + public String getComment() { + return comment; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java new file mode 100644 index 0000000..a845e72 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java @@ -0,0 +1,39 @@ +package com.wdbyte.jcommander; + +import java.net.URL; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.converters.URLConverter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + + @Parameter(names = {"help", "-help", "-h"}, + description = "查看帮助信息", + help = true) + private boolean help; + + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据", + arity = 1) + private String cloneUrl; + + @Parameter(names = {"version", "-version", "-v"}, + description = "显示当前版本号") + private boolean version = false; + + public boolean isHelp() { + return help; + } + + public boolean isVersion() { + return version; + } + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java new file mode 100644 index 0000000..1191d6f --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java @@ -0,0 +1,20 @@ +package com.wdbyte.jcommander.v1; + +import com.beust.jcommander.JCommander; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class GitApp { + + public static void main(String[] args) { + args = new String[]{"clone","http://www.wdbyte.com/test.git"}; + GitCommandOptions gitCommandOptions = new GitCommandOptions(); + JCommander commander = JCommander.newBuilder() + .addObject(gitCommandOptions) + .build(); + commander.parse(args); + System.out.println("clone " + gitCommandOptions.getCloneUrl()); + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java new file mode 100644 index 0000000..5f166b7 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java @@ -0,0 +1,17 @@ +package com.wdbyte.jcommander.v1; + +import com.beust.jcommander.Parameter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据") + private String cloneUrl; + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java new file mode 100644 index 0000000..e669602 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java @@ -0,0 +1,32 @@ +package com.wdbyte.jcommander.v2; + +import com.beust.jcommander.JCommander; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class GitApp { + + public static void main(String[] args) { + //args = new String[] {"clone", "http://www.wdbyte.com/test.git"}; + GitCommandOptions gitCommandOptions = new GitCommandOptions(); + JCommander commander = JCommander.newBuilder() + .programName("git-app") + .addObject(gitCommandOptions) + .build(); + commander.parse(args); + // 打印帮助信息 + if (gitCommandOptions.isHelp()) { + commander.usage(); + return; + } + if (gitCommandOptions.isVersion()) { + System.out.println("git version 2.24.3 (Apple Git-128)"); + return; + } + if (gitCommandOptions.getCloneUrl() != null) { + System.out.println("clone " + gitCommandOptions.getCloneUrl()); + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java new file mode 100644 index 0000000..50837be --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java @@ -0,0 +1,39 @@ +package com.wdbyte.jcommander.v2; + +import com.beust.jcommander.Parameter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + + @Parameter(names = {"help", "-help", "-h"}, + description = "查看帮助信息", + order = 1, + help = true) + private boolean help; + + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据", + order = 3, + arity = 1) + private String cloneUrl; + + @Parameter(names = {"version", "-version", "-v"}, + description = "显示当前版本号", + order = 2) + private boolean version = false; + + public boolean isHelp() { + return help; + } + + public boolean isVersion() { + return version; + } + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java new file mode 100644 index 0000000..8d1c7fd --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java @@ -0,0 +1,32 @@ +package com.wdbyte.jcommander.v3; + +import com.beust.jcommander.JCommander; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class GitApp { + + public static void main(String[] args) { + //args = new String[] {"clone", "ht2tp://www.wdbyte.com/test.git"}; + GitCommandOptions gitCommandOptions = new GitCommandOptions(); + JCommander commander = JCommander.newBuilder() + .programName("git-app") + .addObject(gitCommandOptions) + .build(); + commander.parse(args); + // 打印帮助信息 + if (gitCommandOptions.isHelp()) { + commander.usage(); + return; + } + if (gitCommandOptions.isVersion()) { + System.out.println("git version 2.24.3 (Apple Git-128)"); + return; + } + if (gitCommandOptions.getCloneUrl() != null) { + System.out.println("clone " + gitCommandOptions.getCloneUrl()); + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java new file mode 100644 index 0000000..fb0dc1b --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java @@ -0,0 +1,40 @@ +package com.wdbyte.jcommander.v3; + +import com.beust.jcommander.Parameter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + + @Parameter(names = {"help", "-help", "-h"}, + description = "查看帮助信息", + order = 1, + help = true) + private boolean help; + + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据", + validateWith = UrlParameterValidator.class, + order = 3, + arity = 1) + private String cloneUrl; + + @Parameter(names = {"version", "-version", "-v"}, + description = "显示当前版本号", + order = 2) + private boolean version = false; + + public boolean isHelp() { + return help; + } + + public boolean isVersion() { + return version; + } + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java new file mode 100644 index 0000000..4da9108 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java @@ -0,0 +1,22 @@ +package com.wdbyte.jcommander.v3; + +import java.net.MalformedURLException; +import java.net.URL; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class UrlParameterValidator implements IParameterValidator { + @Override + public void validate(String key, String value) throws ParameterException { + try { + new URL(value); + } catch (MalformedURLException e) { + throw new ParameterException("参数 " + key + " 的值必须是 URL 格式"); + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java new file mode 100644 index 0000000..1842cee --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java @@ -0,0 +1,38 @@ +package com.wdbyte.jcommander.v4; + +import com.beust.jcommander.JCommander; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class GitApp { + + public static void main(String[] args) { + //args = new String[] {"clone", "ht2tp://www.wdbyte.com/test.git"}; + GitCommandOptions gitCommandOptions = new GitCommandOptions(); + GitCommandCommit commandCommit = new GitCommandCommit(); + JCommander commander = JCommander.newBuilder() + .programName("git-app") + .addObject(gitCommandOptions) + .addCommand(commandCommit) + .build(); + commander.parse(args); + // 打印帮助信息 + if (gitCommandOptions.isHelp()) { + commander.usage(); + return; + } + if (gitCommandOptions.isVersion()) { + System.out.println("git version 2.24.3 (Apple Git-128)"); + return; + } + if (gitCommandOptions.getCloneUrl() != null) { + System.out.println("clone " + gitCommandOptions.getCloneUrl()); + } + String parsedCommand = commander.getParsedCommand(); + if ("commit".equals(parsedCommand)) { + System.out.println(commandCommit.getComment()); + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java new file mode 100644 index 0000000..7dd1c04 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java @@ -0,0 +1,24 @@ +package com.wdbyte.jcommander.v4; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; + +/** + * git commit -m "desc" + * @author niulang + * @date 2023/06/07 + */ +@Parameters(commandDescription = "提交文件", commandNames = "commit") +public class GitCommandCommit { + public static final String COMMAND = "commit"; + + @Parameter(names = {"-comment", "-m"}, + description = "请输入注释", + arity = 1, + required = true) + private String comment; + + public String getComment() { + return comment; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java new file mode 100644 index 0000000..86c02db --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java @@ -0,0 +1,40 @@ +package com.wdbyte.jcommander.v4; + +import com.beust.jcommander.Parameter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + + @Parameter(names = {"help", "-help", "-h"}, + description = "查看帮助信息", + order = 1, + help = true) + private boolean help; + + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据", + validateWith = UrlParameterValidator.class, + order = 3, + arity = 1) + private String cloneUrl; + + @Parameter(names = {"version", "-version", "-v"}, + description = "显示当前版本号", + order = 2) + private boolean version = false; + + public boolean isHelp() { + return help; + } + + public boolean isVersion() { + return version; + } + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java new file mode 100644 index 0000000..338e7c2 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java @@ -0,0 +1,22 @@ +package com.wdbyte.jcommander.v4; + +import java.net.MalformedURLException; +import java.net.URL; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class UrlParameterValidator implements IParameterValidator { + @Override + public void validate(String key, String value) throws ParameterException { + try { + new URL(value); + } catch (MalformedURLException e) { + throw new ParameterException("参数 " + key + " 的值必须是 URL 格式"); + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java new file mode 100644 index 0000000..7ecbc54 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java @@ -0,0 +1,45 @@ +package com.wdbyte.jcommander.v5; + +import com.beust.jcommander.JCommander; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class GitApp { + + public static void main(String[] args) { + //args = new String[] {"clone", "ht2tp://www.wdbyte.com/test.git"}; + GitCommandOptions gitCommandOptions = new GitCommandOptions(); + GitCommandCommit commandCommit = new GitCommandCommit(); + GitCommandAdd commandAdd = new GitCommandAdd(); + JCommander commander = JCommander.newBuilder() + .programName("git-app") + .addObject(gitCommandOptions) + .addCommand(commandCommit) + .addCommand(commandAdd) + .build(); + commander.parse(args); + // 打印帮助信息 + if (gitCommandOptions.isHelp()) { + commander.usage(); + return; + } + if (gitCommandOptions.isVersion()) { + System.out.println("git version 2.24.3 (Apple Git-128)"); + return; + } + if (gitCommandOptions.getCloneUrl() != null) { + System.out.println("clone " + gitCommandOptions.getCloneUrl()); + } + String parsedCommand = commander.getParsedCommand(); + if ("commit".equals(parsedCommand)) { + System.out.println(commandCommit.getComment()); + } + if ("add".equals(parsedCommand)) { + for (String file : commandAdd.getFiles()) { + System.out.println("暂存文件:" + file); + } + } + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java new file mode 100644 index 0000000..9e78ce6 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java @@ -0,0 +1,23 @@ +package com.wdbyte.jcommander.v5; + +import java.util.List; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; + +/** + * git add file1 file2 + * + * @author niulang + * @date 2023/06/07 + */ +@Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ") +public class GitCommandAdd { + public static final String COMMAND = "add"; + @Parameter(description = "暂存文件列表") + private List files; + + public List getFiles() { + return files; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java new file mode 100644 index 0000000..7a5f321 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java @@ -0,0 +1,24 @@ +package com.wdbyte.jcommander.v5; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; + +/** + * git commit -m "desc" + * @author niulang + * @date 2023/06/07 + */ +@Parameters(commandDescription = "提交文件", commandNames = "commit") +public class GitCommandCommit { + public static final String COMMAND = "commit"; + + @Parameter(names = {"-comment", "-m"}, + description = "请输入注释", + arity = 1, + required = true) + private String comment; + + public String getComment() { + return comment; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java new file mode 100644 index 0000000..238aa39 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java @@ -0,0 +1,40 @@ +package com.wdbyte.jcommander.v5; + +import com.beust.jcommander.Parameter; + +/** + * @author niulang + * @date 2023/06/07 + */ +public class GitCommandOptions { + + @Parameter(names = {"help", "-help", "-h"}, + description = "查看帮助信息", + order = 1, + help = true) + private boolean help; + + @Parameter(names = {"clone"}, + description = "克隆远程仓库数据", + validateWith = UrlParameterValidator.class, + order = 3, + arity = 1) + private String cloneUrl; + + @Parameter(names = {"version", "-version", "-v"}, + description = "显示当前版本号", + order = 2) + private boolean version = false; + + public boolean isHelp() { + return help; + } + + public boolean isVersion() { + return version; + } + + public String getCloneUrl() { + return cloneUrl; + } +} diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java new file mode 100644 index 0000000..3527e80 --- /dev/null +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java @@ -0,0 +1,22 @@ +package com.wdbyte.jcommander.v5; + +import java.net.MalformedURLException; +import java.net.URL; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +/** + * @author niulang + * @date 2023/06/15 + */ +public class UrlParameterValidator implements IParameterValidator { + @Override + public void validate(String key, String value) throws ParameterException { + try { + new URL(value); + } catch (MalformedURLException e) { + throw new ParameterException("参数 " + key + " 的值必须是 URL 格式"); + } + } +} From a6aa6a40d9a7e5d13c96152d2bf6d702df4bf124 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Fri, 16 Jun 2023 20:54:35 +0800 Subject: [PATCH 47/83] =?UTF-8?q?feat:=20-=20[=E4=BD=BF=E7=94=A8=20JComman?= =?UTF-8?q?der=20=E8=A7=A3=E6=9E=90=E5=91=BD=E4=BB=A4=E8=A1=8C=E5=8F=82?= =?UTF-8?q?=E6=95=B0](https://www.wdbyte.com/tool/jcommander/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ pom.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 543e7f9..3bbe625 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,8 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 >出处:孔子《论语》 一款好用的工具,不仅可以装X,更可以让你事半功倍,准时下班。 + +- [使用 JCommander 解析命令行参数](https://www.wdbyte.com/tool/jcommander/) - [Protobuf 教程](https://www.wdbyte.com/tool/protobuf/) - [Apache HttpClient 5 使用详细教程](https://www.wdbyte.com/tool/httpclient5.html) - [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) diff --git a/pom.xml b/pom.xml index 2452dc4..eb573fb 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ tool-java-apache-common tool-java-hotcode tool-java-protobuf + tool-java-jcommander parent-modules Parent for all java modules From 51e6cef3db5ed1eefb49b31e54a8554a986e9ac9 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Mon, 19 Jun 2023 16:17:48 +0800 Subject: [PATCH 48/83] =?UTF-8?q?docs:=20=E6=B3=A8=E9=87=8A=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E6=94=B9=E6=88=90=E7=BD=91=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/wdbyte/jcommander/FilePathConverter.java | 2 +- .../src/main/java/com/wdbyte/jcommander/GitApp.java | 2 +- .../src/main/java/com/wdbyte/jcommander/GitCommandAdd.java | 2 +- .../src/main/java/com/wdbyte/jcommander/GitCommandCommit.java | 2 +- .../src/main/java/com/wdbyte/jcommander/GitCommandOptions.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v1/GitApp.java | 2 +- .../main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v2/GitApp.java | 2 +- .../main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v3/GitApp.java | 2 +- .../main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java | 2 +- .../java/com/wdbyte/jcommander/v3/UrlParameterValidator.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v4/GitApp.java | 2 +- .../main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java | 2 +- .../main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java | 2 +- .../java/com/wdbyte/jcommander/v4/UrlParameterValidator.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v5/GitApp.java | 2 +- .../src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java | 2 +- .../main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java | 2 +- .../main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java | 2 +- .../java/com/wdbyte/jcommander/v5/UrlParameterValidator.java | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java index a451995..bf88b62 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/FilePathConverter.java @@ -9,7 +9,7 @@ /** * - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class FilePathConverter implements IStringConverter { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java index a9ca569..20203c7 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitApp.java @@ -9,7 +9,7 @@ /** * Git APP * - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java index 92d733e..7fc9ff1 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandAdd.java @@ -9,7 +9,7 @@ /** * git add file1 file2 * - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ @Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ") diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java index 7758197..6710a63 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandCommit.java @@ -5,7 +5,7 @@ /** * git commit -m "desc" - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ @Parameters(commandDescription = "提交文件", commandNames = "commit") diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java index a845e72..f9cc388 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/GitCommandOptions.java @@ -6,7 +6,7 @@ import com.beust.jcommander.converters.URLConverter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java index 1191d6f..f03e882 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitApp.java @@ -3,7 +3,7 @@ import com.beust.jcommander.JCommander; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java index 5f166b7..8e986de 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v1/GitCommandOptions.java @@ -3,7 +3,7 @@ import com.beust.jcommander.Parameter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java index e669602..6271d88 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitApp.java @@ -3,7 +3,7 @@ import com.beust.jcommander.JCommander; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java index 50837be..cff5d4d 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v2/GitCommandOptions.java @@ -3,7 +3,7 @@ import com.beust.jcommander.Parameter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java index 8d1c7fd..9350713 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitApp.java @@ -3,7 +3,7 @@ import com.beust.jcommander.JCommander; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java index fb0dc1b..fd75160 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/GitCommandOptions.java @@ -3,7 +3,7 @@ import com.beust.jcommander.Parameter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java index 4da9108..6ff98fa 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v3/UrlParameterValidator.java @@ -7,7 +7,7 @@ import com.beust.jcommander.ParameterException; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class UrlParameterValidator implements IParameterValidator { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java index 1842cee..33d3dfb 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitApp.java @@ -3,7 +3,7 @@ import com.beust.jcommander.JCommander; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java index 7dd1c04..934c723 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandCommit.java @@ -5,7 +5,7 @@ /** * git commit -m "desc" - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ @Parameters(commandDescription = "提交文件", commandNames = "commit") diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java index 86c02db..32dcc40 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/GitCommandOptions.java @@ -3,7 +3,7 @@ import com.beust.jcommander.Parameter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java index 338e7c2..817bb7f 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v4/UrlParameterValidator.java @@ -7,7 +7,7 @@ import com.beust.jcommander.ParameterException; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class UrlParameterValidator implements IParameterValidator { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java index 7ecbc54..a7ee225 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitApp.java @@ -3,7 +3,7 @@ import com.beust.jcommander.JCommander; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class GitApp { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java index 9e78ce6..e1846f3 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandAdd.java @@ -8,7 +8,7 @@ /** * git add file1 file2 * - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ @Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ") diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java index 7a5f321..6b76c65 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandCommit.java @@ -5,7 +5,7 @@ /** * git commit -m "desc" - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ @Parameters(commandDescription = "提交文件", commandNames = "commit") diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java index 238aa39..0f3b3ee 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/GitCommandOptions.java @@ -3,7 +3,7 @@ import com.beust.jcommander.Parameter; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/07 */ public class GitCommandOptions { diff --git a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java index 3527e80..cda4988 100644 --- a/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java +++ b/tool-java-jcommander/src/main/java/com/wdbyte/jcommander/v5/UrlParameterValidator.java @@ -7,7 +7,7 @@ import com.beust.jcommander.ParameterException; /** - * @author niulang + * @author https://www.wdbyte.com * @date 2023/06/15 */ public class UrlParameterValidator implements IParameterValidator { From 1f416f76fa68b92fe1c52396951888c77ba8fc7b Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 19 Jun 2023 22:44:07 +0800 Subject: [PATCH 49/83] =?UTF-8?q?feat:=20=E6=8E=A5=E5=8F=A3=E5=92=8C?= =?UTF-8?q?=E6=8A=BD=E8=B1=A1=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/wdbyte/oop/abs/AbsPerson2.java | 13 +++++++++++++ .../com/wdbyte/oop/interfac/InterfacePerson.java | 9 +++++++++ 2 files changed, 22 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/InterfacePerson.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson2.java new file mode 100644 index 0000000..2617065 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/abs/AbsPerson2.java @@ -0,0 +1,13 @@ +package com.wdbyte.oop.abs; + +/** + * @author https://www.wdbyte.com + */ +public abstract class AbsPerson2 { + + public void sayHello() { + System.out.println("say hello"); + } + + public abstract void sleep(); +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/InterfacePerson.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/InterfacePerson.java new file mode 100644 index 0000000..0cd8562 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/oop/interfac/InterfacePerson.java @@ -0,0 +1,9 @@ +package com.wdbyte.oop.interfac; + +public interface InterfacePerson { + default void sayHello(){ + System.out.println("say hello"); + } + + void sleep(); +} From 7c506d3ddaba2cca49bfa047b5e6629353359ffb Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 21 Jun 2023 17:12:06 +0800 Subject: [PATCH 50/83] =?UTF-8?q?feat:=20Java=20=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/wdbyte/comment/JavaDocDemo.java | 41 ++ .../java/com/wdbyte/comment/WelcomeMain.java | 51 ++ .../wdbyte/comment/doc/allclasses-frame.html | 19 + .../comment/doc/allclasses-noframe.html | 19 + .../doc/com/wdbyte/comment/JavaDocDemo.html | 310 ++++++++++ .../doc/com/wdbyte/comment/package-frame.html | 20 + .../com/wdbyte/comment/package-summary.html | 140 +++++ .../doc/com/wdbyte/comment/package-tree.html | 129 ++++ .../wdbyte/comment/doc/constant-values.html | 120 ++++ .../wdbyte/comment/doc/deprecated-list.html | 120 ++++ .../java/com/wdbyte/comment/doc/help-doc.html | 217 +++++++ .../com/wdbyte/comment/doc/index-all.html | 157 +++++ .../java/com/wdbyte/comment/doc/index.html | 72 +++ .../com/wdbyte/comment/doc/overview-tree.html | 133 ++++ .../java/com/wdbyte/comment/doc/package-list | 1 + .../java/com/wdbyte/comment/doc/script.js | 30 + .../com/wdbyte/comment/doc/stylesheet.css | 574 ++++++++++++++++++ 17 files changed, 2153 insertions(+) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/JavaDocDemo.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/WelcomeMain.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-frame.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-noframe.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/JavaDocDemo.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-frame.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-summary.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-tree.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/constant-values.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/deprecated-list.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/help-doc.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index-all.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/overview-tree.html create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/package-list create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/script.js create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/stylesheet.css diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/JavaDocDemo.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/JavaDocDemo.java new file mode 100644 index 0000000..0625952 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/JavaDocDemo.java @@ -0,0 +1,41 @@ +package com.wdbyte.comment; + +/** + * 输出一个名称和地域的问候信息。 + * 如:Hello 朋友,welcome to 杭州 + * 主要实现方法是 {@link JavaDocDemo#getMessage(String, String)} + * + * @author wdbyte + * @version 1.0 + * @see com.wdbyte.comment.JavaDocDemo#getMessage(String, String) + * @since 1.0 + */ +public class JavaDocDemo { + + /** + * 启动应用程序 + * + * @param args - 应用启动参数 + */ + public static void main(String[] args) { + System.out.println(getMessage("朋友", "杭州")); + } + + /** + * 返回一个欢迎信息。 + * @see Java Dcoumentation + * @param name - 访问者名称 + * @param region - 地域信息 + * @return - 欢迎信息语句 + */ + public static String getMessage(String name, String region) { + StringBuilder builder = new StringBuilder(); + builder.append("Hello "); + builder.append(name); + builder.append(", Welcome to "); + builder.append(region); + builder.append(" !!"); + return builder.toString(); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/WelcomeMain.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/WelcomeMain.java new file mode 100644 index 0000000..153bed9 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/WelcomeMain.java @@ -0,0 +1,51 @@ +package com.wdbyte.comment; + +/** + * 输出一个名称和地域的问候信息。 + * 如:Hello 朋友,welcome to 杭州 + * + * @author https://www.wdbyte.com + */ +public class WelcomeMain { + + /** + * 启动应用程序 + * + * @param args - 应用启动参数 + */ + public static void main(String[] args) { + System.out.println(getMessage("朋友", "杭州")); + } + + /** + * 返回一个欢迎信息。 + * + * @param name - 访问者名称 + * @param region - 地域信息 + * @return - 欢迎信息 + */ + public static String getMessage(String name, String region) { + StringBuilder builder = new StringBuilder(); + builder.append("Hello "); + builder.append(name); + builder.append(", Welcome to "); + builder.append(region); + builder.append(" !!"); + return builder.toString(); + } + + + /** + * 计算两数之和 + * @param x 数字1 + * @param y 数字2 + * @return + */ + public int add(int x, int y) { + /* + * 计算两数之和 + */ + int s = x + y; + return s; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-frame.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-frame.html new file mode 100644 index 0000000..d1e5c11 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-frame.html @@ -0,0 +1,19 @@ + + + + + +所有类 + + + + + +

所有类

+
+ +
+ + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-noframe.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-noframe.html new file mode 100644 index 0000000..4e6a6c4 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/allclasses-noframe.html @@ -0,0 +1,19 @@ + + + + + +所有类 + + + + + +

所有类

+
+ +
+ + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/JavaDocDemo.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/JavaDocDemo.html new file mode 100644 index 0000000..12f6a1c --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/JavaDocDemo.html @@ -0,0 +1,310 @@ + + + + + +JavaDocDemo + + + + + + + + + + + + +
+
com.wdbyte.comment
+

类 JavaDocDemo

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.wdbyte.comment.JavaDocDemo
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public class JavaDocDemo
    +extends java.lang.Object
    +
    输出一个名称和地域的问候信息。 + 如:Hello 朋友,welcome to 杭州 + 主要实现方法是 getMessage(String, String)
    +
    +
    从以下版本开始:
    +
    1.0
    +
    另请参阅:
    +
    getMessage(String, String)
    +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      构造器概要

      + + + + + + + + +
      构造器 
      构造器和说明
      JavaDocDemo() 
      +
    • +
    + +
      +
    • + + +

      方法概要

      + + + + + + + + + + + + + + +
      所有方法 静态方法 具体方法 
      限定符和类型方法和说明
      static java.lang.StringgetMessage(java.lang.String name, + java.lang.String region) +
      返回一个欢迎信息。
      +
      static voidmain(java.lang.String[] args) +
      启动应用程序
      +
      +
        +
      • + + +

        从类继承的方法 java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      构造器详细资料

      + + + +
        +
      • +

        JavaDocDemo

        +
        public JavaDocDemo()
        +
      • +
      +
    • +
    + +
      +
    • + + +

      方法详细资料

      + + + +
        +
      • +

        main

        +
        public static void main(java.lang.String[] args)
        +
        启动应用程序
        +
        +
        参数:
        +
        args - - 应用启动参数
        +
        +
      • +
      + + + +
        +
      • +

        getMessage

        +
        public static java.lang.String getMessage(java.lang.String name,
        +                                          java.lang.String region)
        +
        返回一个欢迎信息。
        +
        +
        参数:
        +
        name - - 访问者名称
        +
        region - - 地域信息
        +
        返回:
        +
        - 欢迎信息语句
        +
        另请参阅:
        +
        Java Dcoumentation
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-frame.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-frame.html new file mode 100644 index 0000000..cafb6ef --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-frame.html @@ -0,0 +1,20 @@ + + + + + +com.wdbyte.comment + + + + + +

com.wdbyte.comment

+
+

+ +
+ + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-summary.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-summary.html new file mode 100644 index 0000000..14848c8 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-summary.html @@ -0,0 +1,140 @@ + + + + + +com.wdbyte.comment + + + + + + + + + + + +
+

程序包 com.wdbyte.comment

+
+
+
    +
  • + + + + + + + + + + + + +
    类概要 
    说明
    JavaDocDemo +
    输出一个名称和地域的问候信息。
    +
    +
  • +
+
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-tree.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-tree.html new file mode 100644 index 0000000..dad782d --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/com/wdbyte/comment/package-tree.html @@ -0,0 +1,129 @@ + + + + + +com.wdbyte.comment 类分层结构 + + + + + + + + + + + +
+

程序包com.wdbyte.comment的分层结构

+
+
+

类分层结构

+
    +
  • java.lang.Object + +
  • +
+
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/constant-values.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/constant-values.html new file mode 100644 index 0000000..be8d957 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/constant-values.html @@ -0,0 +1,120 @@ + + + + + +常量字段值 + + + + + + + + + + + +
+

常量字段值

+

目录

+
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/deprecated-list.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/deprecated-list.html new file mode 100644 index 0000000..a03d078 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/deprecated-list.html @@ -0,0 +1,120 @@ + + + + + +已过时的列表 + + + + + + + + +
+ + + + + + + +
+ + +
+

已过时的 API

+

目录

+
+ +
+ + + + + + + +
+ + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/help-doc.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/help-doc.html new file mode 100644 index 0000000..b96669f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/help-doc.html @@ -0,0 +1,217 @@ + + + + + +API 帮助 + + + + + + + + + + + +
+

此 API 文档的组织方式

+
此 API (应用程序编程接口) 文档包含对应于导航栏中的项目的页面, 如下所述。
+
+
+
    +
  • +

    程序包

    +

    每个程序包都有一个页面, 其中包含它的类和接口的列表及其概要。此页面可以包含六个类别:

    +
      +
    • 接口 (斜体)
    • +
    • +
    • 枚举
    • +
    • 异常错误
    • +
    • 错误
    • +
    • 注释类型
    • +
    +
  • +
  • +

    类/接口

    +

    每个类, 接口, 嵌套类和嵌套接口都有各自的页面。其中每个页面都由三部分 (类/接口说明, 概要表, 以及详细的成员说明) 组成:

    +
      +
    • 类继承图
    • +
    • 直接子类
    • +
    • 所有已知子接口
    • +
    • 所有已知实现类
    • +
    • 类/接口声明
    • +
    • 类/接口说明
    • +
    +
      +
    • 嵌套类概要
    • +
    • 字段概要
    • +
    • 构造器概要
    • +
    • 方法概要
    • +
    +
      +
    • 字段详细资料
    • +
    • 构造器详细资料
    • +
    • 方法详细资料
    • +
    +

    每个概要条目都包含该项目的详细说明的第一句。概要条目按字母顺序排列, 而详细说明则按其在源代码中出现的顺序排列。这样保持了程序员所建立的逻辑分组。

    +
  • +
  • +

    注释类型

    +

    每个注释类型都有各自的页面, 其中包含以下部分:

    +
      +
    • 注释类型声明
    • +
    • 注释类型说明
    • +
    • 必需元素概要
    • +
    • 可选元素概要
    • +
    • 元素详细资料
    • +
    +
  • +
  • +

    枚举

    +

    每个枚举都有各自的页面, 其中包含以下部分:

    +
      +
    • 枚举声明
    • +
    • 枚举说明
    • +
    • 枚举常量概要
    • +
    • 枚举常量详细资料
    • +
    +
  • +
  • +

    树 (类分层结构)

    +

    对于所有程序包, 有一个类分层结构页面, 以及每个程序包的分层结构。每个分层结构页面都包含类的列表和接口的列表。从java.lang.Object开始, 按继承结构对类进行排列。接口不从java.lang.Object继承。

    +
      +
    • 查看“概览”页面时, 单击 "树" 将显示所有程序包的分层结构。
    • +
    • 查看特定程序包, 类或接口页面时, 单击 "树" 将仅显示该程序包的分层结构。
    • +
    +
  • +
  • +

    已过时的 API

    +

    已过时的 API 页面列出了所有已过时的 API。一般由于进行了改进并且通常提供了替代的 API, 所以建议不要使用已过时的 API。在将来的实现过程中, 可能会删除已过时的 API。

    +
  • +
  • +

    索引

    +

    索引 包含按字母顺序排列的所有类, 接口, 构造器, 方法和字段的列表。

    +
  • +
  • +

    上一个/下一个

    +

    这些链接使您可以转至下一个或上一个类, 接口, 程序包或相关页面。

    +
  • +
  • +

    框架/无框架

    +

    这些链接用于显示和隐藏 HTML 框架。所有页面均具有有框架和无框架两种显示方式。

    +
  • +
  • +

    所有类

    +

    所有类链接显示所有类和接口 (除了非静态嵌套类型)。

    +
  • +
  • +

    序列化表格

    +

    每个可序列化或可外部化的类都有其序列化字段和方法的说明。此信息对重新实现者有用, 而对使用 API 的开发者则没有什么用处。尽管导航栏中没有链接, 但您可以通过下列方式获取此信息: 转至任何序列化类, 然后单击类说明的 "另请参阅" 部分中的 "序列化表格"。

    +
  • +
  • +

    常量字段值

    +

    常量字段值页面列出了静态最终字段及其值。

    +
  • +
+此帮助文件适用于使用标准 doclet 生成的 API 文档。
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index-all.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index-all.html new file mode 100644 index 0000000..06a699f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index-all.html @@ -0,0 +1,157 @@ + + + + + +索引 + + + + + + + + + + + +
C G J M  + + +

C

+
+
com.wdbyte.comment - 程序包 com.wdbyte.comment
+
 
+
+ + + +

G

+
+
getMessage(String, String) - 类 中的静态方法com.wdbyte.comment.JavaDocDemo
+
+
返回一个欢迎信息。
+
+
+ + + +

J

+
+
JavaDocDemo - com.wdbyte.comment中的类
+
+
输出一个名称和地域的问候信息。
+
+
JavaDocDemo() - 类 的构造器com.wdbyte.comment.JavaDocDemo
+
 
+
+ + + +

M

+
+
main(String[]) - 类 中的静态方法com.wdbyte.comment.JavaDocDemo
+
+
启动应用程序
+
+
+C G J M 
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index.html new file mode 100644 index 0000000..720515c --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/index.html @@ -0,0 +1,72 @@ + + + + + +生成的文档 (无标题) + + + + + + +<noscript> +<div>您的浏览器已禁用 JavaScript。</div> +</noscript> +<h2>框架预警</h2> +<p>请使用框架功能查看此文档。如果看到此消息, 则表明您使用的是不支持框架的 Web 客户机。链接到<a href="com/wdbyte/comment/package-summary.html">非框架版本</a>。</p> + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/overview-tree.html b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/overview-tree.html new file mode 100644 index 0000000..50e2869 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/overview-tree.html @@ -0,0 +1,133 @@ + + + + + +类分层结构 + + + + + + + + + + + +
+

所有程序包的分层结构

+程序包分层结构: + +
+
+

类分层结构

+
    +
  • java.lang.Object + +
  • +
+
+ + + + + + diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/package-list b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/package-list new file mode 100644 index 0000000..84f8f0f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/package-list @@ -0,0 +1 @@ +com.wdbyte.comment diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/script.js b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/script.js new file mode 100644 index 0000000..b346356 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/script.js @@ -0,0 +1,30 @@ +function show(type) +{ + count = 0; + for (var key in methods) { + var row = document.getElementById(key); + if ((methods[key] & type) != 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) +{ + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/stylesheet.css b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/stylesheet.css new file mode 100644 index 0000000..98055b2 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/comment/doc/stylesheet.css @@ -0,0 +1,574 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.useSummary td.colFirst, .useSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} From 0bb6f79aad50f66e523be0c67987cbac2d25c590 Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 21 Jun 2023 17:14:58 +0800 Subject: [PATCH 51/83] =?UTF-8?q?feat:=20=E9=99=90=E6=B5=81=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {core-java-rate-limiter => tool-java-rate-limiter}/README.md | 0 {core-java-rate-limiter => tool-java-rate-limiter}/pom.xml | 2 +- .../src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java | 0 .../java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java | 0 .../java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java | 0 .../java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java | 0 .../java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java | 0 .../src/main/resources/limiter.lua | 0 .../src/main/resources/limiter2.lua | 0 .../src/test/java/RedisLuaLimiterByIncr.java | 0 .../src/test/java/RedisLuaLimiterByZset.java | 0 11 files changed, 1 insertion(+), 1 deletion(-) rename {core-java-rate-limiter => tool-java-rate-limiter}/README.md (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/pom.xml (92%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/resources/limiter.lua (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/main/resources/limiter2.lua (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/test/java/RedisLuaLimiterByIncr.java (100%) rename {core-java-rate-limiter => tool-java-rate-limiter}/src/test/java/RedisLuaLimiterByZset.java (100%) diff --git a/core-java-rate-limiter/README.md b/tool-java-rate-limiter/README.md similarity index 100% rename from core-java-rate-limiter/README.md rename to tool-java-rate-limiter/README.md diff --git a/core-java-rate-limiter/pom.xml b/tool-java-rate-limiter/pom.xml similarity index 92% rename from core-java-rate-limiter/pom.xml rename to tool-java-rate-limiter/pom.xml index 9679d8d..9b92fde 100644 --- a/core-java-rate-limiter/pom.xml +++ b/tool-java-rate-limiter/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.wdbyte.rate.limiter - core-java-rate-limiter + tool-java-rate-limiter 17 diff --git a/core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java b/tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java similarity index 100% rename from core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java rename to tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterGuava.java diff --git a/core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java b/tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java similarity index 100% rename from core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java rename to tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSildingLog.java diff --git a/core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java b/tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java similarity index 100% rename from core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java rename to tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow.java diff --git a/core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java b/tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java similarity index 100% rename from core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java rename to tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSimpleWindow0.java diff --git a/core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java b/tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java similarity index 100% rename from core-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java rename to tool-java-rate-limiter/src/main/java/com/wdbyte/rate/limiter/RateLimiterSlidingWindow.java diff --git a/core-java-rate-limiter/src/main/resources/limiter.lua b/tool-java-rate-limiter/src/main/resources/limiter.lua similarity index 100% rename from core-java-rate-limiter/src/main/resources/limiter.lua rename to tool-java-rate-limiter/src/main/resources/limiter.lua diff --git a/core-java-rate-limiter/src/main/resources/limiter2.lua b/tool-java-rate-limiter/src/main/resources/limiter2.lua similarity index 100% rename from core-java-rate-limiter/src/main/resources/limiter2.lua rename to tool-java-rate-limiter/src/main/resources/limiter2.lua diff --git a/core-java-rate-limiter/src/test/java/RedisLuaLimiterByIncr.java b/tool-java-rate-limiter/src/test/java/RedisLuaLimiterByIncr.java similarity index 100% rename from core-java-rate-limiter/src/test/java/RedisLuaLimiterByIncr.java rename to tool-java-rate-limiter/src/test/java/RedisLuaLimiterByIncr.java diff --git a/core-java-rate-limiter/src/test/java/RedisLuaLimiterByZset.java b/tool-java-rate-limiter/src/test/java/RedisLuaLimiterByZset.java similarity index 100% rename from core-java-rate-limiter/src/test/java/RedisLuaLimiterByZset.java rename to tool-java-rate-limiter/src/test/java/RedisLuaLimiterByZset.java From f8dda1be5ac4b44fafb27546de4521eb123fa91e Mon Sep 17 00:00:00 2001 From: niujinpeng Date: Wed, 21 Jun 2023 17:15:19 +0800 Subject: [PATCH 52/83] =?UTF-8?q?feat:=20=E9=99=90=E6=B5=81=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eb573fb..413dd08 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 1.0.0-SNAPSHOT core-java-modules - core-java-rate-limiter + tool-java-rate-limiter tool-java-junit5-jupiter-starter leetcode tool-java-apache-httpclient From 42c006aa9ba6620823f355d857118495027558ac Mon Sep 17 00:00:00 2001 From: niumoo Date: Thu, 12 Oct 2023 16:39:20 +0800 Subject: [PATCH 53/83] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E7=9B=AE?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + core-java-modules/core-java-20/.gitignore | 38 ++++++++ core-java-modules/core-java-20/pom.xml | 20 ++++ .../src/main/java/JEP431Test.java | 63 +++++++++++++ .../src/{ => main/java}/JEP433SwitchTest.java | 0 .../java}/Jep429ScopedValueTest.java | 0 .../java}/Jep432RecordAndInstance.java | 0 .../src/{ => main/java}/RecordTest.java | 0 .../io/image/GeneratorTextImageMini.java | 89 ++++++++++++++++++ .../target/classes/bingdundun.jpeg | Bin 0 -> 22890 bytes core-java-modules/pom.xml | 7 +- pom.xml | 2 + tool-java-classloader/.gitignore | 38 ++++++++ tool-java-classloader/pom.xml | 20 ++++ tool-java-guava/.gitignore | 38 ++++++++ tool-java-guava/pom.xml | 20 ++++ tool-java-object-pool/pom.xml | 2 +- tool-java-protobuf/.gitignore | 38 ++++++++ 18 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 core-java-modules/core-java-20/.gitignore create mode 100644 core-java-modules/core-java-20/pom.xml create mode 100644 core-java-modules/core-java-20/src/main/java/JEP431Test.java rename core-java-modules/core-java-20/src/{ => main/java}/JEP433SwitchTest.java (100%) rename core-java-modules/core-java-20/src/{ => main/java}/Jep429ScopedValueTest.java (100%) rename core-java-modules/core-java-20/src/{ => main/java}/Jep432RecordAndInstance.java (100%) rename core-java-modules/core-java-20/src/{ => main/java}/RecordTest.java (100%) create mode 100644 core-java-modules/core-java-io/src/main/java/com/wdbyte/io/image/GeneratorTextImageMini.java create mode 100644 core-java-modules/core-java-io/target/classes/bingdundun.jpeg create mode 100644 tool-java-classloader/.gitignore create mode 100644 tool-java-classloader/pom.xml create mode 100644 tool-java-guava/.gitignore create mode 100644 tool-java-guava/pom.xml create mode 100644 tool-java-protobuf/.gitignore diff --git a/README.md b/README.md index 3bbe625..a39d68e 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ - [Java 日期时间 Date](https://www.wdbyte.com/java/date/) - [Java 异常处理](https://www.wdbyte.com/java/exception/) - [Java 枚举](https://www.wdbyte.com/java/enum/) +- [Java 注释](https://www.wdbyte.com/java/comment/) - [Java 集合框架](https://www.wdbyte.com/java/collection/) ## Java 进阶 diff --git a/core-java-modules/core-java-20/.gitignore b/core-java-modules/core-java-20/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/core-java-modules/core-java-20/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/core-java-modules/core-java-20/pom.xml b/core-java-modules/core-java-20/pom.xml new file mode 100644 index 0000000..0495012 --- /dev/null +++ b/core-java-modules/core-java-20/pom.xml @@ -0,0 +1,20 @@ + + + + core-java-modules + com.wdbyte.core-java-modules + 1.0.0-SNAPSHOT + + 4.0.0 + + com.wdbyte.jdk20 + core-java-20 + + + 20 + 20 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-20/src/main/java/JEP431Test.java b/core-java-modules/core-java-20/src/main/java/JEP431Test.java new file mode 100644 index 0000000..5096265 --- /dev/null +++ b/core-java-modules/core-java-20/src/main/java/JEP431Test.java @@ -0,0 +1,63 @@ +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.TreeSet; + +/** + * JDK 21 之前,顺序集合中操作体验不一致 + * @author niulang + * @date 2023/10/12ø + */ +public class JEP431Test { + public static void main(String[] args) { + // JDK 21 之前,顺序集合中操作体验不一致 + List listTemp = List.of(1, 2, 3, 4, 5); + + ArrayList list = new ArrayList(listTemp); + Deque deque = new ArrayDeque<>(listTemp); + LinkedHashSet linkedHashSet = new LinkedHashSet<>(listTemp); + TreeSet sortedSet = new TreeSet<>(listTemp); + LinkedHashMap linkedHashMap = new LinkedHashMap<>(); + for (int i = 1; i <= 5; i++) { + linkedHashMap.put(i, i); + } + + // 输出第一个元素 + System.out.println(list.get(0)); + System.out.println(deque.getFirst()); + System.out.println(linkedHashSet.iterator().next()); + System.out.println(sortedSet.first()); + //System.out.println(linkedHashMap.firstEntry());没办法 + System.out.println("-----------------------"); + + // 输出最后一个元素 + System.out.println(list.get(list.size()-1)); + System.out.println(deque.getLast()); + //System.out.println(linkedHashSet()); 没办法,只能遍历 + System.out.println(sortedSet.last()); + //System.out.println(linkedHashMap); 没办法 + System.out.println("-----------------------"); + + // 逆序遍历 + for (var it = list.listIterator(list.size()); it.hasPrevious();) { + var e = it.previous(); + System.out.print(e); + } + System.out.println(); + for (var it = deque.descendingIterator(); it.hasNext();) { + var e = it.next(); + System.out.print(e); + } + System.out.println(); + for (Integer i : sortedSet.descendingSet()) { + System.out.print(i); + } + System.out.println(); + + // sortedSet linkedHashMap 逆序输出很难操作 + + } +} diff --git a/core-java-modules/core-java-20/src/JEP433SwitchTest.java b/core-java-modules/core-java-20/src/main/java/JEP433SwitchTest.java similarity index 100% rename from core-java-modules/core-java-20/src/JEP433SwitchTest.java rename to core-java-modules/core-java-20/src/main/java/JEP433SwitchTest.java diff --git a/core-java-modules/core-java-20/src/Jep429ScopedValueTest.java b/core-java-modules/core-java-20/src/main/java/Jep429ScopedValueTest.java similarity index 100% rename from core-java-modules/core-java-20/src/Jep429ScopedValueTest.java rename to core-java-modules/core-java-20/src/main/java/Jep429ScopedValueTest.java diff --git a/core-java-modules/core-java-20/src/Jep432RecordAndInstance.java b/core-java-modules/core-java-20/src/main/java/Jep432RecordAndInstance.java similarity index 100% rename from core-java-modules/core-java-20/src/Jep432RecordAndInstance.java rename to core-java-modules/core-java-20/src/main/java/Jep432RecordAndInstance.java diff --git a/core-java-modules/core-java-20/src/RecordTest.java b/core-java-modules/core-java-20/src/main/java/RecordTest.java similarity index 100% rename from core-java-modules/core-java-20/src/RecordTest.java rename to core-java-modules/core-java-20/src/main/java/RecordTest.java diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/image/GeneratorTextImageMini.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/image/GeneratorTextImageMini.java new file mode 100644 index 0000000..4bad1d8 --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/image/GeneratorTextImageMini.java @@ -0,0 +1,89 @@ +package com.wdbyte.io.image; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +/** + *

+ * 根据图片生成字符图案 + * 1.图片大小缩放 + * 2.遍历图片像素点 + * 3.获取图片像素点亮度 + * 4.匹配字符 + * 5.输出图案 + * + * @website https://www.wdbyte.com + */ +public class GeneratorTextImageMini { + + public static void main(String[] args) throws Exception { + //BufferedImage image = resizeImage("/Users/darcy/Downloads/sanli.jpg", 120); + BufferedImage image = ImageIO.read(new File("/Users/darcy/Downloads/刘看山.jpg")); + printImage(image); + } + + /** + * 图片缩放 + * + * @param srcImagePath 图片路径 + * @param targetWidth 目标宽度 + * @return + * @throws IOException + */ + public static BufferedImage resizeImage(String srcImagePath, int targetWidth) throws IOException { + Image srcImage = ImageIO.read(new File(srcImagePath)); + int targetHeight = getTargetHeight(targetWidth, srcImage); + BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics2D = resizedImage.createGraphics(); + graphics2D.drawImage(srcImage, 0, 0, targetWidth, targetHeight, null); + graphics2D.dispose(); + return resizedImage; + } + + /** + * 根据指定宽度,计算等比例高度 + * + * @param targetWidth 目标宽度 + * @param srcImage 图片信息 + * @return + */ + private static int getTargetHeight(int targetWidth, Image srcImage) { + int targetHeight = srcImage.getHeight(null); + if (targetWidth < srcImage.getWidth(null)) { + targetHeight = Math.round((float)targetHeight / ((float)srcImage.getWidth(null) / (float)targetWidth)); + } + return targetHeight; + } + + /** + * 图片打印 + * + * @param image + * @throws IOException + */ + public static void printImage(BufferedImage image) throws IOException { + final char[] PIXEL_CHAR_ARRAY = {'W', '@', '#', '8', '&', '*', 'o', ':', '.', ' '}; + //final char[] PIXEL_CHAR_ARRAY = {',', '.', ' '}; + int width = image.getWidth(); + int height = image.getHeight(); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + int rgb = image.getRGB(j, i); + Color color = new Color(rgb); + int red = color.getRed(); + int green = color.getGreen(); + int blue = color.getBlue(); + // 一个用于计算RGB像素点灰度的公式 + Double grayscale = 0.2126 * red + 0.7152 * green + 0.0722 * blue; + double index = grayscale / (Math.ceil(255 / PIXEL_CHAR_ARRAY.length) + 0.5); + System.out.print(PIXEL_CHAR_ARRAY[(int)(Math.floor(index))]); + } + System.out.println(); + } + } + +} diff --git a/core-java-modules/core-java-io/target/classes/bingdundun.jpeg b/core-java-modules/core-java-io/target/classes/bingdundun.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8243a8a745e076f571efcbedfc1611ba50a7c9fe GIT binary patch literal 22890 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 - 1.8 - 1.8 + 21 + 21 core-java-performance core-java-8 core-java-9 + core-java-18 + core-java-20 core-java-performance-code core-java-io core-java-string - core-java-18 core-java-collect core-java-base core-java-os diff --git a/pom.xml b/pom.xml index 413dd08..0e2c7f6 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,8 @@ tool-java-hotcode tool-java-protobuf tool-java-jcommander + tool-java-classloader + tool-java-guava parent-modules Parent for all java modules diff --git a/tool-java-classloader/.gitignore b/tool-java-classloader/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/tool-java-classloader/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/tool-java-classloader/pom.xml b/tool-java-classloader/pom.xml new file mode 100644 index 0000000..3789735 --- /dev/null +++ b/tool-java-classloader/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.wdbyte + parent-modules + 1.0.0-SNAPSHOT + + + tool-java-classloader + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/tool-java-guava/.gitignore b/tool-java-guava/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/tool-java-guava/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/tool-java-guava/pom.xml b/tool-java-guava/pom.xml new file mode 100644 index 0000000..64e6b94 --- /dev/null +++ b/tool-java-guava/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.wdbyte + parent-modules + 1.0.0-SNAPSHOT + + + tool-java-guava + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/tool-java-object-pool/pom.xml b/tool-java-object-pool/pom.xml index f8c4630..7044006 100644 --- a/tool-java-object-pool/pom.xml +++ b/tool-java-object-pool/pom.xml @@ -8,7 +8,7 @@ 1.0.0-SNAPSHOT 4.0.0 - objectpool + tool-java-object-pool 8 diff --git a/tool-java-protobuf/.gitignore b/tool-java-protobuf/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/tool-java-protobuf/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file From dd7f782eb4f1595f71916a9681b370b2f58897ca Mon Sep 17 00:00:00 2001 From: niumoo Date: Thu, 12 Oct 2023 16:40:25 +0800 Subject: [PATCH 54/83] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-java-modules/core-java-20/src/main/java/JEP431Test.java | 2 +- .../src/main/java/com/wdbyte/string/StringUtilsTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-20/src/main/java/JEP431Test.java b/core-java-modules/core-java-20/src/main/java/JEP431Test.java index 5096265..4a2edc0 100644 --- a/core-java-modules/core-java-20/src/main/java/JEP431Test.java +++ b/core-java-modules/core-java-20/src/main/java/JEP431Test.java @@ -8,7 +8,7 @@ /** * JDK 21 之前,顺序集合中操作体验不一致 - * @author niulang + * @author https://www.wdbyte.com * @date 2023/10/12ø */ public class JEP431Test { diff --git a/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java b/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java index fdaedda..51989b2 100644 --- a/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java +++ b/tool-java-apache-common/src/main/java/com/wdbyte/string/StringUtilsTest.java @@ -6,7 +6,7 @@ /** * apache common lang StringUtils test - * @author niulang + * @author https://www.wdbyte.com * @date 2022/11/01 */ public class StringUtilsTest { From 06872dc9628ffab727e659fb9affdbc166931d5f Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 16 Oct 2023 10:57:47 +0800 Subject: [PATCH 55/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Java=2021=20?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/JEP431Test.java | 2 - core-java-modules/core-java-21/README.md | 1 + core-java-modules/core-java-21/pom.xml | 21 ++++++ .../src/main/java/Jep430StringTemplate.java | 67 +++++++++++++++++++ .../main/java/Jep431SequencedCollection.java | 60 +++++++++++++++++ .../src/main/java/Jep440Record.java | 29 ++++++++ .../src/main/java/Jep441SwitchPatten.java | 33 +++++++++ .../src/main/java/Jep443Unname.java | 19 ++++++ .../src/main/java/Jep444VirtualThread.java | 48 +++++++++++++ .../src/main/java/Jep445HelloJava.java | 5 ++ core-java-modules/pom.xml | 1 + 11 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 core-java-modules/core-java-21/README.md create mode 100644 core-java-modules/core-java-21/pom.xml create mode 100644 core-java-modules/core-java-21/src/main/java/Jep430StringTemplate.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep431SequencedCollection.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep440Record.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep441SwitchPatten.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep443Unname.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep444VirtualThread.java create mode 100644 core-java-modules/core-java-21/src/main/java/Jep445HelloJava.java diff --git a/core-java-modules/core-java-20/src/main/java/JEP431Test.java b/core-java-modules/core-java-20/src/main/java/JEP431Test.java index 4a2edc0..22b80f8 100644 --- a/core-java-modules/core-java-20/src/main/java/JEP431Test.java +++ b/core-java-modules/core-java-20/src/main/java/JEP431Test.java @@ -9,7 +9,6 @@ /** * JDK 21 之前,顺序集合中操作体验不一致 * @author https://www.wdbyte.com - * @date 2023/10/12ø */ public class JEP431Test { public static void main(String[] args) { @@ -58,6 +57,5 @@ public static void main(String[] args) { System.out.println(); // sortedSet linkedHashMap 逆序输出很难操作 - } } diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md new file mode 100644 index 0000000..5fd1f86 --- /dev/null +++ b/core-java-modules/core-java-21/README.md @@ -0,0 +1 @@ +## Java 21 新特性示例 diff --git a/core-java-modules/core-java-21/pom.xml b/core-java-modules/core-java-21/pom.xml new file mode 100644 index 0000000..c7fdc19 --- /dev/null +++ b/core-java-modules/core-java-21/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + com.wdbyte.core-java-modules + core-java-modules + 1.0.0-SNAPSHOT + + + com.wdbyte.jdk21 + core-java-21 + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/Jep430StringTemplate.java b/core-java-modules/core-java-21/src/main/java/Jep430StringTemplate.java new file mode 100644 index 0000000..51a7100 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep430StringTemplate.java @@ -0,0 +1,67 @@ +import java.time.LocalDate; +import java.util.FormatProcessor; +import java.util.Locale; + +/** + * 字符串模版 + * + * @author https://www.wdbyte.com + * @date 2023/10/13 + */ +public class Jep430StringTemplate { + + public static void main(String[] args) { + int x = 20; + int y = 3; + String s = x + " + " + y + " = " + (x + y); + System.out.println(s); + + String sb = new StringBuilder().append(x).append(" + ").append(y).append(" = ").append(x + y).toString(); + System.out.println(sb); + + + String sFormat = String.format("%d + %d = %d", x, y, x + y); + System.out.println(sFormat); + + System.out.println("--------------------"); + + // JDK 21 使用字符串模版 STR 进行插值 + String sTemplate = StringTemplate.STR."\{x} + \{y} = \{x+y}"; + System.out.println(sTemplate); + + // 字符串模版也可以先定义模版,再处理插值 + StringTemplate st = StringTemplate.RAW."\{x} + \{y} = \{x+y}"; + String sTemplate2 = StringTemplate.STR.process(st); + System.out.println(sTemplate2); + + System.out.println("--------------------"); + LocalDate now = LocalDate.now(); + String nowStr = StringTemplate.STR."现在是 \{now.getYear()} 年 \{now.getMonthValue()} 月 \{now.getDayOfMonth()} 号"; + System.out.println(nowStr); + + // 字符串模版读取数组,字符串模版也可以嵌套 + String[] infoArr = { "Hello", "Java 21", "https://www.wdbyte.com" }; + String sArray = StringTemplate.STR."\{infoArr[0]}, \{STR."\{infoArr[1]}, \{infoArr[2]}"}"; + System.out.println(sArray); + + // 字符串模版也可以结合多行文本 + String name = "https://www.wdbyte.com"; + String address = "程序猿阿朗"; + String json = StringTemplate.STR.""" + { + "name": "\{name}", + "address": "\{address}" + } + """; + System.out.println(json); + System.out.println("--------------------"); + + } +} + + +record Rectangle(String name, double width, double height) { + double area() { + return width * height; + } +} diff --git a/core-java-modules/core-java-21/src/main/java/Jep431SequencedCollection.java b/core-java-modules/core-java-21/src/main/java/Jep431SequencedCollection.java new file mode 100644 index 0000000..9034ea1 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep431SequencedCollection.java @@ -0,0 +1,60 @@ +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.SequencedCollection; +import java.util.TreeSet; +import java.util.function.Consumer; + +/** + * @author https://www.wdbyte.com + * @date 2023/10/12 + */ +public class Jep431SequencedCollection { + public static void main(String[] args) { + // JDK 21 之后,为所有元素插入有序集合提供了一致的操作 API + List listTemp = List.of(1, 2, 3, 4, 5); + + ArrayList list = new ArrayList(listTemp); + Deque deque = new ArrayDeque<>(listTemp); + LinkedHashSet linkedHashSet = new LinkedHashSet<>(listTemp); + TreeSet sortedSet = new TreeSet<>(listTemp); + LinkedHashMap linkedHashMap = new LinkedHashMap<>(); + for (int i = 1; i <= 5; i++) { + linkedHashMap.put(i, i); + } + + // 输出第一个元素 + System.out.println(list.getFirst()); + System.out.println(deque.getFirst()); + System.out.println(linkedHashSet.getFirst()); + System.out.println(sortedSet.getFirst()); + System.out.println(linkedHashMap.firstEntry()); + System.out.println("-----------------------"); + + // 输出最后一个元素 + System.out.println(list.getLast()); + System.out.println(list.getLast()); + System.out.println(deque.getLast()); + System.out.println(sortedSet.getLast()); + System.out.println(linkedHashMap.lastEntry()); + System.out.println("-----------------------"); + + // 逆序遍历 + Consumer printFn = s -> { + // reversed 逆序元素 + s.reversed().forEach(System.out::print); + System.out.println(); + }; + printFn.accept(list); + printFn.accept(deque); + printFn.accept(linkedHashSet); + printFn.accept(sortedSet); + // 有序 map 接口是 SequencedMap,上面的 consume类型不适用 + linkedHashMap.reversed().forEach((k, v) -> { + System.out.print(k); + }); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/Jep440Record.java b/core-java-modules/core-java-21/src/main/java/Jep440Record.java new file mode 100644 index 0000000..51e59b9 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep440Record.java @@ -0,0 +1,29 @@ +/** + * @author https://www.wdbyte.com + * @date 2023/10/13 + */ +public class Jep440Record { + public static void main(String[] args) { + + Object obj = "Hello www.wdbyte.com"; + if (obj instanceof String s) { + System.out.println(s); + } + + Dog dog = new Dog("Husky", 1); + if (dog instanceof Dog(String name, int age)) { + String res = StringTemplate.STR."name:\{name} age:\{age}"; + System.out.println(res); + } + Object myDog = new MyDog(dog, Color.BLACK); + if (myDog instanceof MyDog(Dog(String name,int age),Color color)){ + String res = StringTemplate.STR."name:\{name} age:\{age} color:\{color}"; + System.out.println(res); + } + } +} + +record Dog(String name, int age) {} +enum Color{WHITE,GREY,BLACK}; +record MyDog(Dog dog,Color color){}; + diff --git a/core-java-modules/core-java-21/src/main/java/Jep441SwitchPatten.java b/core-java-modules/core-java-21/src/main/java/Jep441SwitchPatten.java new file mode 100644 index 0000000..c1d6869 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep441SwitchPatten.java @@ -0,0 +1,33 @@ +/** + * @author https://www.wdbyte.com + * @date 2023/10/13 + */ +public class Jep441SwitchPatten { + + public static void main(String[] args) { + String r1 = formatterPatternSwitch(Integer.valueOf(1)); + String r2 = formatterPatternSwitch(new String("www.wdbyte.com")); + String r3 = formatterPatternSwitch(Double.valueOf(3.14D)); + System.out.println(r1); + System.out.println(r2); + System.out.println(r3); + } + + static String formatterPatternSwitch(Object obj) { + return switch (obj) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> obj.toString(); + }; + } + + static void testFooBarNew(String s) { + switch (s) { + case null -> System.out.println("Oops"); + case "Foo", "Bar" -> System.out.println("Great"); + default -> System.out.println("Ok"); + } + } +} diff --git a/core-java-modules/core-java-21/src/main/java/Jep443Unname.java b/core-java-modules/core-java-21/src/main/java/Jep443Unname.java new file mode 100644 index 0000000..5a4c356 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep443Unname.java @@ -0,0 +1,19 @@ +import java.util.List; + +/** + * @author https://www.wdbyte.com + * @date 2023/10/15 + */ +public class Jep443Unname { + + public static void main(String[] args) { + String _ = "123213"; + Integer _ = 123; + List list = List.of(1, 2, 3, 4, 5, 6, 7, 8); + int count = 0; + for (Integer _ : list) { + count++; + } + System.out.println(count); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/Jep444VirtualThread.java b/core-java-modules/core-java-21/src/main/java/Jep444VirtualThread.java new file mode 100644 index 0000000..52c565c --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep444VirtualThread.java @@ -0,0 +1,48 @@ +import java.time.Duration; +import java.util.concurrent.Executors; +import java.util.stream.IntStream; + +/** + * 虚拟线程 + * + * @author https://www.wdbyte.com + * @date 2023/10/10 + */ +public class Jep444VirtualThread { + public static void main(String[] args) throws InterruptedException { + // 创建并提交执行虚拟线程 + long start = System.currentTimeMillis(); + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + IntStream.range(0, 10_000).forEach(i -> { + executor.submit(() -> { + Thread.sleep(Duration.ofSeconds(1)); + return i; + }); + }); + } + System.out.println("time:" + (System.currentTimeMillis() - start) + "ms"); + + + // 创建一个虚拟线程指定虚拟线程名称 + Thread thread1 = Thread.ofVirtual().name("v-thread").unstarted(() -> { + String threadName = Thread.currentThread().getName(); + System.out.println(String.format("[%s] Hello Virtual Thread", threadName)); + }); + thread1.start(); + System.out.println(thread1.isVirtual()); + + //创建一个线程,启动为虚拟线程 + Thread thread2 = new Thread(() -> { + String threadName = Thread.currentThread().getName(); + System.out.println(String.format("[%s] Hello Virtual Thread 2", threadName)); + }); + + Thread.startVirtualThread(thread2); + + // 判断一个线程是否是虚拟线程 + System.out.println(thread1.isVirtual()); + System.out.println(thread2.isVirtual()); + + Thread.sleep(1000); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/Jep445HelloJava.java b/core-java-modules/core-java-21/src/main/java/Jep445HelloJava.java new file mode 100644 index 0000000..9f5ba6b --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/Jep445HelloJava.java @@ -0,0 +1,5 @@ + +void main(){ + System.out.println("Hello, Java 21!"); +} + diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 71f10f2..ed84483 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -24,6 +24,7 @@ core-java-9 core-java-18 core-java-20 + core-java-21 core-java-performance-code core-java-io core-java-string From 4f94745e2929e0bab159e06c6727dc20523165a3 Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 16 Oct 2023 15:37:39 +0800 Subject: [PATCH 56/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Java=2021=20?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a39d68e..9a6f199 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ ## ☕ Java 新特性 Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错,何况有些新特性是**真香**。 + +-[Java 20 新功能介绍 (LTS)]https://www.wdbyte.com/java/java-21/ - [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) - [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) - [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) From e1e7ce75ec13470e39fd1cdc72326eef7eaae3d8 Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 16 Oct 2023 16:41:17 +0800 Subject: [PATCH 57/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Java=2021=20?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a6f199..18c04d2 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错,何况有些新特性是**真香**。 --[Java 20 新功能介绍 (LTS)]https://www.wdbyte.com/java/java-21/ +- [Java 21 新功能介绍 (LTS)](https://www.wdbyte.com/java/java-21/) - [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) - [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) - [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) From 5fd51348a135c6566c65311608336d818f58c09d Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 16 Oct 2023 16:41:48 +0800 Subject: [PATCH 58/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Java=2021=20?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18c04d2..3b4f6fc 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) - [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) - [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) -- [Java 17 新功能介绍](https://www.wdbyte.com/java/java-17/) +- [Java 17 新功能介绍 (LTS)](https://www.wdbyte.com/java/java-17/) - [Java 16 新功能介绍](https://www.wdbyte.com/java/java-16/) - [Java 15 新功能介绍](https://www.wdbyte.com/java/java-15/) - [Java 14 新特性讲解](https://www.wdbyte.com/java/java-14/) From ac763c61ccc533f85565b7aef3b0c9c07ad0b722 Mon Sep 17 00:00:00 2001 From: niumoo Date: Thu, 19 Oct 2023 21:34:15 +0800 Subject: [PATCH 59/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20java=20list?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-java-modules/core-java-base/README.md | 25 +++++++ .../com/wdbyte/collection/ArrayListTest.java | 63 +++++++++++++++++ .../com/wdbyte/collection/ArrayListTest2.java | 49 +++++++++++++ .../com/wdbyte/collection/ArrayListTest3.java | 54 ++++++++++++++ .../com/wdbyte/collection/ArrayListTest4.java | 70 +++++++++++++++++++ .../src/main/java/com/wdbyte/enum2/Shape.java | 12 ++++ .../main/java/com/wdbyte/enum2/Weekday.java | 11 +++ .../resources/META-INF/maven/archetype.xml | 9 +++ 8 files changed, 293 insertions(+) create mode 100644 core-java-modules/core-java-base/README.md create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Shape.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Weekday.java create mode 100644 core-java-modules/core-java-base/src/main/resources/META-INF/maven/archetype.xml diff --git a/core-java-modules/core-java-base/README.md b/core-java-modules/core-java-base/README.md new file mode 100644 index 0000000..0071ce6 --- /dev/null +++ b/core-java-modules/core-java-base/README.md @@ -0,0 +1,25 @@ +## core-java-base +当前模块包含 Java 核心代码 + +### 相关文章 + +- [JDK、JRE、JVM 的区别](/java/jdk-jre-jvm/) +- [Java 数据类型](/java/data-type/) +- [Java 流程控制](/java/flow-control/) +- [Java String 字符串](/java/java-string/) +- [Java Array 数组](/java/java-array/) +- [Java 多维数组](/java/java-array-mul/) +- [Java StringBuilder](/java/java-stringbuilder/) +- [Java Scanner](/java/scanner/) +- [Java 继承](/java/extends/) +- [Java 接口](/java/interface/) +- [Java 抽象类](/java/abstract/) +- [抽象类和接口的区别](https://www.wdbyte.com/java/abs-interface/) +- [Java 多态](/java/polymorphism/) +- [Java Scanner](/java/scanner/) +- [Java 日期时间Date](/java/date/) +- [Java 异常处理](/java/exception/) +- [Java 枚举](https://www.wdbyte.com/java/enum/) +- [Java 注释](*https://www.wdbyte.com/java/comment/*) +- [Java 集合框架](https://www.wdbyte.com/java/collection/) +- [Java 中使用 List ](https://www.wdbyte.com/java/list/) \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java new file mode 100644 index 0000000..54032e0 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java @@ -0,0 +1,63 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author niulang + * @date 2023/10/19 + */ +public class ArrayListTest { + + public static void main(String[] args) { + //String[] arr = new String[]{"w","d","b","y","t","e"}; + ////arr[7] = "f"; + // + //List list = new ArrayList(); + //list.add("a"); + //list.add("b"); + //list.add("c"); + //list.add("d"); + // + //System.out.println(list.get(2)); + //list.remove(2); + //System.out.println(list.get(2)); + + //List list2 = List.of("www", "wdbyte", "com"); + //list2.add("a"); + //System.out.println(list2); + + List list = new ArrayList(); + list.add("b"); + list.add("c"); + list.add("a"); + list.add("d"); + + System.out.println(list); + + list = list.stream().sorted().collect(Collectors.toList()); + System.out.println(list); + + // 排序时指定降序还是升序:Comparator.reverseOrder() 降序 + list = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList()); + System.out.println(list); + + System.out.println("----------"); + + Collections.sort(list); + System.out.println(list); + // 降序 + Collections.sort(list,Comparator.reverseOrder()); + System.out.println(list); + + list.sort(Comparator.comparing(Function.identity())); + System.out.println(list); + + + + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java new file mode 100644 index 0000000..357e0f2 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java @@ -0,0 +1,49 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +/** + * @author niulang + * @date 2023/10/19 + */ +public class ArrayListTest2 { + + public static void main(String[] args) { + List list = new ArrayList(); + list.add("a"); + list.add("b"); + System.out.println("当前集合:" + list); + System.out.println("获取第一个元素:" + list.get(0)); + list.set(0, "x"); + System.out.println("修改第一个元素为 x:" + list); + list.remove(1); + System.out.println("移除第2个元素后剩余:" + list); + System.out.println("判断元素 x 是否存在:" + list.contains("x")); + System.out.println("判断元素 a 是否存在:" + list.contains("a")); + System.out.println("当前 list 大小:" + list.size()); + + list.add("y"); + list.add("z"); + System.out.println("添加两个元素:" + list); + + System.out.println("遍历元素:"); + for (String string : list) { + System.out.print(string); + } + for (int i = 0; i < list.size(); i++) { + System.out.print(list.get(i)); + } + list.forEach(s -> { + System.out.println(s); + }); + + Iterator iterator = list.iterator(); + while (iterator.hasNext()){ + System.out.println(iterator.next()); + } + + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java new file mode 100644 index 0000000..02b189f --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java @@ -0,0 +1,54 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import com.google.common.collect.Lists; + +/** + * @author niulang + * @date 2023/10/19 + */ +public class ArrayListTest3 { + + public static void main(String[] args) { + List list = new ArrayList(); + list.add("a"); + list.add("b"); + + String[] array = list.toArray(new String[0]); + System.out.println(Arrays.toString(array)); + + String[] array2 = list.stream().toArray(String[]::new); + System.out.println(Arrays.toString(array2)); + + // 数组 -> List + // 方式1 + List list0 = Lists.newArrayList(array); + list0.add("e"); + System.out.println(list0); + + // 方式2 + List list1 = Arrays.stream(array).toList(); + // list1.add("e"); 报错,不能修改 + System.out.println(list1); + + // 方式3 + List list2 = Arrays.asList(array); + //list2.add("e"); 报错,不能修改 + System.out.println(list2); + + // 方式4 + List list3 = new ArrayList<>(Arrays.asList(array)); + list3.add("e"); + System.out.println(list3); + + // 方式5 + List list4 = Arrays.stream(array).collect(Collectors.toList()); + list4.add("e"); + System.out.println(list4); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java new file mode 100644 index 0000000..98200cf --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java @@ -0,0 +1,70 @@ +package com.wdbyte.collection; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.google.common.collect.Lists; + +/** + * @author niulang + * @date 2023/10/19 + */ +public class ArrayListTest4 { + + public static void main(String[] args) { + List list = new ArrayList(); + list.add(new Dog("大黄", 1)); + list.add(new Dog("小黑", 2)); + + Map dogMap = list.stream() + .collect(Collectors.toMap(Dog::getName, Function.identity(), (o, n) -> o)); + System.out.println(dogMap.get("大黄")); + + Map dogMap2 = new HashMap<>(); + for (Dog dog : list) { + dogMap2.put(dog.getName(), dog); + } + System.out.println(dogMap.get("大黄")); + + } + +} + +class Dog { + String name; + Integer age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Dog(String name, Integer age) { + this.name = name; + this.age = age; + } + + @Override + public String toString() { + return "Dog{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Shape.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Shape.java new file mode 100644 index 0000000..8bc2d2d --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Shape.java @@ -0,0 +1,12 @@ +package com.wdbyte.enum2; + +/** + * 形状接口 + */ +public interface Shape { + /** + * 计算面积 + * @return + */ + double getArea(); +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Weekday.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Weekday.java new file mode 100644 index 0000000..e8aa799 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/Weekday.java @@ -0,0 +1,11 @@ +package com.wdbyte.enum2; + +public enum Weekday { + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY +} \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/resources/META-INF/maven/archetype.xml b/core-java-modules/core-java-base/src/main/resources/META-INF/maven/archetype.xml new file mode 100644 index 0000000..5cfc7cc --- /dev/null +++ b/core-java-modules/core-java-base/src/main/resources/META-INF/maven/archetype.xml @@ -0,0 +1,9 @@ + + core-java-base + + src/main/java/App.java + + + src/test/java/AppTest.java + + From d3e0d823d2e53edab6d0d2c7ac68f31ed7c4ccc1 Mon Sep 17 00:00:00 2001 From: niumoo Date: Thu, 19 Oct 2023 21:36:34 +0800 Subject: [PATCH 60/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20java=20list?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + core-java-modules/README.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 3b4f6fc..868440e 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ - [Java 枚举](https://www.wdbyte.com/java/enum/) - [Java 注释](https://www.wdbyte.com/java/comment/) - [Java 集合框架](https://www.wdbyte.com/java/collection/) +- [Java 中使用 List](https://www.wdbyte.com/java/list/) ## Java 进阶 - [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) diff --git a/core-java-modules/README.md b/core-java-modules/README.md index 6a78bae..8f83756 100644 --- a/core-java-modules/README.md +++ b/core-java-modules/README.md @@ -2,6 +2,11 @@ 当前模块包含 Java 核心代码 ### 相关文章 + +- [Java 21 新功能介绍](https://www.wdbyte.com/java/java-21/) +- [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) +- [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) +- [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) - [Java 17 新功能介绍](https://www.wdbyte.com/java/java-17/) - [Java 16 新功能介绍](https://www.wdbyte.com/java/java-16/) - [Java 15 新功能介绍](https://www.wdbyte.com/java/java-15/) From f1f12dfd2f469da152a64072f7fcc3d047d0671f Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 8 Nov 2023 14:05:50 +0800 Subject: [PATCH 61/83] =?UTF-8?q?feat:=20=20[Java=20=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=92=8C=E5=86=99=E5=85=A5=E6=96=87=E4=BB=B6](https://www.wdby?= =?UTF-8?q?te.com/java/io/file-create-write/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wdbyte/collection/ArrayListTest4.java | 13 +++ core-java-modules/core-java-io/README.md | 2 +- core-java-modules/core-java-io/pom.xml | 4 +- .../io/file/FileCreateAndWriteDemo.java | 108 ++++++++++++++++++ core-java-modules/pom.xml | 9 ++ 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java index 98200cf..d49f5b2 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -31,6 +32,18 @@ public static void main(String[] args) { } System.out.println(dogMap.get("大黄")); + List arrayList = new ArrayList(); + arrayList.add("a"); + arrayList.add("b"); + + Iterator iterator = arrayList.iterator(); + while (iterator.hasNext()) { + String next = iterator.next(); + if ("a".equals(next)) { + iterator.remove(); + } + } + System.out.println(arrayList); } } diff --git a/core-java-modules/core-java-io/README.md b/core-java-modules/core-java-io/README.md index 5d1fb00..3f91046 100644 --- a/core-java-modules/core-java-io/README.md +++ b/core-java-modules/core-java-io/README.md @@ -2,5 +2,5 @@ 当前模块包含 IO 相关代码 ### 相关文章 - +- [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) - [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) \ No newline at end of file diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index 2fb5dba..88e5007 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -14,8 +14,8 @@ jar - 1.8 - 1.8 + 21 + 21 diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java new file mode 100644 index 0000000..4f4dddd --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java @@ -0,0 +1,108 @@ +package com.wdbyte.io.file; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2023/11/06 + */ +public class FileCreateAndWriteDemo { + + @Test + public void test0() throws IOException { + String content = "www.wdbyte.com,java 7"; + String filePath = "/Users/darcy/wdbyte/test0.txt"; + try (FileWriter fw = new FileWriter(filePath); + BufferedWriter bw = new BufferedWriter(fw)) { + bw.write(content); + bw.newLine(); + } + + // 追加模式 + try (FileWriter fw = new FileWriter(filePath, true); + BufferedWriter bw = new BufferedWriter(fw)) { + bw.write(content); + bw.newLine(); + } + } + + /** + * JDK 7 + * + * @throws IOException + */ + @Test + public void test1() throws IOException { + String content = "www.wdbyte.com, java 7"; + Path path = Paths.get("/Users/darcy/wdbyte/test1.txt"); + // string -> bytes + Files.write(path, content.getBytes(StandardCharsets.UTF_8)); + } + + /** + * JDK 7 追加 + * @throws IOException + */ + @Test + public void test2() throws IOException { + String content = "www.wdbyte.com,java 7" + System.lineSeparator(); + Path path = Paths.get("/Users/darcy/wdbyte/test2.txt"); + Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, + StandardOpenOption.APPEND); + Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, + StandardOpenOption.APPEND); + } + + /** + * JDK 7 写入 List + * + * @throws IOException + */ + @Test + public void test3() throws IOException { + List dataList = Arrays.asList("www", "wdbyte", "com", "java 7"); + Path path = Paths.get("/Users/darcy/wdbyte/test3.txt"); + Files.write(path, dataList); + } + + @Test + public void test4() throws IOException { + String content = "www.wdbyte.com,java 7"; + Path path = Paths.get("/Users/darcy/wdbyte/test4.txt"); + // 默认 utf_8 + try (BufferedWriter bw = Files.newBufferedWriter(path)) { + bw.write(content); + bw.newLine(); + } + // 追加模式 + try (BufferedWriter bw = Files.newBufferedWriter(path, + StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { + bw.write(content); + bw.newLine(); + } + } + + /** + * JDK 11 + * + * @throws IOException + */ + @Test + public void test5() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/test5.txt"); + Files.writeString(path, "www.wdbyte.com,java 11"); + } + + +} diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index ed84483..b3a49a2 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -33,4 +33,13 @@ core-java-os + + + org.junit.jupiter + junit-jupiter + 5.9.1 + + + + \ No newline at end of file From b4f265b9090d09dd234ae003e2ec9f9e8158cb5b Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 8 Nov 2023 14:06:23 +0800 Subject: [PATCH 62/83] =?UTF-8?q?feat:=20=20[Java=20=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=92=8C=E5=86=99=E5=85=A5=E6=96=87=E4=BB=B6](https://www.wdby?= =?UTF-8?q?te.com/java/io/file-create-write/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 868440e..0db6717 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ - [Java 集合框架](https://www.wdbyte.com/java/collection/) - [Java 中使用 List](https://www.wdbyte.com/java/list/) +## Java I/O 教程 +- [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) + ## Java 进阶 - [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) From bcc1c8b5c7e33726ac0a936b6473b76028ae2e08 Mon Sep 17 00:00:00 2001 From: niumoo Date: Thu, 9 Nov 2023 14:36:34 +0800 Subject: [PATCH 63/83] =?UTF-8?q?feat:=20-=20[Java=20=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=96=87=E4=BB=B6](https://www.wdbyte.com/java/io/file-read/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + core-java-modules/core-java-io/README.md | 1 + .../java/com/wdbyte/io/file/FileReadDemo.java | 168 ++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java diff --git a/README.md b/README.md index 0db6717..fbbfa9a 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ ## Java I/O 教程 - [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) +- [Java 读取文件](https://www.wdbyte.com/java/io/file-read/) ## Java 进阶 - [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) diff --git a/core-java-modules/core-java-io/README.md b/core-java-modules/core-java-io/README.md index 3f91046..8ebf834 100644 --- a/core-java-modules/core-java-io/README.md +++ b/core-java-modules/core-java-io/README.md @@ -2,5 +2,6 @@ 当前模块包含 IO 相关代码 ### 相关文章 +- [Java 读取文件](https://www.wdbyte.com/java/io/file-read/) - [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) - [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java new file mode 100644 index 0000000..041a6b9 --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java @@ -0,0 +1,168 @@ +package com.wdbyte.io.file; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2023/11/08 + */ +public class FileReadDemo { + + public static void main(String[] args) { + Path path = Paths.get("/Users/darcy/wdbyte"); + System.out.println(Files.isDirectory(path)); + System.out.println(path.toFile().isFile()); + System.out.println(path.toFile().isDirectory()); + } + + /** + * java 8 + * + * @throws IOException + */ + @Test + public void test1() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/log.txt"); + List lines = Files.readAllLines(path, StandardCharsets.UTF_8); + for (String line : lines) { + System.out.println(line); + } + } + + /** + * java 8 + * + * @throws IOException + */ + @Test + public void test2() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/log.txt"); + byte[] bytes = Files.readAllBytes(path); + String content = new String(bytes, StandardCharsets.UTF_8); + System.out.println(content); + } + + /** + * java 8 + * + * @throws IOException + */ + @Test + public void test3() throws IOException, InterruptedException { + Path path = Paths.get("/Users/darcy/wdbyte/log.txt"); + try (Stream stream = Files.lines(path);) { + stream.forEach(System.out::println); + } + try (Stream stream = Files.lines(path);) { + stream.parallel().forEachOrdered(System.out::println); + } + } + + /** + * java 11 + * 要求:文件小于2G + * + * @throws IOException + */ + @Test + public void test4() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/log.txt"); + String content = Files.readString(path, StandardCharsets.UTF_8); + System.out.println(content); + } + + @Test + public void test5() { + File file = new File("/Users/darcy/wdbyte/log.txt"); + String line; + // 默认读取缓冲区大小 8K + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + while ((line = br.readLine()) != null) { + System.out.println(line); + } + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + + // 定义缓冲区大小为 128 K + int buffer = 128 * 1024; + try (BufferedReader br = new BufferedReader(new FileReader(file), buffer)) { + while ((line = br.readLine()) != null) { + System.out.println(line); + } + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * java 8 + * + * @throws IOException + */ + @Test + public void test6() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/log.txt"); + String line; + try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8);) { + while ((line = br.readLine()) != null) { + System.out.println(line); + } + } + } + + /** + * 自古以来 + */ + @Test + public void test7() { + File file = new File("/Users/darcy/wdbyte/log.txt"); + try (Scanner sc = new Scanner(new FileReader(file))) { + while (sc.hasNextLine()) { + String line = sc.nextLine(); + System.out.println(line); + } + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * 自古以来 + */ + @Test + public void test8() { + File file = new File("/Users/darcy/wdbyte/log.txt"); + try (FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis);) { + + StringBuilder content = new StringBuilder(); + int data; + while ((data = bis.read()) != -1) { + content.append((char)data); + } + System.out.println(content.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + } +} From 09d3bde74d730176135b3ce3a5b85a0f0988b875 Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 18 Dec 2023 21:53:12 +0800 Subject: [PATCH 64/83] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E4=BB=B6IO=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-java-modules/core-java-io/pom.xml | 10 +- .../com/wdbyte/io/file/FileAppendDemo.java | 179 ++++++++++++++++++ .../java/com/wdbyte/io/file/FileDelete.java | 73 +++++++ .../java/com/wdbyte/io/file/FileReadDemo.java | 10 + 4 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java create mode 100644 core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index 88e5007..30c75c1 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -22,10 +22,14 @@ com.google.guava guava - 31.0.1-jre - jar - provided + 32.1.3-jre + + commons-io + commons-io + 2.7 + + diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java new file mode 100644 index 0000000..6d43afb --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java @@ -0,0 +1,179 @@ +package com.wdbyte.io.file; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Charsets; +import com.google.common.io.FileWriteMode; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2023/12/12 + */ +public class FileAppendDemo { + + @Test + public void appendLine1() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/test1.txt"); + // 写入一行数据 + Files.write(path, "line append1".getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE, StandardOpenOption.APPEND); + // 写入一个换行符 + Files.write(path, System.lineSeparator().getBytes(StandardCharsets.UTF_8), + StandardOpenOption.APPEND); + } + + @Test + public void appendLine2() throws IOException { + String path = "/Users/darcy/wdbyte/test1.txt"; + try (FileWriter fileWriter = new FileWriter(path, true)) { + fileWriter.write("line append2"); + fileWriter.write(System.lineSeparator()); + } + } + @Test + public void appendLine3() throws IOException { + String path = "/Users/darcy/wdbyte/test1.txt"; + try (FileWriter fileWriter = new FileWriter(path, true)) { + BufferedWriter bw = new BufferedWriter(fileWriter); + bw.write("line append3"); + bw.newLine(); + } + } + + @Test + public void appendLine4() throws IOException { + String path = "/Users/darcy/wdbyte/test1.txt"; + try (FileOutputStream fileOutputStream = new FileOutputStream(path, true)) { + fileOutputStream.write("line append4".getBytes(StandardCharsets.UTF_8)); + fileOutputStream.write(System.lineSeparator().getBytes(StandardCharsets.UTF_8)); + } + } + + /** + * java 11 Files.writeString + * @throws IOException + */ + public void appendLineJava11() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/test1.txt"); + Files.writeString(path, "line appendLineJava11", + StandardOpenOption.CREATE, + StandardOpenOption.APPEND); + } + + + /** + * Java 8 + * + * @throws IOException + */ + @Test + public void appendLineJava8() throws IOException { + Path path = Paths.get("/Users/darcy/wdbyte/test1.txt"); + List dataList = new ArrayList<>(); + dataList.add("line1 appendLineJava8"); + dataList.add("line2 appendLineJava8"); + dataList.add("line3 appendLineJava8"); + + Files.write(path, dataList, + StandardOpenOption.CREATE, + StandardOpenOption.APPEND); + + Files.write(path, System.lineSeparator().getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE, + StandardOpenOption.APPEND); + } + + @Test + public void appendLineList() throws IOException { + String path = "/Users/darcy/wdbyte/test1.txt"; + List dataList = new ArrayList<>(); + dataList.add("line1 appendLineList"); + dataList.add("line2 appendLineList"); + dataList.add("line3 appendLineList"); + + try (FileWriter fileWriter = new FileWriter(path, true)) { + BufferedWriter bw = new BufferedWriter(fileWriter); + for (String data : dataList) { + bw.write(data); + bw.newLine(); + } + } + } + + @Test + public void appendByCommonsIo() throws IOException { + File file = new File("/Users/darcy/wdbyte/test1.txt"); + String content = "hello commons io,appendByCommonsIo"; + FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8, true); + FileUtils.writeStringToFile(file, System.lineSeparator(), StandardCharsets.UTF_8, true); + } + + @Test + public void appendListByCommonsIo() throws IOException { + File file = new File("/Users/darcy/wdbyte/test1.txt"); + List dataList = new ArrayList<>(); + dataList.add("line1 hello commons io,appendListByCommonsIo"); + dataList.add("line2 hello commons io,appendListByCommonsIo"); + dataList.add("line3 hello commons io,appendListByCommonsIo"); + FileUtils.writeLines(file, dataList, true); + } + + @Test + public void appendData(){ + // 创建File对象指向要追加内容的文件 + File file = new File("/Users/darcy/wdbyte/test1.txt"); + // 要追加的内容 + String contentToAppend = "Hello, Guava!"; + try { + // 使用Guava的Files类以追加模式写入内容 + com.google.common.io.Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND) + .write(contentToAppend); + + // 如果需要追加新行,可以使用下面的代码 + com.google.common.io.Files.asCharSink(file, Charsets.UTF_8, com.google.common.io.FileWriteMode.APPEND) + .write(contentToAppend + System.lineSeparator()); + System.out.println("Content appended successfully."); + } catch (IOException e) { + System.err.println("Error appending content to file: " + e.getMessage()); + } + } + + @Test + public void appendDataListByGuava(){ + // 创建File对象指向要追加内容的文件 + File file = new File("/Users/darcy/wdbyte/test1.txt"); + + // 要追加的内容 + List dataList = new ArrayList<>(); + dataList.add("line1 hello commons io,appendDataListByGuava"); + dataList.add("line2 hello commons io,appendDataListByGuava"); + dataList.add("line3 hello commons io,appendDataListByGuava"); + + try { + // 使用Guava的Files类以追加模式写入内容 + com.google.common.io.Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND) + .writeLines(dataList); + + System.out.println("Content appended successfully."); + } catch (IOException e) { + System.err.println("Error appending content to file: " + e.getMessage()); + } + } + + + + +} diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java new file mode 100644 index 0000000..5882f01 --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java @@ -0,0 +1,73 @@ +package com.wdbyte.io.file; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2023/12/18 + */ +public class FileDelete { + + @Test + public void deleteFile() { + Path path = Paths.get("/Users/darcy/wdbyte/test.txt"); + try { + Files.delete(path); + System.out.println("文件删除成功"); + } catch (Exception e) { + System.out.println("文件删除失败"); + e.printStackTrace(); + } + } + + @Test + public void deleteIfExists() { + Path path = Paths.get("/Users/darcy/wdbyte/test.txt"); + try { + boolean deleted = Files.deleteIfExists(path); + if (deleted) { + System.out.println("文件删除成功"); + } else { + System.out.println("文件不存在或者无法删除"); + } + } catch (Exception e) { + System.out.println("文件删除失败"); + e.printStackTrace(); + } + } + + @Test + public void delete() { + File file = new File("/Users/darcy/wdbyte/test.txt"); + if (file.delete()) { + System.out.println("文件删除成功"); + } else { + System.out.println("文件删除失败"); + } + } + + @Test + public void deleteOnExit() { + File file = new File("/Users/darcy/wdbyte/test.txt"); + file.deleteOnExit(); + } + + @Test + public void forceDelete() { + File file = new File("/Users/darcy/wdbyte/test.txt"); + try { + FileUtils.forceDelete(file); + System.out.println("文件删除成功"); + } catch (Exception e) { + System.out.println("文件删除失败"); + e.printStackTrace(); + } + } + +} diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java index 041a6b9..87e35b2 100644 --- a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java @@ -15,6 +15,7 @@ import java.util.Scanner; import java.util.stream.Stream; +import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.Test; /** @@ -165,4 +166,13 @@ public void test8() { e.printStackTrace(); } } + + @Test + public void readFileByApacheCommons() throws IOException { + File file = new File("/Users/darcy/wdbyte/test.txt"); + List list = FileUtils.readLines(file, StandardCharsets.UTF_8); + for (String data : list) { + System.out.println(data); + } + } } From a74ba18aa9d52c603b177b6d0540820ef15e2f39 Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 18 Dec 2023 21:54:16 +0800 Subject: [PATCH 65/83] README: UPDATE --- README.md | 82 +++++++++++++++--------- core-java-modules/core-java-io/README.md | 4 +- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index fbbfa9a..0784977 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,17 @@ 文章内容也都可以访问网站 [https://www.wdbyte.com](https://www.wdbyte.com) 进行阅读。 - ## ⏳ Java 开发 + +- [如何破解滑动验证码?](https://www.wdbyte.com/java/img-verification/) +- [你好 ChatGPT, 帮我看下这段代码有什么问题?](https://www.wdbyte.com/java/chatgpt-files-list.html) - [JUnit5 单元测试教程](https://www.wdbyte.com/java/junit5.html) - [使用 StringUtils.split 的坑](https://www.wdbyte.com/java/stringutils_split.html) - [必应壁纸,我的第一个 400 Star 开源项目](https://www.wdbyte.com/bing-wallpaper-400.html) - [Java 中的对象池化](https://www.wdbyte.com/java/object-pool.html) - [5种限流算法,7种限流方式,挡住突发流量?](https://www.wdbyte.com/java/rate-limiter.html) - [Java 中拼接 String 的 N 种方式](https://www.wdbyte.com/java/string-concat.html) -- [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) +- [字符作画,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) - [Java 中 RMI 的使用](https://www.wdbyte.com/2021/05/java/java-rmi/) - [如何使用 Github Actions 自动抓取每日必应壁纸?](https://www.wdbyte.com/2021/03/bing-wallpaper-github-action/) - [三种骚操作绕过迭代器遍历时的数据修改异常](https://www.wdbyte.com/2021/02/develop/interator-update/) @@ -35,7 +37,8 @@ - [如何使用 Lombok 进行优雅的编码](https://www.wdbyte.com/2018/12/develop/tool-lombok/) - [使用MyBatis Generator自动生成Model、Dao、Mapper相关代码](https://www.wdbyte.com/2017/11/develop/tool-mybatis-generator/) -## 🌿 Java 基础教程 +## 😍 Java 基础教程 + - [JDK、JRE、JVM 的区别](https://www.wdbyte.com/java/jdk-jre-jvm/) - [Java 数据类型](https://www.wdbyte.com/java/data-type/) - [Java 流程控制](https://www.wdbyte.com/java/flow-control/) @@ -43,24 +46,32 @@ - [Java Array 数组](https://www.wdbyte.com/java/java-array/) - [Java 多维数组](https://www.wdbyte.com/java/java-array-mul/) - [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder/) +- [Java Scanner](https://www.wdbyte.com/java/scanner/) - [Java 继承](https://www.wdbyte.com/java/extends/) - [Java 接口](https://www.wdbyte.com/java/interface/) - [Java 抽象类](https://www.wdbyte.com/java/abstract/) +- [抽象类和接口的区别](https://www.wdbyte.com/java/abs-interface/) - [Java 多态](https://www.wdbyte.com/java/polymorphism/) - [Java Scanner](https://www.wdbyte.com/java/scanner/) -- [Java 日期时间 Date](https://www.wdbyte.com/java/date/) +- [Java 日期时间Date](https://www.wdbyte.com/java/date/) - [Java 异常处理](https://www.wdbyte.com/java/exception/) - [Java 枚举](https://www.wdbyte.com/java/enum/) -- [Java 注释](https://www.wdbyte.com/java/comment/) +- [Java 注释](*https://www.wdbyte.com/java/comment/*) - [Java 集合框架](https://www.wdbyte.com/java/collection/) -- [Java 中使用 List](https://www.wdbyte.com/java/list/) +- [Java 中使用 List ](https://www.wdbyte.com/java/list/) + +## 😃Java I/O 教程 -## Java I/O 教程 - [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) - [Java 读取文件](https://www.wdbyte.com/java/io/file-read/) +- [Java 追加内容到文件](https://www.wdbyte.com/java/io/file-append/) +- [Java 如何删除文件](https://www.wdbyte.com/java/io/file-delete/) + +## 🎉 Java 进阶教程 -## Java 进阶 - [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) +- [Java 热加载手动实现](https://www.wdbyte.com/2019/10/jvm/java-hotput/) + ## 🌿 SpringBoot 2.x 教程 @@ -70,9 +81,9 @@ - [Spring Boot 系列(二)Spring Boot 配置文件](https://www.wdbyte.com/2019/01/springboot/springboot01-config/) - [Spring Boot 系列(三)Spring Boot 自动配置](https://www.wdbyte.com/2019/01/springboot/springboot03-auto-config/) - [Spring Boot 系列(四)Spring Boot 日志框架](https://www.wdbyte.com/2019/01/springboot/springboot04-log/) -- [Spring Boot 系列(五)web 开发之静态资源和模版引擎](https://www.wdbyte.com/2019/02/springboot/springboot-05-web-static-template/) -- [Spring Boot 系列(六)web 开发之拦截器和三大组件](https://www.wdbyte.com/2019/02/springboot/springboot-06-web-filter-apo-webbase/) -- [Spring Boot 系列(七)web 开发之异常错误处理机制剖析](https://www.wdbyte.com/2019/02/springboot/springboot-07-web-exception/) +- [Spring Boot 系列(五)Web 开发之静态资源和模版引擎](https://www.wdbyte.com/2019/02/springboot/springboot-05-web-static-template/) +- [Spring Boot 系列(六)Web 开发之拦截器和三大组件](https://www.wdbyte.com/2019/02/springboot/springboot-06-web-filter-apo-webbase/) +- [Spring Boot 系列(七)Web 开发之异常错误处理机制剖析](https://www.wdbyte.com/2019/02/springboot/springboot-07-web-exception/) - [Spring Boot 系列(八)动态 Banner 与图片转字符图案的手动实现](https://www.wdbyte.com/2019/02/springboot/springboot-08-banner/) - [Spring Boot 系列(九)使用 Spring JDBC 和 Druid 数据源监控](https://www.wdbyte.com/2019/02/springboot/springboot-09-data-jdbc/) - [Spring Boot 系列(十)使用 Spring data jpa 访问数据库](https://www.wdbyte.com/2019/03/springboot/springboot-10-data-jpa/) @@ -97,11 +108,11 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Java 20 新功能介绍](https://www.wdbyte.com/java/java-20/) - [Java 19 新功能介绍](https://www.wdbyte.com/java/java-19/) - [Java 18 新功能介绍](https://www.wdbyte.com/java/java-18/) -- [Java 17 新功能介绍 (LTS)](https://www.wdbyte.com/java/java-17/) +- [Java 17 新功能介绍](https://www.wdbyte.com/java/java-17/) - [Java 16 新功能介绍](https://www.wdbyte.com/java/java-16/) - [Java 15 新功能介绍](https://www.wdbyte.com/java/java-15/) -- [Java 14 新特性讲解](https://www.wdbyte.com/java/java-14/) -- [Java 13 新特性讲解](https://www.wdbyte.com/java/java-13/) +- [Java 14 新特性介绍](https://www.wdbyte.com/java/java-14/) +- [Java 13 新特性介绍](https://www.wdbyte.com/java/java-13/) - [Java 12 新特性介绍](https://www.wdbyte.com/2020/02/jdk/jdk12-feature/) - [Java 11 新特性介绍](https://www.wdbyte.com/2020/03/jdk/jdk11-feature/) - [Java 10 新特性介绍](https://www.wdbyte.com/2020/02/jdk/jdk10-feature/) @@ -112,8 +123,8 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Java 8 函数接口 Supplier ](https://www.wdbyte.com/java8/java8-supplier/) - [Java 8 函数接口 Predicate ](https://www.wdbyte.com/java8/java8-predicate/) - [Java 8 函数接口 Function ](https://www.wdbyte.com/java8/java8-function/) +- [Java 8 Lambda 和 Comparator 排序](https://www.wdbyte.com/java8/comparator/) - [Java 8 新特性 - forEach 遍历](https://www.wdbyte.com/java8/java8-foreach/) - - [Java 8 新特性 - LocalDate、LocalDateTime 时间处理介绍](https://www.wdbyte.com/2019/10/jdk/jdk8-time/) - [Java 8 新特性 - 使用 Optional优雅的处理空指针](https://www.wdbyte.com/2019/11/jdk/jdk8-optional/) - [Java 8 新特性 - Lambda 表达式、函数接口了解一下](https://www.wdbyte.com/2019/11/jdk/jdk8-lambda/) @@ -123,28 +134,36 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 以上 Java 新功能文章源码: [Github.com/niumoo/jdk-feature](https://github.com/niumoo/jdk-feature) -## 🔬 JDK 源码分析 +## 🔬 JDK 源码分析 面试必备的 JDK 源码分析。探寻 JDK 大佬的设计思路。没有链接部分为后续更新内容,持续更新中。 -- [集合 -「源码分析」CopyOnWriteArrayList 中的隐藏的知识,你Get了吗?](https://www.wdbyte.com/2020/10/jdk/src-copyonwritearraylist/) -- [集合 -「源码分析」ArrayList和LinkedList如何实现的?我看你还有机会!](https://www.wdbyte.com/2020/08/jdk/src-arraylist-linkedlist/) -- [集合 -「源码分析」还不懂 ConcurrentHashMap ?这份源码分析了解一下](https://www.wdbyte.com/2020/04/jdk/concurrent-hashmap/) -- [集合 -「源码分析」最通俗易懂的 HashMap 源码分析解读](https://www.wdbyte.com/2020/03/jdk/hashmap/) -- 集合 -「源码分析」TreeSet -- 集合 -「源码分析」LinkedHashSet +- [集合 - CopyOnWriteArrayList 实现原理和源码分析](https://www.wdbyte.com/2020/10/jdk/src-copyonwritearraylist/) +- [集合 - ArrayList和LinkedList 实现原理和源码分析](https://www.wdbyte.com/2020/08/jdk/src-arraylist-linkedlist/) +- 集合 -「源码分析」Vector +- [集合 - ConcurrentHashMap 实现原理和源码分析](https://www.wdbyte.com/2020/04/jdk/concurrent-hashmap/) +- [集合 - HashMap 实现原理和源码分析](https://www.wdbyte.com/2020/03/jdk/hashmap/) +- 集合 - TreeMap 实现原理和源码分析 +- 集合 - TreeSet 实现原理和源码分析 +- 集合 - LinkedHashSet 实现原理和源码分析 - 基础类 - Object -- 基础类 - String +- 基础类 - String - 基础类 - StringBuffer & StringBuilder ## 💻 Java 并发编程 -- 线程基础之通知、等待、休眠、让行、中断 -- ThreadLocal +- Java 线程创建与运行 +- Java 线程通知与等待 +- Java 线程休眠与让行 +- Java 线程中断与停止 +- Java 线程死锁 +- Java 线程的上下文切换 +- Java 守护线程与用户线程 +- Java ThreadLocal - 内存可见性、伪共享 -- synchronized -- volatile +- Java synchronized +- Java volatile - 原子操作 - 排它锁、悲观锁、乐观锁、公平锁、非公平锁、独占锁、共享锁、重入锁、自旋锁 - ThreadLocalRandom @@ -170,8 +189,9 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - 锁的自动优化升级策略 ## 🔍 Java 性能分析 - - [Java 中的5个代码性能提升技巧,最高提升9.5倍](https://www.wdbyte.com/java/code-5-tips.html) +- [JMC 使用教程](https://www.wdbyte.com/java/performance/jmc.html) +- [JFR 使用教程](https://www.wdbyte.com/java/performance/jfr.html) - [使用 JMX 监控和管理 Java 程序](https://www.wdbyte.com/java/jmx.html) - [Java 中的监控与管理原理概述](https://www.wdbyte.com/java/monitoring.html) - [JMH-大厂是如何使用JMH进行Java代码性能测试的?必须掌握!](https://www.wdbyte.com/2020/08/develop/tool-jmh/) @@ -201,12 +221,11 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Apache HttpClient 5 使用详细教程](https://www.wdbyte.com/tool/httpclient5.html) - [Jackson 解析 JSON 详细教程](https://www.wdbyte.com/tool/jackson.html) - [Java 反编译工具的使用与对比分析](https://www.wdbyte.com/2021/05/java-decompiler/) -- [可以Postman,也可以cURL.进来领略下cURL的独门绝技](https://www.wdbyte.com/2020/06/tool/curl/) -- [抛弃Eclipse,投入IDEA 的独孤求败江湖](https://www.wdbyte.com/2019/10/develop/idea-skill/) +- [cURL 使用教程](https://www.wdbyte.com/2020/06/tool/curl/) +- [Java IDEA 使用教程](https://www.wdbyte.com/2019/10/develop/idea-skill/) - [使用Apache Ant 进行Java web项目打包并部署至TOMCAT](https://www.wdbyte.com/2017/11/develop/tool-apache-ant/) - [Linux配置Tomcat的单机多实例](https://www.wdbyte.com/2018/08/develop/install-tomcat-many-instance/) - [Linux定时任务crontab的使用](https://www.wdbyte.com/2018/05/linux/linux-crontab/) -- [原来热加载如此简单,手动写一个 Java 热加载吧](https://www.wdbyte.com/2019/10/jvm/java-hotput/) - [Manjaro Linux 入门使用教程](https://www.wdbyte.com/2020/04/linux/linux-manjaro/) - [Ubuntu18 的超详细常用软件安装](https://www.wdbyte.com/2018/11/linux/start-ubuntu/) @@ -220,7 +239,6 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)](https://www.wdbyte.com/2018/10/io/io2-nio/) - [IO通信模型(一)同步阻塞模式BIO(Blocking IO)](https://www.wdbyte.com/2018/10/io/io1-bio/) - ## 🗺 贡献与建议 1. 内容难免存在笔误,一个错别字,一个语法错误,都是贡献。 diff --git a/core-java-modules/core-java-io/README.md b/core-java-modules/core-java-io/README.md index 8ebf834..85360a7 100644 --- a/core-java-modules/core-java-io/README.md +++ b/core-java-modules/core-java-io/README.md @@ -2,6 +2,8 @@ 当前模块包含 IO 相关代码 ### 相关文章 -- [Java 读取文件](https://www.wdbyte.com/java/io/file-read/) - [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) +- [Java 读取文件](https://www.wdbyte.com/java/io/file-read/) +- [Java 追加内容到文件](https://www.wdbyte.com/java/io/file-append/) +- [Java 如何删除文件](https://www.wdbyte.com/java/io/file-delete/) - [字符图案,我用字符画个冰墩墩](https://www.wdbyte.com/java/char-image.html) \ No newline at end of file From 0fae92c5eb8bd76adcecc159ab987b711a3a4300 Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 27 Feb 2024 20:10:26 +0800 Subject: [PATCH 66/83] feat: add springboot+jpa+sqlite --- springboot/springboot-sqlite-jpa/README.md | 19 ++ springboot/springboot-sqlite-jpa/mvnw | 308 ++++++++++++++++++ springboot/springboot-sqlite-jpa/mvnw.cmd | 205 ++++++++++++ springboot/springboot-sqlite-jpa/pom.xml | 81 +++++ .../springsqlite/SpringBootSqliteApp.java | 13 + .../controller/SqliteController.java | 66 ++++ .../springsqlite/model/WebsiteUser.java | 43 +++ .../repository/WebsiteUserRepository.java | 11 + .../src/main/resources/application.properties | 7 + .../SpringbootSqliteJpaApplicationTests.java | 13 + 10 files changed, 766 insertions(+) create mode 100644 springboot/springboot-sqlite-jpa/README.md create mode 100755 springboot/springboot-sqlite-jpa/mvnw create mode 100644 springboot/springboot-sqlite-jpa/mvnw.cmd create mode 100644 springboot/springboot-sqlite-jpa/pom.xml create mode 100644 springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java create mode 100644 springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java create mode 100644 springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/model/WebsiteUser.java create mode 100644 springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java create mode 100644 springboot/springboot-sqlite-jpa/src/main/resources/application.properties create mode 100644 springboot/springboot-sqlite-jpa/src/test/java/com/wdbyte/springbootsqlitejpa/SpringbootSqliteJpaApplicationTests.java diff --git a/springboot/springboot-sqlite-jpa/README.md b/springboot/springboot-sqlite-jpa/README.md new file mode 100644 index 0000000..bf0984a --- /dev/null +++ b/springboot/springboot-sqlite-jpa/README.md @@ -0,0 +1,19 @@ +# Srping Boot + JPA + Sqlite + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.2.3/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.2.3/maven-plugin/reference/html/#build-image) +* [Spring Web](https://docs.spring.io/spring-boot/docs/3.2.3/reference/htmlsingle/index.html#web) +* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/3.2.3/reference/htmlsingle/index.html#data.sql.jpa-and-spring-data) + +### Guides +The following guides illustrate how to use some features concretely: + +* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) +* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) +* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) +* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) + diff --git a/springboot/springboot-sqlite-jpa/mvnw b/springboot/springboot-sqlite-jpa/mvnw new file mode 100755 index 0000000..66df285 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot/springboot-sqlite-jpa/mvnw.cmd b/springboot/springboot-sqlite-jpa/mvnw.cmd new file mode 100644 index 0000000..95ba6f5 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/springboot/springboot-sqlite-jpa/pom.xml b/springboot/springboot-sqlite-jpa/pom.xml new file mode 100644 index 0000000..47d85ed --- /dev/null +++ b/springboot/springboot-sqlite-jpa/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + com.wdbyte + springboot-sqlite-jpa + 0.0.1-SNAPSHOT + springboot-sqlite-jpa + Demo project for Spring Boot + + 21 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.hibernate.orm + hibernate-community-dialects + 6.4.3.Final + + + + org.xerial + sqlite-jdbc + 3.45.1.0 + + + org.projectlombok + lombok + true + + + org.apache.commons + commons-lang3 + 3.13.0 + + + commons-codec + commons-codec + 1.16.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java new file mode 100644 index 0000000..d238e29 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java @@ -0,0 +1,13 @@ +package com.wdbyte.springsqlite; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootSqliteApp { + + public static void main(String[] args) { + SpringApplication.run(SpringBootSqliteApp.class, args); + } + +} diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java new file mode 100644 index 0000000..132d69c --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java @@ -0,0 +1,66 @@ +package com.wdbyte.springsqlite.controller; + +import java.time.LocalDateTime; + +import com.wdbyte.springsqlite.model.WebsiteUser; +import com.wdbyte.springsqlite.repository.WebsiteUserRepository; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author niulang + * @date 2024/02/27 + */ +@Slf4j +@RestController +public class SqliteController { + + @Autowired + private WebsiteUserRepository userRepository; + + @GetMapping("/sqlite/init") + public String init() { + for (int i = 0; i < 10; i++) { + WebsiteUser websiteUser = new WebsiteUser(); + // 随机4个字母 + websiteUser.setUsername(RandomStringUtils.randomAlphabetic(4)); + // 随机16个字符用于密码加盐加密 + websiteUser.setSalt(RandomStringUtils.randomAlphanumeric(16)); + String password = "123456"; + // 密码存储 = md5(密码+盐) + password = password + websiteUser.getSalt(); + websiteUser.setPassword(DigestUtils.md5Hex(password)); + websiteUser.setCreatedAt(LocalDateTime.now()); + websiteUser.setUpdatedAt(LocalDateTime.now()); + websiteUser.setStatus("active"); + WebsiteUser saved = userRepository.save(websiteUser); + log.info("init user {}", saved.getUsername()); + } + return "init success"; + } + + @GetMapping("/sqlite/find") + public String findByUsername(String username) { + WebsiteUser websiteUser = userRepository.findByUsername(username); + return websiteUser.toString(); + } + + @GetMapping("/sqlite/login") + public String findByUsername(String username, String password) { + WebsiteUser websiteUser = userRepository.findByUsername(username); + if (websiteUser == null) { + return "login failed"; + } + password = password + websiteUser.getSalt(); + if (StringUtils.equals(DigestUtils.md5Hex(password), websiteUser.getPassword())) { + return "login succeeded"; + } else { + return "login failed"; + } + } +} diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/model/WebsiteUser.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/model/WebsiteUser.java new file mode 100644 index 0000000..264eec0 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/model/WebsiteUser.java @@ -0,0 +1,43 @@ +package com.wdbyte.springsqlite.model; + +import java.time.LocalDateTime; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Entity +@Getter +@Setter +@ToString +@Table(name = "website_user") +public class WebsiteUser { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "username", nullable = false, unique = true, length = 64) + private String username; + + @Column(name = "password", nullable = false, length = 255) + private String password; + + @Column(name = "salt", nullable = false, length = 16) + private String salt; + + @Column(name = "status", nullable = false, length = 16, columnDefinition = "VARCHAR(16) DEFAULT 'active'") + private String status; + + @Column(name = "created_at", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime createdAt; + + @Column(name = "updated_at", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updatedAt; +} diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java new file mode 100644 index 0000000..7f830a2 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java @@ -0,0 +1,11 @@ +package com.wdbyte.springsqlite.repository; + +import com.wdbyte.springsqlite.model.WebsiteUser; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface WebsiteUserRepository extends CrudRepository { + + WebsiteUser findByUsername(String name); +} \ No newline at end of file diff --git a/springboot/springboot-sqlite-jpa/src/main/resources/application.properties b/springboot/springboot-sqlite-jpa/src/main/resources/application.properties new file mode 100644 index 0000000..fa5d94e --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.url=jdbc:sqlite:springboot-sqlite-jpa.db +spring.datasource.driver-class-name=org.sqlite.JDBC + +# JPA Properties +spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true diff --git a/springboot/springboot-sqlite-jpa/src/test/java/com/wdbyte/springbootsqlitejpa/SpringbootSqliteJpaApplicationTests.java b/springboot/springboot-sqlite-jpa/src/test/java/com/wdbyte/springbootsqlitejpa/SpringbootSqliteJpaApplicationTests.java new file mode 100644 index 0000000..7d48850 --- /dev/null +++ b/springboot/springboot-sqlite-jpa/src/test/java/com/wdbyte/springbootsqlitejpa/SpringbootSqliteJpaApplicationTests.java @@ -0,0 +1,13 @@ +package com.wdbyte.springbootsqlitejpa; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringbootSqliteJpaApplicationTests { + + @Test + void contextLoads() { + } + +} From 39c0d444bedb4ba28ca322d94863a8c02b784c0e Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 27 Feb 2024 23:43:46 +0800 Subject: [PATCH 67/83] feat: add springboot+jpa+sqlite --- .../java/com/wdbyte/springsqlite/SpringBootSqliteApp.java | 3 +++ .../wdbyte/springsqlite/controller/SqliteController.java | 6 ++++-- .../springsqlite/repository/WebsiteUserRepository.java | 5 +++++ .../src/main/resources/application.properties | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java index d238e29..f54d63a 100644 --- a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/SpringBootSqliteApp.java @@ -3,6 +3,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +/** + * @author https://www.wdbyte.com + */ @SpringBootApplication public class SpringBootSqliteApp { diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java index 132d69c..b78d228 100644 --- a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/controller/SqliteController.java @@ -13,8 +13,7 @@ import org.springframework.web.bind.annotation.RestController; /** - * @author niulang - * @date 2024/02/27 + * @author https://www.wdbyte.com */ @Slf4j @RestController @@ -47,6 +46,9 @@ public String init() { @GetMapping("/sqlite/find") public String findByUsername(String username) { WebsiteUser websiteUser = userRepository.findByUsername(username); + if (websiteUser == null) { + return null; + } return websiteUser.toString(); } diff --git a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java index 7f830a2..12b6af0 100644 --- a/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java +++ b/springboot/springboot-sqlite-jpa/src/main/java/com/wdbyte/springsqlite/repository/WebsiteUserRepository.java @@ -7,5 +7,10 @@ @Repository public interface WebsiteUserRepository extends CrudRepository { + /** + * 根据 username 查询数据 + * @param name + * @return + */ WebsiteUser findByUsername(String name); } \ No newline at end of file diff --git a/springboot/springboot-sqlite-jpa/src/main/resources/application.properties b/springboot/springboot-sqlite-jpa/src/main/resources/application.properties index fa5d94e..3ee254a 100644 --- a/springboot/springboot-sqlite-jpa/src/main/resources/application.properties +++ b/springboot/springboot-sqlite-jpa/src/main/resources/application.properties @@ -1,7 +1,7 @@ spring.datasource.url=jdbc:sqlite:springboot-sqlite-jpa.db spring.datasource.driver-class-name=org.sqlite.JDBC - # JPA Properties spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect +# create ?????????update????????? spring.jpa.hibernate.ddl-auto=update -spring.jpa.show-sql=true +spring.jpa.show-sql=true \ No newline at end of file From f5a1d62f269da4e199b4e3a7742b2e0992e5410e Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 28 Feb 2024 15:04:30 +0800 Subject: [PATCH 68/83] feat: add springboot+jpa+sqlite --- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.jar create mode 100644 springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.properties diff --git a/springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.jar b/springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.properties b/springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..5f0536e --- /dev/null +++ b/springboot/springboot-sqlite-jpa/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar From 78c287c82ca0ad2fec8157bf4d6d8f448c93c297 Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 28 Feb 2024 19:41:21 +0800 Subject: [PATCH 69/83] update readme.md --- README.md | 14 ++++++++++--- springboot/springboot-sqlite-jpa/README.md | 23 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0784977..f1456ed 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,10 @@ 未读代码

-目录中没有链接的部分,后续更新,感谢你的 ​STAR​ ,有问题或者建议可以[一起完善](Accept#-%E8%B4%A1%E7%8C%AE%E4%B8%8E%E5%BB%BA%E8%AE%AE)。 -文章内容也都可以访问网站 [https://www.wdbyte.com](https://www.wdbyte.com) 进行阅读。 +目录中没有链接的部分,后续更新,感谢你的关注 ,有问题或者建议可以[一起完善](#🗺-贡献与建议)。 +> Hi there 👋 我是阿朗, 一名 Java 开发者,热衷于分享一些通俗易懂的技术文章。 分享几句鸡汤,长寿在于生活规律;成功在于坚持不懈。 做好的事情,而不是好做的事情。 + ## ⏳ Java 开发 @@ -96,6 +97,7 @@ - [Spring Boot 系列(十七)迅速使用 Spring Boot Admin 监控你的 Spring Boot 程序](https://www.wdbyte.com/2019/12/springboot/springboot-17-admin/) - [Spring Boot 系列(十八)最详细的 Spring Boot 多模块开发与排坑指南](https://www.wdbyte.com/2020/03/springboot/springboot-18-module/) - [Spring Boot 系列(十九)SpringBoot 的多数据源配置](https://www.wdbyte.com/2020/12/springboot/springboot-multiple-datasource/) +- [Spring Boot 系列(二十)Spring Boot,JPA与SQLite 的快速启动](https://www.wdbyte.com/springboot/sqlite/) 以上 Spring Boot 文章源码:[Github.com/niumoo/springboot](https://github.com/niumoo/springboot/) @@ -209,6 +211,9 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - 堆 - 图 +## 🍔 数据库 +- [SQLite 入门教程](https://www.wdbyte.com/db/sqlite/) + ## 🧰 工具技巧 >“工欲善其事,必先利其器” @@ -239,9 +244,12 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)](https://www.wdbyte.com/2018/10/io/io2-nio/) - [IO通信模型(一)同步阻塞模式BIO(Blocking IO)](https://www.wdbyte.com/2018/10/io/io1-bio/) + ## 🗺 贡献与建议 -1. 内容难免存在笔误,一个错别字,一个语法错误,都是贡献。 +反馈地址:[https://github.com/niumoo/JavaNotes/issues](https://github.com/niumoo/JavaNotes/issues) + +1. 内容难免存在笔误,一个错别字,一个语法错误,都是建议。 2. 文章中的错误和不足,或者不完善的地方都可以进行补充或者修改。 3. 我没有涉及到的知识点,也可以进行补充。 diff --git a/springboot/springboot-sqlite-jpa/README.md b/springboot/springboot-sqlite-jpa/README.md index bf0984a..5be62f4 100644 --- a/springboot/springboot-sqlite-jpa/README.md +++ b/springboot/springboot-sqlite-jpa/README.md @@ -1,5 +1,28 @@ # Srping Boot + JPA + Sqlite +使用 **Spring Boot** 可以快速的创建一个基于Spring 的、独立的、生产级的应用程序,并且可以直接运行。Spring Boot 采用习惯性配置,整合大量 Spring 组建和第三方库,让你只需要少量的修改就可以轻松上手。 + +- [Spring Boot 系列(一)Spring Boot 入门篇](https://www.wdbyte.com/2019/01/springboot/springboot01-quick-start/) +- [Spring Boot 系列(二)Spring Boot 配置文件](https://www.wdbyte.com/2019/01/springboot/springboot01-config/) +- [Spring Boot 系列(三)Spring Boot 自动配置](https://www.wdbyte.com/2019/01/springboot/springboot03-auto-config/) +- [Spring Boot 系列(四)Spring Boot 日志框架](https://www.wdbyte.com/2019/01/springboot/springboot04-log/) +- [Spring Boot 系列(五)Web 开发之静态资源和模版引擎](https://www.wdbyte.com/2019/02/springboot/springboot-05-web-static-template/) +- [Spring Boot 系列(六)Web 开发之拦截器和三大组件](https://www.wdbyte.com/2019/02/springboot/springboot-06-web-filter-apo-webbase/) +- [Spring Boot 系列(七)Web 开发之异常错误处理机制剖析](https://www.wdbyte.com/2019/02/springboot/springboot-07-web-exception/) +- [Spring Boot 系列(八)动态 Banner 与图片转字符图案的手动实现](https://www.wdbyte.com/2019/02/springboot/springboot-08-banner/) +- [Spring Boot 系列(九)使用 Spring JDBC 和 Druid 数据源监控](https://www.wdbyte.com/2019/02/springboot/springboot-09-data-jdbc/) +- [Spring Boot 系列(十)使用 Spring data jpa 访问数据库](https://www.wdbyte.com/2019/03/springboot/springboot-10-data-jpa/) +- [Spring Boot 系列(十一)使用 Mybatis(自动生成插件) 访问数据库](https://www.wdbyte.com/2019/03/springboot/springboot-11-data-mybatis/) +- [Spring Boot 系列(十二)使用 Mybatis 集成 pagehelper 分页插件和 mapper 插件](https://www.wdbyte.com/2019/03/springboot/springboot-12-data-mybatis-page/) +- [Spring Boot 系列(十三)使用邮件服务](https://www.wdbyte.com/2019/03/springboot/springboot-13-email/) +- [Spring Boot 系列(十四)迅速启用 HTTPS 加密你的网站](https://www.wdbyte.com/2019/08/springboot/springboot-14-https/) +- [Spring Boot 系列(十五)如何编写自己的 Springboot starter](https://www.wdbyte.com/2019/11/springboot/springboot-15-my-starter/) +- [Spring Boot 系列(十六)你真的了解 Swagger 文档吗?](https://www.wdbyte.com/2019/11/springboot/springboot-16-web-swagger/) +- [Spring Boot 系列(十七)迅速使用 Spring Boot Admin 监控你的 Spring Boot 程序](https://www.wdbyte.com/2019/12/springboot/springboot-17-admin/) +- [Spring Boot 系列(十八)最详细的 Spring Boot 多模块开发与排坑指南](https://www.wdbyte.com/2020/03/springboot/springboot-18-module/) +- [Spring Boot 系列(十九)SpringBoot 的多数据源配置](https://www.wdbyte.com/2020/12/springboot/springboot-multiple-datasource/) +- [Spring Boot 系列(二十)Spring Boot,JPA与SQLite 的快速启动](https://www.wdbyte.com/springboot/sqlite/) +- ### Reference Documentation For further reference, please consider the following sections: From d69973d0babeeecc5e172c0cc094e4de1d184c8b Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 5 Mar 2024 11:43:53 +0800 Subject: [PATCH 70/83] code: add java arrays demo --- .../com/wdbyte/collection/EnumMapTest.java | 25 +++ .../com/wdbyte/collection/JavaArrays.java | 146 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java create mode 100644 core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java diff --git a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java new file mode 100644 index 0000000..4646e7d --- /dev/null +++ b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java @@ -0,0 +1,25 @@ +package com.wdbyte.collection; + +import java.util.EnumMap; + +/** + * @author niulang + * @date 2023/10/20 + */ +public class EnumMapTest { + public static void main(String[] args) { + EnumMap enumMap = new EnumMap(Week.class); + enumMap.put(Week.a,null); + System.out.println(enumMap.get(Week.a)); + } +} + +enum Week { + a, + b, + c, + d, + e, + f, + g +} diff --git a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java new file mode 100644 index 0000000..47da76b --- /dev/null +++ b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java @@ -0,0 +1,146 @@ +package com.wdbyte.collection; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.function.IntFunction; +import java.util.function.ToIntFunction; + +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2024/03/04 + */ +public class JavaArrays { + + @Test + public void print() { + String[] arr = new String[] {"a", "b", "c", "d"}; + System.out.println(Arrays.toString(arr)); + } + + @Test + public void init() { + String[] arr = new String[] {"a", "b", "c", "d"}; + String[] copyOf2 = Arrays.copyOf(arr, 2); + String[] copyOfRange = Arrays.copyOfRange(arr, 1, 3); + + System.out.println(Arrays.toString(arr)); + System.out.println(Arrays.toString(copyOf2)); + System.out.println(Arrays.toString(copyOfRange)); + + // 目标大小大于原始大小,则copyOf 会用null填充数组 。 + String[] copyOf10 = Arrays.copyOf(arr, 10); + System.out.println(Arrays.toString(copyOf10)); + } + + @Test + public void fill() { + String[] arr = new String[5]; + Arrays.fill(arr, "java"); + System.out.println(Arrays.toString(arr)); + + // 生成 100以内的 随机数 + IntFunction intFunction = i -> new Random().nextInt(100); + Integer[] intArr = new Integer[5]; + Arrays.setAll(intArr, intFunction); + System.out.println(Arrays.toString(intArr)); + } + + @Test + public void diff() { + String[] arr = new String[] {"a", "b", "c", "d"}; + Object[] arr1 = new Object[] {arr, new String[] {"a", "b", "c", "d"}}; + Object[] arr2 = new Object[] {arr, arr}; + + System.out.println(Arrays.equals(arr1, arr2)); + System.out.println(Arrays.deepEquals(arr1, arr2)); + + // hashCode + System.out.println(Arrays.hashCode(arr2)); + System.out.println(Arrays.deepHashCode(arr2)); + + arr[0] = null; + System.out.println(Arrays.hashCode(arr2)); + System.out.println(Arrays.deepHashCode(arr2)); + } + + @Test + public void sort() { + // 生成 100以内的 随机数 + IntFunction intFunction = i -> new Random().nextInt(100); + Integer[] intArr = new Integer[5]; + Arrays.setAll(intArr, intFunction); + System.out.println(Arrays.toString(intArr)); + + Arrays.sort(intArr); + System.out.println(Arrays.toString(intArr)); + + //long cost = 0; + //for (int ii = 0; ii < 10; ii++) { + // IntFunction intFunction = i -> new Random().nextInt(100000); + // Integer[] intArr = new Integer[100000]; + // Arrays.setAll(intArr, intFunction); + // + // long start = System.currentTimeMillis(); + // Arrays.sort(intArr); + // long end = System.currentTimeMillis(); + // cost = cost + (end - start); + //} + //System.out.println(cost / 10); + // + //cost = 0; + //for (int ii = 0; ii < 10; ii++) { + // IntFunction intFunction = i -> new Random().nextInt(100000); + // Integer[] intArr = new Integer[100000]; + // Arrays.setAll(intArr, intFunction); + // + // long start = System.currentTimeMillis(); + // Arrays.parallelSort(intArr); + // long end = System.currentTimeMillis(); + // cost = cost + (end - start); + //} + //System.out.println(cost / 10); + } + + @Test + public void search() { + Integer[] intArr = new Integer[] {2, 3, 4, 5, 6, 7, 8, 9}; + int index = Arrays.binarySearch(intArr, 3); + System.out.println("index:"+index); + System.out.println(intArr[index]); + } + + @Test + public void stream() { + Integer[] intArr = new Integer[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + System.out.println(Arrays.stream(intArr).count()); + ToIntFunction toIntFunction = i -> (int)i; + System.out.println(Arrays.stream(intArr).mapToInt(toIntFunction).sum()); + } + + @Test + public void cast() { + String[] arr = new String[] {"a", "b", "c", "d"}; + Object[] arr2 = new Object[] {arr, arr}; + + System.out.println(Arrays.toString(arr)); + System.out.println(Arrays.toString(arr2)); + + System.out.println(Arrays.deepToString(arr)); + System.out.println(Arrays.deepToString(arr2)); + + List list = Arrays.asList(arr); + System.out.println(list); + System.out.println(list.getClass()); + // list.add("e"); 报错 + } + + @Test + public void prefix() { + Integer[] intArr = new Integer[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + Arrays.parallelPrefix(intArr, (left, right) -> left + right); + System.out.println(Arrays.toString(intArr)); + } +} From bb9512ff9406ac457b49f0a409b9f5d0e6a439f5 Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 6 Mar 2024 20:07:45 +0800 Subject: [PATCH 71/83] feat: add springboot hello demo --- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + springboot/springboot-hello/README.md | 1 + springboot/springboot-hello/mvnw | 308 ++++++++++++++++++ springboot/springboot-hello/mvnw.cmd | 205 ++++++++++++ springboot/springboot-hello/pom.xml | 35 ++ .../com/wdbyte/start/HelloController.java | 20 ++ .../java/com/wdbyte/start/SpringBootApp.java | 16 + .../src/main/resources/application.properties | 1 + 9 files changed, 588 insertions(+) create mode 100644 springboot/springboot-hello/.mvn/wrapper/maven-wrapper.jar create mode 100644 springboot/springboot-hello/.mvn/wrapper/maven-wrapper.properties create mode 100644 springboot/springboot-hello/README.md create mode 100755 springboot/springboot-hello/mvnw create mode 100644 springboot/springboot-hello/mvnw.cmd create mode 100644 springboot/springboot-hello/pom.xml create mode 100644 springboot/springboot-hello/src/main/java/com/wdbyte/start/HelloController.java create mode 100644 springboot/springboot-hello/src/main/java/com/wdbyte/start/SpringBootApp.java create mode 100644 springboot/springboot-hello/src/main/resources/application.properties diff --git a/springboot/springboot-hello/.mvn/wrapper/maven-wrapper.jar b/springboot/springboot-hello/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/springboot/springboot-hello/.mvn/wrapper/maven-wrapper.properties b/springboot/springboot-hello/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..5f0536e --- /dev/null +++ b/springboot/springboot-hello/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/springboot/springboot-hello/README.md b/springboot/springboot-hello/README.md new file mode 100644 index 0000000..c038db4 --- /dev/null +++ b/springboot/springboot-hello/README.md @@ -0,0 +1 @@ +# Srping Boot 简单 Web 接口 diff --git a/springboot/springboot-hello/mvnw b/springboot/springboot-hello/mvnw new file mode 100755 index 0000000..66df285 --- /dev/null +++ b/springboot/springboot-hello/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot/springboot-hello/mvnw.cmd b/springboot/springboot-hello/mvnw.cmd new file mode 100644 index 0000000..95ba6f5 --- /dev/null +++ b/springboot/springboot-hello/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/springboot/springboot-hello/pom.xml b/springboot/springboot-hello/pom.xml new file mode 100644 index 0000000..343a330 --- /dev/null +++ b/springboot/springboot-hello/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + com.wdbyte + springboot-hello + 0.0.1-SNAPSHOT + springboot-hello + Demo project for Spring Boot + + 21 + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot/springboot-hello/src/main/java/com/wdbyte/start/HelloController.java b/springboot/springboot-hello/src/main/java/com/wdbyte/start/HelloController.java new file mode 100644 index 0000000..e887c46 --- /dev/null +++ b/springboot/springboot-hello/src/main/java/com/wdbyte/start/HelloController.java @@ -0,0 +1,20 @@ +package com.wdbyte.start; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author https://www.wdbyte.com + */ +@RestController +public class HelloController { + + @GetMapping("/hello") + public String hello(String username) { + if (username == null) { + return "Hello,Who are you?"; + } + return "Hello," + username; + } + +} diff --git a/springboot/springboot-hello/src/main/java/com/wdbyte/start/SpringBootApp.java b/springboot/springboot-hello/src/main/java/com/wdbyte/start/SpringBootApp.java new file mode 100644 index 0000000..6f46204 --- /dev/null +++ b/springboot/springboot-hello/src/main/java/com/wdbyte/start/SpringBootApp.java @@ -0,0 +1,16 @@ +package com.wdbyte.start; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author https://www.wdbyte.com + */ +@SpringBootApplication +public class SpringBootApp { + + public static void main(String[] args) { + SpringApplication.run(SpringBootApp.class, args); + } + +} diff --git a/springboot/springboot-hello/src/main/resources/application.properties b/springboot/springboot-hello/src/main/resources/application.properties new file mode 100644 index 0000000..a3ac65c --- /dev/null +++ b/springboot/springboot-hello/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 \ No newline at end of file From 7963384049d4ed0dbe341f8520393591664bb924 Mon Sep 17 00:00:00 2001 From: niumoo Date: Fri, 8 Mar 2024 09:06:42 +0800 Subject: [PATCH 72/83] update README.md --- README.md | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index f1456ed..baab1c6 100644 --- a/README.md +++ b/README.md @@ -44,20 +44,27 @@ - [Java 数据类型](https://www.wdbyte.com/java/data-type/) - [Java 流程控制](https://www.wdbyte.com/java/flow-control/) - [Java String 字符串](https://www.wdbyte.com/java/java-string/) -- [Java Array 数组](https://www.wdbyte.com/java/java-array/) -- [Java 多维数组](https://www.wdbyte.com/java/java-array-mul/) - [Java StringBuilder](https://www.wdbyte.com/java/java-stringbuilder/) - [Java Scanner](https://www.wdbyte.com/java/scanner/) -- [Java 继承](https://www.wdbyte.com/java/extends/) -- [Java 接口](https://www.wdbyte.com/java/interface/) -- [Java 抽象类](https://www.wdbyte.com/java/abstract/) -- [抽象类和接口的区别](https://www.wdbyte.com/java/abs-interface/) - [Java 多态](https://www.wdbyte.com/java/polymorphism/) - [Java Scanner](https://www.wdbyte.com/java/scanner/) - [Java 日期时间Date](https://www.wdbyte.com/java/date/) - [Java 异常处理](https://www.wdbyte.com/java/exception/) - [Java 枚举](https://www.wdbyte.com/java/enum/) - [Java 注释](*https://www.wdbyte.com/java/comment/*) + +### Java 数组 +- [Java Array 数组](https://www.wdbyte.com/java/java-array/) +- [Java 多维数组](https://www.wdbyte.com/java/java-array-mul/) +- [Java Arrays 教程](https://www.wdbyte.com/java/arrays/) + +### Java 面向对象 +- [Java 继承](https://www.wdbyte.com/java/extends/) +- [Java 接口](https://www.wdbyte.com/java/interface/) +- [Java 抽象类](https://www.wdbyte.com/java/abstract/) +- [抽象类和接口的区别](https://www.wdbyte.com/java/abs-interface/) + +### Java 集合 - [Java 集合框架](https://www.wdbyte.com/java/collection/) - [Java 中使用 List ](https://www.wdbyte.com/java/list/) @@ -72,6 +79,7 @@ - [ProcessBuilder API 使用教程](https://www.wdbyte.com/java/os/processbuilder/) - [Java 热加载手动实现](https://www.wdbyte.com/2019/10/jvm/java-hotput/) +- [Jpackage - 制作无需预装 Java 环境的 Jar 可执行程序](https://www.wdbyte.com/java/jpackage/) ## 🌿 SpringBoot 2.x 教程 @@ -97,7 +105,7 @@ - [Spring Boot 系列(十七)迅速使用 Spring Boot Admin 监控你的 Spring Boot 程序](https://www.wdbyte.com/2019/12/springboot/springboot-17-admin/) - [Spring Boot 系列(十八)最详细的 Spring Boot 多模块开发与排坑指南](https://www.wdbyte.com/2020/03/springboot/springboot-18-module/) - [Spring Boot 系列(十九)SpringBoot 的多数据源配置](https://www.wdbyte.com/2020/12/springboot/springboot-multiple-datasource/) -- [Spring Boot 系列(二十)Spring Boot,JPA与SQLite 的快速启动](https://www.wdbyte.com/springboot/sqlite/) +- [Spring Boot 系列(二十)三分钟,Spring Boot、JPA 与 SQLite 的快速启动](https://www.wdbyte.com/springboot/sqlite/) 以上 Spring Boot 文章源码:[Github.com/niumoo/springboot](https://github.com/niumoo/springboot/) @@ -253,31 +261,15 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 2. 文章中的错误和不足,或者不完善的地方都可以进行补充或者修改。 3. 我没有涉及到的知识点,也可以进行补充。 -## 🏃 我的痕迹 - -1. 我的网站:[https://www.wdbyte.com/](https://www.wdbyte.com/) - -2. GitHub:[https://github.com/niumoo](https://github.com/niumoo) - -3. C SDN:[https://blog.csdn.net/u013735734](https://blog.csdn.net/u013735734) - -4. 博客园:[https://www.cnblogs.com/niumoo/](https://www.cnblogs.com/niumoo/) -5. 掘 金:[https://juejin.im/user/5a62d481f265da3e2a0dac9b](https://juejin.im/user/5a62d481f265da3e2a0dac9b) +### 公众号 -6. 知 乎:[https://www.zhihu.com/people/bpdwn](https://www.zhihu.com/people/bpdwn) +可以关注「 **程序猿阿朗** 」公众号。即使查看更新的文章以及分享的干货。 + 等你很久 ### 联系我 -可以添加我的微信 wn8398 一起交流。 - -交个朋友 - -### 公众号 - -有帮助可以点「**赞**」在看或 :star: **Star**,谢谢你! - -如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注「 **未读代码** 」公众号。 +等不及了,还不添加我微信一起交个朋友。 -等你很久 +交个朋友 \ No newline at end of file From 7ac14dcb05dad99c8fcd52d729730604057338f7 Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 19 Mar 2024 20:29:41 +0800 Subject: [PATCH 73/83] update README.md --- README.md | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index baab1c6..4cf43e1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@

+ 目录中没有链接的部分,后续更新,感谢你的关注 ,有问题或者建议可以[一起完善](#🗺-贡献与建议)。 > Hi there 👋 我是阿朗, 一名 Java 开发者,热衷于分享一些通俗易懂的技术文章。 分享几句鸡汤,长寿在于生活规律;成功在于坚持不懈。 做好的事情,而不是好做的事情。 @@ -142,25 +143,6 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Java 7 新特性 - 和低效 IO 说再见,Files,Paths,Path 文件操作介绍](https://www.wdbyte.com/2020/09/jdk/jdk7-file-pahs/) - [Java 7 新特性 - 新特性 - 快来补一波 Java 7 语法特性](https://www.wdbyte.com/2020/01/jdk/jdk7-start/) -以上 Java 新功能文章源码: [Github.com/niumoo/jdk-feature](https://github.com/niumoo/jdk-feature) - -## 🔬 JDK 源码分析 - -面试必备的 JDK 源码分析。探寻 JDK 大佬的设计思路。没有链接部分为后续更新内容,持续更新中。 - -- [集合 - CopyOnWriteArrayList 实现原理和源码分析](https://www.wdbyte.com/2020/10/jdk/src-copyonwritearraylist/) -- [集合 - ArrayList和LinkedList 实现原理和源码分析](https://www.wdbyte.com/2020/08/jdk/src-arraylist-linkedlist/) -- 集合 -「源码分析」Vector -- [集合 - ConcurrentHashMap 实现原理和源码分析](https://www.wdbyte.com/2020/04/jdk/concurrent-hashmap/) -- [集合 - HashMap 实现原理和源码分析](https://www.wdbyte.com/2020/03/jdk/hashmap/) -- 集合 - TreeMap 实现原理和源码分析 -- 集合 - TreeSet 实现原理和源码分析 -- 集合 - LinkedHashSet 实现原理和源码分析 -- 基础类 - Object -- 基础类 - String -- 基础类 - StringBuffer & StringBuilder - - ## 💻 Java 并发编程 - Java 线程创建与运行 @@ -208,6 +190,26 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 - [Arthas - Java 线上问题定位处理的终极利器](https://www.wdbyte.com/2019/11/arthas/) - [超好用的自带火焰图的 Java 性能分析工具 Async-profiler 了解一下](https://www.wdbyte.com/2019/12/async-profiler/) +## 🔬 JDK 源码分析 + +面试必备的 JDK 源码分析。探寻 JDK 大佬的设计思路。没有链接部分为后续更新内容,持续更新中。 + +- [集合 - CopyOnWriteArrayList 实现原理和源码分析](https://www.wdbyte.com/2020/10/jdk/src-copyonwritearraylist/) +- [集合 - ArrayList和LinkedList 实现原理和源码分析](https://www.wdbyte.com/2020/08/jdk/src-arraylist-linkedlist/) +- 集合 -「源码分析」Vector +- [集合 - ConcurrentHashMap 实现原理和源码分析](https://www.wdbyte.com/2020/04/jdk/concurrent-hashmap/) +- [集合 - HashMap 实现原理和源码分析](https://www.wdbyte.com/2020/03/jdk/hashmap/) +- 集合 - TreeMap 实现原理和源码分析 +- 集合 - TreeSet 实现原理和源码分析 +- 集合 - LinkedHashSet 实现原理和源码分析 +- 基础类 - Object +- 基础类 - String +- 基础类 - StringBuffer & StringBuilder + +## 认证授权 +- [JSON Web Token 入门教程](https://www.wdbyte.com/auth/jwt/) + + ## 🧱 数据结构 - 数组 @@ -272,4 +274,4 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 等不及了,还不添加我微信一起交个朋友。 -交个朋友 \ No newline at end of file +交个朋友 From 07be111fb8cdc1bada0fd68b0f8c676871905c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=8C=BF=E9=98=BF=E6=9C=97?= Date: Wed, 20 Mar 2024 19:28:20 +0800 Subject: [PATCH 74/83] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4cf43e1..25f3fac 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ > Hi there 👋 我是阿朗, 一名 Java 开发者,热衷于分享一些通俗易懂的技术文章。 分享几句鸡汤,长寿在于生活规律;成功在于坚持不懈。 做好的事情,而不是好做的事情。 +## 赏个 Star + +[![Star History Chart](https://api.star-history.com/svg?repos=niumoo/JavaNotes&type=Date)](https://star-history.com/#niumoo/JavaNotes&Date) + ## ⏳ Java 开发 - [如何破解滑动验证码?](https://www.wdbyte.com/java/img-verification/) From fb08995bed8d61a00307cc77897882d8416897ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=8C=BF=E9=98=BF=E6=9C=97?= Date: Wed, 20 Mar 2024 19:29:43 +0800 Subject: [PATCH 75/83] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 25f3fac..1f330c6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ ## 赏个 Star -[![Star History Chart](https://api.star-history.com/svg?repos=niumoo/JavaNotes&type=Date)](https://star-history.com/#niumoo/JavaNotes&Date) +[![Stargazers over time](https://starchart.cc/niumoo/JavaNotes.svg?background=%23FFFFFF&axis=%23333333&line=%23e76060)](https://starchart.cc/niumoo/JavaNotes) + ## ⏳ Java 开发 From 6bc22c2a090e0707a27498257911828e204759db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=8C=BF=E9=98=BF=E6=9C=97?= Date: Wed, 20 Mar 2024 19:30:12 +0800 Subject: [PATCH 76/83] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1f330c6..1ec435e 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,6 @@ > Hi there 👋 我是阿朗, 一名 Java 开发者,热衷于分享一些通俗易懂的技术文章。 分享几句鸡汤,长寿在于生活规律;成功在于坚持不懈。 做好的事情,而不是好做的事情。 -## 赏个 Star - -[![Stargazers over time](https://starchart.cc/niumoo/JavaNotes.svg?background=%23FFFFFF&axis=%23333333&line=%23e76060)](https://starchart.cc/niumoo/JavaNotes) - - ## ⏳ Java 开发 - [如何破解滑动验证码?](https://www.wdbyte.com/java/img-verification/) @@ -269,6 +264,11 @@ Java 版本任你发,我用 Java 8 。但是多学点这种装x技巧总没错 3. 我没有涉及到的知识点,也可以进行补充。 +## 赏个 Star + +[![Stargazers over time](https://starchart.cc/niumoo/JavaNotes.svg?background=%23FFFFFF&axis=%23333333&line=%23e76060)](https://starchart.cc/niumoo/JavaNotes) + + ### 公众号 可以关注「 **程序猿阿朗** 」公众号。即使查看更新的文章以及分享的干货。 From cf38764c543f10595ba9a4509e9f2f758ca58015 Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 2 Apr 2024 14:04:34 +0800 Subject: [PATCH 77/83] =?UTF-8?q?project:=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=89=AB=E7=A0=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + .../springboot-weixin-qrcode-login/README.md | 1 + .../springboot-weixin-qrcode-login/mvnw | 308 ++++++++++++++++++ .../springboot-weixin-qrcode-login/mvnw.cmd | 205 ++++++++++++ .../springboot-weixin-qrcode-login/pom.xml | 98 ++++++ .../java/com/wdbyte/weixin/SpringBootApp.java | 18 + .../com/wdbyte/weixin/config/JwtFilter.java | 94 ++++++ .../controller/WeixinServerController.java | 53 +++ .../controller/WeixinUserController.java | 57 ++++ .../com/wdbyte/weixin/model/ApiResult.java | 32 ++ .../wdbyte/weixin/model/ReceiveMessage.java | 58 ++++ .../com/wdbyte/weixin/model/WeixinQrCode.java | 16 + .../weixin/service/WeixinUserService.java | 13 + .../service/impl/WeixinUserServiceImpl.java | 73 +++++ .../java/com/wdbyte/weixin/util/AesUtils.java | 62 ++++ .../com/wdbyte/weixin/util/ApiResultUtil.java | 30 ++ .../java/com/wdbyte/weixin/util/HttpUtil.java | 44 +++ .../java/com/wdbyte/weixin/util/JwtUtil.java | 88 +++++ .../java/com/wdbyte/weixin/util/KeyUtils.java | 25 ++ .../com/wdbyte/weixin/util/WeixinApiUtil.java | 74 +++++ .../com/wdbyte/weixin/util/WeixinMsgUtil.java | 68 ++++ .../weixin/util/WeixinQrCodeCacheUtil.java | 35 ++ .../java/com/wdbyte/weixin/util/XmlUtil.java | 32 ++ .../src/main/resources/application.properties | 6 + 25 files changed, 1492 insertions(+) create mode 100644 springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.jar create mode 100644 springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.properties create mode 100644 springboot/springboot-weixin-qrcode-login/README.md create mode 100755 springboot/springboot-weixin-qrcode-login/mvnw create mode 100644 springboot/springboot-weixin-qrcode-login/mvnw.cmd create mode 100644 springboot/springboot-weixin-qrcode-login/pom.xml create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ReceiveMessage.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/HttpUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/JwtUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java create mode 100644 springboot/springboot-weixin-qrcode-login/src/main/resources/application.properties diff --git a/springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.jar b/springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.properties b/springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..5f0536e --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/springboot/springboot-weixin-qrcode-login/README.md b/springboot/springboot-weixin-qrcode-login/README.md new file mode 100644 index 0000000..30d0f64 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/README.md @@ -0,0 +1 @@ +# Srping Boot 微信扫码登录示例 diff --git a/springboot/springboot-weixin-qrcode-login/mvnw b/springboot/springboot-weixin-qrcode-login/mvnw new file mode 100755 index 0000000..66df285 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot/springboot-weixin-qrcode-login/mvnw.cmd b/springboot/springboot-weixin-qrcode-login/mvnw.cmd new file mode 100644 index 0000000..95ba6f5 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/springboot/springboot-weixin-qrcode-login/pom.xml b/springboot/springboot-weixin-qrcode-login/pom.xml new file mode 100644 index 0000000..4c1a316 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + com.wdbyte + springboot-weixin-qrcode-login + 0.0.1-SNAPSHOT + springboot-weixin-qrcode-login + Demo project for Spring Boot + + 21 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.projectlombok + lombok + true + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.15.2 + + + + org.apache.commons + commons-lang3 + 3.14.0 + + + + commons-codec + commons-codec + 1.16.0 + + + + + org.apache.httpcomponents.client5 + httpclient5 + 5.1.3 + + + + org.apache.httpcomponents.client5 + httpclient5-fluent + 5.1.3 + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.45 + + + + com.google.guava + guava + 33.0.0-jre + + + + + com.auth0 + java-jwt + 4.4.0 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java new file mode 100644 index 0000000..ca1c5dd --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java @@ -0,0 +1,18 @@ +package com.wdbyte.weixin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; + +/** + * @author https://www.wdbyte.com + */ +@SpringBootApplication +@ServletComponentScan(basePackages = "com.wdbyte.weixin.config") +public class SpringBootApp { + + public static void main(String[] args) { + SpringApplication.run(SpringBootApp.class, args); + } + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java new file mode 100644 index 0000000..1bce112 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java @@ -0,0 +1,94 @@ +package com.wdbyte.weixin.config; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.auth0.jwt.interfaces.Claim; +import com.wdbyte.weixin.util.ApiResultUtil; +import com.wdbyte.weixin.util.JwtUtil; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/** + * JWT过滤器,拦截 /api/* 请求 + */ +@Slf4j +@WebFilter(filterName = "JwtFilter", urlPatterns = "/api/*") +public class JwtFilter implements Filter { + private static List EXCLUDE_PATH_LIST = new ArrayList<>(); + + static { + EXCLUDE_PATH_LIST.add("/api/v1/user/qrcode"); + EXCLUDE_PATH_LIST.add("/api/v1/user/code"); + EXCLUDE_PATH_LIST.add("/api/v1/user/login/code"); + EXCLUDE_PATH_LIST.add("/api/v1/user/login/qrcode"); + EXCLUDE_PATH_LIST.add("/api/v1/weixin/check"); + EXCLUDE_PATH_LIST.add("/api/v1/github/webhooks"); + } + + private JwtUtil jwtUtil; + + public JwtFilter(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException { + + final HttpServletRequest request = (HttpServletRequest)req; + final HttpServletResponse response = (HttpServletResponse)res; + log.info("session id:{}", request.getRequestedSessionId()); + + response.setCharacterEncoding("UTF-8"); + String path = request.getRequestURI(); + for (String excludePath : EXCLUDE_PATH_LIST) { + if (excludePath.startsWith(path)) { + chain.doFilter(request, response); + return; + } + } + // 除OPTIONS外,其他请求应由JWT进行检查 + if ("OPTIONS".equals(request.getMethod())) { + response.setStatus(HttpServletResponse.SC_OK); + chain.doFilter(request, response); + return; + } + + //获取请求头里的token + String authorization = request.getHeader("Authorization"); + if (authorization == null || !StringUtils.startsWith(authorization, "Bearer ")) { + response.getWriter().write(ApiResultUtil.error("authentication failed")); + return; + } + authorization = StringUtils.replaceOnce(authorization, "Bearer ", StringUtils.EMPTY); + Map userData = jwtUtil.verifyToken(authorization); + if (userData == null) { + response.getWriter().write(ApiResultUtil.error("authentication failed")); + return; + } + String openId = userData.get(JwtUtil.OPEN_ID).asString(); + //拦截器 拿到用户信息,放到request中 + request.setAttribute(JwtUtil.OPEN_ID, openId); + chain.doFilter(req, res); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void destroy() { + } +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java new file mode 100644 index 0000000..b3ff9dd --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java @@ -0,0 +1,53 @@ +package com.wdbyte.weixin.controller; + +import com.wdbyte.weixin.service.WeixinUserService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author https://www.wdbyte.com + * @date 2024/01/16 + */ +@Slf4j +@RestController +public class WeixinServerController { + + @Autowired + private WeixinUserService weixinUserService; + + @GetMapping(value = "/api/v1/weixin/check") + public String weixinCheck(HttpServletRequest request) { + String signature = request.getParameter("signature"); + String timestamp = request.getParameter("timestamp"); + String nonce = request.getParameter("nonce"); + String echostr = request.getParameter("echostr"); + + if (StringUtils.isEmpty(signature) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce)) { + return ""; + } + weixinUserService.checkSignature(signature, timestamp, nonce); + return echostr; + } + + @PostMapping(value = "/api/v1/weixin/check") + public String weixinMsg(@RequestBody String requestBody, @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) { + + log.debug("requestBody:{}", requestBody); + log.debug("signature:{}", signature); + log.debug("timestamp:{}", timestamp); + log.debug("nonce:{}", nonce); + + weixinUserService.checkSignature(signature, timestamp, nonce); + return weixinUserService.handleWeixinMsg(requestBody); + } + + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java new file mode 100644 index 0000000..658b585 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java @@ -0,0 +1,57 @@ +package com.wdbyte.weixin.controller; + +import com.wdbyte.weixin.model.WeixinQrCode; +import com.wdbyte.weixin.util.ApiResultUtil; +import com.wdbyte.weixin.util.JwtUtil; +import com.wdbyte.weixin.util.WeixinApiUtil; +import com.wdbyte.weixin.util.WeixinQrCodeCacheUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author https://www.wdbyte.com + * @date 2024/03/16 + */ +@CrossOrigin(origins = {"https://www.wdbyte.com", "https://bing.wdbyte.com", "http://localhost:8000"}) +@Slf4j +@RestController +public class WeixinUserController { + + @Autowired + private WeixinApiUtil weixinApiUtil; + + @Autowired + private JwtUtil jwtUtil; + + @GetMapping(value = "/api/v1/user/qrcode") + public String getQrCode() { + WeixinQrCode qrCode = weixinApiUtil.getQrCode(); + qrCode.setUrl(null); + qrCode.setExpireSeconds(null); + return ApiResultUtil.success(qrCode); + } + + /** + * 校验是否扫描完成 + * 完成,返回 JWT + * 未完成,返回 check faild + * + * @param ticket + * @return + */ + @GetMapping(value = "/api/v1/user/login/qrcode") + public String userLogin(String ticket) { + String openId = WeixinQrCodeCacheUtil.get(ticket); + if (StringUtils.isNotEmpty(openId)) { + log.info("login success,open id:{}", openId); + return ApiResultUtil.success(jwtUtil.createToken(openId)); + } + log.info("login error,ticket:{}", ticket); + return ApiResultUtil.error("check faild"); + } + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java new file mode 100644 index 0000000..54b73e8 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java @@ -0,0 +1,32 @@ +package com.wdbyte.weixin.model; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * @author https://www.wdbyte.com + * @date 2022/01/04 + */ +@Slf4j +@Getter +@Setter +public class ApiResult { + private Integer code; + private String message; + private Object data; + + public ApiResult() { + } + + public ApiResult(Integer code, String message) { + this.code = code; + this.message = message; + } + + public ApiResult(Integer code, String message, Object data) { + this.code = code; + this.message = message; + this.data = data; + } +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ReceiveMessage.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ReceiveMessage.java new file mode 100644 index 0000000..38f8d13 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ReceiveMessage.java @@ -0,0 +1,58 @@ +package com.wdbyte.weixin.model; + +import lombok.Data; + +@Data +public class ReceiveMessage { + /** + * 开发者微信号 + */ + private String toUserName; + /** + * 发送方账号(一个openid) + */ + private String fromUserName; + /** + * 消息创建时间(整形) + */ + private String createTime; + /** + * 消息类型 + */ + private String msgType; + /** + * 文本消息内容 + */ + private String content; + /** + * 消息ID 64位 + */ + String msgId; + /** + * 消息的数据ID 消息来自文章才有 + */ + private String msgDataId; + /** + * 多图文时第几篇文章,从1开始 消息如果来自文章才有 + */ + private String idx; + /** + * 订阅事件 subscribe 订阅 unsbscribe 取消订阅 + */ + private String event; + /** + * 扫码 - ticket + */ + private String ticket; + + public String getReplyTextMsg(String msg) { + String xml = "\n" + + " \n" + + " \n" + + " " + System.currentTimeMillis() + "\n" + + " \n" + + " \n" + + " "; + return xml; + } +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java new file mode 100644 index 0000000..b7dac86 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java @@ -0,0 +1,16 @@ +package com.wdbyte.weixin.model; + +import lombok.Data; + +/** + * @author https://www.wdbyte.com + * @date 2024/03/15 + */ +@Data +public class WeixinQrCode { + + private String ticket; + private Long expireSeconds; + private String url; + private String qrCodeUrl; +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java new file mode 100644 index 0000000..f81123a --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java @@ -0,0 +1,13 @@ +package com.wdbyte.weixin.service; + +/** + * @author niulang + * @date 2024/03/24 + */ +public interface WeixinUserService { + + void checkSignature(String signature, String timestamp, String nonce); + + String handleWeixinMsg(String body); + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java new file mode 100644 index 0000000..cce6eda --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java @@ -0,0 +1,73 @@ +package com.wdbyte.weixin.service.impl; + +import java.util.Arrays; + +import com.wdbyte.weixin.model.ReceiveMessage; +import com.wdbyte.weixin.service.WeixinUserService; +import com.wdbyte.weixin.util.WeixinMsgUtil; +import com.wdbyte.weixin.util.WeixinQrCodeCacheUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * @author niulang + * @date 2024/03/24 + */ +@Slf4j +@Service +public class WeixinUserServiceImpl implements WeixinUserService { + + private String token; + + public WeixinUserServiceImpl(@Value("${weixin.token}") String token) { + this.token = token; + } + + @Override + public void checkSignature(String signature, String timestamp, String nonce) { + String[] arr = new String[] {token, timestamp, nonce}; + Arrays.sort(arr); + StringBuilder content = new StringBuilder(); + for (String str : arr) { + content.append(str); + } + String tmpStr = DigestUtils.sha1Hex(content.toString()); + if (tmpStr.equals(signature)) { + log.info("check success"); + return; + } + log.error("check fail"); + throw new RuntimeException("check fail"); + } + + @Override + public String handleWeixinMsg(String requestBody) { + ReceiveMessage receiveMessage = WeixinMsgUtil.msgToReceiveMessage(requestBody); + // 扫码登录 + if (WeixinMsgUtil.isScanQrCode(receiveMessage)) { + return handleScanLogin(receiveMessage); + } + // 关注 + if (WeixinMsgUtil.isEventAndSubscribe(receiveMessage)) { + return receiveMessage.getReplyTextMsg("欢迎关注【程序猿阿朗】公众号"); + } + return receiveMessage.getReplyTextMsg("收到(自动回复)"); + } + + /** + * 处理扫码登录 + * + * @param receiveMessage + * @return + */ + private String handleScanLogin(ReceiveMessage receiveMessage) { + String qrCodeTicket = WeixinMsgUtil.getQrCodeTicket(receiveMessage); + if (WeixinQrCodeCacheUtil.get(qrCodeTicket) == null) { + String openId = receiveMessage.getFromUserName(); + WeixinQrCodeCacheUtil.put(qrCodeTicket, openId); + } + return receiveMessage.getReplyTextMsg("你已成功登录!"); + } +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java new file mode 100644 index 0000000..62ecd3a --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java @@ -0,0 +1,62 @@ +package com.wdbyte.weixin.util; + +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Java 使用 AES 加密算法进行加密解密 + * */ +@Component +public class AesUtils { + + /** + * 秘钥(需要使用长度为16、24或32的字节数组作为AES算法的密钥,否则就会遇到java.security.InvalidKeyException异常) + */ + @Value("${ase.util.secret}") + public String key; + + /** + * AES算法加密 + * @Param:text原文 + * @Param:key密钥 + * */ + + @SneakyThrows + public String aesEncrypt(String text) { + // 创建AES加密算法实例(根据传入指定的秘钥进行加密) + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); + // 初始化为加密模式,并将密钥注入到算法中 + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + // 将传入的文本加密 + byte[] encrypted = cipher.doFinal(text.getBytes()); + //生成密文 + // 将密文进行Base64编码,方便传输 + return Base64.getEncoder().encodeToString(encrypted); + } + + /** + * AES算法解密 + * @Param:base64Encrypted密文 + * @Param:key密钥 + * */ + public String aesDecrypt(String base64Encrypted) throws Exception { + // 创建AES解密算法实例 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); + + // 初始化为解密模式,并将密钥注入到算法中 + cipher.init(Cipher.DECRYPT_MODE, keySpec); + // 将Base64编码的密文解码 + byte[] encrypted = Base64.getDecoder().decode(base64Encrypted); + // 解密 + byte[] decrypted = cipher.doFinal(encrypted); + return new String(decrypted); + } +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java new file mode 100644 index 0000000..e2ad247 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java @@ -0,0 +1,30 @@ +package com.wdbyte.weixin.util; + +import com.alibaba.fastjson2.JSON; + +import com.wdbyte.weixin.model.ApiResult; + +/** + * @author https://www.wdbyte.com + * @date 2023/11/22 + */ +public class ApiResultUtil { + + private static Integer SUCCESS_CODE = 200; + private static String SUCCESS_MESSAGE = "success"; + private static Integer ERROR_CODE = -1; + private static String ERROR_MESSAGE = "error"; + + public static String success() { + return JSON.toJSONString(new ApiResult(SUCCESS_CODE, SUCCESS_MESSAGE, new Object())); + } + + public static String success(Object data) { + return JSON.toJSONString(new ApiResult(SUCCESS_CODE, SUCCESS_MESSAGE, data)); + } + + public static String error(Object data) { + return JSON.toJSONString(new ApiResult(ERROR_CODE, ERROR_MESSAGE, data)); + } + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/HttpUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/HttpUtil.java new file mode 100644 index 0000000..d536530 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/HttpUtil.java @@ -0,0 +1,44 @@ +package com.wdbyte.weixin.util; + +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.client5.http.fluent.Response; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; + +public class HttpUtil { + + public static String get(String url) { + String result = null; + try { + Response response = Request.get(url).execute(); + result = response.returnContent().asString(); + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + + public static String post(String url, String jsonBody) { + String result = null; + HttpPost httpPost = new HttpPost(url); + httpPost.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON)); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + // 获取响应信息 + result = EntityUtils.toString(response.getEntity()); + } + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + return result; + } + +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/JwtUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/JwtUtil.java new file mode 100644 index 0000000..581a0a3 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/JwtUtil.java @@ -0,0 +1,88 @@ +package com.wdbyte.weixin.util; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Jwt工具类,生成JWT和认证 + */ +@Slf4j +@Component +public class JwtUtil { + + @Autowired + private AesUtils aesUtils; + + @Value("${key.jwt.secret}") + public String secret; + + private JWTVerifier verifier; + + @PostConstruct + public synchronized void init() { + log.info("init jwt verifier"); + verifier = JWT.require(Algorithm.HMAC256(secret)).build(); + } + + /** + * 过期时间,单位为秒,3天 + **/ + private static final long EXPIRATION = 3 * 24 * 3600L; + /** + * open id + */ + public static final String OPEN_ID = "oid"; + + /** + * 生成用户token,设置token超时时间 + */ + public String createToken(String openId) { + Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000); + Map map = new HashMap<>(); + map.put("alg", "HS256"); + map.put("typ", "JWT"); + String token = JWT.create() + // 添加头部 + .withHeader(map) + // 可以将基本信息放到claims中 + .withClaim(OPEN_ID, openId) + //超时设置,设置过期的日期 + .withExpiresAt(expireDate) + //签发时间 + .withIssuedAt(new Date()) + //SECRET加密 + .sign(Algorithm.HMAC256(secret)); + return aesUtils.aesEncrypt(token); + } + + /** + * 校验token并解析token + */ + public Map verifyToken(String token) { + try { + token = aesUtils.aesDecrypt(token); + DecodedJWT jwt = verifier.verify(token); + return jwt.getClaims(); + } catch (Exception e) { + log.error(String.format("verifyToken error,token:%s,msg:%s", token, e.getMessage()), e); + if (e instanceof TokenExpiredException) { + throw new RuntimeException("jwt verify token error"); + } + } + return null; + } + +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java new file mode 100644 index 0000000..983b5b4 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java @@ -0,0 +1,25 @@ +package com.wdbyte.weixin.util; + +import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * @author https://www.wdbyte.com + * @date 2023/11/23 + */ +public class KeyUtils { + + public synchronized static String key6() { + return RandomStringUtils.randomAlphanumeric(6); + } + + public synchronized static String key16() { + return RandomStringUtils.randomAlphanumeric(16); + } + + public static String uuid32() { + return UUID.randomUUID().toString().replace("-", ""); + } + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java new file mode 100644 index 0000000..562648a --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java @@ -0,0 +1,74 @@ +package com.wdbyte.weixin.util; + +import java.net.URI; +import java.time.LocalDateTime; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; + +import com.wdbyte.weixin.model.WeixinQrCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * @author https://www.wdbyte.com + * @date 2024/01/16 + */ +@Slf4j +@Component +public class WeixinApiUtil { + + @Value("${weixin.appid}") + public String appId; + + @Value("${weixin.appsecret}") + public String appSecret; + + private static String QR_CODE_URL_PREFIX = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="; + + private static String ACCESS_TOKEN = null; + private static LocalDateTime ACCESS_TOKEN_EXPIRE_TIME = null; + + /** + * 获取唯一 access token + * + * @return + */ + public synchronized String getAccessToken() { + if (ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRE_TIME.isAfter(LocalDateTime.now())) { + return ACCESS_TOKEN; + } + String api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; + String result = HttpUtil.get(api); + JSONObject jsonObject = JSON.parseObject(result); + ACCESS_TOKEN = jsonObject.getString("access_token"); + ACCESS_TOKEN_EXPIRE_TIME = LocalDateTime.now().plusSeconds(jsonObject.getLong("expires_in") - 10); + return ACCESS_TOKEN; + } + + /** + * https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html + * + * @return + */ + public WeixinQrCode getQrCode() { + String api = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + getAccessToken(); + int timeout = 10 * 60 ; + String jsonBody = String.format("{\n" + + " \"expire_seconds\": %d,\n" + + " \"action_name\": \"QR_STR_SCENE\",\n" + + " \"action_info\": {\n" + + " \"scene\": {\n" + + " \"scene_str\": \"%s\"\n" + + " }\n" + + " }\n" + + "}", timeout, KeyUtils.uuid32()); + String result = HttpUtil.post(api, jsonBody); + log.info("get qr code params:{}", jsonBody); + log.info("get qr code result:{}", result); + WeixinQrCode weixinQrCode = JSON.parseObject(result, WeixinQrCode.class); + weixinQrCode.setQrCodeUrl(QR_CODE_URL_PREFIX + URI.create(weixinQrCode.getTicket()).toASCIIString()); + return weixinQrCode; + } +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java new file mode 100644 index 0000000..2554d62 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java @@ -0,0 +1,68 @@ +package com.wdbyte.weixin.util; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; + +import com.wdbyte.weixin.model.ReceiveMessage; +import org.apache.commons.lang3.StringUtils; + +/** + * @author https://www.wdbyte.com + * @date 2024/01/21 + */ +public class WeixinMsgUtil { + + // 事件-关注 + private static String EVENT_SUBSCRIBE = "subscribe"; + + /** + * 微信消息转对象 + * + * @param xml + * @return + */ + public static ReceiveMessage msgToReceiveMessage(String xml) { + JSONObject jsonObject = JSON.parseObject(XmlUtil.xml2json(xml)); + ReceiveMessage receiveMessage = new ReceiveMessage(); + receiveMessage.setToUserName(jsonObject.getString("ToUserName")); + receiveMessage.setFromUserName(jsonObject.getString("FromUserName")); + receiveMessage.setCreateTime(jsonObject.getString("CreateTime")); + receiveMessage.setMsgType(jsonObject.getString("MsgType")); + receiveMessage.setContent(jsonObject.getString("Content")); + receiveMessage.setMsgId(jsonObject.getString("MsgId")); + receiveMessage.setEvent(jsonObject.getString("Event")); + receiveMessage.setTicket(jsonObject.getString("Ticket")); + return receiveMessage; + } + + /** + * 是否是订阅事件 + * + * @param receiveMessage + * @return + */ + public static boolean isEventAndSubscribe(ReceiveMessage receiveMessage) { + return StringUtils.equals(receiveMessage.getEvent(),EVENT_SUBSCRIBE); + } + + /** + * 是否是二维码扫描事件 + * + * @param receiveMessage + * @return + */ + public static boolean isScanQrCode(ReceiveMessage receiveMessage) { + return StringUtils.isNotEmpty(receiveMessage.getTicket()); + } + + /** + * 获取扫描的二维码 Ticket + * + * @param receiveMessage + * @return + */ + public static String getQrCodeTicket(ReceiveMessage receiveMessage) { + return receiveMessage.getTicket(); + } + +} \ No newline at end of file diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java new file mode 100644 index 0000000..a69c56e --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java @@ -0,0 +1,35 @@ +package com.wdbyte.weixin.util; + +import java.util.LinkedHashMap; + +/** + * 微信二维码缓存工具类 + * + * @author https://www.wdbyte.com + * @date 2024/03/16 + */ +public class WeixinQrCodeCacheUtil { + private static long MAX_CACHE_SIZE = 10000; + private static LinkedHashMap QR_CODE_TICKET_MAP = new LinkedHashMap<>(); + + /** + * 增加一个 Ticket + * 首次 put:value 为 "" + * 再次 put: value 有 openId,若openId已经存在,则已被扫码 + * + * @param key + * @param value + */ + public synchronized static void put(String key, String value) { + QR_CODE_TICKET_MAP.put(key, value); + if (QR_CODE_TICKET_MAP.size() > MAX_CACHE_SIZE) { + String first = QR_CODE_TICKET_MAP.keySet().stream().findFirst().get(); + QR_CODE_TICKET_MAP.remove(first); + } + } + + public synchronized static String get(String key) { + return QR_CODE_TICKET_MAP.remove(key); + } + +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java new file mode 100644 index 0000000..e8c4dea --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java @@ -0,0 +1,32 @@ +package com.wdbyte.weixin.util; + +import com.alibaba.fastjson2.JSON; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * @author https://www.wdbyte.com + * @date 2024/01/18 + */ +@Slf4j +public class XmlUtil { + + public static String xml2json(String requestBody) { + requestBody = StringUtils.trim(requestBody); + XmlMapper xmlMapper = new XmlMapper(); + JsonNode node = null; + try { + node = xmlMapper.readTree(requestBody.getBytes()); + ObjectMapper jsonMapper = new ObjectMapper(); + return jsonMapper.writeValueAsString(node); + } catch (Exception e) { + log.error("xml 2 json error,msg:" + e.getMessage(), e); + } + return null; + } +} diff --git a/springboot/springboot-weixin-qrcode-login/src/main/resources/application.properties b/springboot/springboot-weixin-qrcode-login/src/main/resources/application.properties new file mode 100644 index 0000000..453f434 --- /dev/null +++ b/springboot/springboot-weixin-qrcode-login/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.port= +weixin.appid= +weixin.appsecret= +weixin.token= +ase.util.secret= +key.jwt.secret= \ No newline at end of file From a9d4766e102b989b65a880068c5cc9b6991ce756 Mon Sep 17 00:00:00 2001 From: niumoo Date: Tue, 2 Apr 2024 15:59:27 +0800 Subject: [PATCH 78/83] =?UTF-8?q?project:=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=89=AB=E7=A0=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/wdbyte/weixin/SpringBootApp.java | 6 +++--- .../java/com/wdbyte/weixin/config/JwtFilter.java | 13 +++++-------- .../weixin/controller/WeixinServerController.java | 8 +++----- .../weixin/controller/WeixinUserController.java | 5 ++--- .../java/com/wdbyte/weixin/model/ApiResult.java | 1 - .../com/wdbyte/weixin/model/WeixinQrCode.java | 1 - .../wdbyte/weixin/service/WeixinUserService.java | 3 +-- .../service/impl/WeixinUserServiceImpl.java | 8 ++------ .../java/com/wdbyte/weixin/util/AesUtils.java | 12 +++++++----- .../com/wdbyte/weixin/util/ApiResultUtil.java | 1 - .../java/com/wdbyte/weixin/util/KeyUtils.java | 1 - .../com/wdbyte/weixin/util/WeixinApiUtil.java | 15 ++++++++++----- .../com/wdbyte/weixin/util/WeixinMsgUtil.java | 3 +-- .../wdbyte/weixin/util/WeixinQrCodeCacheUtil.java | 1 - .../main/java/com/wdbyte/weixin/util/XmlUtil.java | 4 ---- 15 files changed, 34 insertions(+), 48 deletions(-) diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java index ca1c5dd..5720502 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/SpringBootApp.java @@ -11,8 +11,8 @@ @ServletComponentScan(basePackages = "com.wdbyte.weixin.config") public class SpringBootApp { - public static void main(String[] args) { - SpringApplication.run(SpringBootApp.class, args); - } + public static void main(String[] args) { + SpringApplication.run(SpringBootApp.class, args); + } } diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java index 1bce112..03de5c5 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/config/JwtFilter.java @@ -21,20 +21,17 @@ import org.apache.commons.lang3.StringUtils; /** - * JWT过滤器,拦截 /api/* 请求 + * JWT过滤器,拦截 /user/* 请求 */ @Slf4j -@WebFilter(filterName = "JwtFilter", urlPatterns = "/api/*") +@WebFilter(filterName = "JwtFilter", urlPatterns = {"/user/*"}) public class JwtFilter implements Filter { private static List EXCLUDE_PATH_LIST = new ArrayList<>(); static { - EXCLUDE_PATH_LIST.add("/api/v1/user/qrcode"); - EXCLUDE_PATH_LIST.add("/api/v1/user/code"); - EXCLUDE_PATH_LIST.add("/api/v1/user/login/code"); - EXCLUDE_PATH_LIST.add("/api/v1/user/login/qrcode"); - EXCLUDE_PATH_LIST.add("/api/v1/weixin/check"); - EXCLUDE_PATH_LIST.add("/api/v1/github/webhooks"); + EXCLUDE_PATH_LIST.add("/user/qrcode"); + EXCLUDE_PATH_LIST.add("/user/login/qrcode"); + EXCLUDE_PATH_LIST.add("/weixin/check"); } private JwtUtil jwtUtil; diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java index b3ff9dd..95740bc 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinServerController.java @@ -13,7 +13,6 @@ /** * @author https://www.wdbyte.com - * @date 2024/01/16 */ @Slf4j @RestController @@ -22,7 +21,7 @@ public class WeixinServerController { @Autowired private WeixinUserService weixinUserService; - @GetMapping(value = "/api/v1/weixin/check") + @GetMapping(value = "/weixin/check") public String weixinCheck(HttpServletRequest request) { String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); @@ -36,9 +35,9 @@ public String weixinCheck(HttpServletRequest request) { return echostr; } - @PostMapping(value = "/api/v1/weixin/check") + @PostMapping(value = "/weixin/check") public String weixinMsg(@RequestBody String requestBody, @RequestParam("signature") String signature, - @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) { + @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) { log.debug("requestBody:{}", requestBody); log.debug("signature:{}", signature); @@ -49,5 +48,4 @@ public String weixinMsg(@RequestBody String requestBody, @RequestParam("signatur return weixinUserService.handleWeixinMsg(requestBody); } - } diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java index 658b585..074022d 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/controller/WeixinUserController.java @@ -14,7 +14,6 @@ /** * @author https://www.wdbyte.com - * @date 2024/03/16 */ @CrossOrigin(origins = {"https://www.wdbyte.com", "https://bing.wdbyte.com", "http://localhost:8000"}) @Slf4j @@ -27,7 +26,7 @@ public class WeixinUserController { @Autowired private JwtUtil jwtUtil; - @GetMapping(value = "/api/v1/user/qrcode") + @GetMapping(value = "/user/qrcode") public String getQrCode() { WeixinQrCode qrCode = weixinApiUtil.getQrCode(); qrCode.setUrl(null); @@ -43,7 +42,7 @@ public String getQrCode() { * @param ticket * @return */ - @GetMapping(value = "/api/v1/user/login/qrcode") + @GetMapping(value = "/user/login/qrcode") public String userLogin(String ticket) { String openId = WeixinQrCodeCacheUtil.get(ticket); if (StringUtils.isNotEmpty(openId)) { diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java index 54b73e8..83c4279 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/ApiResult.java @@ -6,7 +6,6 @@ /** * @author https://www.wdbyte.com - * @date 2022/01/04 */ @Slf4j @Getter diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java index b7dac86..66bdf65 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/model/WeixinQrCode.java @@ -4,7 +4,6 @@ /** * @author https://www.wdbyte.com - * @date 2024/03/15 */ @Data public class WeixinQrCode { diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java index f81123a..2d1cd71 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/WeixinUserService.java @@ -1,8 +1,7 @@ package com.wdbyte.weixin.service; /** - * @author niulang - * @date 2024/03/24 + * @Author 公众号:程序猿阿朗 */ public interface WeixinUserService { diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java index cce6eda..78939d0 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/service/impl/WeixinUserServiceImpl.java @@ -12,19 +12,15 @@ import org.springframework.stereotype.Service; /** - * @author niulang - * @date 2024/03/24 + * @Author 公众号:程序猿阿朗 */ @Slf4j @Service public class WeixinUserServiceImpl implements WeixinUserService { + @Value("${weixin.token}") private String token; - public WeixinUserServiceImpl(@Value("${weixin.token}") String token) { - this.token = token; - } - @Override public void checkSignature(String signature, String timestamp, String nonce) { String[] arr = new String[] {token, timestamp, nonce}; diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java index 62ecd3a..5c1cd39 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/AesUtils.java @@ -11,24 +11,25 @@ /** * Java 使用 AES 加密算法进行加密解密 - * */ + */ @Component public class AesUtils { /** - * 秘钥(需要使用长度为16、24或32的字节数组作为AES算法的密钥,否则就会遇到java.security.InvalidKeyException异常) + * 秘钥(需要使用长度为16、24或32的字节数组作为AES算法的密钥,否则就会遇到java.security.InvalidKeyException异常) */ @Value("${ase.util.secret}") public String key; /** * AES算法加密 + * * @Param:text原文 * @Param:key密钥 - * */ + */ @SneakyThrows - public String aesEncrypt(String text) { + public String aesEncrypt(String text) { // 创建AES加密算法实例(根据传入指定的秘钥进行加密) Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); @@ -43,9 +44,10 @@ public String aesEncrypt(String text) { /** * AES算法解密 + * * @Param:base64Encrypted密文 * @Param:key密钥 - * */ + */ public String aesDecrypt(String base64Encrypted) throws Exception { // 创建AES解密算法实例 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java index e2ad247..d68f622 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/ApiResultUtil.java @@ -6,7 +6,6 @@ /** * @author https://www.wdbyte.com - * @date 2023/11/22 */ public class ApiResultUtil { diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java index 983b5b4..d56ebe0 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/KeyUtils.java @@ -6,7 +6,6 @@ /** * @author https://www.wdbyte.com - * @date 2023/11/23 */ public class KeyUtils { diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java index 562648a..6a3f8b0 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinApiUtil.java @@ -13,7 +13,6 @@ /** * @author https://www.wdbyte.com - * @date 2024/01/16 */ @Slf4j @Component @@ -29,9 +28,13 @@ public class WeixinApiUtil { private static String ACCESS_TOKEN = null; private static LocalDateTime ACCESS_TOKEN_EXPIRE_TIME = null; + /** + * 二维码 Ticket 过期时间 + */ + private static int QR_CODE_TICKET_TIMEOUT = 10 * 60; /** - * 获取唯一 access token + * 获取 access token * * @return */ @@ -39,7 +42,8 @@ public synchronized String getAccessToken() { if (ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRE_TIME.isAfter(LocalDateTime.now())) { return ACCESS_TOKEN; } - String api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; + String api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + + appSecret; String result = HttpUtil.get(api); JSONObject jsonObject = JSON.parseObject(result); ACCESS_TOKEN = jsonObject.getString("access_token"); @@ -48,13 +52,14 @@ public synchronized String getAccessToken() { } /** + * 获取二维码 Ticket + * * https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html * * @return */ public WeixinQrCode getQrCode() { String api = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + getAccessToken(); - int timeout = 10 * 60 ; String jsonBody = String.format("{\n" + " \"expire_seconds\": %d,\n" + " \"action_name\": \"QR_STR_SCENE\",\n" @@ -63,7 +68,7 @@ public WeixinQrCode getQrCode() { + " \"scene_str\": \"%s\"\n" + " }\n" + " }\n" - + "}", timeout, KeyUtils.uuid32()); + + "}", QR_CODE_TICKET_TIMEOUT, KeyUtils.uuid32()); String result = HttpUtil.post(api, jsonBody); log.info("get qr code params:{}", jsonBody); log.info("get qr code result:{}", result); diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java index 2554d62..a48c0cb 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinMsgUtil.java @@ -8,7 +8,6 @@ /** * @author https://www.wdbyte.com - * @date 2024/01/21 */ public class WeixinMsgUtil { @@ -42,7 +41,7 @@ public static ReceiveMessage msgToReceiveMessage(String xml) { * @return */ public static boolean isEventAndSubscribe(ReceiveMessage receiveMessage) { - return StringUtils.equals(receiveMessage.getEvent(),EVENT_SUBSCRIBE); + return StringUtils.equals(receiveMessage.getEvent(), EVENT_SUBSCRIBE); } /** diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java index a69c56e..1e55d9e 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/WeixinQrCodeCacheUtil.java @@ -6,7 +6,6 @@ * 微信二维码缓存工具类 * * @author https://www.wdbyte.com - * @date 2024/03/16 */ public class WeixinQrCodeCacheUtil { private static long MAX_CACHE_SIZE = 10000; diff --git a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java index e8c4dea..bc56199 100644 --- a/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java +++ b/springboot/springboot-weixin-qrcode-login/src/main/java/com/wdbyte/weixin/util/XmlUtil.java @@ -1,17 +1,13 @@ package com.wdbyte.weixin.util; -import com.alibaba.fastjson2.JSON; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.web.bind.annotation.RequestBody; /** * @author https://www.wdbyte.com - * @date 2024/01/18 */ @Slf4j public class XmlUtil { From 34398bdd15d7af282daabf9a68c04b4a566379fd Mon Sep 17 00:00:00 2001 From: niumoo Date: Wed, 24 Apr 2024 09:39:15 +0800 Subject: [PATCH 79/83] =?UTF-8?q?feat:[Java=20=E6=96=AD=E8=A8=80=20Assert?= =?UTF-8?q?=20=E4=BD=BF=E7=94=A8=E6=95=99=E7=A8=8B=E4=B8=8E=E6=9C=80?= =?UTF-8?q?=E4=BD=B3=E5=AE=9E=E8=B7=B5](https://www.wdbyte.com/java/assert?= =?UTF-8?q?/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 + core-java-modules/core-java-base/README.md | 3 +- .../java/com/wdbyte/assert1/AssertDemo1.java | 29 ++++++++ .../java/com/wdbyte/assert1/AssertDemo2.java | 24 ++++++ .../java/com/wdbyte/assert1/AssertDemo3.java | 20 +++++ .../java/com/wdbyte/assert1/AssertDemo4.java | 25 +++++++ .../java/com/wdbyte/assert1/AssertDemo5.java | 25 +++++++ .../wdbyte/assert1/InitializationDemo.java | 28 +++++++ .../java/com/wdbyte/enum2/WeekdayTest.java | 1 - .../wdbyte/thread/CompletableFutureTest.java | 74 +++++++++++++++++++ 10 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/InitializationDemo.java create mode 100644 core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java diff --git a/README.md b/README.md index 1ec435e..763ca75 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,9 @@ - [Java 集合框架](https://www.wdbyte.com/java/collection/) - [Java 中使用 List ](https://www.wdbyte.com/java/list/) +### 代码测试 +- [Java 断言 Assert 使用教程与最佳实践](https://www.wdbyte.com/java/assert/) + ## 😃Java I/O 教程 - [Java 创建和写入文件](https://www.wdbyte.com/java/io/file-create-write/) diff --git a/core-java-modules/core-java-base/README.md b/core-java-modules/core-java-base/README.md index 0071ce6..5b2d151 100644 --- a/core-java-modules/core-java-base/README.md +++ b/core-java-modules/core-java-base/README.md @@ -22,4 +22,5 @@ - [Java 枚举](https://www.wdbyte.com/java/enum/) - [Java 注释](*https://www.wdbyte.com/java/comment/*) - [Java 集合框架](https://www.wdbyte.com/java/collection/) -- [Java 中使用 List ](https://www.wdbyte.com/java/list/) \ No newline at end of file +- [Java 中使用 List ](https://www.wdbyte.com/java/list/) +- [Java 断言 Assert 使用教程与最佳实践](https://www.wdbyte.com/java/assert/) \ No newline at end of file diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java new file mode 100644 index 0000000..9d808cf --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java @@ -0,0 +1,29 @@ +package com.wdbyte.assert1; + +import java.util.Arrays; +import java.util.List; + +/** + * @author niulang + * @date 2024/04/22 + */ +public class AssertDemo1 { + public static void main(String[] args) { + + List list = Arrays.asList("1", "2"); + boolean result = list.remove("x"); + //assert result; + assert result : "移除失败"; + System.out.println(calc(100, 10)); + + // 手动开启断言 + //ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true); + //System.out.println(calc(100, 0)); + } + + public static int calc(int a, int b) { + assert b != 0 : "除数不能为0"; + return a / b; + + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java new file mode 100644 index 0000000..1cc5664 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java @@ -0,0 +1,24 @@ +package com.wdbyte.assert1; + +import java.util.Arrays; +import java.util.List; + +import static com.google.common.base.Verify.*; + +/** + * @author niulang + * @date 2024/04/22 + */ +public class AssertDemo2 { + public static void main(String[] args) { + int x = 100; + verifyNotNull(x != 0); + System.out.println(calc(100, 10)); + System.out.println(calc(100, 0)); + } + + public static int calc(int a, int b) { + verify(b != 0, "除数不能为0"); + return a / b; + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java new file mode 100644 index 0000000..3f02ca2 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java @@ -0,0 +1,20 @@ +package com.wdbyte.assert1; + +import java.util.Arrays; +import java.util.List; + +/** + * @author niulang + * @date 2024/04/22 + */ +public class AssertDemo3 { + static final boolean asserts = false; // 设置为 false 来消除断言 + + public static void main(String[] args) { + List list = Arrays.asList("1", "2"); + boolean result = list.remove("x"); + if (asserts) { + assert result : "移除失败"; + } + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java new file mode 100644 index 0000000..b324a0d --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java @@ -0,0 +1,25 @@ +package com.wdbyte.assert1; + +import java.util.Arrays; +import java.util.List; + +/** + * @author niulang + * @date 2024/04/22 + */ +public class AssertDemo4 { + + static { + boolean assertsEnabled = false; + assert assertsEnabled = true; // 故意产生副作用!!! + if (!assertsEnabled) { + throw new RuntimeException("必须启用断言!!!"); + } + } + + public static void main(String[] args) { + List list = Arrays.asList("1", "2"); + boolean result = list.remove("x"); + assert result : "移除失败"; + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java new file mode 100644 index 0000000..6d008c4 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java @@ -0,0 +1,25 @@ +package com.wdbyte.assert1; + +import java.util.Arrays; +import java.util.List; + +import com.google.common.base.Preconditions; +import com.google.common.base.Verify; +import org.apache.commons.lang3.Validate; +import org.junit.jupiter.api.Assertions; + +/** + * @author niulang + * @date 2024/04/22 + */ +public class AssertDemo5 { + + public static void main(String[] args) { + List list = Arrays.asList("1", "2"); + boolean result = list.remove("x"); + Assertions.assertTrue(result); + Preconditions.checkNotNull("","msg"); + Validate.isTrue(list.isEmpty(),"msg"); + Verify.verify(list.isEmpty(),"msg"); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/InitializationDemo.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/InitializationDemo.java new file mode 100644 index 0000000..cfebe99 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/InitializationDemo.java @@ -0,0 +1,28 @@ +package com.wdbyte.assert1; + +public class InitializationDemo { + + static { + init(); + } + + static void init() { + System.out.println("Static initialization block called"); + // 假设这里有一个重要的初始化逻辑 + // 这个方法错误地在静态初始化之前被调用了 + assert isProperlyInitialized() : "System not properly initialized"; + } + + static boolean isProperlyInitialized() { + // 这里返回 false 模拟系统未被正确初始化 + return false; + } + + public InitializationDemo() { + System.out.println("Constructor called"); + } + + public static void main(String[] args) { + new InitializationDemo(); + } +} diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java index 6d83265..30e6fd8 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/enum2/WeekdayTest.java @@ -11,7 +11,6 @@ public static void main(String[] args) { System.out.println("Today is Monday."); } - Weekday[] weekdays = Weekday.values(); for (Weekday weekday : weekdays) { System.out.println(weekday); diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java new file mode 100644 index 0000000..af22eb6 --- /dev/null +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java @@ -0,0 +1,74 @@ +package com.wdbyte.thread; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +import org.junit.jupiter.api.Test; + +/** + * @author niulang + * @date 2023/11/01 + */ +public class CompletableFutureTest { + + /** + * 异步执行程序后,对正常响应和异常响应进行处理 + */ + @Test + public void completableFutureTest1() { + CompletableFuture completableFuture1 = CompletableFuture.supplyAsync(() -> { + sleep(2000); + System.out.println("do....."); + return 1; + }); + + completableFuture1.thenAccept(res -> { + System.out.println("收到结果:" + res + ); + }); + + System.out.println("等待"); + sleep(10 * 1000); + } + @Test + public void completableFutureTest2() { + CompletableFuture completableFuture2 = CompletableFuture.supplyAsync(() -> { + sleep(2000); + System.out.println("do2....."); + return 10 / 0; + }); + completableFuture2.exceptionally(except -> { + System.out.println("发生异常:" + except.getMessage()); + return 0; + }); + + System.out.println("等待"); + sleep(10 * 1000); + } + + @Test + public void completableFutureTest3() { + CompletableFuture completableFuture1 = CompletableFuture.supplyAsync(() -> { + sleep(2000); + System.out.println("do....."); + return 1; + }); + + completableFuture1.thenAccept(res -> { + System.out.println("收到结果:" + res + ); + }); + + System.out.println("等待"); + sleep(10 * 1000); + } + + void sleep(long millis){ + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + +} From 4fc2f5bf44978729c4ca4efd375a4dc43622d6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E6=9C=97?= Date: Mon, 28 Apr 2025 16:24:04 +0800 Subject: [PATCH 80/83] code opt --- core-java-modules/core-java-22/pom.xml | 14 ++++ .../src/main/java/com/wdbyte/Main.java | 21 ++++++ core-java-modules/core-java-8/pom.xml | 5 -- .../src/main/java/com/wdbyte/Jdk8Lambda.java | 32 ++++++-- .../main/java/com/wdbyte/Jdk8Optional.java | 29 ++++++-- pom.xml | 5 -- .../src/main/java/com/wdbyte/jackson/Cat.java | 23 +++++- .../main/java/com/wdbyte/jackson/Order.java | 33 ++++++--- .../main/java/com/wdbyte/jackson/Person.java | 45 +++++++++++- .../main/java/com/wdbyte/jackson/Student.java | 73 ++++++++++++++----- 10 files changed, 220 insertions(+), 60 deletions(-) create mode 100644 core-java-modules/core-java-22/pom.xml create mode 100644 core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java diff --git a/core-java-modules/core-java-22/pom.xml b/core-java-modules/core-java-22/pom.xml new file mode 100644 index 0000000..4fc6401 --- /dev/null +++ b/core-java-modules/core-java-22/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.wdbyte.core-java-modules + core-java-22 + 1.0.0-SNAPSHOT + + 22 + 22 + UTF-8 + + \ No newline at end of file diff --git a/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java b/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java new file mode 100644 index 0000000..b7e6be5 --- /dev/null +++ b/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java @@ -0,0 +1,21 @@ +package com.wdbyte; + +/** + * @author niulang + * @date 2025/04/28 + */ +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + //TIP Press with your caret at the highlighted text + // to see how IntelliJ IDEA suggests fixing it. + System.out.printf("Hello and welcome!"); + + for (int i = 1; i <= 5; i++) { + //TIP Press to start debugging your code. We have set one breakpoint + // for you, but you can always add more by pressing . + System.out.println("i = " + i); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-8/pom.xml b/core-java-modules/core-java-8/pom.xml index 2ae8b99..132cc2e 100644 --- a/core-java-modules/core-java-8/pom.xml +++ b/core-java-modules/core-java-8/pom.xml @@ -35,11 +35,6 @@ org.junit.jupiter junit-jupiter - - org.projectlombok - lombok - 1.18.22 - \ No newline at end of file diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java index 357f967..cbd5029 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Lambda.java @@ -1,9 +1,5 @@ package com.wdbyte; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; import org.junit.jupiter.api.Test; import java.util.*; @@ -70,13 +66,33 @@ public void functionLambdaTest() { } - @Getter - @Setter - @ToString - @AllArgsConstructor static class User { private String name; private Integer age; + + public User() { + } + + public User(String name, Integer age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } } public static List userList = new ArrayList(); diff --git a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java index ec3fa57..fc080a8 100644 --- a/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java +++ b/core-java-modules/core-java-8/src/main/java/com/wdbyte/Jdk8Optional.java @@ -2,8 +2,6 @@ import java.util.Optional; - -import lombok.Data; import org.junit.jupiter.api.Test; /** @@ -182,23 +180,44 @@ public void optionalTest() { /** * 计算机 */ -@Data class Computer { private Optional soundCard; + + public Optional getSoundCard() { + return soundCard; + } + + public void setSoundCard(Optional soundCard) { + this.soundCard = soundCard; + } } /** * 声卡 */ -@Data class SoundCard { private Optional usb; + + public Optional getUsb() { + return usb; + } + + public void setUsb(Optional usb) { + this.usb = usb; + } } /** * USB */ -@Data class Usb { private String version; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } } diff --git a/pom.xml b/pom.xml index 0e2c7f6..b55b3df 100644 --- a/pom.xml +++ b/pom.xml @@ -45,10 +45,5 @@ commons-lang3 ${commons-lang3.version} - - org.projectlombok - lombok - ${lombok.version} - diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java index 5492a46..be544cd 100644 --- a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Cat.java @@ -1,15 +1,12 @@ package com.wdbyte.jackson; import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSetter; -import lombok.Data; /** * @author https://www.wdbyte.com * @date 2022/07/17 */ -@Data public class Cat { @JsonSetter(value = "catName") @@ -21,4 +18,24 @@ public class Cat { public String getName() { return name; } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Cat() { + } + + public Cat(String name, Integer age) { + this.name = name; + this.age = age; + } } diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java index 6318eb3..38eb08d 100644 --- a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Order.java @@ -1,24 +1,15 @@ package com.wdbyte.jackson; -import java.time.LocalDateTime; -import java.util.Date; - import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonSetter; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.Date; /** * @author https://www.wdbyte.com * @date 2022/07/17 */ -//@Data -@AllArgsConstructor -@NoArgsConstructor -@ToString public class Order { @JsonSetter(value = "orderId") @@ -54,4 +45,22 @@ public LocalDateTime getUpdateTime() { public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; } + + @Override + public String toString() { + return "Order{" + + "id=" + id + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } + + public Order() { + } + + public Order(Integer id, Date createTime, LocalDateTime updateTime) { + this.id = id; + this.createTime = createTime; + this.updateTime = updateTime; + } } diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java index 3bc1210..b1f2a72 100644 --- a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Person.java @@ -2,16 +2,55 @@ import java.util.List; -import lombok.Data; - /** * @author https://www.wdbyte.com * @date 2022/07/16 */ -@Data public class Person { private String name; private Integer age; private List skillList; + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + ", skillList=" + skillList + + '}'; + } + + public Person(String name, Integer age, List skillList) { + this.name = name; + this.age = age; + this.skillList = skillList; + } + + public Person() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public List getSkillList() { + return skillList; + } + + public void setSkillList(List skillList) { + this.skillList = skillList; + } } diff --git a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java index 377253d..f5baec4 100644 --- a/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java +++ b/tool-java-jackson/src/main/java/com/wdbyte/jackson/Student.java @@ -1,36 +1,20 @@ package com.wdbyte.jackson; -import java.util.HashMap; -import java.util.Map; - import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.google.common.collect.Maps; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; + +import java.util.HashMap; +import java.util.Map; /** * @author https://www.wdbyte.com * @date 2022/07/17 */ -@ToString -@AllArgsConstructor -@NoArgsConstructor public class Student { - @Getter - @Setter private String name; - @Getter - @Setter private Integer age; - @Getter - @Setter private Map diyMap = new HashMap<>(); @JsonAnyGetter @@ -45,4 +29,55 @@ public void otherField(String key, String value) { this.diyMap.put(key, value); } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Map getDiyMap() { + return diyMap; + } + + public void setDiyMap(Map diyMap) { + this.diyMap = diyMap; + } + + public Map getInitMap() { + return initMap; + } + + public void setInitMap(Map initMap) { + this.initMap = initMap; + } + + public Student() { + } + + public Student(String name, Integer age, Map diyMap, Map initMap) { + this.name = name; + this.age = age; + this.diyMap = diyMap; + this.initMap = initMap; + } + + @Override + public String toString() { + return "Student{" + + "name='" + name + '\'' + + ", age=" + age + + ", diyMap=" + diyMap + + ", initMap=" + initMap + + '}'; + } } From 36ec1faf3fdbbc6bf21333ad6d49d2b144f00f0e Mon Sep 17 00:00:00 2001 From: niumoo Date: Mon, 28 Apr 2025 17:27:44 +0800 Subject: [PATCH 81/83] code opt --- .../core-java-22/src/main/java/com/wdbyte/Main.java | 2 +- .../src/main/java/com/wdbyte/assert1/AssertDemo1.java | 2 +- .../src/main/java/com/wdbyte/assert1/AssertDemo2.java | 2 +- .../src/main/java/com/wdbyte/assert1/AssertDemo3.java | 2 +- .../src/main/java/com/wdbyte/assert1/AssertDemo4.java | 2 +- .../src/main/java/com/wdbyte/assert1/AssertDemo5.java | 2 +- .../src/main/java/com/wdbyte/collection/ArrayListTest.java | 2 +- .../src/main/java/com/wdbyte/collection/ArrayListTest2.java | 2 +- .../src/main/java/com/wdbyte/collection/ArrayListTest3.java | 2 +- .../src/main/java/com/wdbyte/collection/ArrayListTest4.java | 2 +- .../src/main/java/com/wdbyte/thread/CompletableFutureTest.java | 2 +- .../src/main/java/com/wdbyte/collection/EnumMapTest.java | 2 +- .../src/main/java/com/wdbyte/collection/JavaArrays.java | 2 +- .../src/main/java/com/wdbyte/io/file/FileAppendDemo.java | 2 +- .../main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java | 2 +- .../src/main/java/com/wdbyte/io/file/FileDelete.java | 2 +- .../src/main/java/com/wdbyte/io/file/FileReadDemo.java | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java b/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java index b7e6be5..cbe7f6f 100644 --- a/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java +++ b/core-java-modules/core-java-22/src/main/java/com/wdbyte/Main.java @@ -1,7 +1,7 @@ package com.wdbyte; /** - * @author niulang + * @author www.wdbyte.com * @date 2025/04/28 */ //TIP To Run code, press or diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java index 9d808cf..50490a5 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo1.java @@ -4,7 +4,7 @@ import java.util.List; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/04/22 */ public class AssertDemo1 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java index 1cc5664..735c2bb 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo2.java @@ -6,7 +6,7 @@ import static com.google.common.base.Verify.*; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/04/22 */ public class AssertDemo2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java index 3f02ca2..09e2272 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo3.java @@ -4,7 +4,7 @@ import java.util.List; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/04/22 */ public class AssertDemo3 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java index b324a0d..565de43 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo4.java @@ -4,7 +4,7 @@ import java.util.List; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/04/22 */ public class AssertDemo4 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java index 6d008c4..4c37dde 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/assert1/AssertDemo5.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Assertions; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/04/22 */ public class AssertDemo5 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java index 54032e0..582a6f3 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest.java @@ -8,7 +8,7 @@ import java.util.stream.Collectors; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/10/19 */ public class ArrayListTest { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java index 357e0f2..f18c9b1 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest2.java @@ -6,7 +6,7 @@ import java.util.Vector; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/10/19 */ public class ArrayListTest2 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java index 02b189f..a88fd7a 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest3.java @@ -9,7 +9,7 @@ import com.google.common.collect.Lists; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/10/19 */ public class ArrayListTest3 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java index d49f5b2..93d09e4 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/collection/ArrayListTest4.java @@ -12,7 +12,7 @@ import com.google.common.collect.Lists; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/10/19 */ public class ArrayListTest4 { diff --git a/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java b/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java index af22eb6..7887015 100644 --- a/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java +++ b/core-java-modules/core-java-base/src/main/java/com/wdbyte/thread/CompletableFutureTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/11/01 */ public class CompletableFutureTest { diff --git a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java index 4646e7d..1370449 100644 --- a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java +++ b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/EnumMapTest.java @@ -3,7 +3,7 @@ import java.util.EnumMap; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/10/20 */ public class EnumMapTest { diff --git a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java index 47da76b..144cdcb 100644 --- a/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java +++ b/core-java-modules/core-java-collect/src/main/java/com/wdbyte/collection/JavaArrays.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2024/03/04 */ public class JavaArrays { diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java index 6d43afb..53879c8 100644 --- a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileAppendDemo.java @@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/12/12 */ public class FileAppendDemo { diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java index 4f4dddd..158942d 100644 --- a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileCreateAndWriteDemo.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/11/06 */ public class FileCreateAndWriteDemo { diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java index 5882f01..f865382 100644 --- a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileDelete.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/12/18 */ public class FileDelete { diff --git a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java index 87e35b2..276e0e8 100644 --- a/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java +++ b/core-java-modules/core-java-io/src/main/java/com/wdbyte/io/file/FileReadDemo.java @@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test; /** - * @author niulang + * @author www.wdbyte.com * @date 2023/11/08 */ public class FileReadDemo { From b845e908161ae9e3882458bb99b7361ac235753f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E6=9C=97?= Date: Thu, 22 Jan 2026 00:08:52 +0800 Subject: [PATCH 82/83] add spring-mcp-server-manual --- .../.mvn/wrapper/maven-wrapper.properties | 3 + spring-ai/spring-mcp-server-manual/README.md | 26 ++ spring-ai/spring-mcp-server-manual/mvnw | 295 ++++++++++++++++++ spring-ai/spring-mcp-server-manual/mvnw.cmd | 189 +++++++++++ spring-ai/spring-mcp-server-manual/pom.xml | 42 +++ .../ai/mcp/manual/McpWeatherController.java | 119 +++++++ .../SpringMcpServerManualApplication.java | 13 + .../src/main/resources/application.properties | 1 + 8 files changed, 688 insertions(+) create mode 100644 spring-ai/spring-mcp-server-manual/.mvn/wrapper/maven-wrapper.properties create mode 100644 spring-ai/spring-mcp-server-manual/README.md create mode 100755 spring-ai/spring-mcp-server-manual/mvnw create mode 100644 spring-ai/spring-mcp-server-manual/mvnw.cmd create mode 100644 spring-ai/spring-mcp-server-manual/pom.xml create mode 100644 spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/McpWeatherController.java create mode 100644 spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/SpringMcpServerManualApplication.java create mode 100644 spring-ai/spring-mcp-server-manual/src/main/resources/application.properties diff --git a/spring-ai/spring-mcp-server-manual/.mvn/wrapper/maven-wrapper.properties b/spring-ai/spring-mcp-server-manual/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..8dea6c2 --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip diff --git a/spring-ai/spring-mcp-server-manual/README.md b/spring-ai/spring-mcp-server-manual/README.md new file mode 100644 index 0000000..af5c1b2 --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/README.md @@ -0,0 +1,26 @@ +这个基于 Spring Boot 和 Fastjson 的 MCP(Model Context Protocol)服务实现,是一个遵循 JSON-RPC 2.0 规范的轻量级工具服务端,旨在为大语言模型(LLM)提供标准化的外部能力接口 36。 + +以下是该实现的核心架构与技术特点介绍: + +### 1. 核心协议架构 +该实现采用了 MCP 的 Streamable HTTP 传输机制,通过单一的 HTTP POST 端点(/mcp)处理所有交互逻辑 26。 + +消息格式:所有请求和响应均严格遵循 JSON-RPC 2.0 结构,包含 jsonrpc、id、method 和 params 字段 6。 +生命周期管理:手动实现了 MCP 协议定义的完整链路,包括初始化握手(initialize)、初始化完成通知(notifications/initialized)、工具发现(tools/list)以及工具执行(tools/call) 56。 +### 2. Java 21 技术优化 +利用 Java 21 的现代语法特性极大简化了协议模版代码: + +Record 记录类:使用 record 定义 JsonRpcRequest、Tool 和 ToolCallResult 等数据模型。这消除了 Getter/Setter 等样板代码,确保了消息对象的不可变性,并自动支持 JSON 序列化。 +Switch 表达式:在控制器中使用增强的 switch 表达式处理 method 分发。这种方式比传统的 if-else 更具读性,且利用 yield 关键字实现了逻辑的紧凑闭环。 +文本块(Text Blocks):利用 """ 语法定义工具的 JSON Schema。这使得复杂的输入参数描述(如 inputSchema)在代码中能以原始 JSON 格式直观呈现,便于维护 5。 +### 3. 工具定义与执行逻辑 +该服务模拟了一个名为 getWeather 的城市天气查询工具: + +工具发现:在 tools/list 阶段,服务端会返回该工具的名称、描述以及基于 JSON Schema 的参数定义(要求必填 city 字符串),以便 LLM 理解如何调用该工具 56。 +参数解析:通过 Fastjson 的 JSONObject 直接处理动态参数。在 tools/call 触发时,程序会从 arguments 映射中提取城市名称,并返回标准化的内容结构。 +响应规范:响应体封装在 content 数组中,并包含 isError 标识,这符合 MCP 对工具执行结果的标准化要求 6。 +### 4. 最佳实践体现 +轻量化:不依赖于复杂的 MCP 官方 SDK,仅通过 Spring Boot 基础框架和 Fastjson 实现,适合快速集成到现有生产微服务中 2。 +无状态处理:服务设计为无状态,符合 MCP Streamable HTTP 的简化模式,便于水平扩展。 +错误处理基础:虽然为简易版,但结构上预留了 isError 字段,允许在工具内部出错时让 LLM 感知并尝试自我修正 6。 +这种实现方式展示了如何通过极简的代码量构建符合开放协议标准的 AI 插件系统,降低了 LLM 与私有数据源及外部工具对接的复杂度 13。 \ No newline at end of file diff --git a/spring-ai/spring-mcp-server-manual/mvnw b/spring-ai/spring-mcp-server-manual/mvnw new file mode 100755 index 0000000..bd8896b --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/mvnw @@ -0,0 +1,295 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.4 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/spring-ai/spring-mcp-server-manual/mvnw.cmd b/spring-ai/spring-mcp-server-manual/mvnw.cmd new file mode 100644 index 0000000..92450f9 --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/mvnw.cmd @@ -0,0 +1,189 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/spring-ai/spring-mcp-server-manual/pom.xml b/spring-ai/spring-mcp-server-manual/pom.xml new file mode 100644 index 0000000..1e9f19e --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 4.0.1 + + + com.wdbyte.ai.mcp.manual + spring-mcp-server-manual + 0.0.1-SNAPSHOT + spring-mcp-server-manual + spring-mcp-server-manual + + 21 + + + + org.springframework.boot + spring-boot-starter-webmvc + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.60 + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/McpWeatherController.java b/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/McpWeatherController.java new file mode 100644 index 0000000..76f2cb8 --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/McpWeatherController.java @@ -0,0 +1,119 @@ +package com.wdbyte.ai.mcp.manual; + +import java.util.List; +import java.util.Map; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.JSONWriter.Feature; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/mcp") +public class McpWeatherController { + + private static final Logger log = LoggerFactory.getLogger(McpWeatherController.class); + + // 1. 静态化工具定义,使 tools/list 极其简洁 + private static final List AVAILABLE_TOOLS = List.of( + new Tool("getWeather", "获取指定城市的天气预报", + JSONObject.parseObject(""" + { + "type": "object", + "properties": { "city": { "type": "string", "description": "城市名" } }, + "required": ["city"], + "additionalProperties": false + } + """)) + ); + + @PostMapping(consumes = "application/json", produces = "application/json") + public ResponseEntity handleMcpRequest(@RequestBody JsonRpcRequest request) { + Object id = request.id(); + + var response = switch (request.method()) { + case "initialize" -> ok(id, new InitializeResult()); + case "notifications/initialized" -> accepted(); + case "ping" -> ok(id, Map.of()); + case "tools/list" -> ok(id, Map.of("tools", AVAILABLE_TOOLS)); + case "tools/call" -> handleToolCall(id, request.params()); + default -> ResponseEntity.notFound().build(); + }; + log.info("\nrequest: {}\nresponse: {}", JSON.toJSONString(request), JSON.toJSONString(response.getBody())); + return response; + } + + /** + * 优雅处理工具调用:直接通过 JSONObject 转换,无需 String 二次中转 + */ + private ResponseEntity handleToolCall(Object id, JSONObject params) { + if (params == null) return badRequest(); + + var callParams = params.toJavaObject(ToolCallParams.class); + + // 使用 switch 处理多工具扩展性更好 + return switch (callParams.name()) { + case "getWeather" -> { + String city = String.valueOf(callParams.arguments().getOrDefault("city", "未知城市")); + yield ok(id, new ToolCallResult(city + "今日雷暴雨,建议居家")); + } + default -> badRequest(); + }; + } + + // --- 辅助方法 --- + private static ResponseEntity ok(Object id, Object result) { + return ResponseEntity.ok(new JsonRpcResponse(id, result)); + } + + private static ResponseEntity accepted() { + return ResponseEntity.status(202).build(); + } + + private static ResponseEntity badRequest() { + return ResponseEntity.badRequest().build(); + } + + // --- MCP 协议 Records (Java 21) --- + + // 将 params 定义为 JSONObject,方便后续 toJavaObject 转换 + public record JsonRpcRequest(String jsonrpc, Object id, String method, JSONObject params) {} + + public record JsonRpcResponse(String jsonrpc, Object id, Object result) { + public JsonRpcResponse(Object id, Object result) { + this("2.0", id, result); + } + } + + // 初始化结果模型 + public record InitializeResult(String protocolVersion, Capabilities capabilities, ServerInfo serverInfo) { + public InitializeResult() { + this("2025-06-18", new Capabilities(new Tools(false)), new ServerInfo("mcp-weather-server", "1.0.0")); + } + } + + public record ServerInfo(String name, String version) {} + public record Capabilities(Tools tools) {} + public record Tools(boolean listChanged) {} + + // 工具定义模型 + public record Tool(String name, String description, Object inputSchema) {} + + // 工具调用参数模型 + public record ToolCallParams(String name, Map arguments) {} + + // 响应内容模型 + public record Content(String type, String text) { + public Content(String text) { this("text", text); } + } + + public record ToolCallResult(List content, boolean isError) { + public ToolCallResult(String text) { + this(List.of(new Content(text)), false); + } + } +} diff --git a/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/SpringMcpServerManualApplication.java b/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/SpringMcpServerManualApplication.java new file mode 100644 index 0000000..48f4ffe --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/src/main/java/com/wdbyte/ai/mcp/manual/SpringMcpServerManualApplication.java @@ -0,0 +1,13 @@ +package com.wdbyte.ai.mcp.manual; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringMcpServerManualApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringMcpServerManualApplication.class, args); + } + +} diff --git a/spring-ai/spring-mcp-server-manual/src/main/resources/application.properties b/spring-ai/spring-mcp-server-manual/src/main/resources/application.properties new file mode 100644 index 0000000..bbc9400 --- /dev/null +++ b/spring-ai/spring-mcp-server-manual/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=spring-mcp-server-manual From 5eb085a1211442df4baf458fde27ae9ed7a06755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E6=9C=97?= Date: Thu, 22 Jan 2026 00:28:33 +0800 Subject: [PATCH 83/83] update readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 763ca75..3d12432 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ > Hi there 👋 我是阿朗, 一名 Java 开发者,热衷于分享一些通俗易懂的技术文章。 分享几句鸡汤,长寿在于生活规律;成功在于坚持不懈。 做好的事情,而不是好做的事情。 +## AI 开发 + +- [MCP Streamable HTTP 协议入门与 100 行代码实现](https://wdbyte.com/spring-mcp-server-manual/) + ## ⏳ Java 开发 - [如何破解滑动验证码?](https://www.wdbyte.com/java/img-verification/)