From ead3d16257a842538a1b6d63c660d0ca145ea320 Mon Sep 17 00:00:00 2001 From: xking Date: Fri, 16 May 2025 18:15:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java/Guava中的类型增强.md | 637 ++++++++++++++++++++++++++++++++ java/mybatis-plus.md | 10 + openwrt/openVPN.md | 29 ++ 3 files changed, 676 insertions(+) create mode 100644 java/Guava中的类型增强.md create mode 100644 java/mybatis-plus.md create mode 100644 openwrt/openVPN.md diff --git a/java/Guava中的类型增强.md b/java/Guava中的类型增强.md new file mode 100644 index 0000000..d7799df --- /dev/null +++ b/java/Guava中的类型增强.md @@ -0,0 +1,637 @@ +# Guava中的类型增强 + +Map - Table、BiMap、Multimap、RangeMap、ClassToInstanceMap + + + +#### 1. 简介[#](https://www.cnblogs.com/cao-lei/p/17806222.html#3979976375) + +  日常开发中使用Map时经常会遇到很多复杂的处理场景,例如:多个键的Map、不仅可以根据键获取值也可以根据值获取键且不用遍历、重复键的Map、数字等范围内映射相同的值、内存中缓存对象等,Guava提供了以上场景的解决方案。 + +| 场景 | 解决方案 | 具体实现 | +| ------------------------------------------------ | ------------------ | ------------------------------------------------------------ | +| 多个键的Map | Table | HashBasedTable、TreeBasedTable、ImmutableTable | +| 不仅可以根据键获取值也可以根据值获取键且不用遍历 | BiMap | HashBiMap、ImmutableBiMap | +| 重复键的Map | Multimap | ArrayListMultimap、LinkedListMultimap、LinkedHashMultimap、ImmutableListMultimap、ImmutableSetMultimap | +| 数字等范围内映射相同的值 | RangeMap | TreeRangeMap、ImmutableRangeMap | +| 内存中缓存对象 | ClassToInstanceMap | MutableClassToInstanceMap、ImmutableClassToInstanceMap | + +  本博客将详细描述具体的示例代码。 + +#### 2. 添加依赖[#](https://www.cnblogs.com/cao-lei/p/17806222.html#1443701749) + +  Maven项目pom.xml中添加依赖: + +```xml +Copy + com.google.guava + guava + 32.0.0-jre + +``` + +#### 3. Tbale - 表结构数据[#](https://www.cnblogs.com/cao-lei/p/17806222.html#848306248) + +  官方注释翻译:将一对有序键(称为行键和列键)与单个值相关联的集合。 +  示例代码(需求: 记录各个公司每个部门的人数): + +```swift +Copy// HashMap +Map deptMap = new HashMap<>(); +deptMap.put("A部门", 10); +deptMap.put("B部门", 20); +Map> companyMap = new HashMap<>(); +companyMap.put("xx公司", deptMap); +// HashMap 获取值 +Integer val = companyMap.get("xx公司").get("A部门"); +System.out.println("HashMap 获取值: " + val); + +// 创建Hash类型Table, 基于Hash表实现 +// Table中三个泛型: R-行, C-列, V-值 +Table hashTable = HashBasedTable.create(); +hashTable.put("xx公司", "A部门", 10); +hashTable.put("xx公司", "B部门", 20); +hashTable.put("xx公司", "C部门", 30); + +System.out.println("\nHash Table: " + hashTable); + +// 创建Tree类型Table, 基于红黑树实现 +Table treeTable = TreeBasedTable.create(); +treeTable.put("xx公司", "C部门", 30); +treeTable.put("xx公司", "B部门", 20); +treeTable.put("xx公司", "A部门", 10); + +System.out.println("\nTree Table: " + treeTable); + +// 创建不可变Table, 无法新增、更新或删除 +Table immutableTable = ImmutableTable.builder() + .put("xx公司", "C部门", 30) + .put("xx公司", "B部门", 20) + .put("xx公司", "A部门", 10) + .build(); + +System.out.println("\nImmutable Table: " + immutableTable); + +// Table 获取值 +Integer val2 = hashTable.get("xx公司", "A部门"); +System.out.println("\nTable 获取值: " + val2); + +// Table 删除值 +Integer remove = hashTable.remove("xx公司", "C部门"); +System.out.println("\nTable 删除值: " + remove); + +// 根据行获取列和值映射 +Map columnvalueMap = hashTable.row("xx公司"); +System.out.println("\nTable 列和值 映射: " + columnvalueMap); + +// 根据列获取行和值映射 +Map rowvalueMap = hashTable.column("A部门"); +System.out.println("\nTable 行和值 映射: " + rowvalueMap); + +// 获取key集合 +Set rowKeySet = hashTable.rowKeySet(); +System.out.println("\nTable Row key 集合: " + rowKeySet); +Set columnKeySet = hashTable.columnKeySet(); +System.out.println("\nTable Column key 集合: " + columnKeySet); + +// 获取值集合 +Collection values = hashTable.values(); +System.out.println("\nTable 值集合: " + values); + +// 判断包含行 +boolean containsRow = hashTable.containsRow("xx公司"); +System.out.println("\nTable 包含行: " + containsRow); + +// 判断包含列 +boolean containsColumn = hashTable.containsColumn("A部门"); +System.out.println("\nTable 包含列: " + containsColumn); + +// 判断包含行和列 +boolean contains = hashTable.contains("xx公司", "A部门"); +System.out.println("\nTable 包含行和列: " + contains); + +// 判断包含值 +boolean containsValue = hashTable.containsValue(10); +System.out.println("\nTable 包含值: " + containsValue); + +// 行和列转置 - 行 转 列 +Table transposeTable = Tables.transpose(hashTable); + +// 获取所有的行 +Set> cells = transposeTable.cellSet(); + +// 遍历输出 +System.out.println("\n遍历输出开始----------------------------"); +cells.forEach(cell -> System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + ", " + cell.getValue())); +System.out.println("\n遍历输出结束----------------------------"); + +// 转换为嵌套的Map +Map> rowMap = hashTable.rowMap(); +System.out.println("\nTable RowMap: " + rowMap); +Map> columnMap = hashTable.columnMap(); +System.out.println("\nTable ColumnMap: " + columnMap); +``` + +  执行结果: + +```yaml +CopyHashMap 获取值: 10 + +Hash Table: {xx公司={A部门=10, B部门=20, C部门=30}} + +Tree Table: {xx公司={A部门=10, B部门=20, C部门=30}} + +Immutable Table: {xx公司={C部门=30, B部门=20, A部门=10}} + +Table 获取值: 10 + +Table 删除值: 30 + +Table 列和值 映射: {A部门=10, B部门=20} + +Table 行和值 映射: {xx公司=10} + +Table Row key 集合: [xx公司] + +Table Column key 集合: [A部门, B部门] + +Table 值集合: [10, 20] + +Table 包含行: true + +Table 包含列: true + +Table 包含行和列: true + +Table 包含值: true + +遍历输出开始---------------------------- +A部门, xx公司, 10 +B部门, xx公司, 20 + +遍历输出结束---------------------------- + +Table RowMap: {xx公司={A部门=10, B部门=20}} + +Table ColumnMap: {A部门={xx公司=10}, B部门={xx公司=20}} +``` + +#### 4. BiMap - 双向映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#2347438548) + +  官方注释翻译:双映射(或“双向映射”)是一种保留其值及其键的唯一性的映射。此约束使双映射能够支持“反向视图”,即另一个双映射,其中包含与此双映射相同的条目,但具有相反的键和值。 +  示例代码(需求: 数组和英文翻译): + +```csharp +Copy// 创建BiMap, 底层为两个Hash表的Map +BiMap biMap = HashBiMap.create(); +biMap.put(1, "one"); +biMap.put(2, "two"); +biMap.put(3, "three"); +biMap.put(4, "four"); +biMap.put(5, "five"); + +System.out.println("BiMap: " + biMap); + +// 创建不可变BiMap, 无法新增、更新或删除 +BiMap immutableBiMap = ImmutableBiMap.builder() + .put(1, "one") + .put(2, "two") + .put(3, "three") + .put(4, "four") + .put(5, "five") + .build(); + +System.out.println("\nImmutable BiMap: " + immutableBiMap); + +// 通过key获取value +String value = biMap.get(1); +System.out.println("\nBiMap 根据key获取value: " + value); + +Integer key = biMap.inverse().get("one"); +System.out.println("\nBiMap 根据value获取key: " + key); + +// 翻转后修改 +biMap.inverse().put("six", 6); +// 返回双映射的逆视图, 并没有创建新对象, 还是之前的对象, 所以操作翻转后的BiMap会影响之前的BiMap +System.out.println("\nBiMap 被影响: " + biMap); + +// 底层是HashMap, key不可重复 +// value不可重复 +try { + biMap.put(11, "one"); +} catch (Exception e) { + System.err.println("BiMap 替换value异常: " + e.getMessage()); +} + +// 翻转后key不能重复 +try { + biMap.inverse().put("first", 1); +} catch (Exception e) { + System.err.println("BiMap 替换key异常: " + e.getMessage()); +} + +// key和value可为null +biMap.put(null, null); +System.out.println("\nBiMap 根据Null key获取Null value: " + biMap.get(null)); +System.out.println("\nBiMap 根据Null value获取Null key: " + biMap.inverse().get(null)); + +// 强制替换key +biMap.forcePut(11, "one"); +System.out.println("\nBiMap 获取新key: " + biMap.inverse().get("one")); + +// values为Set集合 +Set values = biMap.values(); +System.out.println("\nBiMap 不重复的value: " + values); +``` + +  执行结果: + +```mipsasm +CopyBiMap: {1=one, 2=two, 3=three, 4=four, 5=five} + +Immutable BiMap: {1=one, 2=two, 3=three, 4=four, 5=five} + +BiMap 根据key获取value: one + +BiMap 根据value获取key: 1 + +BiMap 被影响: {1=one, 2=two, 3=three, 4=four, 5=five, 6=six} +BiMap 替换value异常: value already present: one +BiMap 替换key异常: key already present: 1 + +BiMap 根据Null key获取Null value: null + +BiMap 根据Null value获取Null key: null + +BiMap 获取新key: 11 + +BiMap 不重复的value: [two, three, four, five, six, null, one] +``` + +#### 5. Multimap - 多重映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#819077997) + +  官方注释翻译将键映射到值的集合,类似于 Map,但其中每个键可能与 多个 值相关联。 +  示例代码(需求: 学生和各科选修课成绩): + +```swift +Copy// 创建Multimap, key为HashMap, value为ArrayList +Multimap arrayListMultimap = ArrayListMultimap.create(); +arrayListMultimap.put("张三", 90); +arrayListMultimap.put("张三", 80); +arrayListMultimap.put("张三", 100); +arrayListMultimap.put("李四", 88); + +System.out.println("Multimap key为HashMap, value为ArrayList: " + arrayListMultimap); + +// 创建Multimap, key为HashMap, value为HashSet +Multimap hashMultimap = HashMultimap.create(); +hashMultimap.put("张三", 90); +hashMultimap.put("张三", 80); +hashMultimap.put("张三", 100); +hashMultimap.put("李四", 88); + +System.out.println("\nMultimap key为HashMap, value为HashSet: " + hashMultimap); + +// 创建Multimap, key为LinkedHashMap, value为LinkedList +Multimap linkedListMultimap = LinkedListMultimap.create(); +linkedListMultimap.put("张三", 90); +linkedListMultimap.put("张三", 80); +linkedListMultimap.put("张三", 100); +linkedListMultimap.put("李四", 88); + +System.out.println("\nMultimap key为LinkedHashMap, value为LinkedList: " + linkedListMultimap); + +// 创建Multimap, key为LinkedHashMap, value为LinkedHashMap +Multimap linkedHashMultimap = LinkedHashMultimap.create(); +linkedHashMultimap.put("张三", 90); +linkedHashMultimap.put("张三", 80); +linkedHashMultimap.put("张三", 100); +linkedHashMultimap.put("李四", 88); + +System.out.println("\nMultimap key为LinkedHashMap, value为LinkedHashMap: " + linkedHashMultimap); + +// 创建Multimap, key为TreeMap, value为TreeSet +Multimap treeMultimap = TreeMultimap.create(); +treeMultimap.put("张三", 90); +treeMultimap.put("张三", 80); +treeMultimap.put("张三", 100); +treeMultimap.put("李四", 88); + +System.out.println("\nMultimap key为TreeMap, value为TreeSet: " + treeMultimap); + +// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableList +Multimap immutableListMultimap = ImmutableListMultimap.builder() + .put("张三", 90) + .put("张三", 80) + .put("张三", 100) + .put("李四", 88) + .build(); + +System.out.println("\nMultimap key为ImmutableMap, value为ImmutableList: " + immutableListMultimap); + +// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableSet +Multimap immutableSetMultimap = ImmutableSetMultimap.builder() + .put("张三", 90) + .put("张三", 80) + .put("张三", 100) + .put("李四", 88) + .build(); + +System.out.println("\nMultimap key为ImmutableMap, value为ImmutableSet: " + immutableSetMultimap); + +// 获取值 +Collection values = arrayListMultimap.get("张三"); +System.out.println("\nMultimap 获取值集合: " + values); + +// 获取不存在key的值, 返回的是空集合, 而不是null +Collection valuesByNotExistsKey = arrayListMultimap.get("王五"); +System.out.println("\nMultimap 获取不存在的Key值集合: " + valuesByNotExistsKey); + +// 获取值集合添加值 +// 返回的是多重映射中关联的值的视图集合, 并没有创建新对象, 还是之前的对象, 所以操作值集合会影响之前的Multimap +values.add(60); +System.out.println("\nMultimap 被影响: " + arrayListMultimap); + +// 获取大小 +System.out.println("\nMultimap 大小:" + arrayListMultimap.size()); + +// 判断是否为空 +System.out.println("\nMultimap 是否为空: " + arrayListMultimap.isEmpty()); + +// 包含key +System.out.println("\nMultimap 包含key: " + arrayListMultimap.containsKey("张三")); + +// 包含value +System.out.println("\nMultimap 包含value: " + arrayListMultimap.containsValue(60)); + +// 包含key-value键值对 +System.out.println("\nMultimap 包含key-value对: " + arrayListMultimap.containsEntry("张三", 60)); + +// 替换value +arrayListMultimap.replaceValues("张三", Arrays.asList(10, 20, 30)); +System.out.println("\nMultimap 替换value: " + arrayListMultimap); + +// 根据key-value删除 +arrayListMultimap.remove("张三", 10); +System.out.println("\nMultimap 根据key-value删除: " + arrayListMultimap); + +// 根据key删除 +Collection removeAll = arrayListMultimap.removeAll("张三"); +System.out.println("\nMultimap 根据key删除: " + removeAll); + +// 获取key集合 +Set keySet = arrayListMultimap.keySet(); +System.out.println("\nMultimap 获取key集合(HashSet): " + keySet); +Multiset keys = arrayListMultimap.keys(); +System.out.println("\nMultimap 获取key集合(MultiSet): " + keys); + +// 获取所有的key-value +Collection> entries = arrayListMultimap.entries(); +System.out.println("\n遍历key-value开始--------------------------"); +entries.forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue())); +System.out.println("\n遍历key-value结束--------------------------"); + +// 转换为Map> +Map> collectionMap = arrayListMultimap.asMap(); +System.out.println("\nMultimap 转换为Map>: " + collectionMap); +``` + +  执行结果: + +```mipsasm +CopyMultimap key为HashMap, value为ArrayList: {李四=[88], 张三=[90, 80, 100]} + +Multimap key为HashMap, value为HashSet: {李四=[88], 张三=[80, 100, 90]} + +Multimap key为LinkedHashMap, value为LinkedList: {张三=[90, 80, 100], 李四=[88]} + +Multimap key为LinkedHashMap, value为LinkedHashMap: {张三=[90, 80, 100], 李四=[88]} + +Multimap key为TreeMap, value为TreeSet: {张三=[80, 90, 100], 李四=[88]} + +Multimap key为ImmutableMap, value为ImmutableList: {张三=[90, 80, 100], 李四=[88]} + +Multimap key为ImmutableMap, value为ImmutableSet: {张三=[90, 80, 100], 李四=[88]} + +Multimap 获取值集合: [90, 80, 100] + +Multimap 获取不存在的Key值集合: [] + +Multimap 被影响: {李四=[88], 张三=[90, 80, 100, 60]} + +Multimap 大小:5 + +Multimap 是否为空: false + +Multimap 包含key: true + +Multimap 包含value: true + +Multimap 包含key-value对: true + +Multimap 替换value: {李四=[88], 张三=[10, 20, 30]} + +Multimap 根据key-value删除: {李四=[88], 张三=[20, 30]} + +Multimap 根据key删除: [20, 30] + +Multimap 获取key集合(HashSet): [李四] + +Multimap 获取key集合(MultiSet): [李四] + +遍历key-value开始-------------------------- +李四 : 88 + +遍历key-value结束-------------------------- + +Multimap 转换为Map>: {李四=[88]} +``` + +#### 6. RangeMap - 范围映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#684335507) + +  官方注释翻译:从不相交的非空范围到非 null 值的映射。查询查找与包含指定键的范围(如果有)关联的值。 +  示例代码(需求:考试成绩分类): + +```swift +Copy// if-else +int score = 88; +String rank; +if (0 <= score && score < 60) { + rank = "不及格"; +} else if (60 <= score && score <= 84) { + rank = "及格"; +} else if (84 < score && score <= 100) { + rank = "优秀"; +} else { + rank = "无效"; +} + +System.out.println("if-else 获取值: " + rank); + +// 创建RangeMap, 基于TreeMap(红黑树)实现 +RangeMap treeRangeMap = TreeRangeMap.create(); +treeRangeMap.put(Range.closedOpen(0, 60), "不及格"); +treeRangeMap.put(Range.closed(60, 84), "及格"); +treeRangeMap.put(Range.openClosed(84, 100), "优秀"); +treeRangeMap.put(Range.lessThan(0), "无效"); +treeRangeMap.put(Range.greaterThan(100), "无效"); + +rank = treeRangeMap.get(score); +System.out.println("\nRangeMap 获取值: " + rank); + +// 创建不可变RangeMap, 无法新增、更新或删除 +ImmutableRangeMap immutableRangeMap = ImmutableRangeMap.builder() + .put(Range.closedOpen(0, 60), "不及格") + .put(Range.closed(60, 84), "及格") + .put(Range.openClosed(84, 100), "优秀") + .put(Range.lessThan(0), "无效") + .put(Range.greaterThan(100), "无效") + .build(); + +rank = immutableRangeMap.get(score); +System.out.println("\nImmutableRangeMap 获取值: " + rank); + +// 获取key-value对 +Map.Entry, String> entry = treeRangeMap.getEntry(88); +System.out.println("\nRangeMap 获取key-value对: " + entry.getKey() + " : " + entry.getValue()); + +// 返回不可变的升序的Map +Map, String> asMapOfRanges = treeRangeMap.asMapOfRanges(); +System.out.println("\nRangeMap 不可变的升序的Map: " + asMapOfRanges); + +// 返回不可变的降序的Map +Map, String> asDescendingMapOfRanges = treeRangeMap.asDescendingMapOfRanges(); +System.out.println("\nRangeMap 不可变的降序的Map: " + asDescendingMapOfRanges); + +// 相连范围合并 +RangeMap treeRangeMap2 = TreeRangeMap.create(); +treeRangeMap2.putCoalescing(Range.closedOpen(0, 60), "不及格"); +treeRangeMap2.putCoalescing(Range.closed(60, 84), "及格"); +treeRangeMap2.putCoalescing(Range.openClosed(84, 100), "及格"); // 或者 [60..84]范围合并 +treeRangeMap2.putCoalescing(Range.lessThan(0), "无效"); +treeRangeMap2.putCoalescing(Range.greaterThan(100), "无效"); +System.out.println("\nRangeMap 不合并相连范围: " + treeRangeMap.asMapOfRanges()); +System.out.println("RangeMap 合并相连范围: " + treeRangeMap2.asMapOfRanges()); + +// 最小范围 +Range span = treeRangeMap.span(); +System.out.println("\nRangeMap 最小范围: " + span); + +// 子范围Map +RangeMap subRangeMap = treeRangeMap.subRangeMap(Range.closed(70, 90)); +System.out.println("\nRangeMap 子范围Map: " + subRangeMap); + +// 合并范围 +treeRangeMap.merge(Range.closed(60, 100), "及格", (s, s2) -> s2); +System.out.println("\nRangeMap 合并Map: " + treeRangeMap); + +// 移除范围 +treeRangeMap.remove(Range.open(90, 95)); +System.out.println("\nRangeMap 移除范围: " + treeRangeMap); + +// 清除所有范围 +treeRangeMap.clear(); +System.out.println("\nRangeMap 清除所有范围: " + treeRangeMap); +``` + +  执行结果: + +```javascript +Copyif-else 获取值: 优秀 + +RangeMap 获取值: 优秀 + +ImmutableRangeMap 获取值: 优秀 + +RangeMap 获取key-value对: (84..100] : 优秀 + +RangeMap 不可变的升序的Map: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效} + +RangeMap 不可变的降序的Map: {(100..+∞)=无效, (84..100]=优秀, [60..84]=及格, [0..60)=不及格, (-∞..0)=无效} + +RangeMap 不合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效} +RangeMap 合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..100]=及格, (100..+∞)=无效} + +RangeMap 最小范围: (-∞..+∞) + +RangeMap 子范围Map: {[70..84]=及格, (84..90]=优秀} + +RangeMap 合并Map: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=及格, (100..+∞)=无效] + +RangeMap 移除范围: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..90]=及格, [95..100]=及格, (100..+∞)=无效] + +RangeMap 清除所有范围: [] +``` + +#### 7. ClassToInstanceMap - 类型映射到实例Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#85873049) + +  官方注释翻译:映射,其每个条目将一个 Java 原始类型 映射到该类型的实例。除了实现 Map之外,还提供额外的类型安全操作 putInstance 和 getInstance 。与任何其他 Map映射一样,此映射可能包含基元类型的条目,并且基元类型及其相应的包装器类型可以映射到不同的值。 +  示例代码(需求:缓存Bean(不交给Spring管理,自己管理Bean)): + +```csharp +Copyclass UserBean { + private final Integer id; + private final String username; + + public UserBean(Integer id, String username) { + this.id = id; + this.username = username; + } + + @Override + public String toString() { + return "UserBean{" + "id=" + id + ", username='" + username + '\'' + '}'; + } +} +// 创建Bean +UserBean userBean = new UserBean(1, "张三"); + +// HashMap +HashMap hashMap = new HashMap<>(); +hashMap.put(UserBean.class, userBean); + +// 获取值,需要强转 +UserBean value = (UserBean) hashMap.get(UserBean.class); +System.out.println("HashMap 获取对象实例: " + value); +System.out.println("HashMap 获取对象实例等于创建的Bean: " + (value == userBean)); + +// 创建ClassToInstanceMap +ClassToInstanceMap classToInstanceMap = MutableClassToInstanceMap.create(); +classToInstanceMap.putInstance(UserBean.class, userBean); + +// 获取值,无需强转 +UserBean value2 = classToInstanceMap.getInstance(UserBean.class); +System.out.println("\nClassToInstanceMap 获取对象实例: " + value2); +System.out.println("ClassToInstanceMap 获取对象实例等于创建的Bean: " + (value2 == userBean)); + +// 创建不可变ClassToInstanceMap, 无法新增、更新或删除 +ClassToInstanceMap immutableClassToInstanceMap = ImmutableClassToInstanceMap.builder() + .put(UserBean.class, userBean) + .build(); + +// 获取值,无需强转 +UserBean value3 = immutableClassToInstanceMap.getInstance(UserBean.class); +System.out.println("\nImmutableClassToInstanceMap 获取对象实例: " + value3); +System.out.println("ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: " + (value3 == userBean)); + + +// 限制类型,避免使用HashMap存储对象时,因为使用Object值类型而在添加缓存时需要今天类型校验 +ClassToInstanceMap classToInstanceMap1 = MutableClassToInstanceMap.create(); +classToInstanceMap1.put(ArrayList.class, new ArrayList()); +classToInstanceMap1.put(HashSet.class, new HashSet()); +// 编译保存: 'put(java.lang.Class, java.util.Collection)' in 'com.google.common.collect.MutableClassToInstanceMap' cannot be applied to '(java.lang.Class, java.util.HashMap)' +// classToInstanceMap1.put(HashMap.class, new HashMap()); +``` + +  执行结果: + +```bash +CopyHashMap 获取对象实例: UserBean{id=1, username='张三'} +HashMap 获取对象实例等于创建的Bean: true + +ClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'} +ClassToInstanceMap 获取对象实例等于创建的Bean: true + +ImmutableClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'} +ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: true +``` \ No newline at end of file diff --git a/java/mybatis-plus.md b/java/mybatis-plus.md new file mode 100644 index 0000000..8adac3a --- /dev/null +++ b/java/mybatis-plus.md @@ -0,0 +1,10 @@ +### mybtais-plus + +mybtais-plus 默认空字段 不插入 导致生成的sql 字段不完整, + +在批量插入时, 因为每个po 空值不确定 导致 sql 重写失效, + + + + +&reWriteBatchedInserts=true \ No newline at end of file diff --git a/openwrt/openVPN.md b/openwrt/openVPN.md new file mode 100644 index 0000000..764f671 --- /dev/null +++ b/openwrt/openVPN.md @@ -0,0 +1,29 @@ +## openWrt 路由器中的 openVPN 组件 + +| **连接类型** | 配置文件说明 | **模式** | **网络类型** | **适用场景** | **对应配置文件示例** | +| :-------------------- | ----------------------------------------------------------- | :------- | :---------------- | :----------------------------------------------------------- | :------------------- | +| **client_tap_bridge** | Client configuration for an ethernet bridge VPN | 客户端 | TAP(以太网桥接) | 客户端需完全接入服务器局域网(如访问 SMB 共享、网络打印机等) | `client-bridge.conf` | +| **client_tun** | Client configuration for a routed multi-client VPN | 客户端 | TUN(IP 路由) | 标准多客户端 VPN,适用于远程办公、访问内网服务 | `client-routed.conf` | +| **client_tun_ptp** | Simple client configuration for a routed point-to-point VPN | 客户端 | TUN(点对点路由) | 仅 1 对 1 连接,适合设备间专用加密隧道(如远程管理) | `client-p2p.conf` | +| **server_tap_bridge** | Server configuration for an ethernet bridge VPN | 服务器 | TAP(以太网桥接) | 服务器提供桥接模式 VPN,客户端像本地设备一样访问整个 LAN | `server-bridge.conf` | +| **server_tun** | Server configuration for a routed multi-client VPN | 服务器 | TUN(IP 路由) | 标准多客户端 VPN 服务器,适用于企业远程访问 | `server-routed.conf` | +| **server_tun_ptp** | Simple server configuration for a routed point-to-point VPN | 服务器 | TUN(点对点路由) | 仅支持 1 对 1 连接的 VPN 服务器(如站点间 VPN) | `server-p2p.conf` | + +### **关键说明**: + +1. **配置文件名**: + - 通常 OpenVPN 会根据 `option value` 生成对应的配置文件(如 `client_tun` → `client-routed.conf`)。 + - 实际文件名可能因系统不同有所变化,但逻辑一致。 +2. **TAP vs. TUN**: + - **TAP(`tap_bridge`)**:模拟以太网设备,适合需要广播/组播的应用(如网络游戏、局域网发现)。 + - **TUN(`tun`)**:仅路由 IP 流量,更高效,适合大多数 VPN(如网页访问、SSH)。 +3. **多客户端 vs. 点对点(P2P)**: + - **普通模式(`server_tun`/`client_tun`)**:支持多个客户端同时连接。 + - **点对点(`_ptp`)**:仅限两个节点直接通信,延迟更低。 + +### **典型应用**: + +- **企业远程办公** → `server_tun` + `client_tun` +- **家庭局域网扩展** → `server_tap_bridge` + `client_tap_bridge` +- **服务器间加密通道** → `server_tun_ptp` + `client_tun_ptp` +