Dock-MultiCtrl/admin/src/main/java/com/multictrl/common/utils/Utils.java

283 lines
8.9 KiB
Java
Raw Normal View History

2026-05-12 11:06:16 +08:00
package com.multictrl.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
2026-06-10 17:47:16 +08:00
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.filter.NameFilter;
2026-05-12 11:06:16 +08:00
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.mp4.Mp4MetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.multictrl.common.exception.ExceptionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* 通用工具
*
* @author Sdy
* @since 1.0.0 2026/4/24
*/
@Slf4j
public class Utils {
/**
* 线程休息n毫秒
*/
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
log.error("线程睡眠异常:{}", ExceptionUtils.getErrorStackTrace(e));
}
}
/*
* 驼峰转下划线
*/
public static JSONObject beanToSnakeJson(Object obj) {
JSONObject camelJson = JSONUtil.parseObj(obj);
JSONObject snakeJson = new JSONObject();
for (String key : camelJson.keySet()) {
String snakeKey = StrUtil.toUnderlineCase(key); // 驼峰转下划线
Object value = camelJson.get(key);
// 递归处理嵌套 JSONObject 或 JSONArray
if (value instanceof JSONObject) {
value = beanToSnakeJson(value); // 递归转换
} else if (value instanceof JSONArray) {
JSONArray arr = new JSONArray();
for (Object item : (JSONArray) value) {
if (item instanceof JSONObject) {
arr.add(beanToSnakeJson(item));
} else {
arr.add(item);
}
}
value = arr;
}
snakeJson.set(snakeKey, value);
}
return snakeJson;
}
2026-06-10 17:47:16 +08:00
/*
* 阿里FastJson2驼峰转下划线
*/
public static com.alibaba.fastjson2.JSONObject beanToSnakeJsonFastJson(Object o) {
NameFilter snakeCaseFilter = (object, name, value)
-> name.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
return com.alibaba.fastjson2.JSONObject.parseObject(JSON.toJSONString(o, snakeCaseFilter));
}
2026-05-12 11:06:16 +08:00
/**
* 获取最后两个字符
* "a/b/c/d" "c/d"
*/
public static String getLastTwoSegments(String str, String separator) {
if (StrUtil.isBlank(str)) return str;
// 按分隔符切割
List<String> parts = StrUtil.split(str, separator);
if (parts.size() <= 2) {
return str; // 不足两段则原样返回
} else {
// 取最后两段
List<String> lastTwo = parts.subList(parts.size() - 2, parts.size());
return CollUtil.join(lastTwo, String.valueOf(separator));
}
}
/**
* 文件转md5
*/
public static String md5File(String path) {
StringBuilder sb = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(FileUtils.readFileToByteArray(new File(path)));
byte[] b = md.digest();
int d;
for (byte value : b) {
d = value;
if (d < 0) {
d = value & 0xff;
// 与上一行效果等同
// i += 256;
}
if (d < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(d));
}
} catch (NoSuchAlgorithmException | IOException e) {
log.error("md5 fail", e);
}
return sb.toString();
}
/**
* 获取文本的md5
*/
public static String md5Txt(String context) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] buffer = context.getBytes();
md.update(buffer, 0, buffer.length);
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException exception) {
log.error("md5 fail", exception);
}
return null;
}
/**
* 获取图片的Windows XP Keywords
*/
public static String getImageWindowsXpKeywords(String mediaPath) {
Metadata metadata;
try {
metadata = JpegMetadataReader.readMetadata(new File(mediaPath));
for (Directory exif : metadata.getDirectories()) {
for (Tag tag : exif.getTags()) {
if ("Windows XP Keywords".equals(tag.getTagName())) {
return tag.getDescription();
}
}
}
} catch (JpegProcessingException | IOException e) {
log.error("error", e);
}
return null;
}
public static long getImageTime(String mediaPath) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
Metadata metadata;
try {
metadata = JpegMetadataReader.readMetadata(new File(mediaPath));
for (Directory exif : metadata.getDirectories()) {
for (Tag tag : exif.getTags()) {
if ("Date/Time".equals(tag.getTagName())) {
return sdf.parse(tag.getDescription()).getTime();
}
}
}
} catch (JpegProcessingException | IOException e) {
log.error("error", e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return 0;
}
public static long getVideoTime(String videoPath) {
Metadata metadata;
try {
metadata = Mp4MetadataReader.readMetadata(new File(videoPath));
for (Directory exif : metadata.getDirectories()) {
for (Tag tag : exif.getTags()) {
if ("Creation Time".equals(tag.getTagName())) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",
Locale.US);
Date d = sdf.parse(tag.getDescription());
return d.getTime();
} catch (ParseException ignored) {
}
}
}
}
} catch (IOException e) {
log.error("error", e);
}
return 0;
}
/**
* 格式化double保留指定位小数四舍五入
*
* @param value 原始数值
* @param scale 小数位数
* @return 格式化后的字符串
*/
private static String format(double value, int scale) {
if (Double.isNaN(value) || Double.isInfinite(value)) {
return "0";
}
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(scale, RoundingMode.HALF_UP);
return bd.stripTrailingZeros().toPlainString();
}
/**
* 字节数格式化为人性化字符串自动选择B, KB, MB, GB, TB
* 1024进制
*
* @param bytes 字节数
* @return "1.45 GB"
*/
public static String formatBytes(long bytes) {
if (bytes < 0) {
return "0 B";
}
if (bytes < 1024) {
return bytes + " B";
}
int exp = (int) (Math.log(bytes) / Math.log(1024));
char pre = "KMGTPE".charAt(exp - 1);
double result = bytes / Math.pow(1024, exp);
return format(result, 2) + " " + pre + "B";
}
/**
* 将秒转换为分秒
*/
public static String calculateSeconds(long totalSeconds) {
// 处理负数
if (totalSeconds < 0) {
return "-" + calculateSeconds(-totalSeconds);
}
long hours = totalSeconds / 3600;
long minutes = (totalSeconds % 3600) / 60;
long seconds = totalSeconds % 60;
StringBuilder sb = new StringBuilder();
if (hours > 0) {
sb.append(hours).append('h');
}
if (minutes > 0) {
sb.append(minutes).append('m');
}
// 当所有部分都为0时至少显示 "0s"
if (seconds > 0 || sb.isEmpty()) {
sb.append(seconds).append('s');
}
return sb.toString();
}
2026-05-12 11:06:16 +08:00
}