package com.my.blog.website.utils; import java.util.Arrays; import java.util.Random; /** * 封装UUID */ public abstract class UUID { static Random r = new Random(); /** * 根据一个范围,生成一个随机的整数 * * @param min * 最小值(包括) * @param max * 最大值(包括) * @return 随机数 */ public static int random(int min, int max) { return r.nextInt(max - min + 1) + min; } private static final char[] _UU64 = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".toCharArray(); private static final char[] _UU32 = "0123456789abcdefghijklmnopqrstuv".toCharArray(); /** * @return 64进制表示的紧凑格式的 UUID */ public static String UU64() { return UU64(java.util.UUID.randomUUID()); } /** * 返回一个 UUID ,并用 64 进制转换成紧凑形式的字符串,内容为 [\\-0-9a-zA-Z_] * <p> * 比如一个类似下面的 UUID: * * <pre> * a6c5c51c-689c-4525-9bcd-c14c1e107c80 * 一共 128 位,分做L64 和 R64,分为为两个 64位数(两个 long) * > L = uu.getLeastSignificantBits(); * > UUID = uu.getMostSignificantBits(); * 而一个 64 进制数,是 6 位,因此我们取值的顺序是 * 1. 从L64位取10次,每次取6位 * 2. 从L64位取最后的4位 + R64位头2位拼上 * 3. 从R64位取10次,每次取6位 * 4. 剩下的两位最后取 * 这样,就能用一个 22 长度的字符串表示一个 32 长度的UUID,压缩了 1/3 * </pre> * * @param uu * UUID 对象 * @return 64进制表示的紧凑格式的 UUID */ public static String UU64(java.util.UUID uu) { int index = 0; char[] cs = new char[22]; long L = uu.getMostSignificantBits(); long R = uu.getLeastSignificantBits(); long mask = 63; // 从L64位取10次,每次取6位 for (int off = 58; off >= 4; off -= 6) { long hex = (L & (mask << off)) >>> off; cs[index++] = _UU64[(int) hex]; } // 从L64位取最后的4位 + R64位头2位拼上 int l = (int) (((L & 0xF) << 2) | ((R & (3 << 62)) >>> 62)); cs[index++] = _UU64[l]; // 从R64位取10次,每次取6位 for (int off = 56; off >= 2; off -= 6) { long hex = (R & (mask << off)) >>> off; cs[index++] = _UU64[(int) hex]; } // 剩下的两位最后取 cs[index++] = _UU64[(int) (R & 3)]; // 返回字符串 return new String(cs); } /** * 从一个 UU64 恢复回一个 UUID 对象 * * @param uu64 * 64进制表示的 UUID, 内容为 [\\-0-9a-zA-Z_] * @return UUID 对象 */ public static java.util.UUID fromUU64(String uu64) { String uu16 = UU16FromUU64(uu64); return java.util.UUID.fromString(UU(uu16)); } public static String UU32(java.util.UUID uu) { StringBuilder sb = new StringBuilder(); long m = uu.getMostSignificantBits(); long l = uu.getLeastSignificantBits(); for (int i = 0; i < 13; i++) { sb.append(_UU32[(int) (m >> ((13 - i - 1) * 5)) & 31]); } for (int i = 0; i < 13; i++) { sb.append(_UU32[(int) (l >> ((13 - i - 1)) * 5) & 31]); } return sb.toString(); } public static String UU32() { return UU32(java.util.UUID.randomUUID()); } public static java.util.UUID fromUU32(String u32) { return new java.util.UUID(parseUnsignedLong(u32.substring(0, 13), 32), parseUnsignedLong(u32.substring(13), 32)); } public static long parseUnsignedLong(String s, int radix) { int len = s.length(); long first = Long.parseLong(s.substring(0, len - 1), radix); int second = Character.digit(s.charAt(len - 1), radix); return first * radix + second; } /** * 将紧凑格式的 UU16 字符串变成标准 UUID 格式的字符串 * * @param uu16 * @return 标准 UUID 字符串 */ public static String UU(String uu16) { StringBuilder sb = new StringBuilder(); sb.append(uu16.substring(0, 8)); sb.append('-'); sb.append(uu16.substring(8, 12)); sb.append('-'); sb.append(uu16.substring(12, 16)); sb.append('-'); sb.append(uu16.substring(16, 20)); sb.append('-'); sb.append(uu16.substring(20)); return sb.toString(); } private static final char[] _UU16 = "0123456789abcdef".toCharArray(); /** * 将一个 UU64 表示的紧凑字符串,变成 UU16 表示的字符串 * * <pre> * 每次取2个字符,恢复成3个byte,重复10次, 最后一次,是用最后2个字符,恢复回2个byte </prev> * * @param uu64 * uu64 64进制表示的 UUID, 内容为 [\\-0-9a-zA-Z_] * @return 16进制表示的紧凑格式的 UUID */ public static String UU16FromUU64(String uu64) { byte[] bytes = new byte[32]; char[] cs = uu64.toCharArray(); int index = 0; // 每次取2个字符,恢复成3个byte,重复10次, for (int i = 0; i < 10; i++) { int off = i * 2; char cl = cs[off]; char cr = cs[off + 1]; int l = Arrays.binarySearch(_UU64, cl); int r = Arrays.binarySearch(_UU64, cr); int n = (l << 6) | r; bytes[index++] = (byte) ((n & 0xF00) >>> 8); bytes[index++] = (byte) ((n & 0xF0) >>> 4); bytes[index++] = (byte) (n & 0xF); } // 最后一次,是用最后2个字符,恢复回2个byte char cl = cs[20]; char cr = cs[21]; int l = Arrays.binarySearch(_UU64, cl); int r = Arrays.binarySearch(_UU64, cr); int n = (l << 2) | r; bytes[index++] = (byte) ((n & 0xF0) >>> 4); bytes[index++] = (byte) (n & 0xF); // 返回 UUID 对象 char[] names = new char[32]; for (int i = 0; i < bytes.length; i++) names[i] = _UU16[bytes[i]]; return new String(names); } /** * 返回指定长度由随机数字+小写字母组成的字符串 * * @param length * 指定长度 * @return 随机字符串 */ public static String captchaChar(int length) { return captchaChar(length, false); } /** * 返回指定长度随机数字+字母(大小写敏感)组成的字符串 * * @param length * 指定长度 * @param caseSensitivity * 是否区分大小写 * @return 随机字符串 */ public static String captchaChar(int length, boolean caseSensitivity) { StringBuilder sb = new StringBuilder(); Random rand = new Random();// 随机用以下三个随机生成器 Random randdata = new Random(); int data = 0; for (int i = 0; i < length; i++) { int index = rand.nextInt(caseSensitivity ? 3 : 2); // 目的是随机选择生成数字,大小写字母 switch (index) { case 0: data = randdata.nextInt(10);// 仅仅会生成0~9, 0~9的ASCII为48~57 sb.append(data); break; case 1: data = randdata.nextInt(26) + 97;// 保证只会产生ASCII为97~122(a-z)之间的整数, sb.append((char) data); break; case 2: // caseSensitivity为true的时候, 才会有大写字母 data = randdata.nextInt(26) + 65;// 保证只会产生ASCII为65~90(A~Z)之间的整数 sb.append((char) data); break; } } return sb.toString(); } /** * 返回指定长度随机数字组成的字符串 * * @param length * 指定长度 * @return 随机字符串 */ public static String captchaNumber(int length) { StringBuilder sb = new StringBuilder(); Random rand = new Random(); for (int i = 0; i < length; i++) { sb.append(rand.nextInt(10)); } return sb.toString(); } }