都快3202年了,你还不会用Java生成计算机统一标识符

Java生成计算机统一标识符

计算机统一标识符的概念

什么是计算机统一标识符?计算机统一标识符就相当于每台电脑每个系统的“身份证”。它是唯一的。通常,计算机统一标识符是根据电脑的硬件情况(主板、cpu的序列号,mac地址)和系统情况(windows/linux/unix)生成的。

Java语言的实现

下面这段代码浅浅的实现了计算机统一标识符

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 

* ComputerUniqueIdentificationUtil
* 计算机唯一标识工具 *

* * @author Heping_Ge2333 * @version 2.0 * @since 2022/12/23 */
@Slf4j public class ComputerUniqueIdentificationUtil { /** * Windows OS Identification */ public static final String WINDOWS = "WINDOWS"; /** * Linux OS Identification */ public static final String LINUX = "LINUX"; /** * Unix OS Identification */ public static final String UNIX = "UNIX"; /** * 正则表达式 */ public static final String REGEX = "\\b\\w+:\\w+:\\w+:\\w+:\\w+:\\w+\\b"; private static final String WINDOWS_MOTHERBOARD_INFO_ERROR_MSG = "获取 Windows 主板信息错误"; private static final String WINDOWS_MAC_ADDRESS_ERROR_MSG = "获取 Windows MAC 信息错误"; private static final String WINDOWS_CPU_INFO_ERROR_MSG = "获取 Windows CPU 信息错误"; private static final String LINUX_MOTHERBOARD_INFO_ERROR_MSG = "获取 Linux 主板信息错误"; private static final String LINUX_MAC_ADDRESS_ERROR_MSG = "获取 Linux MAC 信息错误"; private static final String LINUX_CPU_INFO_ERROR_MSG = "获取 Linux CPU 信息错误"; private static final String DELETE_FILE_ERROR_MSG = "删除文件时发生了错误"; private ComputerUniqueIdentificationUtil() { } /** * 在 Windows 环境下执行一个 vbs 脚本, 并返回运行结果 * * @param result 用于存储返回结果的 StringBuilder * @param file 存储 vbs 代码的文件 * @param fw 存储 vbs 代码文件的输入流 * @param vbs 要执行的代码 * @throws IOException 写入 vbs 脚本至文件 或 读取结果时发生 IO异常 * @author Heping_Ge2333 */ private static void loadVBS(StringBuilder result, File file, FileWriter fw, String vbs) throws IOException { fw.write(vbs); fw.close(); Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = input.readLine()) != null) { result.append(line); } input.close(); } /** * 获取 Windows 主板序列号 * * @return String - 计算机主板序列号 * @author Heping_Ge2333 */ private static String getWindowsMotherboardSerialNumber() { StringBuilder result = new StringBuilder(); try { File file = File.createTempFile("realhowto", ".vbs"); file.deleteOnExit(); FileWriter fw = new java.io.FileWriter(file); String vbs = """ Set objWMIService = GetObject("winmgmts:\\\\.\\root\\cimv2") Set colItems = objWMIService.ExecQuery _\s ("Select * from Win32_BaseBoard")\s For Each objItem in colItems\s Wscript.Echo objItem.SerialNumber\s exit for ' do the first cpu only!\s Next\s """; loadVBS(result, file, fw, vbs); } catch (Exception e) { log.error(WINDOWS_MOTHERBOARD_INFO_ERROR_MSG, e); } return result.toString().trim(); } /** * 获取 Linux 主板序列号 * * @return String - 计算机主板序列号 * @author Heping_Ge2333 */ private static String getLinuxMotherboardSerialNumber() { String result = CommonConstants.EMPTY_STR; String motherboardCmd = "dmidecode | grep 'Serial Number' | awk '{print $3}' | tail -1"; Process p; try { // 管道 p = Runtime.getRuntime().exec(new String[]{"sh", "-c", motherboardCmd}); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); result = br.readLine(); br.close(); } catch (IOException e) { log.error(LINUX_MOTHERBOARD_INFO_ERROR_MSG, e); } return result; } /** * 从字节获取 MAC 地址 * * @param bytes - 字节 * @return String - MAC * @author Heping_Ge2333 */ private static String getMacAddressFromBytes(byte[] bytes) { StringBuilder mac = new StringBuilder(); byte currentByte; boolean first = false; for (byte b : bytes) { if (first) { mac.append("-"); } currentByte = (byte) ((b & 240) >> 4); mac.append(String.format("%02X", currentByte)); currentByte = (byte) (b & 15); mac.append(String.format("%02X", currentByte)); first = true; } return mac.toString().toUpperCase(); } /** * 获取 Windows 网卡的 MAC 地址 * * @return String - MAC 地址 * @author Heping_Ge2333 */ private static String getWindowsMACAddress() { InetAddress ip; NetworkInterface ni; List<String> macList = new ArrayList<>(); try { Enumeration<NetworkInterface> netInterfaces = NetworkInterface .getNetworkInterfaces(); while (netInterfaces.hasMoreElements()) { ni = netInterfaces.nextElement(); // 遍历所有 IP 特定情况,可以考虑用 ni.getName() 判断 Enumeration<InetAddress> ips = ni.getInetAddresses(); while (ips.hasMoreElements()) { ip = ips.nextElement(); // 非127.0.0.1 if (!ip.isLoopbackAddress() && ip.getHostAddress().matches("(\\d{1,3}\\.){3}\\d{1,3}")) { macList.add(getMacAddressFromBytes(ni.getHardwareAddress())); } } } } catch (Exception e) { log.error(WINDOWS_MAC_ADDRESS_ERROR_MSG, e); } if (!macList.isEmpty()) { return macList.get(0); } else { return ""; } } /** * 获取 Linux 网卡的 MAC 地址 (如果 Linux 下有 eth0 这个网卡) * * @return String - MAC 地址 * @author Heping_Ge2333 */ private static String getLinuxMACAddressForEth0() { String mac = null; BufferedReader bufferedReader = null; Process process; try { // Linux下的命令,一般取eth0作为本地主网卡 process = Runtime.getRuntime().exec("ipconfig eth0"); // 显示信息中包含有 MAC 地址信息 bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; int index; while ((line = bufferedReader.readLine()) != null) { // 寻找标示字符串[hwaddr] index = line.toLowerCase().indexOf("hwaddr"); if (index >= 0) { // // 找到并取出 MAC 地址并去除2边空格 mac = line.substring(index + "hwaddr".length() + 1).trim(); break; } } } catch (IOException e) { log.error(LINUX_MAC_ADDRESS_ERROR_MSG, e); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e1) { log.error(LINUX_MAC_ADDRESS_ERROR_MSG, e1); } } return mac; } /** * 获取 Linux 网卡的 MAC 地址 * * @return String - MAC 地址 * @author Heping_Ge2333 */ private static String getLinuxMACAddress() { String mac = null; BufferedReader bufferedReader = null; Process process; try { // Linux下的命令 显示或设置网络设备 process = Runtime.getRuntime().exec("ipconfig"); // 显示信息中包含有 MAC 地址信息 bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = bufferedReader.readLine()) != null) { Pattern pat = Pattern.compile(REGEX); Matcher mat = pat.matcher(line); if (mat.find()) { mac = mat.group(0); } } } catch (IOException e) { log.error(LINUX_MAC_ADDRESS_ERROR_MSG, e); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e1) { log.error(LINUX_MAC_ADDRESS_ERROR_MSG, e1); } } return mac; } /** * 获取 Windows 的 CPU 序列号 * * @return String - CPU 序列号 * @author Heping_Ge2333 */ private static String getWindowsProcessorSerialNumber() { StringBuilder result = new StringBuilder(); try { File file = File.createTempFile("tmp", ".vbs"); file.deleteOnExit(); FileWriter fw = new java.io.FileWriter(file); String vbs = """ Set objWMIService = GetObject("winmgmts:\\\\.\\root\\cimv2") Set colItems = objWMIService.ExecQuery _\s ("Select * from Win32_Processor")\s For Each objItem in colItems\s Wscript.Echo objItem.ProcessorId\s exit for ' do the first cpu only!\s Next\s """; loadVBS(result, file, fw, vbs); if (!file.delete()) { log.error(DELETE_FILE_ERROR_MSG); } } catch (Exception e) { log.error(WINDOWS_CPU_INFO_ERROR_MSG, e); } return result.toString().trim(); } /** * 获取 Linux 的 CPU 序列号 * * @return String - CPU 序列号 * @author Heping_Ge2333 */ private static String getLinuxProcessorSerialNumber() { String result = ""; String CPU_ID_CMD = "dmidecode"; BufferedReader bufferedReader; Process p; try { // 管道 p = Runtime.getRuntime().exec(new String[]{"sh", "-c", CPU_ID_CMD}); bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; int index; while ((line = bufferedReader.readLine()) != null) { index = line.toLowerCase().indexOf("uuid"); if (index >= 0) { result = line.substring(index + "uuid".length() + 1).trim(); break; } } } catch (IOException e) { log.error(LINUX_CPU_INFO_ERROR_MSG, e); } return result.trim(); } /** * 获取当前计算机操作系统名称 例如:Windows,Linux,Unix等. * * @return String - 计算机操作系统名称 * @author Heping_Ge2333 */ public static String getOSName() { return System.getProperty("os.name").toUpperCase(); } /** * 获取当前计算机操作系统名称前缀 例如:Windows, Linux, Unix等. * * @return String - 计算机操作系统名称 * @author Heping_Ge2333 */ public static String getOSNamePrefix() { String name = getOSName(); if (name.startsWith(WINDOWS)) { return WINDOWS; } else if (name.startsWith(LINUX)) { return LINUX; } else if (name.startsWith(UNIX)) { return UNIX; } else { return CommonConstants.EMPTY_STR; } } /** * 获取当前计算机主板序列号 * * @return String - 计算机主板序列号 * @author Heping_Ge2333 */ public static String getMotherBoardSerialNumber() { return switch (getOSNamePrefix()) { case WINDOWS -> getWindowsMotherboardSerialNumber(); case LINUX -> getLinuxMotherboardSerialNumber(); default -> CommonConstants.EMPTY_STR; }; } /** * 获取当前计算机网卡的 MAC 地址 * * @return String - 网卡的 MAC 地址 * @author Heping_Ge2333 */ public static String getMACAddress() { switch (getOSNamePrefix()) { case WINDOWS -> { return getWindowsMACAddress(); } case LINUX -> { String macAddressForEth0 = getLinuxMACAddressForEth0(); if (StringUtil.isEmpty(macAddressForEth0)) { macAddressForEth0 = getLinuxMACAddress(); } return macAddressForEth0; } default -> { return CommonConstants.EMPTY_STR; } } } /** * 获取当前计算机的 CPU 序列号 * * @return String - CPU 序列号 * @author Heping_Ge2333 */ public static String getCPUSerialNumber() { return switch (getOSNamePrefix()) { case WINDOWS -> getWindowsProcessorSerialNumber(); case LINUX -> getLinuxProcessorSerialNumber(); default -> CommonConstants.EMPTY_STR; }; } /** * 获取计算机唯一标识 * * @return ComputerUniqueIdentification - 计算机唯一标识 * @author Heping_Ge2333 */ public static ComputerUniqueIdentification getComputerUniqueIdentification() { return new ComputerUniqueIdentification(getOSNamePrefix(), getMotherBoardSerialNumber(), getMACAddress(), getCPUSerialNumber()); } /** * 获取计算机唯一标识的 json 格式文本 * * @return String - 计算机唯一标识 * @author Heping_Ge2333 */ public static String getComputerUniqueIdentificationString() { return getComputerUniqueIdentification().toString(); } /** * 获取计算机唯一标识的SHA-512哈希值 * * @return 计算机唯一标识的SHA-512哈希值 */ public static String getComputerUniqueIdentificationHash() { return HashUtil.sha512(getComputerUniqueIdentification()); } /** *

* ComputerUniqueIdentification
* 计算机唯一标识 *

* * @author Heping_Ge2333 * @version 2.0 * @since 2022/12/13 */
@Data private static class ComputerUniqueIdentification { private final String osNamePrefix; private final String motherboardSerialNumber; private final String macAddress; private final String cpuSerialNumber; public ComputerUniqueIdentification(String osNamePrefix, String motherboardSerialNumber, String macAddress, String cpuSerialNumber) { this.osNamePrefix = osNamePrefix; this.motherboardSerialNumber = motherboardSerialNumber; this.macAddress = macAddress; this.cpuSerialNumber = cpuSerialNumber; } /** * 将计算机唯一标识转化为 json 并返回 * * @return 转化后的结果 */ @Override public String toString() { return '{' + "\n\t\"osNamePrefix\": \"" + osNamePrefix + "\"," + "\n\t\"motherboardSerialNumber\": \"" + motherboardSerialNumber + "\"," + "\n\t\"macAddress\": \"" + macAddress + "\"," + "\n\t\"cpuSerialNumber\": \"" + cpuSerialNumber + "\"" + "\n}"; } } }

这是项目里还有用到的几个工具类:
CommonConstants.java

//CommonConstants.java

/**
 * 

* CommonConstants
* 常用常量集合 *

* * @author Heping_Ge2333 * @version 1.0 * @since 2022/12/23 */
public class CommonConstants { /** * 空字符串 */ public static final String EMPTY_STR = ""; private CommonConstants() { } }

ConvertUtil.java:

//ConvertUtil.java

import java.math.BigInteger;

/**
 * 

* ConvertUtil
* 转换工具 *

* * @author Heping_Ge2333 * @version 1.0 * @since 2022/12/23 */
public class ConvertUtil { private ConvertUtil() { } /** * 将字节数组转换为字符串 * * @param bytes 待转换的字节数组 * @return 转换成的字符串 */ public static String convertBytesToString(byte[] bytes) { BigInteger no = new BigInteger(1, bytes); // Convert message digest into hex value String text = no.toString(16); while (text.length() < 32) { text = "0" + text; } return text; } }

HashUtil.java:

//HashUtil.java

import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 

* HashUtil
* 哈希算法工具 *

* * @author Heping_Ge2333 * @version 1.0 * @since 2022/12/23 */
@Slf4j public class HashUtil { /** * MD5 */ public static final String MD5 = "MD5"; /** * SHA-256 */ public static final String SHA_256 = "SHA-256"; /** * SHA-512 */ public static final String SHA_512 = "SHA-512"; private static final String NO_SUCH_ALGO_ERROR_MSG = "找不到指定的算法"; private HashUtil() { } /** * 获取对象的哈希值 * * @param algo 算法名称 * @param msg 原字符串 * @return 字节数组形式的哈希值 */ public static byte[] getHash(String algo, String msg) { try { MessageDigest md = MessageDigest.getInstance(algo); md.update(msg.getBytes(StandardCharsets.UTF_8)); byte[] bytes = md.digest(); return bytes; } catch (NoSuchAlgorithmException e) { log.error(NO_SUCH_ALGO_ERROR_MSG + " " + algo + " !", e); return null; } } /** * 获取对象的MD5哈希值 * * @param obj 原对象 * @return 原对象的MD5值 */ public static String md5(Object obj) { return ConvertUtil.convertBytesToString(getHash(MD5, obj.toString())); } /** * 获取对象的MD5哈希值 * * @param obj 原对象 * @return 原对象的MD5值 */ public static String sha256(Object obj) { return ConvertUtil.convertBytesToString(getHash(SHA_256, obj.toString())); } /** * 获取对象的MD5哈希值 * * @param obj 原对象 * @return 原对象的MD5值 */ public static String sha512(Object obj) { return ConvertUtil.convertBytesToString(getHash(SHA_512, obj.toString())); } }

StringUtil.java:

//StringUtil.java

/**
 * 

* StringUtil
* 字符串工具 *

* * @author Heping_Ge2333 * @version 1.0 * @since 2022/12/23 */
public class StringUtil { private StringUtil() { } /** * 判断字符串是否为空字符串 * * @param str 要判断的字符串 * @return 是否为空 */ public static boolean isEmpty(String str) { if (str == null) return true; return str.replaceAll("\\s", "").equals(CommonConstants.EMPTY_STR); } }

注意:本项目中使用了lombok和Slf4j,请自行配置。

写在最后

如果你有什么疑惑的话,可以在评论去留言。也欢迎各位大佬在评论区发表自己的看法。

你可能感兴趣的:(java)