我一直以为fastjson的坑是最多的,今天用了一下Gson,它的坑也不少,Long类型在反序列化的时候会将数据转化为科学计数法。
2024-11-06 start:
/**
* @author haijin
* @description: 文本解析工具类,提供从字符串中提取指定内容的常用方法
* @date 2024/10/23 16:50
*/
public class TextUtil {
/**
* 获取从第一个匹配的起始关键字之后,到多个结束关键字中最早出现的那个之间的最短子串(正向查找)。
* 如果未找到起始关键字或所有结束关键字,则返回原字符串。
*
* @param str 源字符串
* @param first 起始关键字
* @param secondKeys 多个可能的结束关键字
* @return 提取的子字符串
*/
public static String getShortStringBetweenKeys(String str, String first, String[] secondKeys) {
return getShortStringBetweenKeys(str, first, secondKeys, true);
}
/**
* 获取从最后一个匹配的起始关键字之后,到多个结束关键字中最早出现的那个之间的最短子串(逆向查找起始关键字)。
* 常用于匹配最近一次出现的起始标记。
*
* @param str 源字符串
* @param first 起始关键字
* @param secondKeys 多个可能的结束关键字
* @return 提取的子字符串
*/
public static String getShortStringBetweenLastKeys(String str, String first, String[] secondKeys) {
return getShortStringBetweenKeys(str, first, secondKeys, false);
}
/**
* 获取从起始关键字之后,到多个结束关键字中最早出现的那个之间的最短子串。
* 可选择从前往后(asc=true)或从后往前(asc=false)查找起始关键字。
*
* @param str 源字符串
* @param first 起始关键字
* @param secondKeys 多个可能的结束关键字
* @param asc true表示正向查找起始关键字,false表示逆向查找
* @return 提取的子字符串
*/
public static String getShortStringBetweenKeys(String str, String first, String[] secondKeys, boolean asc) {
if (str != null && first != null && secondKeys != null) {
int firstIndex = -1;
if (asc) {
firstIndex = str.indexOf(first);
} else {
firstIndex = str.lastIndexOf(first);
}
if (firstIndex != -1) {
int secondIndex = -1;
firstIndex += first.length(); // 移动到起始关键字之后
for (int i = 0; i < secondKeys.length; i++) {
int index = str.indexOf(secondKeys[i], firstIndex);
if (index != -1 && (secondIndex == -1 || index < secondIndex)) {
secondIndex = index; // 找到最早出现的结束关键字
}
}
if (secondIndex == -1) {
secondIndex = str.length(); // 如果没有结束关键字,则截取到字符串末尾
}
str = str.substring(firstIndex, secondIndex);
}
}
return str;
}
/**
* 获取从第一个匹配的起始关键字之后,到第一个匹配的结束关键字之间的子串。
* 如果未找到起始关键字,则返回空字符串;如果未找到结束关键字,则截取到字符串末尾。
*
* @param str 源字符串
* @param first 起始关键字
* @param second 结束关键字
* @return 提取的子字符串
*/
public static String getStringBetweenKeys(String str, String first, String second) {
if (str != null && first != null && second != null) {
int firstIndex = str.indexOf(first);
if (firstIndex != -1) {
firstIndex += first.length();
int secondIndex = str.indexOf(second, firstIndex);
if (secondIndex == -1) {
secondIndex = str.length();
}
str = str.substring(firstIndex, secondIndex);
} else {
str = "";
}
}
return str;
}
/**
* 获取从最后一个匹配的起始关键字之后,到下一个结束关键字之间的子串。
* 特别适用于起始和结束关键字相同的情况(如引号、括号等)。
*
* @param str 源字符串
* @param first 起始关键字
* @param second 结束关键字
* @return 提取的子字符串
*/
public static String getStringBetweenLastKeys(String str, String first, String second) {
if (str != null && first != null && second != null) {
int firstIndex = str.lastIndexOf(first);
// 如果起始和结束关键字相同,需避免匹配到同一个位置
if (firstIndex != -1 && first.equals(second)) {
firstIndex = str.lastIndexOf(first, firstIndex - first.length());
}
if (firstIndex != -1) {
firstIndex += first.length();
int secondIndex = str.indexOf(second, firstIndex);
if (secondIndex == -1) {
secondIndex = str.length();
}
str = str.substring(firstIndex, secondIndex);
}
}
return str;
}
/**
* 获取从指定关键字第一次出现之后的所有内容(从字符串开头查找)。
* 如果关键字不存在,则行为未定义(可能抛出异常)。
*
* @param str 源字符串
* @param key 关键字
* @return 关键字之后的子字符串
*/
public static String getStringAfterKey(String str, String key) {
return getStringAfterKey(str, key, 0);
}
/**
* 获取从指定关键字在给定索引后第一次出现之后的所有内容。
* 常用于查找多次出现的关键字。
*
* @param str 源字符串
* @param key 关键字
* @param fromIndex 开始查找的索引位置
* @return 关键字之后的子字符串
*/
public static String getStringAfterKey(String str, String key, int fromIndex) {
if (str != null && key != null) {
str = str.substring(str.indexOf(key, fromIndex) + key.length());
}
return str;
}
/**
* 获取从最后一个匹配的关键字之后的所有内容。
*
* @param str 源字符串
* @param key 关键字
* @return 最后一个关键字之后的子字符串
*/
public static String getStringAfterLastKey(String str, String key) {
if (str != null && key != null) {
str = str.substring(str.lastIndexOf(key) + key.length());
}
return str;
}
/**
* 获取从字符串开头到第一个匹配的关键字之前的内容。
* 如果关键字不存在,则返回原字符串。
*
* @param str 源字符串
* @param key 关键字
* @return 关键字之前的子字符串
*/
public static String getStringBeforeKey(String str, String key) {
if (str != null && key != null && str.indexOf(key) != -1) {
str = str.substring(0, str.indexOf(key));
}
return str;
}
/**
* 获取从字符串开头到多个关键字中最早出现的那个之前的内容。
* 常用于提取直到某个分隔符之前的内容。
*
* @param str 源字符串
* @param keys 多个可能的关键字
* @return 第一个关键字之前的所有内容
*/
public static String getStringBeforeKeys(String str, String... keys) {
int firstIndex = -1;
for (int i = 0; i < keys.length; i++) {
int index = str.indexOf(keys[i]);
if (index != -1 && (firstIndex == -1 || index < firstIndex)) {
firstIndex = index;
}
}
if (firstIndex == -1) {
firstIndex = str.length();
}
str = str.substring(0, firstIndex);
return str;
}
/**
* 获取从字符串开头到最后一个匹配的关键字之前的内容。
*
* @param str 源字符串
* @param key 关键字
* @return 最后一个关键字之前的内容
*/
public static String getStringBeforeLastKey(String str, String key) {
if (str != null && key != null && str.lastIndexOf(key) != -1) {
str = str.substring(0, str.lastIndexOf(key));
}
return str;
}
}
电话脱敏:
/**
* 电话脱敏
* @param phoneNumber 电话号码
* @return ignore
*/
private String maskPhoneNumber(String phoneNumber) {
if (phoneNumber == null || phoneNumber.length() < 8) {
return phoneNumber;
}
return phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7);
}
end
2025-03-19 start:
将一个时间片分片(每10分钟一个分片)
/**
* 将时间段拆分为 10 分钟一段的时间片
*
* @param startTimeStr 开始时间字符串(格式:yyyy-MM-dd HH:mm:ss)
* @param endTimeStr 结束时间字符串(格式:yyyy-MM-dd HH:mm:ss)
* @return 拆分后的时间片列表,每个时间片是一个 Map
*/
public static List<Map<String, String>> splitTimeRange(String startTimeStr, String endTimeStr) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 将字符串解析为 LocalDateTime
LocalDateTime startTime = LocalDateTime.parse(startTimeStr, formatter);
LocalDateTime endTime = LocalDateTime.parse(endTimeStr, formatter);
List<Map<String, String>> timeRanges = new ArrayList<>();
// 如果开始时间大于结束时间,直接返回空列表
if (startTime.isAfter(endTime)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
LocalDateTime currentStart = startTime;
// 循环拆分时间段
while (currentStart.isBefore(endTime)) {
LocalDateTime currentEnd = currentStart.plusMinutes(10);
if (currentEnd.isAfter(endTime)) {
currentEnd = endTime;
}
Map<String, String> timeRange = new HashMap<>();
timeRange.put("startTime", currentStart.format(formatter));
timeRange.put("endTime", currentEnd.format(formatter));
timeRanges.add(timeRange);
currentStart = currentEnd;
}
return timeRanges;
}
时间校验:
// 定义时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 解析输入的时间字符串为LocalDateTime对象
LocalDateTime startTimeDate = LocalDateTime.parse(startTime, formatter);
LocalDateTime endTimeDate = LocalDateTime.parse(endTime, formatter);
// 判断开始时间是否小于结束时间
if (startTimeDate.isAfter(endTimeDate) || startTimeDate.isEqual(endTimeDate)) {
throw new Exception("开始时间要小于结束时间");
}
// 计算时间差
Duration duration = Duration.between(startTimeDate, endTimeDate);
// 判断是否超过一个小时
if (duration.getSeconds() > 3600) {
throw new Exception("输入的时间不能超过一个小时");
}
end
2025-10-11 start:
springboot项目中读取resource中的文本:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
public class TextLoader {
public static String loadLargeString() throws Exception {
Path path = Paths.get(Objects.requireNonNull(
TextLoader.class.getClassLoader().getResource("large_text.txt")
).toURI());
return Files.readString(path);
}
}
end