概述
使用 Base64 编码来对 UUID(Universally Unique Identifiers) 存储在一些特定的场合被广泛的使用。使用 Base64 对比直接使用 UUID 进行存储来说能够更多的节约空间。
在这里,使用 Base64 来对 UUID 进行存储,涉及到一些类型的转换的。Base64 是编码算法,在实际使用的时候我们更多会用到 Byte 数组的方式来进行编码的。这样我们就比较明确在对其进行 Base64 转换之前,我们应该要先干什么了。
使用 byte[]和 Base64.Encoder
Base64.Encoder
就能够提供 byte[]
的 Base64 编码了,我们先使用这个最简单的方式来进行处理。
编码
首先我们需要给出的 UUID 位中创建出我们需要的 byte 数组。
我们先获得 UUID 的 most significant bits 和 least significant bits,然后放入我们 byte 数组中的 0-7 和 8-15 的位置。
程序代码如下:
private byte[] convertToByteArray(UUID uuid) { byte[] result = new byte[16]; long mostSignificantBits = uuid.getMostSignificantBits(); fillByteArray(0, 8, result, mostSignificantBits); long leastSignificantBits = uuid.getLeastSignificantBits(); fillByteArray(8, 16, result, leastSignificantBits); return result; }
上面的代码中还有一个 fillByteArray 方法,这个方法,这个方法将会把我们的 bit 存如 byte array 数组中,同时还会移动 8 位。
方法的代码如下:
void fillByteArray(int start, int end, byte[] result, long bits) { for (int i = start; i < end; i++) { int shift = i * 8; result[i] = (byte) ((int) (255L & bits >> shift)); } }
当我们获得 byte 数组后,我们就可以调用 JDK 的 Base64.Encoder 方法来直接进行编码了成一个 Base64 加密字符串了。
完整的测试代码如下:
UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c"); @Test void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() { String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw=="; byte[] uuidBytes = convertToByteArray(originalUUID); String encodedUUID = Base64.getEncoder().encodeToString(uuidBytes); assertEquals(expectedEncodedString, encodedUUID); }
解码
把我们获得的 UUID Base64 字符串进行解码,我们可以使用完全相反的方法:
@Test public void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() { String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw=="; byte[] decodedBytes = Base64.getDecoder().decode(expectedEncodedString); UUID uuid = convertToUUID(decodedBytes); }
首先把 Base64 字符串解码成 Byte 数组,然后调用我们的转换方法,把我们获得 byte 数组转换成为 UUID 对象。
UUID convertToUUID(byte[] src) { long mostSignificantBits = convertBytesToLong(src, 0); long leastSignificantBits = convertBytesToLong(src, 8); return new UUID(mostSignificantBits, leastSignificantBits); }
在上面的方法中,我们分别对 UUID 中需要使用的 most significant bits 和 less significant bits 分别进行转换,然后再组合在一起。
转换的方法如下:
long convertBytesToLong(byte[] uuidBytes, int start) { long result = 0; for(int i = 0; i < 8; i++) { int shift = i * 8; long bits = (255L & (long)uuidBytes[i + start]) << shift; long mask = 255L << shift; result = result & ~mask | bits; } return result; }
通过上面的测试代码,可以看到代码的转换都顺利完成了。
使用 ByteBuffer 和 Base64.getUrlEncoder()
如果我们还使用 JDK 的 API 的话,我们还可以把上面的代码进行一些简化。
编码
通过使用 ByteBuffer,我们可以使用非常简单的下面 2 行代码把 UUID 的 bit 转换为 buffer wrapping 数组。
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); byteBuffer.putLong(originalUUID.getMostSignificantBits()); byteBuffer.putLong(originalUUID.getLeastSignificantBits());
当程序执行完上面的 2 行代码后,我们将会获得 一个 ByteBuffer 对象,这个对象中存储的是 UUID 转换过来的数据。
针对编码,我们就可以使用 Base64.getUrlEncoder() 方法,这个方法的参数我们可以使用 ByteBuffer 转换成 array 就可以了,因为 ByteBuffer 转换成 Array 是返回 Array 的。
String encodedUUID = Base64.getUrlEncoder().encodeToString(byteBuffer.array());
针对上面代码的修改,我们只需要下面简单的几行代码就可以完成 UUID 到 Base64 的转换。
@Test public void givenUUID_whenEncodingUsingByteBufferAndBase64UrlEncoder_thenGiveExpectedEncodedString() { String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA=="; ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); byteBuffer.putLong(originalUUID.getMostSignificantBits()); byteBuffer.putLong(originalUUID.getLeastSignificantBits()); String encodedUUID = Base64.getUrlEncoder().encodeToString(byteBuffer.array()); assertEquals(expectedEncodedString, encodedUUID); }
解码
解码就使用 Base64.UrlDecoder() 即可,Base64.UrlDecoder() 的解码结果为 byte 数组,所以我们还需要用 ByteBuffer.wrap 把解码后的数组包装成 ByteBuffer 对象。
@Test void givenEncodedString_whenDecodingUsingByteBufferAndBase64UrlDecoder_thenGiveExpectedUUID() { String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA=="; byte[] decodedBytes = Base64.getUrlDecoder().decode(expectedEncodedString); ByteBuffer byteBuffer = ByteBuffer.wrap(decodedBytes); long mostSignificantBits = byteBuffer.getLong(); long leastSignificantBits = byteBuffer.getLong(); UUID uuid = new UUID(mostSignificantBits, leastSignificantBits); assertEquals(originalUUID, uuid); }
缩短编码后字符串
在我们完成上面的编码后,我们会看到字符串的最后还有 2 个等号 “==” 。为了进一步节约我们的存储空间,我们可以把这 2 个等号从字符串中删除。
我们可以配置编码函数,告诉编码函数不要在字符串的末尾添加 2 个等号。
String encodedUUID = Base64.getUrlEncoder().withoutPadding().encodeToString(byteBuffer.array()); assertEquals(expectedEncodedString, encodedUUID);
针对解码的方法来说,我们并不需要对方法进行任何改变,因为现在的解码方法已经能够正确识别 Base64 字符串的末尾是不是有 2 个等号,并且可都兼容。
使用 Apache Commons Conversion Utils 和Codec Utils 工具类
在这部分,我们使用 Apache Commons Conversion Utils 的工具类来先把 UUID 对象转换为 UUID byte 数组,然后使用 Apache Commons Codec Utils 工具类来把进行 Base64 的字符串处理。
依赖
为了完成上面 2 个步骤,我们需要分别使用 Apache Commons Lang library 和 commons-codec 类库
在我们的 pom.xml 项目文件中,分别添加上面 2 个类库的依赖。
通常你的项目基本上都会包含进来的,如果没有的话再添加。
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.14.0</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.16.0</version> </dependency>
编码
上面的编码就非常简单了,直接使用 Conversion.uuidToByteArray 方法,把要编码的 UUID 对象传进来,然后直接 Base64,使用 URL 安全的方法。
@Test void givenUUID_whenEncodingUsingApacheUtils_thenGiveExpectedEncodedString() { String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw"; byte[] bytes = Conversion.uuidToByteArray(originalUUID, new byte[16], 0, 16); String encodedUUID = encodeBase64URLSafeString(bytes); assertEquals(expectedEncodedString, encodedUUID); }
通过上面的代码,我们可以看到结果是 Base 64 已经把最后的 2 个等号删掉了。
解码
针对解码来说,我们使用的是 JDK 的 Base64.decodeBase64() 方法,然后调用 Conversion.byteArrayToUuid()
把解码后的 byte 数组转换为 UUID 对象。
@Test void givenEncodedString_whenDecodingUsingApacheUtils_thenGiveExpectedUUID() { String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw"; byte[] decodedBytes = decodeBase64(expectedEncodedString); UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0); assertEquals(originalUUID, uuid); }
结论
UUID 是广泛使用的 ID 识别标识,我们通过对 Base64 的转换来让 UUID 能够以更小的数据量来进行存储。
转换的关键就在于 UUID 先要转换为 byte 数组,然后 Base64 是对 byte[]
数组进行编码的。
总结:
本文详细介绍了如何使用Base64编码来转换和存储Java中的UUID。这种方法可以有效地减少传输和存储的开销,特别是在处理大量唯一标识符时。我们探讨了如何实现将UUID转换为Base64字符串以及如何将Base64字符串转回UUID的操作。此外,我们也讨论了一些可能遇到的挑战和注意事项。通过这些简单的编程技巧,开发人员可以在保证数据唯一性的同时提高系统的整体效率。
本文来源于#HoneyMoose,由@ZhanShen 整理发布。如若内容造成侵权/违法违规/事实不符,请联系本站客服处理!
该文章观点仅代表作者本人,不代表本站立场。本站不承担相关法律责任。
如若转载,请注明出处:https://www.zhanid.com/biancheng/1290.html