0

Java中将UUID存储为Base64字符串3种方法

 3 months ago
source link: https://www.jdon.com/72393.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Java中将UUID存储为Base64字符串3种方法

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

第一种方法:使用byte[]和Base64.Encoder进行编码
我们将从使用byte[]和Base64.Encoder的最直接的编码方法开始。

1、编码
从 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、解码
要从 Base64 编码的字符串中解码 UUID,我们可以通过以下方式执行相反的操作:

@Test
public void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() {
    String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw==";
    byte[] decodedBytes = Base64.getDecoder().decode(expectedEncodedString);
    UUID uuid = convertToUUID(decodedBytes);
}

首先,我们使用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相匹配。

第二种方法:使用ByteBuffer和Base64.getUrlEncoder()进行编码
使用 JDK 的标准功能,我们可以简化上面编写的代码。

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

2. 解码
我们可以使用ByteBuffer和Base64.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。

减少编码UUID的长度
正如我们在前面几节中看到的,Base64 默认情况下在末尾包含“==” 。为了节省更多字节,我们可以修剪这个结尾。
为此,我们可以将编码器配置为不添加填充:

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

结果,我们可以看到编码后的字符串没有多余的字符。无需更改我们的解码器,因为它将以相同的方式处理编码字符串的两种变体。

第三种:使用 Apache Commons 中的转换实用程序和编解码器实用程序进行编码
在本节中,我们将使用Apache Commons Conversion utils中的uuidToByteArray来创建 UUID 字节数组。另外,我们将使用Apache Commons Base64 utils中的encodeBase64URLSafeString。

为了演示这种编码方法,我们将使用 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>

1. 编码
我们只需两行代码即可对 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);
}

正如我们所看到的,结果已经被修剪并且不包含待定的结局。

2. 解码
我们将从Apache Commons调用Base64.decodeBase64()和Conversion.byteArrayToUuid()进行反向操作:

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

我们成功获得了原始的UUID。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK