使用 URI 来校验 url,如下代码:
import org.apache.commons.validator.routines.UrlValidator;
import java.net.URI;
import java.net.URISyntaxException;
public class UrlUtils {
public static void main(String[] args) {
String url = "http://www.jiaobuchong.com?name=tom&request={\"hobby\":\"film\"}";
System.out.println(new UrlValidator().isValid(url));
isValidUrl(url);
}
public static boolean isValidUrl(String url) {
try {
URI uri = new URI(url);
return true;
} catch (URISyntaxException e) {
e.printStackTrace();
}
return false;
}
}
如果 url 含有 {}""
则会抛出 URISyntaxException,校验不通过。 看了一下 URI 里面的源码,有个校验还挺有意思的。
一、分析 checkChar 方法
1、通过 highMask 获取合法字符范围的二进制
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
private static final long L_LOWALPHA = 0L;
private static final long L_UPALPHA = 0L;
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
private static final long H_LOWALPHA = highMask('a', 'z');
private static final long H_UPALPHA = highMask('A', 'Z');
checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
L_ALPHA 与的结果是 0,下面就要开始比较有意思的部分了,来看 highMask 到底做了什么:
// Compute a high-order mask for the characters
// between first and last, inclusive
private static long highMask(char first, char last) {
long m = 0;
// Math.min 表示从 ASCII 的范围里取值
// Math.max(Math.min(first, 127), 64) 表示在 ASCII 码表[64, 127]之间的字符
// 减去 64 表示不包括 64 这个字符,相对 64 之间还有多少个个字符
int f = Math.max(Math.min(first, 127), 64) - 64;
int l = Math.max(Math.min(last, 127), 64) - 64;
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
highMask(‘a’, ‘z’ ) m 的二进制:
highMask(‘A’, ‘Z’ ) m 的二进制:
H_ALPHA = H_LOWALPHA | H_UPALPHA 相与的结果是:
11111111111111111111111111000000111111111111111111111111110
,相与之后的结果 H_UPALPHA 表示 a-zA-Z
这个范围的字符,一个萝卜一个坑,不在这个范围的数据对应的坑位就是 0。
2、match 方法
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
return false;
if (c < 64)
return ((1L << c) & lowMask) != 0;
if (c < 128)
// 左移 (c - 64) 位,和 highMask 进行 & 运算,如果不等于 0 就表示这个字符是合法的
return ((1L << (c - 64)) & highMask) != 0;
return false;
}
二、分析 checkChars 方法
通过上面的分析,URI 判断是否合法字符的原理就是:将和合法范围的字符转成一个二进制数,然后将传进来的字符和这个二进制进行与运算,如果不等于 0 就表示这个字符是合法的。
再来分析一下这个方法:
checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
通过代码中的计算,L_SCHEME 的结果是:
0 | lowMask('0', '9') | lowMask("+-.")
H_SCHEME:
H_SCHEME = highMask('a', 'z') | highMask('A', 'Z') | 0 | highMask("+-.")
来看 lowMask的代码,生成的结果 m 表示 [0-9] 二进制的范围:
// Compute a low-order mask for the characters
// between first and last, inclusive
private static long lowMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 63), 0);
int l = Math.max(Math.min(last, 63), 0);
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
然后 在 match 方法里:
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
return false;
if (c < 64)
// 对于小于 64 的字符,和 lowMask 进行与运算,不等于0表示合法的字符
return ((1L << c) & lowMask) != 0;
if (c < 128)
return ((1L << (c - 64)) & highMask) != 0;
return false;
}