判断输入的主机号是否为32位,如果不等于32位则返回失败;将主机号经过AES加密算法中密钥为“1234567890123456”的ECB模式加密后,用base64编码形式打印,再经过md5加密算法将打印出来的base64编码生成32位散列值,作为用于激活操作系统的序列号,并基于序列号生成相应的二维码。输入的主机号和输出的序列号需要存储到数据库中。(这个二维码是不变的的,变的是二维码里面的内容在本地)
先去创建一个二维码(里面的内容随便照片、文字)
依赖
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version> <!-- 根据最新版本调整 -->
</dependency>
代码展示
private static final String AES_KEY = "1234567890123456";
@Override
public Result<String> generate(String hao) {
// 验证主机号长度
if (hao.length() != 32) {
Result.error("主机号长度不合法,操作失败!");
}
// AES加密
String encryptedHostNumber = encryptAES(hao, AES_KEY);
// Base64编码
String base64Encoded = Base64.getEncoder().encodeToString(encryptedHostNumber.getBytes(StandardCharsets.UTF_8));
// MD5加密
String md5Hash = generateMD5Hash(base64Encoded);
// 生成二维码(这里省略生成二维码的步骤)
try {
// 二维码内容
String qrCodeData = md5Hash;
// 设置二维码的宽度和高度
int width = 300;
int height = 300;
// 设置二维码图片保存路径
String filePath = "之前本地报错的二维码";//自己的
// 自己的服务器地址
String endpoint = "";
// 自己的AccessKeyId
String accessKeyId = "";
// 自己的AccessKeySecret
String accessKeySecret = "";
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String fileUrl="";
try {
File file = new File(filePath);
String objectName = "aaa.png"; // OSS 对象名称
// 设置一个字符串变量bucketName,
String bucketName="";//自己的
// 上传文件
ossClient.putObject(bucketName, objectName, file);
System.out.println("文件上传成功!");
// 如果需要获取上传后的文件 URL,可以使用以下代码
fileUrl = "https://" + bucketName + "." + endpoint + "/" + objectName;
System.out.println("文件访问地址:" + fileUrl);
} finally {
// 关闭 OSS 客户端
ossClient.shutdown();
}
// 存储到数据库
saveToDatabase(hao, md5Hash,fileUrl);
System.out.println("操作成功!生成的序列号为:" + md5Hash);
// 设置二维码图片格式
String fileType = "png";
// 创建 BitMatrix 对象
BitMatrix bitMatrix = new QRCodeWriter().encode(qrCodeData, BarcodeFormat.QR_CODE, width, height);
// 将 BitMatrix 转换为 BufferedImage
Path path = Paths.get(filePath);
MatrixToImageWriter.writeToPath(bitMatrix, fileType, path);
} catch (WriterException e) {
throw new RuntimeException("生成二维码失败", e);
}
return null;
}
public static class MatrixToImageWriter {
// 定义二维码颜色的常量
private static final int BLACK = 0xFF000000; // #00000000
private static final int WHITE = 0xFFFFFFFF; // #FFFFFFFF
// 私有构造函数,防止外部实例化
private MatrixToImageWriter() {}
/**
* 将二维码矩阵写入指定路径的图片文件
*
* @param matrix 二维码矩阵
* @param format 图片格式
* @param path 图片保存路径
* @throws RuntimeException 如果写入二维码图片失败,则抛出运行时异常
*/
public static void writeToPath(BitMatrix matrix, String format, Path path) {
try {
// 创建二维码转换为图片的配置对象
MatrixToImageConfig config = new MatrixToImageConfig(BLACK, WHITE);
// 将二维码矩阵写入指定路径的图片文件
MatrixToImageWriter.writeToPath(matrix, format, path, config);
} catch (Exception e) {
throw new RuntimeException("写入二维码图片失败", e);
}
}
/**
* 将二维码矩阵写入指定路径的图片文件
* @param matrix 二维码矩阵
* @param format 图片格式
* @param path 图片保存路径
* @param config 二维码图像配置
*/
public static void writeToPath(BitMatrix matrix, String format, Path path, MatrixToImageConfig config) {
try {
// 将二维码矩阵转换为缓冲图像
BufferedImage image = toBufferedImage(matrix, config);
// 将缓冲图像写入指定路径的图片文件
if (!ImageIO.write(image, format, path.toFile())) {
throw new RuntimeException("写入二维码图片失败");
}
} catch (IOException e) {
throw new RuntimeException("写入二维码图片失败", e);
}
}
/**
* 将二进制矩阵转换为缓冲图像对象
* @param matrix 二进制矩阵
* @param config 图像配置
* @return 缓冲图像对象
*/
private static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config) {
// 获取矩阵的宽度和高度
int width = matrix.getWidth();
int height = matrix.getHeight();
// 创建具有指定宽度、高度和颜色模型的缓冲图像对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 遍历矩阵的每个元素
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
// 将矩阵中的元素转换为像素颜色,并存储在图像对象中
image.setRGB(x, y, matrix.get(x, y) ? config.getPixelOnColor() : config.getPixelOffColor());
}
}
// 返回图像对象
return image;
}
public static class MatrixToImageConfig {
// 用于配置矩阵转换为图像的参数
private final int onColor; // 亮色
private final int offColor; // 暗色
// 构造方法
public MatrixToImageConfig(int onColor, int offColor) {
this.onColor = onColor;
this.offColor = offColor;
}
// 获取亮色
public int getPixelOnColor() {
return onColor;
}
// 获取暗色
public int getPixelOffColor() {
return offColor;
}
}
}
private static void saveToDatabase(String hostNumber, String serialNumber,String fileUrl) {
try {
// 假设你有一个数据库连接,并且有一个表用于存储主机号和序列号
String jdbcUrl = "jdbc:mysql://自己的服务器ip:3306/自己的库";
String username = "账号";
String password = "密码";
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
// 插入数据
String sql = "要执行的sql";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setString(1, hostNumber);//参数1对应占位符1
preparedStatement.setString(2, serialNumber);
preparedStatement.setString(3, fileUrl);
preparedStatement.executeUpdate();
}
connection.close();
} catch (Exception e) {
throw new RuntimeException("存储到数据库失败", e);
}
}
private static String encryptAES(String input, String key) {
try {
// 使用AES算法创建一个加密器对象
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 将key转换为字节数组,并使用UTF-8编码
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
// 初始化加密器,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 对输入的input进行加密,先将input转换为字节数组,然后使用加密器进行加密,最后将加密结果转换为字符串
return new String(cipher.doFinal(input.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
} catch (Exception e) {
// 如果出现异常,将异常包装成运行时异常并抛出
throw new RuntimeException("AES加密失败", e);
}
}
private static String generateMD5Hash(String input) {
try {
// 创建一个MessageDigest对象,使用MD5算法
MessageDigest md = MessageDigest.getInstance("MD5");
// 将输入的字节数据通过MessageDigest算法进行哈希计算
byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 创建一个StringBuilder对象,用于存储哈希结果的十六进制字符串
StringBuilder hexString = new StringBuilder();
// 遍历哈希结果的每个字节
for (byte b : hashBytes) {
// 将字节数据转换为十六进制字符串
String hex = Integer.toHexString(0xFF & b);
// 如果转换结果长度为1,则在前面添加一个0,保证十六进制字符串长度为2
if (hex.length() == 1) {
hexString.append('0');
}
// 将转换后的十六进制字符添加到StringBuilder对象中
hexString.append(hex);
}
// 返回哈希结果的十六进制字符串
return hexString.toString();
} catch (Exception e) {
// 如果发生异常,抛出运行时异常,并设置详细信息为"MD5加密失败",并将原始异常作为原因
throw new RuntimeException("MD5加密失败", e);
}
}