Java中将UUID存储为Base64字符串的方法实现
概述
使用 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[]
数组进行编码的。
到此这篇关于Java中将UUID存储为Base64字符串的方法实现的文章就介绍到这了,更多相关Java UUID存储为Base64内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
基于javaWeb 项目SSM配置要点及可能遇到的问题和解决方法
下面小编就为大家带来一篇基于javaWeb 项目SSM配置要点及可能遇到的问题和解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-10-10
最新评论