1.update code;

2.fix doc;
3.add test method;
This commit is contained in:
emptypoint 2023-03-05 13:38:35 +08:00
parent 09c3dd9565
commit f79c670446
4 changed files with 85 additions and 98 deletions

View File

@ -8,13 +8,12 @@ import cn.hutool.core.util.CharUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
/** /**
* IPV4地址工具类 * IPV4地址工具类
* *
* <p>pr自https://gitee.com/loolly/hutool/pulls/161</p> * <p><a href="https://gitee.com/loolly/hutool/pulls/161">工具类来源pr</a></p>
* *
* <p>名词解释 * <p>名词解释
* <ul> * <ul>
@ -22,7 +21,7 @@ import java.util.regex.Matcher;
* <li>ip的Long类型有效位32位每8位可以转为一个十进制数例如0xC0A802FA 转为点分十进制是192.168.2.250</li> * <li>ip的Long类型有效位32位每8位可以转为一个十进制数例如0xC0A802FA 转为点分十进制是192.168.2.250</li>
* <li>掩码地址点分十进制例如255.255.255.0</li> * <li>掩码地址点分十进制例如255.255.255.0</li>
* <li>掩码位int类型例如 24, 它代表的掩码地址为255.255.255.0掩码位和掩码地址的相互转换请使用 {@link MaskBit}</li> * <li>掩码位int类型例如 24, 它代表的掩码地址为255.255.255.0掩码位和掩码地址的相互转换请使用 {@link MaskBit}</li>
* <li>CIDR无类域间路由形如xxx.xxx.xxx.xxx/掩码位</li> * <li>CIDR无类域间路由形如xxx.xxx.xxx.xxx/掩码位192.168.1.101/24</li>
* <li>全量地址区间内所有ip地址包含区间两端</li> * <li>全量地址区间内所有ip地址包含区间两端</li>
* <li>可用地址区间内所有ip地址但是不包含区间两端</li> * <li>可用地址区间内所有ip地址但是不包含区间两端</li>
* </ul> * </ul>
@ -39,7 +38,7 @@ public class Ipv4Util implements Ipv4Pool {
* *
* @param ip IP地址点分十进制xxx.xxx.xxx.xxx * @param ip IP地址点分十进制xxx.xxx.xxx.xxx
* @param mask 掩码地址点分十进制255.255.255.0 * @param mask 掩码地址点分十进制255.255.255.0
* @return 返回 {@literal xxx.xxx.xxx.xxx/掩码位} 的格式 * @return 返回 {@literal xxx.xxx.xxx.xxx/掩码位} 的格式例如192.168.1.101/24
*/ */
public static String formatIpBlock(final String ip, final String mask) { public static String formatIpBlock(final String ip, final String mask) {
return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(mask); return ip + IP_MASK_SPLIT_MARK + getMaskBitByMask(mask);
@ -78,31 +77,20 @@ public class Ipv4Util implements Ipv4Pool {
assertMaskBitValid(maskBit); assertMaskBitValid(maskBit);
// 避免后续的计算异常 // 避免后续的计算异常
if (countByMaskBit(maskBit, isAll) == 0) { if (countByMaskBit(maskBit, isAll) == 0) {
return new ArrayList<>(0); return ListUtil.zero();
} }
if (maskBit == IPV4_MASK_BIT_MAX) { final long startIp = getBeginIpLong(ip, maskBit);
final List<String> list = new ArrayList<>(isAll ? 1 : 0); final long endIp = getEndIpLong(ip, maskBit);
if (isAll) {
list.add(ip);
}
return list;
}
String startIp = getBeginIpStr(ip, maskBit);
String endIp = getEndIpStr(ip, maskBit);
if (isAll) { if (isAll) {
return list(startIp, endIp); return list(startIp, endIp);
} }
// 可用地址排除开始和结束的地址 // 可用地址: 排除开始和结束的地址
int lastDotIndex = startIp.lastIndexOf(CharUtil.DOT) + 1; if (startIp + 1 > endIp - 1) {
startIp = StrUtil.subPre(startIp, lastDotIndex) + return ListUtil.zero();
(Integer.parseInt(Objects.requireNonNull(StrUtil.subSuf(startIp, lastDotIndex))) + 1); }
lastDotIndex = endIp.lastIndexOf(CharUtil.DOT) + 1; return list(startIp + 1, endIp - 1);
endIp = StrUtil.subPre(endIp, lastDotIndex) +
(Integer.parseInt(Objects.requireNonNull(StrUtil.subSuf(endIp, lastDotIndex))) - 1);
return list(startIp, endIp);
} }
/** /**
@ -128,57 +116,30 @@ public class Ipv4Util implements Ipv4Pool {
final int count = countByIpRange(ipFrom, ipTo); final int count = countByIpRange(ipFrom, ipTo);
final List<String> ips = new ArrayList<>(count); final List<String> ips = new ArrayList<>(count);
// 是否是循环的第一个值
boolean aIsStart = true, bIsStart = true, cIsStart = true;
// 是否是循环的最后一个值
boolean aIsEnd, bIsEnd, cIsEnd;
// 循环的结束值
final int aEnd = getPartOfIpLong(ipTo, 1);
int bEnd;
int cEnd;
int dEnd;
final StringBuilder sb = StrUtil.builder(15); final StringBuilder sb = StrUtil.builder(15);
for (int a = getPartOfIpLong(ipFrom, 1); a <= aEnd; a++) { for (long ip = ipFrom, end = ipTo + 1; ip < end; ip++) {
aIsEnd = (a == aEnd);
// 本次循环的结束结束值
bEnd = aIsEnd ? getPartOfIpLong(ipTo, 2) : 255;
for (int b = (aIsStart ? getPartOfIpLong(ipFrom, 2) : 0); b <= bEnd; b++) {
// 在上一个循环是最后值的基础上进行判断
bIsEnd = aIsEnd && (b == bEnd);
cEnd = bIsEnd ? getPartOfIpLong(ipTo, 3) : 255;
for (int c = (bIsStart ? getPartOfIpLong(ipFrom, 3) : 0); c <= cEnd; c++) {
// 在之前循环是最后值的基础上进行判断
cIsEnd = bIsEnd && (c == cEnd);
dEnd = cIsEnd ? getPartOfIpLong(ipTo, 4) : 255;
for (int d = (cIsStart ? getPartOfIpLong(ipFrom, 4) : 0); d <= dEnd; d++) {
sb.setLength(0); sb.setLength(0);
ips.add(sb.append(a).append(CharUtil.DOT) ips.add(sb.append((int) (ip >> 24) & 0xFF).append(CharUtil.DOT)
.append(b).append(CharUtil.DOT) .append((int) (ip >> 16) & 0xFF).append(CharUtil.DOT)
.append(c).append(CharUtil.DOT) .append((int) (ip >> 8) & 0xFF).append(CharUtil.DOT)
.append(d) .append((int) ip & 0xFF)
.toString()); .toString());
} }
cIsStart = false;
}
bIsStart = false;
}
aIsStart = false;
}
return ips; return ips;
} }
/** /**
* 根据 ip的long值 获取 ip字符串xxx.xxx.xxx.xxx * 根据 ip的long值 获取 ip字符串xxx.xxx.xxx.xxx
* *
* @param longIp IP的long表示形式 * @param ip IP的long表示形式
* @return 点分十进制ip地址 * @return 点分十进制ip地址
*/ */
public static String longToIpv4(final long longIp) { public static String longToIpv4(final long ip) {
return StrUtil.builder(15) return StrUtil.builder(15)
.append(getPartOfIpLong(longIp, 1)).append(CharUtil.DOT) .append((int) (ip >> 24) & 0xFF).append(CharUtil.DOT)
.append(getPartOfIpLong(longIp, 2)).append(CharUtil.DOT) .append((int) (ip >> 16) & 0xFF).append(CharUtil.DOT)
.append(getPartOfIpLong(longIp, 3)).append(CharUtil.DOT) .append((int) (ip >> 8) & 0xFF).append(CharUtil.DOT)
.append(getPartOfIpLong(longIp, 4)) .append((int) ip & 0xFF)
.toString(); .toString();
} }
@ -214,7 +175,7 @@ public class Ipv4Util implements Ipv4Pool {
* @param maskBit 给定的掩码位30 * @param maskBit 给定的掩码位30
* @return 起始IP的长整型表示 * @return 起始IP的长整型表示
*/ */
public static Long getBeginIpLong(final String ip, final int maskBit) { public static long getBeginIpLong(final String ip, final int maskBit) {
assertMaskBitValid(maskBit); assertMaskBitValid(maskBit);
return ipv4ToLong(ip) & MaskBit.getMaskIpLong(maskBit); return ipv4ToLong(ip) & MaskBit.getMaskIpLong(maskBit);
} }
@ -237,8 +198,8 @@ public class Ipv4Util implements Ipv4Pool {
* @param maskBit 给定的掩码位30 * @param maskBit 给定的掩码位30
* @return 终止IP的长整型表示 * @return 终止IP的长整型表示
*/ */
public static Long getEndIpLong(final String ip, final int maskBit) { public static long getEndIpLong(final String ip, final int maskBit) {
return getBeginIpLong(ip, maskBit) + ~MaskBit.getMaskIpLong(maskBit); return getBeginIpLong(ip, maskBit) + (IPV4_NUM_MAX & ~MaskBit.getMaskIpLong(maskBit));
} }
/** /**
@ -257,7 +218,7 @@ public class Ipv4Util implements Ipv4Pool {
/** /**
* 获取 子网内的 地址总数 * 获取 子网内的 地址总数
* *
* @param maskBit 掩码位取值范围({@link Ipv4Pool#IPV4_MASK_BIT_VALID_MIN}, {@link Ipv4Pool#IPV4_MASK_BIT_MAX}] * @param maskBit 掩码位取值范围({@link #IPV4_MASK_BIT_VALID_MIN}, {@link #IPV4_MASK_BIT_MAX}]
* @param isAll true:全量地址false:可用地址 * @param isAll true:全量地址false:可用地址
* @return 子网内地址总数 * @return 子网内地址总数
*/ */
@ -276,10 +237,11 @@ public class Ipv4Util implements Ipv4Pool {
/** /**
* 根据 掩码位 获取 掩码地址 * 根据 掩码位 获取 掩码地址
* *
* @param maskBit 掩码位24取值范围[{@link Ipv4Pool#IPV4_MASK_BIT_VALID_MIN}, {@link Ipv4Pool#IPV4_MASK_BIT_MAX}] * @param maskBit 掩码位24取值范围[{@link #IPV4_MASK_BIT_VALID_MIN}, {@link #IPV4_MASK_BIT_MAX}]
* @return 掩码地址点分十进制:255.255.255.0 * @return 掩码地址点分十进制:255.255.255.0
*/ */
public static String getMaskByMaskBit(final int maskBit) { public static String getMaskByMaskBit(final int maskBit) {
assertMaskBitValid(maskBit);
return MaskBit.get(maskBit); return MaskBit.get(maskBit);
} }
@ -296,10 +258,10 @@ public class Ipv4Util implements Ipv4Pool {
Assert.isTrue(fromIpLong <= toIpLong, "Start IP must be less than or equal to end IP!"); Assert.isTrue(fromIpLong <= toIpLong, "Start IP must be less than or equal to end IP!");
return StrUtil.builder(15) return StrUtil.builder(15)
.append(255 - getPartOfIpLong(toIpLong, 1) + getPartOfIpLong(fromIpLong, 1)).append(CharUtil.DOT) .append(255 - getPartOfIp(toIpLong, 1) + getPartOfIp(fromIpLong, 1)).append(CharUtil.DOT)
.append(255 - getPartOfIpLong(toIpLong, 2) + getPartOfIpLong(fromIpLong, 2)).append(CharUtil.DOT) .append(255 - getPartOfIp(toIpLong, 2) + getPartOfIp(fromIpLong, 2)).append(CharUtil.DOT)
.append(255 - getPartOfIpLong(toIpLong, 3) + getPartOfIpLong(fromIpLong, 3)).append(CharUtil.DOT) .append(255 - getPartOfIp(toIpLong, 3) + getPartOfIp(fromIpLong, 3)).append(CharUtil.DOT)
.append(255 - getPartOfIpLong(toIpLong, 4) + getPartOfIpLong(fromIpLong, 4)) .append(255 - getPartOfIp(toIpLong, 4) + getPartOfIp(fromIpLong, 4))
.toString(); .toString();
} }
@ -311,9 +273,7 @@ public class Ipv4Util implements Ipv4Pool {
* @return IP数量 * @return IP数量
*/ */
public static int countByIpRange(final String fromIp, final String toIp) { public static int countByIpRange(final String fromIp, final String toIp) {
final long toIpLong = ipv4ToLong(toIp); return countByIpRange(ipv4ToLong(fromIp), ipv4ToLong(toIp));
final long fromIpLong = ipv4ToLong(fromIp);
return countByIpRange(fromIpLong, toIpLong);
} }
/** /**
@ -327,10 +287,10 @@ public class Ipv4Util implements Ipv4Pool {
Assert.isTrue(fromIp <= toIp, "Start IP must be less than or equal to end IP!"); Assert.isTrue(fromIp <= toIp, "Start IP must be less than or equal to end IP!");
int count = 1; int count = 1;
count += (getPartOfIpLong(toIp, 4) - getPartOfIpLong(fromIp, 4)); count += (getPartOfIp(toIp, 4) - getPartOfIp(fromIp, 4))
count += (getPartOfIpLong(toIp, 3) - getPartOfIpLong(fromIp, 3)) << 8; + ((getPartOfIp(toIp, 3) - getPartOfIp(fromIp, 3)) << 8)
count += (getPartOfIpLong(toIp, 2) - getPartOfIpLong(fromIp, 2)) << 16; + ((getPartOfIp(toIp, 2) - getPartOfIp(fromIp, 2)) << 16)
count += (getPartOfIpLong(toIp, 1) - getPartOfIpLong(fromIp, 1)) << 24; + ((getPartOfIp(toIp, 1) - getPartOfIp(fromIp, 1)) << 24);
return count; return count;
} }
@ -347,7 +307,7 @@ public class Ipv4Util implements Ipv4Pool {
/** /**
* 判断掩码位是否合法 * 判断掩码位是否合法
* *
* @param maskBit 掩码位有效范围[{@link Ipv4Pool#IPV4_MASK_BIT_VALID_MIN}, {@link Ipv4Pool#IPV4_MASK_BIT_MAX}] * @param maskBit 掩码位有效范围[{@link #IPV4_MASK_BIT_VALID_MIN}, {@link #IPV4_MASK_BIT_MAX}]
* @return true掩码位合法false掩码位不合法 * @return true掩码位合法false掩码位不合法
*/ */
public static boolean isMaskBitValid(final int maskBit) { public static boolean isMaskBitValid(final int maskBit) {
@ -424,7 +384,7 @@ public class Ipv4Util implements Ipv4Pool {
/** /**
* 获取ip(Long类型)指定部分的十进制值{@literal X.X.X.X }形式中每个部分的值 * 获取ip(Long类型)指定部分的十进制值{@literal X.X.X.X }形式中每个部分的值
* <p>例如ip为{@literal 0xC0A802FA}第1部分的值为 * <p>例如ip为{@literal 0xC0A802FA}
* <ul> * <ul>
* <li>第1部分的值为{@literal 0xC0}十进制值为192</li> * <li>第1部分的值为{@literal 0xC0}十进制值为192</li>
* <li>第2部分的值为{@literal 0xA8}十进制值为168</li> * <li>第2部分的值为{@literal 0xA8}十进制值为168</li>
@ -437,16 +397,16 @@ public class Ipv4Util implements Ipv4Pool {
* @return ip地址指定部分的十进制值 * @return ip地址指定部分的十进制值
* @since 6.0.0 * @since 6.0.0
*/ */
public static int getPartOfIpLong(final long ip, final int position) { public static int getPartOfIp(final long ip, final int position) {
switch (position) { switch (position) {
case 1: case 1:
return ((int) ip >> 24) & 0xFF; return (int) (ip >> 24) & 0xFF;
case 2: case 2:
return ((int) ip >> 16) & 0xFF; return (int) (ip >> 16) & 0xFF;
case 3: case 3:
return ((int) ip >> 8) & 0xFF; return (int) (ip >> 8) & 0xFF;
case 4: case 4:
return ((int) ip) & 0xFF; return (int)ip & 0xFF;
default: default:
throw new IllegalArgumentException("Illegal position of ip Long: " + position); throw new IllegalArgumentException("Illegal position of ip Long: " + position);
} }
@ -462,10 +422,14 @@ public class Ipv4Util implements Ipv4Pool {
private static long matchAddress(final Matcher matcher) { private static long matchAddress(final Matcher matcher) {
int addr = 0; int addr = 0;
// 每个点分十进制数字 转为 8位二进制 // 每个点分十进制数字 转为 8位二进制
for (int i = 1; i <= 4; ++i) { addr |= Integer.parseInt(matcher.group(1));
addr <<= 8; addr <<= 8;
addr |= Integer.parseInt(matcher.group(i)); addr |= Integer.parseInt(matcher.group(2));
} addr <<= 8;
addr |= Integer.parseInt(matcher.group(3));
addr <<= 8;
addr |= Integer.parseInt(matcher.group(4));
// int的最高位无法直接使用转为Long // int的最高位无法直接使用转为Long
if (addr < 0) { if (addr < 0) {
return IPV4_NUM_MAX & addr; return IPV4_NUM_MAX & addr;

View File

@ -5,6 +5,9 @@ import cn.hutool.core.map.BiMap;
import java.util.HashMap; import java.util.HashMap;
import static cn.hutool.core.net.Ipv4Pool.IPV4_MASK_BIT_MAX;
import static cn.hutool.core.net.Ipv4Pool.IPV4_NUM_MAX;
/** /**
* 掩码位和掩码之间的Map对应 * 掩码位和掩码之间的Map对应
* *
@ -84,6 +87,6 @@ public class MaskBit {
*/ */
public static long getMaskIpLong(final int maskBit) { public static long getMaskIpLong(final int maskBit) {
Assert.isTrue(MASK_BIT_MAP.containsKey(maskBit), "非法的掩码位数:{}", maskBit); Assert.isTrue(MASK_BIT_MAP.containsKey(maskBit), "非法的掩码位数:{}", maskBit);
return (0xffffffffL << (32 - maskBit)) & 0xffffffffL; return (IPV4_NUM_MAX << (IPV4_MASK_BIT_MAX - maskBit)) & IPV4_NUM_MAX;
} }
} }

View File

@ -6,6 +6,13 @@ import org.junit.function.ThrowingRunnable;
public class Ipv4UtilTest { public class Ipv4UtilTest {
@Test
public void formatIpBlockTest() {
for (int i = Ipv4Util.IPV4_MASK_BIT_VALID_MIN; i < Ipv4Util.IPV4_MASK_BIT_MAX; i++) {
Assert.assertEquals("192.168.1.101/" + i, Ipv4Util.formatIpBlock("192.168.1.101", Ipv4Util.getMaskByMaskBit(i)));
}
}
@Test @Test
public void getMaskBitByMaskTest() { public void getMaskBitByMaskTest() {
final int maskBitByMask = Ipv4Util.getMaskBitByMask("255.255.255.0"); final int maskBitByMask = Ipv4Util.getMaskBitByMask("255.255.255.0");
@ -66,7 +73,10 @@ public class Ipv4UtilTest {
testGenerateIpList(ip, 32, false); testGenerateIpList(ip, 32, false);
testGenerateIpList(ip, 32, true); testGenerateIpList(ip, 32, true);
}
@Test
public void listTest2() {
testGenerateIpList("10.1.0.1", "10.2.1.2"); testGenerateIpList("10.1.0.1", "10.2.1.2");
testGenerateIpList("10.2.1.1", "10.2.1.2"); testGenerateIpList("10.2.1.1", "10.2.1.2");
@ -182,4 +192,13 @@ public class Ipv4UtilTest {
Assert.assertFalse(Ipv4Util.isPublicIP("172.20.10.1")); Assert.assertFalse(Ipv4Util.isPublicIP("172.20.10.1"));
} }
@Test
public void getMaskBitByIpRange() {
final String ip = "192.168.100.2";
for (int i = 1; i <= 32; i++) {
String beginIpStr = Ipv4Util.getBeginIpStr(ip, i);
String endIpStr = Ipv4Util.getEndIpStr(ip, i);
Assert.assertEquals(Ipv4Util.getMaskByMaskBit(i), Ipv4Util.getMaskByIpRange(beginIpStr, endIpStr));
}
}
} }

View File

@ -350,6 +350,7 @@ public class Entity extends Dict {
* *
* @param field 字段名 * @param field 字段名
* @param charset 编码 * @param charset 编码
* @param defaultValue 默认值
* @return 字段对应值 * @return 字段对应值
*/ */
public String getStr(final String field, final Charset charset, final String defaultValue) { public String getStr(final String field, final Charset charset, final String defaultValue) {