Java中將UUID存儲(chǔ)為Base64字符串的方法實(shí)現(xiàn)
概述
使用 Base64 編碼來(lái)對(duì) UUID(Universally Unique Identifiers) 存儲(chǔ)在一些特定的場(chǎng)合被廣泛的使用。使用 Base64 對(duì)比直接使用 UUID 進(jìn)行存儲(chǔ)來(lái)說(shuō)能夠更多的節(jié)約空間。

本文對(duì)這方面的相關(guān)內(nèi)容和問(wèn)題進(jìn)行探討。
在這里,使用 Base64 來(lái)對(duì) UUID 進(jìn)行存儲(chǔ),涉及到一些類型的轉(zhuǎn)換的。Base64 是編碼算法,在實(shí)際使用的時(shí)候我們更多會(huì)用到 Byte 數(shù)組的方式來(lái)進(jìn)行編碼的。這樣我們就比較明確在對(duì)其進(jìn)行 Base64 轉(zhuǎn)換之前,我們應(yīng)該要先干什么了。
使用 byte[]和 Base64.Encoder
Base64.Encoder 就能夠提供 byte[] 的 Base64 編碼了,我們先使用這個(gè)最簡(jiǎn)單的方式來(lái)進(jìn)行處理。
編碼
首先我們需要給出的 UUID 位中創(chuàng)建出我們需要的 byte 數(shù)組。
我們先獲得 UUID 的 most significant bits 和 least significant bits,然后放入我們 byte 數(shù)組中的 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;
}
上面的代碼中還有一個(gè) fillByteArray 方法,這個(gè)方法,這個(gè)方法將會(huì)把我們的 bit 存如 byte array 數(shù)組中,同時(shí)還會(huì)移動(dòng) 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));
}
}
當(dāng)我們獲得 byte 數(shù)組后,我們就可以調(diào)用 JDK 的 Base64.Encoder 方法來(lái)直接進(jìn)行編碼了成一個(gè) Base64 加密字符串了。
完整的測(cè)試代碼如下:
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 字符串進(jìn)行解碼,我們可以使用完全相反的方法:
@Test
public void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() {
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw==";
byte[] decodedBytes = Base64.getDecoder().decode(expectedEncodedString);
UUID uuid = convertToUUID(decodedBytes);
}
首先把 Base64 字符串解碼成 Byte 數(shù)組,然后調(diào)用我們的轉(zhuǎn)換方法,把我們獲得 byte 數(shù)組轉(zhuǎn)換成為 UUID 對(duì)象。
UUID convertToUUID(byte[] src) {
long mostSignificantBits = convertBytesToLong(src, 0);
long leastSignificantBits = convertBytesToLong(src, 8);
return new UUID(mostSignificantBits, leastSignificantBits);
}
在上面的方法中,我們分別對(duì) UUID 中需要使用的 most significant bits 和 less significant bits 分別進(jìn)行轉(zhuǎn)換,然后再組合在一起。
轉(zhuǎn)換的方法如下:
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;
}
通過(guò)上面的測(cè)試代碼,可以看到代碼的轉(zhuǎn)換都順利完成了。
使用 ByteBuffer 和 Base64.getUrlEncoder()
如果我們還使用 JDK 的 API 的話,我們還可以把上面的代碼進(jìn)行一些簡(jiǎn)化。
編碼
通過(guò)使用 ByteBuffer,我們可以使用非常簡(jiǎn)單的下面 2 行代碼把 UUID 的 bit 轉(zhuǎn)換為 buffer wrapping 數(shù)組。
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); byteBuffer.putLong(originalUUID.getMostSignificantBits()); byteBuffer.putLong(originalUUID.getLeastSignificantBits());
當(dāng)程序執(zhí)行完上面的 2 行代碼后,我們將會(huì)獲得 一個(gè) ByteBuffer 對(duì)象,這個(gè)對(duì)象中存儲(chǔ)的是 UUID 轉(zhuǎn)換過(guò)來(lái)的數(shù)據(jù)。
針對(duì)編碼,我們就可以使用 Base64.getUrlEncoder() 方法,這個(gè)方法的參數(shù)我們可以使用 ByteBuffer 轉(zhuǎn)換成 array 就可以了,因?yàn)?ByteBuffer 轉(zhuǎn)換成 Array 是返回 Array 的。
String encodedUUID = Base64.getUrlEncoder().encodeToString(byteBuffer.array());
針對(duì)上面代碼的修改,我們只需要下面簡(jiǎn)單的幾行代碼就可以完成 UUID 到 Base64 的轉(zhuǎn)換。
@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() 的解碼結(jié)果為 byte 數(shù)組,所以我們還需要用 ByteBuffer.wrap 把解碼后的數(shù)組包裝成 ByteBuffer 對(duì)象。
@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);
}
縮短編碼后字符串
在我們完成上面的編碼后,我們會(huì)看到字符串的最后還有 2 個(gè)等號(hào) “==” 。為了進(jìn)一步節(jié)約我們的存儲(chǔ)空間,我們可以把這 2 個(gè)等號(hào)從字符串中刪除。
我們可以配置編碼函數(shù),告訴編碼函數(shù)不要在字符串的末尾添加 2 個(gè)等號(hào)。
String encodedUUID = Base64.getUrlEncoder().withoutPadding().encodeToString(byteBuffer.array()); assertEquals(expectedEncodedString, encodedUUID);
針對(duì)解碼的方法來(lái)說(shuō),我們并不需要對(duì)方法進(jìn)行任何改變,因?yàn)楝F(xiàn)在的解碼方法已經(jīng)能夠正確識(shí)別 Base64 字符串的末尾是不是有 2 個(gè)等號(hào),并且可都兼容。
使用 Apache Commons Conversion Utils 和Codec Utils 工具類
在這部分,我們使用 Apache Commons Conversion Utils 的工具類來(lái)先把 UUID 對(duì)象轉(zhuǎn)換為 UUID byte 數(shù)組,然后使用 Apache Commons Codec Utils 工具類來(lái)把進(jìn)行 Base64 的字符串處理。
依賴
為了完成上面 2 個(gè)步驟,我們需要分別使用 Apache Commons Lang library 和 commons-codec 類庫(kù)
在我們的 pom.xml 項(xiàng)目文件中,分別添加上面 2 個(gè)類庫(kù)的依賴。
通常你的項(xiàng)目基本上都會(huì)包含進(jìn)來(lái)的,如果沒(méi)有的話再添加。
<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>
編碼
上面的編碼就非常簡(jiǎn)單了,直接使用 Conversion.uuidToByteArray 方法,把要編碼的 UUID 對(duì)象傳進(jìn)來(lái),然后直接 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);
}
通過(guò)上面的代碼,我們可以看到結(jié)果是 Base 64 已經(jīng)把最后的 2 個(gè)等號(hào)刪掉了。
解碼
針對(duì)解碼來(lái)說(shuō),我們使用的是 JDK 的 Base64.decodeBase64() 方法,然后調(diào)用 Conversion.byteArrayToUuid() 把解碼后的 byte 數(shù)組轉(zhuǎn)換為 UUID 對(duì)象。
@Test
void givenEncodedString_whenDecodingUsingApacheUtils_thenGiveExpectedUUID() {
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
byte[] decodedBytes = decodeBase64(expectedEncodedString);
UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0);
assertEquals(originalUUID, uuid);
}
結(jié)論
UUID 是廣泛使用的 ID 識(shí)別標(biāo)識(shí),我們通過(guò)對(duì) Base64 的轉(zhuǎn)換來(lái)讓 UUID 能夠以更小的數(shù)據(jù)量來(lái)進(jìn)行存儲(chǔ)。
轉(zhuǎn)換的關(guān)鍵就在于 UUID 先要轉(zhuǎn)換為 byte 數(shù)組,然后 Base64 是對(duì) byte[] 數(shù)組進(jìn)行編碼的。
到此這篇關(guān)于Java中將UUID存儲(chǔ)為Base64字符串的方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java UUID存儲(chǔ)為Base64內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中TransactionTemplate事務(wù)管理的實(shí)現(xiàn)
Spring Boot提供了多種方式來(lái)管理事務(wù),其中之一是使用TransactionTemplate,本文主要介紹了SpringBoot中TransactionTemplate事務(wù)管理的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04
Java實(shí)現(xiàn)簡(jiǎn)單臺(tái)球游戲
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單臺(tái)球游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
J2EE Servlet上傳文件到服務(wù)器并相應(yīng)顯示功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了J2EE Servlet上傳文件到服務(wù)器,并相應(yīng)顯示,在文中上傳方式使用的是post不能使用get,具體實(shí)例代碼大家參考下本文2018-07-07
java中\(zhòng)t,\n,\r,\b,\f 的作用及說(shuō)明
這篇文章主要介紹了java中\(zhòng)t,\n,\r,\b,\f 的作用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
關(guān)于Spring統(tǒng)一異常處理及說(shuō)明
這篇文章主要介紹了關(guān)于Spring統(tǒng)一異常處理及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Nacos客戶端配置中心緩存動(dòng)態(tài)更新實(shí)現(xiàn)源碼
這篇文章主要為大家介紹了Nacos客戶端配置中心緩存動(dòng)態(tài)更新實(shí)現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-03-03
解決idea的debug模式突然變卡,項(xiàng)目啟動(dòng)變慢的狀況
這篇文章主要介紹了解決idea的debug模式突然變卡,項(xiàng)目啟動(dòng)變慢的狀況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
java抓取網(wǎng)頁(yè)或文件中的郵箱號(hào)碼
這篇文章主要為大家詳細(xì)介紹了java如何抓取網(wǎng)頁(yè)或文件中的郵箱號(hào)碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
SpringBoot整合Redis實(shí)現(xiàn)消息發(fā)布與訂閱的示例代碼
能實(shí)現(xiàn)發(fā)送與接收信息的中間介有很多,比如:RocketMQ、RabbitMQ、ActiveMQ、Kafka等,本文主要介紹了Redis的推送與訂閱功能并集成Spring Boot的實(shí)現(xiàn),感興趣的可以了解一下2022-08-08
Spring中的模塊與應(yīng)用場(chǎng)景詳解
這篇文章主要介紹了Spring中的模塊與應(yīng)用場(chǎng)景詳解,Spring 框架可以為 Java 應(yīng)用程序開(kāi)發(fā)提供全面的基礎(chǔ)設(shè)施支持,它是現(xiàn)在非常流行的 Java 開(kāi)源框架,對(duì)于一個(gè) Java 開(kāi)發(fā)人員來(lái)說(shuō),熟練掌握 Spring 是必不可少的,需要的朋友可以參考下2023-09-09

