**1. **

使用Base64编码字符串是一种广泛采用的方法,用于存储通用唯一标识符(UUID)。这相比标准的UUID字符串表示法提供了更紧凑的结果。本文将探讨将UUID编码为Base64字符串的各种方法。

2. 使用byte[]Base64.Encoder编码

我们首先通过byte[]Base64.Encoder进行最直接的编码。

2.1. 编码

我们将从UUID的位创建一个字节数组。为此,我们将取UUID的最高位和最低位,并分别放在数组的索引0-7和8-15处:

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;
}

在填充方法中,我们将位移动到数组中,每迭代一次转换为字节并左移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));
    }
}

接下来,我们将使用JDK的Base64.Encoder将字节数组编码为字符串:

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);
}

如我们所见,得到的值正是我们期望的。

2.2. 解码

从Base64编码的字符串解码UUID,我们可以执行相反的操作:

首先,我们使用Base64.Decoder从编码字符串获取字节数组,然后调用我们的转换方法,从这个数组创建UUID:

UUID convertToUUID(byte[] src) {
    long mostSignificantBits = convertBytesToLong(src, 0);
    long leastSignificantBits = convertBytesToLong(src, 8);

    return new UUID(mostSignificantBits, leastSignificantBits);
}

我们将数组的部分转换为最高和最低位长的表示形式,并使用它们生成UUID。

转换方法如下:

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;
}

在这个方法中,我们遍历字节数组,将每个字节转换为位,并将它们放入结果中。

正如我们所见,解码后的最终结果将与我们用于编码的原始UUID匹配

3. 使用ByteBufferBase64.getUrlEncoder()编码

利用JDK的标准功能,我们可以简化上述编写出的代码。

3.1. 编码

使用ByteBuffer,我们可以仅用几行代码就完成将UUID转换为字节数组的过程:

ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(originalUUID.getMostSignificantBits());
byteBuffer.putLong(originalUUID.getLeastSignificantBits());

我们创建了一个包含字节数组的缓冲区,并放入UUID的最高和最低位。

为了编码,我们将使用Base64.getUrlEncoder()

String encodedUUID = Base64.getUrlEncoder().encodeToString(byteBuffer.array());

结果是,我们仅用4行代码创建了Base64编码的UUID:

@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);
}

3.2. 解码

我们可以使用ByteBufferBase64.UrlDecoder()执行相反的操作:

@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);
}

如我们所见,我们成功地从编码字符串解码出了预期的UUID。

4. 缩短编码UUID的长度

如前所见,Base64默认情况下会在末尾添加“==”。为了节省更多字节,我们可以去掉这个结尾。为此,我们可以配置编码器不添加填充:

String encodedUUID = 
  Base64.getUrlEncoder().withoutPadding().encodeToString(byteBuffer.array());

assertEquals(expectedEncodedString, encodedUUID);

因此,我们可以看到编码字符串没有额外的字符。由于编码器无需更改,因为它能以相同的方式处理两种编码字符串的变体。

5. 使用Apache Commons的转换和编码工具进行编码

在本节中,我们将使用Apache Commons Conversion库的uuidToByteArray将UUID转换为字节数组,以及使用Apache Commons Base64库的encodeBase64URLSafeString进行编码。

5.1. 依赖关系

为了演示这种编码方法,我们将使用Apache Commons Lang库。请在pom.xml中添加其依赖项

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

另一个我们将使用的依赖项commons-codec

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.16.0</version>
</dependency>

5.2. 编码

我们只需两行代码即可编码UUID:

@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);
}

如我们所见,结果已经修剪过,不包含多余的结尾。

5.3. 解码

我们将通过调用Base64.decodeBase64()Conversion.byteArrayToUuid()从Apache Commons进行反向操作来获取原始UUID:

@Test
void givenEncodedString_whenDecodingUsingApacheUtils_thenGiveExpectedUUID() {
    String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
    byte[] decodedBytes = decodeBase64(expectedEncodedString);
    UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0);
    assertEquals(originalUUID, uuid);
}

我们成功获得了原始UUID。

6. 总结

UUID是一种广泛使用的数据类型,其中一种编码方法是使用Base64。在这篇文章中,我们探讨了几种将UUID编码为Base64的方法。

如往常一样,完整的源代码可以在GitHub上找到。