使用Java实现价格加密与优化功能

 更新时间:2025年01月20日 08:31:22   作者:码农阿豪@新空间代码工作室  
在现代软件开发中,数据加密是一个非常重要的环节,尤其是在处理敏感信息(如价格、用户数据等)时,本文将详细介绍如何使用 Java 实现价格加密,并对代码进行优化,需要的朋友可以参考下

引言

在现代软件开发中,数据加密是一个非常重要的环节,尤其是在处理敏感信息(如价格、用户数据等)时。本文将详细介绍如何使用 Java 实现价格加密,并对代码进行优化,以提高其健壮性、可维护性和性能。

1. 背景

在广告交易系统中,价格信息通常需要加密以确保其安全性。Google 的 DoubleClick Ad Exchange 提供了一种加密方案,使用 HMAC-SHA1 算法对价格进行加密。本文将基于这一方案,实现一个价格加密工具,并逐步优化代码。

2. 实现价格加密

2.1 加密原理

DoubleClick 的加密方案使用两个密钥:

  • 加密密钥(Encryption Key):用于加密价格数据。
  • 完整性密钥(Integrity Key):用于生成签名,确保数据的完整性。

加密后的数据格式如下:

initVector:16 || E(payload:?) || I(signature:4)

其中:

  • initVector 是初始化向量,包含时间戳和服务器 ID。
  • E(payload) 是加密后的价格数据。
  • I(signature) 是完整性签名。

2.2 基础实现

以下是基础的价格加密实现:

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class PriceEncryptor {

    private static final String HMAC_ALGORITHM = "HmacSHA1";

    /**
     * 加密价格
     *
     * @param winPrice 价格字符串
     * @param enKey    加密密钥(Base64 编码)
     * @param ivKey    完整性密钥(Base64 编码)
     * @return 加密后的价格字符串(Base64 编码)
     * @throws IllegalArgumentException 如果参数无效
     * @throws RuntimeException         如果加密失败
     */
    public static String priceEncrypt(String winPrice, String enKey, String ivKey) {
        // 参数校验
        Objects.requireNonNull(winPrice, "价格不能为空");
        Objects.requireNonNull(enKey, "加密密钥不能为空");
        Objects.requireNonNull(ivKey, "完整性密钥不能为空");

        if (winPrice.trim().isEmpty()) {
            throw new IllegalArgumentException("价格不能为空字符串");
        }

        try {
            // 将价格转换为 double
            double priceValue = Double.parseDouble(winPrice);

            // 解析密钥
            SecretKey encryptionKey = decodeBase64ToSecretKey(enKey, HMAC_ALGORITHM);
            SecretKey integrityKey = decodeBase64ToSecretKey(ivKey, HMAC_ALGORITHM);

            // 创建加密工具
            DoubleClickCrypto.Keys keys = new DoubleClickCrypto.Keys(encryptionKey, integrityKey);
            DoubleClickCrypto.Price crypto = new DoubleClickCrypto.Price(keys);

            // 加密价格
            return crypto.encodePriceValue(priceValue, null);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("价格格式无效: " + winPrice, e);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /**
     * 将 Base64 编码的密钥转换为 SecretKey
     *
     * @param base64Key Base64 编码的密钥
     * @param algorithm 密钥算法
     * @return SecretKey
     * @throws IllegalArgumentException 如果密钥无效
     */
    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("无效的 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("加密后价格:" + bidPrice);
        } catch (Exception e) {
            System.err.println("加密失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

2.3 代码说明

  1. 参数校验

    • 使用 Objects.requireNonNull 检查 winPriceenKey 和 ivKey 是否为 null
    • 检查 winPrice 是否为空字符串。
  2. 异常处理

    • 捕获 NumberFormatException,提供清晰的错误信息。
    • 捕获其他异常,统一抛出 RuntimeException
  3. 密钥解析

    • 将 Base64 编码的密钥转换为 SecretKey
  4. 加密逻辑

    • 使用 DoubleClickCrypto.Price 对价格进行加密。

3. 优化代码

3.1 参数校验

在加密方法中,参数校验是必不可少的。我们使用 Objects.requireNonNull 来确保参数不为 null,并检查价格字符串是否为空。

Objects.requireNonNull(winPrice, "价格不能为空");
Objects.requireNonNull(enKey, "加密密钥不能为空");
Objects.requireNonNull(ivKey, "完整性密钥不能为空");

if (winPrice.trim().isEmpty()) {
    throw new IllegalArgumentException("价格不能为空字符串");
}

3.2 异常处理

为了提供更好的错误信息,我们捕获 NumberFormatException 并抛出 IllegalArgumentException。其他异常则统一抛出 RuntimeException

try {
    double priceValue = Double.parseDouble(winPrice);
    // ...
} catch (NumberFormatException e) {
    throw new IllegalArgumentException("价格格式无效: " + winPrice, e);
} catch (Exception e) {
    throw new RuntimeException("加密失败", e);
}

3.3 代码复用

将密钥解析逻辑封装到 decodeBase64ToSecretKey 方法中,避免重复代码。

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("无效的 Base64 密钥: " + base64Key, e);
    }
}

3.4 性能优化

如果 priceEncrypt 方法会被频繁调用,可以考虑将 DoubleClickCrypto.Keys 和 DoubleClickCrypto.Price 的实例缓存起来,避免重复创建。

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 实例。

DoubleClickCrypto.Price crypto = getCrypto(enKey, ivKey);
return crypto.encodePriceValue(priceValue, null);

4. 总结

通过以上步骤,我们实现了一个健壮、高效的价格加密工具。优化后的代码具有以下优点:

  • 健壮性:通过参数校验和异常处理,确保代码在异常情况下也能正常运行。
  • 可维护性:通过代码复用和模块化设计,提高了代码的可读性和可维护性。
  • 性能:通过缓存加密工具实例,减少了重复创建对象的开销。

到此这篇关于使用Java实现价格加密与优化功能的文章就介绍到这了,更多相关Java价格加密与优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java集合总结

    Java集合总结

    今天小编就为大家分享一篇关于Java集合总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • SpringBoot yaml语法与数据读取操作详解

    SpringBoot yaml语法与数据读取操作详解

    YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言),本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • mybatis-sqlserver批量新增返回id方式

    mybatis-sqlserver批量新增返回id方式

    这篇文章主要介绍了mybatis-sqlserver批量新增返回id方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java实例域初始化方法及顺序

    Java实例域初始化方法及顺序

    这篇文章主要介绍了Java实例域初始化方法及顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 挑战4道Java试题

    挑战4道Java试题

    这篇文章主要为大家分享了4道Java基础题,帮助大家巩固基础知识,夯实java基础技能,感兴趣的朋友快点挑战
    2015-12-12
  • java如何实现树形查询

    java如何实现树形查询

    这篇文章主要介绍了java实现树形查询方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Java运行时数据区域(内存划分)的深入讲解

    Java运行时数据区域(内存划分)的深入讲解

    听说Java运行时环境的内存划分是挺进BAT的必经之路,这篇文章主要给大家介绍了关于Java运行时数据区域(内存划分)的相关资料,需要的朋友可以参考下
    2021-06-06
  • 使用MyBatis拦截器实现SQL的完整打印

    使用MyBatis拦截器实现SQL的完整打印

    当我们使用Mybatis结合Mybatis-plus进行开发时,为了查看执行sql的信息通常我们可以通过属性配置的方式打印出执行的sql语句,但这样的打印出了sql语句常带有占位符信息,不利于排错,所以本文介绍了构建MyBatis拦截器,实现SQL的完整打印,需要的朋友可以参考下
    2024-07-07
  • 用Rational Rose逆向工程(java)生成类图(教程和错误解决)

    用Rational Rose逆向工程(java)生成类图(教程和错误解决)

    Rational Rose有个很方便的功能,将项目中的JAVA代码自动转换成UML类图
    2013-02-02
  • SpringBoot接口防重复提交的三种解决方案

    SpringBoot接口防重复提交的三种解决方案

    在Web开发中,防止用户重复提交表单是一个常见的需求,用户可能会因为网络延迟、误操作等原因多次点击提交按钮,导致后台接收到多个相同的请求,本文将介绍几种在Spring Boot中实现接口防重复提交的方法,需要的朋友可以参考下
    2024-11-11

最新评论