使用Java實(shí)現(xiàn)價(jià)格加密與優(yōu)化功能
引言
在現(xiàn)代軟件開(kāi)發(fā)中,數(shù)據(jù)加密是一個(gè)非常重要的環(huán)節(jié),尤其是在處理敏感信息(如價(jià)格、用戶數(shù)據(jù)等)時(shí)。本文將詳細(xì)介紹如何使用 Java 實(shí)現(xiàn)價(jià)格加密,并對(duì)代碼進(jìn)行優(yōu)化,以提高其健壯性、可維護(hù)性和性能。
1. 背景
在廣告交易系統(tǒng)中,價(jià)格信息通常需要加密以確保其安全性。Google 的 DoubleClick Ad Exchange 提供了一種加密方案,使用 HMAC-SHA1 算法對(duì)價(jià)格進(jìn)行加密。本文將基于這一方案,實(shí)現(xiàn)一個(gè)價(jià)格加密工具,并逐步優(yōu)化代碼。
2. 實(shí)現(xiàn)價(jià)格加密
2.1 加密原理
DoubleClick 的加密方案使用兩個(gè)密鑰:
- 加密密鑰(Encryption Key):用于加密價(jià)格數(shù)據(jù)。
- 完整性密鑰(Integrity Key):用于生成簽名,確保數(shù)據(jù)的完整性。
加密后的數(shù)據(jù)格式如下:
initVector:16 || E(payload:?) || I(signature:4)
其中:
initVector
是初始化向量,包含時(shí)間戳和服務(wù)器 ID。E(payload)
是加密后的價(jià)格數(shù)據(jù)。I(signature)
是完整性簽名。
2.2 基礎(chǔ)實(shí)現(xiàn)
以下是基礎(chǔ)的價(jià)格加密實(shí)現(xiàn):
import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class PriceEncryptor { private static final String HMAC_ALGORITHM = "HmacSHA1"; /** * 加密價(jià)格 * * @param winPrice 價(jià)格字符串 * @param enKey 加密密鑰(Base64 編碼) * @param ivKey 完整性密鑰(Base64 編碼) * @return 加密后的價(jià)格字符串(Base64 編碼) * @throws IllegalArgumentException 如果參數(shù)無(wú)效 * @throws RuntimeException 如果加密失敗 */ public static String priceEncrypt(String winPrice, String enKey, String ivKey) { // 參數(shù)校驗(yàn) Objects.requireNonNull(winPrice, "價(jià)格不能為空"); Objects.requireNonNull(enKey, "加密密鑰不能為空"); Objects.requireNonNull(ivKey, "完整性密鑰不能為空"); if (winPrice.trim().isEmpty()) { throw new IllegalArgumentException("價(jià)格不能為空字符串"); } try { // 將價(jià)格轉(zhuǎn)換為 double double priceValue = Double.parseDouble(winPrice); // 解析密鑰 SecretKey encryptionKey = decodeBase64ToSecretKey(enKey, HMAC_ALGORITHM); SecretKey integrityKey = decodeBase64ToSecretKey(ivKey, HMAC_ALGORITHM); // 創(chuàng)建加密工具 DoubleClickCrypto.Keys keys = new DoubleClickCrypto.Keys(encryptionKey, integrityKey); DoubleClickCrypto.Price crypto = new DoubleClickCrypto.Price(keys); // 加密價(jià)格 return crypto.encodePriceValue(priceValue, null); } catch (NumberFormatException e) { throw new IllegalArgumentException("價(jià)格格式無(wú)效: " + winPrice, e); } catch (Exception e) { throw new RuntimeException("加密失敗", e); } } /** * 將 Base64 編碼的密鑰轉(zhuǎn)換為 SecretKey * * @param base64Key Base64 編碼的密鑰 * @param algorithm 密鑰算法 * @return SecretKey * @throws IllegalArgumentException 如果密鑰無(wú)效 */ private static SecretKey decodeBase64ToSecretKey(String base64Key, String algorithm) { try { byte[] keyBytes = Base64.getDecoder().decode(base64Key); return new SecretKeySpec(keyBytes, algorithm); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("無(wú)效的 Base64 密鑰: " + base64Key, e); } } public static void main(String[] args) { try { String bidPrice = priceEncrypt("88", "your_base64_encoded_enKey", "your_base64_encoded_ivKey"); System.out.println("加密后價(jià)格:" + bidPrice); } catch (Exception e) { System.err.println("加密失敗: " + e.getMessage()); e.printStackTrace(); } } }
2.3 代碼說(shuō)明
參數(shù)校驗(yàn):
- 使用
Objects.requireNonNull
檢查winPrice
、enKey
和ivKey
是否為null
。 - 檢查
winPrice
是否為空字符串。
- 使用
異常處理:
- 捕獲
NumberFormatException
,提供清晰的錯(cuò)誤信息。 - 捕獲其他異常,統(tǒng)一拋出
RuntimeException
。
- 捕獲
密鑰解析:
- 將 Base64 編碼的密鑰轉(zhuǎn)換為
SecretKey
。
- 將 Base64 編碼的密鑰轉(zhuǎn)換為
加密邏輯:
- 使用
DoubleClickCrypto.Price
對(duì)價(jià)格進(jìn)行加密。
- 使用
3. 優(yōu)化代碼
3.1 參數(shù)校驗(yàn)
在加密方法中,參數(shù)校驗(yàn)是必不可少的。我們使用 Objects.requireNonNull
來(lái)確保參數(shù)不為 null
,并檢查價(jià)格字符串是否為空。
Objects.requireNonNull(winPrice, "價(jià)格不能為空"); Objects.requireNonNull(enKey, "加密密鑰不能為空"); Objects.requireNonNull(ivKey, "完整性密鑰不能為空"); if (winPrice.trim().isEmpty()) { throw new IllegalArgumentException("價(jià)格不能為空字符串"); }
3.2 異常處理
為了提供更好的錯(cuò)誤信息,我們捕獲 NumberFormatException
并拋出 IllegalArgumentException
。其他異常則統(tǒng)一拋出 RuntimeException
。
try { double priceValue = Double.parseDouble(winPrice); // ... } catch (NumberFormatException e) { throw new IllegalArgumentException("價(jià)格格式無(wú)效: " + winPrice, e); } catch (Exception e) { throw new RuntimeException("加密失敗", e); }
3.3 代碼復(fù)用
將密鑰解析邏輯封裝到 decodeBase64ToSecretKey
方法中,避免重復(fù)代碼。
private static SecretKey decodeBase64ToSecretKey(String base64Key, String algorithm) { try { byte[] keyBytes = Base64.getDecoder().decode(base64Key); return new SecretKeySpec(keyBytes, algorithm); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("無(wú)效的 Base64 密鑰: " + base64Key, e); } }
3.4 性能優(yōu)化
如果 priceEncrypt
方法會(huì)被頻繁調(diào)用,可以考慮將 DoubleClickCrypto.Keys
和 DoubleClickCrypto.Price
的實(shí)例緩存起來(lái),避免重復(fù)創(chuàng)建。
private static final Map<String, DoubleClickCrypto.Price> CRYPTO_CACHE = new ConcurrentHashMap<>(); private static DoubleClickCrypto.Price getCrypto(String enKey, String ivKey) { String cacheKey = enKey + "|" + ivKey; return CRYPTO_CACHE.computeIfAbsent(cacheKey, k -> { SecretKey encryptionKey = decodeBase64ToSecretKey(enKey, HMAC_ALGORITHM); SecretKey integrityKey = decodeBase64ToSecretKey(ivKey, HMAC_ALGORITHM); DoubleClickCrypto.Keys keys = new DoubleClickCrypto.Keys(encryptionKey, integrityKey); return new DoubleClickCrypto.Price(keys); }); }
然后在 priceEncrypt
方法中使用 getCrypto
獲取 DoubleClickCrypto.Price
實(shí)例。
DoubleClickCrypto.Price crypto = getCrypto(enKey, ivKey); return crypto.encodePriceValue(priceValue, null);
4. 總結(jié)
通過(guò)以上步驟,我們實(shí)現(xiàn)了一個(gè)健壯、高效的價(jià)格加密工具。優(yōu)化后的代碼具有以下優(yōu)點(diǎn):
- 健壯性:通過(guò)參數(shù)校驗(yàn)和異常處理,確保代碼在異常情況下也能正常運(yùn)行。
- 可維護(hù)性:通過(guò)代碼復(fù)用和模塊化設(shè)計(jì),提高了代碼的可讀性和可維護(hù)性。
- 性能:通過(guò)緩存加密工具實(shí)例,減少了重復(fù)創(chuàng)建對(duì)象的開(kāi)銷。
到此這篇關(guān)于使用Java實(shí)現(xiàn)價(jià)格加密與優(yōu)化功能的文章就介紹到這了,更多相關(guān)Java價(jià)格加密與優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot yaml語(yǔ)法與數(shù)據(jù)讀取操作詳解
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一種標(biāo)記語(yǔ)言)的遞歸縮寫(xiě)。在開(kāi)發(fā)的這種語(yǔ)言時(shí),YAML 的意思其實(shí)是:“Yet Another Markup Language”(仍是一種標(biāo)記語(yǔ)言),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域(內(nèi)存劃分)的深入講解
聽(tīng)說(shuō)Java運(yùn)行時(shí)環(huán)境的內(nèi)存劃分是挺進(jìn)BAT的必經(jīng)之路,這篇文章主要給大家介紹了關(guān)于Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域(內(nèi)存劃分)的相關(guān)資料,需要的朋友可以參考下2021-06-06使用MyBatis攔截器實(shí)現(xiàn)SQL的完整打印
當(dāng)我們使用Mybatis結(jié)合Mybatis-plus進(jìn)行開(kāi)發(fā)時(shí),為了查看執(zhí)行sql的信息通常我們可以通過(guò)屬性配置的方式打印出執(zhí)行的sql語(yǔ)句,但這樣的打印出了sql語(yǔ)句常帶有占位符信息,不利于排錯(cuò),所以本文介紹了構(gòu)建MyBatis攔截器,實(shí)現(xiàn)SQL的完整打印,需要的朋友可以參考下2024-07-07用Rational Rose逆向工程(java)生成類圖(教程和錯(cuò)誤解決)
Rational Rose有個(gè)很方便的功能,將項(xiàng)目中的JAVA代碼自動(dòng)轉(zhuǎn)換成UML類圖2013-02-02