SpringBoot 高效工具类大全
SpringBoot 高效工具类大全
目录
-
1. 引言:为什么需要工具类 -
2. 日期时间工具类 -
3. 字符串处理工具类 -
4. JSON 处理工具类 -
5. 文件操作工具类 -
6. HTTP 请求工具类 -
7. 加密解密工具类 -
8. Bean 转换工具类 -
9. 验证工具类 -
10. 缓存工具类 -
11. Excel 处理工具类 -
12. 总结
1. 引言:为什么需要工具类
1.1 工具类的价值
┌─────────────────────────────────────────────────────────────┐
│ 工具类的核心价值 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 提高开发效率 │
│ - 避免重复造轮子 │
│ - 一行代码完成复杂操作 │
│ │
│ ✅ 保证代码质量 │
│ - 统一处理边界情况 │
│ - 经过充分测试验证 │
│ │
│ ✅ 降低维护成本 │
│ - 集中管理通用逻辑 │
│ - 修改一处,全局生效 │
│ │
│ ✅ 提升代码可读性 │
│ - 语义化的方法名 │
│ - 减少样板代码 │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 工具类设计原则
|
|
|
|
|---|---|---|
| 单一职责 |
|
|
| 静态方法 |
|
|
| 私有构造 |
|
|
| 线程安全 |
|
|
| 异常处理 |
|
|
| 文档完善 |
|
|
2. 日期时间工具类
2.1 DateUtils 完整实现
package com.example.common.utils;
import lombok.extern.slf4j.Slf4j;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
/**
* 日期时间工具类
*
* 基于 Java 8+ Date/Time API,线程安全
*/
@Slf4j
public class DateUtils {
private DateUtils() {
throw new IllegalStateException("Utility class");
}
// ==================== 常用格式 ====================
public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final String DATETIME_PATTERN = "yyyyMMddHHmmss";
public static final String CHINESE_PATTERN = "yyyy 年 MM 月 dd 日";
private static final DateTimeFormatter DEFAULT_FORMATTER =
DateTimeFormatter.ofPattern(DEFAULT_PATTERN);
// ==================== 格式化 ====================
/**
* 日期转字符串(默认格式)
*/
public static String format(LocalDateTime dateTime) {
return format(dateTime, DEFAULT_PATTERN);
}
/**
* 日期转字符串(指定格式)
*/
public static String format(LocalDateTime dateTime, String pattern) {
if (dateTime == null) {
return null;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return dateTime.format(formatter);
}
/**
* 日期转字符串(Date 类型)
*/
public static String formatDate(Date date) {
if (date == null) {
return null;
}
return format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
}
/**
* 时间戳转字符串
*/
public static String formatTimestamp(Long timestamp) {
if (timestamp == null) {
return null;
}
LocalDateTime dateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(timestamp),
ZoneId.systemDefault()
);
return format(dateTime);
}
// ==================== 解析 ====================
/**
* 字符串转日期(默认格式)
*/
public static LocalDateTime parse(String dateTimeStr) {
return parse(dateTimeStr, DEFAULT_PATTERN);
}
/**
* 字符串转日期(指定格式)
*/
public static LocalDateTime parse(String dateTimeStr, String pattern) {
if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
return null;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(dateTimeStr, formatter);
} catch (Exception e) {
log.error("日期解析失败:{}", dateTimeStr, e);
return null;
}
}
/**
* 字符串转日期(返回 Date)
*/
public static Date parseToDate(String dateTimeStr) {
LocalDateTime dateTime = parse(dateTimeStr);
if (dateTime == null) {
return null;
}
return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
}
// ==================== 计算 ====================
/**
* 获取当前日期时间
*/
public static LocalDateTime now() {
return LocalDateTime.now();
}
/**
* 获取当前日期(无时间)
*/
public static LocalDate today() {
return LocalDate.now();
}
/**
* 获取当前时间戳(毫秒)
*/
public static Long currentTimestamp() {
return System.currentTimeMillis();
}
/**
* 获取当前时间戳(秒)
*/
public static Long currentTimestampSeconds() {
return Instant.now().getEpochSecond();
}
/**
* 增加天数
*/
public static LocalDateTime addDays(LocalDateTime dateTime, int days) {
return dateTime.plusDays(days);
}
/**
* 减少天数
*/
public static LocalDateTime minusDays(LocalDateTime dateTime, int days) {
return dateTime.minusDays(days);
}
/**
* 增加月
*/
public static LocalDateTime addMonths(LocalDateTime dateTime, int months) {
return dateTime.plusMonths(months);
}
/**
* 获取月初
*/
public static LocalDateTime getMonthStart(LocalDateTime dateTime) {
return dateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
}
/**
* 获取月末
*/
public static LocalDateTime getMonthEnd(LocalDateTime dateTime) {
return dateTime.withDayOfMonth(dateTime.toLocalDate().lengthOfMonth())
.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
}
/**
* 获取本周开始(周一)
*/
public static LocalDateTime getWeekStart(LocalDateTime dateTime) {
return dateTime.with(DayOfWeek.MONDAY).withHour(0).withMinute(0).withSecond(0).withNano(0);
}
/**
* 获取本周结束(周日)
*/
public static LocalDateTime getWeekEnd(LocalDateTime dateTime) {
return dateTime.with(DayOfWeek.SUNDAY).withHour(23).withMinute(59).withSecond(59).withNano(999999999);
}
// ==================== 比较 ====================
/**
* 计算两个日期相差的天数
*/
public static long daysBetween(LocalDateTime start, LocalDateTime end) {
return ChronoUnit.DAYS.between(start, end);
}
/**
* 计算两个日期相差的小时数
*/
public static long hoursBetween(LocalDateTime start, LocalDateTime end) {
return ChronoUnit.HOURS.between(start, end);
}
/**
* 计算两个日期相差的分钟数
*/
public static long minutesBetween(LocalDateTime start, LocalDateTime end) {
return ChronoUnit.MINUTES.between(start, end);
}
/**
* 判断是否过期
*/
public static boolean isExpired(LocalDateTime expireTime) {
return LocalDateTime.now().isAfter(expireTime);
}
/**
* 判断是否在两个日期之间
*/
public static boolean isBetween(LocalDateTime dateTime, LocalDateTime start, LocalDateTime end) {
return !dateTime.isBefore(start) && !dateTime.isAfter(end);
}
// ==================== 特殊日期 ====================
/**
* 获取今天开始时间
*/
public static LocalDateTime getTodayStart() {
return LocalDate.now().atStartOfDay();
}
/**
* 获取今天结束时间
*/
public static LocalDateTime getTodayEnd() {
return LocalDate.now().atTime(23, 59, 59);
}
/**
* 获取昨天开始时间
*/
public static LocalDateTime getYesterdayStart() {
return LocalDate.now().minusDays(1).atStartOfDay();
}
/**
* 获取本月第一天
*/
public static LocalDateTime getCurrentMonthStart() {
return getMonthStart(LocalDateTime.now());
}
/**
* 获取本月最后一天
*/
public static LocalDateTime getCurrentMonthEnd() {
return getMonthEnd(LocalDateTime.now());
}
/**
* 获取年龄
*/
public static int getAge(LocalDate birthDate) {
if (birthDate == null) {
throw new IllegalArgumentException("出生日期不能为空");
}
return Period.between(birthDate, LocalDate.now()).getYears();
}
/**
* 获取星座
*/
public static String getZodiacSign(int month, int day) {
int[] days = {20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 22, 22};
String[] signs = {"摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座",
"巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"};
if (day < days[month - 1]) {
return signs[month - 1];
} else {
return signs[month];
}
}
}
2.2 实际使用场景
// 场景 1:订单过期判断
public class OrderService {
public boolean isOrderExpired(Order order) {
// 订单 30 分钟后过期
LocalDateTime expireTime = DateUtils.addMinutes(order.getCreateTime(), 30);
return DateUtils.isExpired(expireTime);
}
public List<Order> getTodayOrders() {
LocalDateTime start = DateUtils.getTodayStart();
LocalDateTime end = DateUtils.getTodayEnd();
return orderRepository.findByCreateTimeBetween(start, end);
}
public Map<String, Long> getMonthlyStats() {
LocalDateTime start = DateUtils.getCurrentMonthStart();
LocalDateTime end = DateUtils.getCurrentMonthEnd();
long count = orderRepository.countByCreateTimeBetween(start, end);
BigDecimal amount = orderRepository.sumAmountByCreateTimeBetween(start, end);
return Map.of(
"count", count,
"amount", amount.longValue()
);
}
}
// 场景 2:用户年龄计算
public class UserService {
public void register(User user) {
int age = DateUtils.getAge(user.getBirthDate());
if (age < 18) {
throw new BusinessException("未满 18 岁不能注册");
}
// 设置星座
String zodiac = DateUtils.getZodiacSign(
user.getBirthDate().getMonthValue(),
user.getBirthDate().getDayOfMonth()
);
user.setZodiac(zodiac);
userRepository.save(user);
}
}
// 场景 3:定时任务
@Component
public class ScheduledTasks {
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨 1 点
public void cleanupExpiredData() {
LocalDateTime expireTime = DateUtils.addDays(LocalDateTime.now(), -30);
int count = logRepository.deleteByCreateTimeBefore(expireTime);
log.info("清理过期日志 {} 条", count);
}
}
3. 字符串处理工具类
3.1 StringUtils 完整实现
package com.example.common.utils;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 字符串处理工具类
*/
public class StringUtils {
private StringUtils() {
throw new IllegalStateException("Utility class");
}
// ==================== 基础判断 ====================
/**
* 判断是否为空(null 或 "")
*/
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
/**
* 判断是否不为空
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* 判断是否为空白(null、"" 或纯空格)
*/
public static boolean isBlank(String str) {
return str == null || str.trim().isEmpty();
}
/**
* 判断是否不为空白
*/
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
* 判断是否全为数字
*/
public static boolean isNumeric(String str) {
if (isEmpty(str)) {
return false;
}
return str.matches("^\\d+$");
}
/**
* 判断是否全为字母
*/
public static boolean isAlpha(String str) {
if (isEmpty(str)) {
return false;
}
return str.matches("^[a-zA-Z]+$");
}
/**
* 判断是否全为字母或数字
*/
public static boolean isAlphanumeric(String str) {
if (isEmpty(str)) {
return false;
}
return str.matches("^[a-zA-Z0-9]+$");
}
// ==================== 处理 ====================
/**
* 去除首尾空格,空串返回 null
*/
public static String trim(String str) {
return str == null ? null : str.trim();
}
/**
* 去除首尾空格,空串返回空串
*/
public static String trimToEmpty(String str) {
return str == null ? "" : str.trim();
}
/**
* 去除首尾空格,空串返回 null
*/
public static String trimToNull(String str) {
if (str == null) {
return null;
}
String trimmed = str.trim();
return trimmed.isEmpty() ? null : trimmed;
}
/**
* 转小写,null 安全
*/
public static String toLowerCase(String str) {
return str == null ? null : str.toLowerCase();
}
/**
* 转大写,null 安全
*/
public static String toUpperCase(String str) {
return str == null ? null : str.toUpperCase();
}
/**
* 首字母大写
*/
public static String capitalize(String str) {
if (isEmpty(str)) {
return str;
}
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
/**
* 首字母小写
*/
public static String uncapitalize(String str) {
if (isEmpty(str)) {
return str;
}
return Character.toLowerCase(str.charAt(0)) + str.substring(1);
}
// ==================== 截取 ====================
/**
* 截取字符串(防止越界)
*/
public static String substring(String str, int start) {
if (str == null) {
return null;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0 || start >= str.length()) {
return "";
}
return str.substring(start);
}
/**
* 截取字符串(指定长度)
*/
public static String substring(String str, int start, int end) {
if (str == null) {
return null;
}
if (start < 0) {
start = str.length() + start;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = 0;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return "";
}
return str.substring(start, end);
}
/**
* 截取字符串(超出显示省略号)
*/
public static String abbreviate(String str, int maxWidth) {
return abbreviate(str, maxWidth, "...");
}
/**
* 截取字符串(超出显示指定后缀)
*/
public static String abbreviate(String str, int maxWidth, String suffix) {
if (str == null) {
return null;
}
if (str.length() <= maxWidth) {
return str;
}
suffix = suffix == null ? "" : suffix;
if (maxWidth <= suffix.length()) {
return suffix.substring(0, maxWidth);
}
return str.substring(0, maxWidth - suffix.length()) + suffix;
}
// ==================== 查找 ====================
/**
* 查找子字符串位置
*/
public static int indexOf(String str, String searchStr) {
if (str == null || searchStr == null) {
return -1;
}
return str.indexOf(searchStr);
}
/**
* 是否包含子字符串
*/
public static boolean contains(String str, String searchStr) {
return indexOf(str, searchStr) >= 0;
}
/**
* 是否以指定前缀开头
*/
public static boolean startsWith(String str, String prefix) {
if (str == null || prefix == null) {
return false;
}
return str.startsWith(prefix);
}
/**
* 是否以指定后缀结尾
*/
public static boolean endsWith(String str, String suffix) {
if (str == null || suffix == null) {
return false;
}
return str.endsWith(suffix);
}
// ==================== 替换 ====================
/**
* 替换字符串
*/
public static String replace(String str, String searchString, String replacement) {
if (isEmpty(str) || isEmpty(searchString)) {
return str;
}
return str.replace(searchString, replacement);
}
/**
* 替换多个
*/
public static String replaceEach(String str, String[] searchList, String[] replacementList) {
if (isEmpty(str) || searchList == null || replacementList == null) {
return str;
}
if (searchList.length != replacementList.length) {
throw new IllegalArgumentException("Search and Replace array lengths don't match");
}
String result = str;
for (int i = 0; i < searchList.length; i++) {
result = result.replace(searchList[i], replacementList[i]);
}
return result;
}
/**
* 移除指定字符
*/
public static String remove(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
return str.replace(remove, "");
}
/**
* 移除所有空格
*/
public static String removeSpaces(String str) {
if (isEmpty(str)) {
return str;
}
return str.replace(" ", "");
}
// ==================== 分割 ====================
/**
* 分割字符串
*/
public static List<String> split(String str, String separator) {
if (isEmpty(str)) {
return Collections.emptyList();
}
if (separator == null) {
return Collections.singletonList(str);
}
return Arrays.stream(str.split(separator))
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
/**
* 分割字符串(逗号分隔)
*/
public static List<String> splitByComma(String str) {
return split(str, ",");
}
/**
* 分割字符串(分号分隔)
*/
public static List<String> splitBySemicolon(String str) {
return split(str, ";");
}
/**
* 连接字符串
*/
public static String join(List<String> list, String separator) {
if (list == null || list.isEmpty()) {
return "";
}
return String.join(separator, list);
}
/**
* 连接字符串(逗号分隔)
*/
public static String joinByComma(List<String> list) {
return join(list, ",");
}
// ==================== 正则 ====================
/**
* 正则匹配
*/
public static boolean matches(String str, String regex) {
if (isEmpty(str) || isEmpty(regex)) {
return false;
}
return str.matches(regex);
}
/**
* 提取所有匹配
*/
public static List<String> extractAll(String str, String regex) {
if (isEmpty(str) || isEmpty(regex)) {
return Collections.emptyList();
}
List<String> matches = new ArrayList<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
matches.add(matcher.group());
}
return matches;
}
/**
* 提取第一个匹配
*/
public static String extractFirst(String str, String regex) {
List<String> matches = extractAll(str, regex);
return matches.isEmpty() ? null : matches.get(0);
}
// ==================== 特殊格式 ====================
/**
* 手机号脱敏(138****1234)
*/
public static String maskPhone(String phone) {
if (isEmpty(phone) || phone.length() != 11) {
return phone;
}
return phone.substring(0, 3) + "****" + phone.substring(7);
}
/**
* 邮箱脱敏(t**@example.com)
*/
public static String maskEmail(String email) {
if (isEmpty(email) || !email.contains("@")) {
return email;
}
String[] parts = email.split("@");
String username = parts[0];
String domain = parts[1];
if (username.length() <= 2) {
return username + "@" + domain;
}
return username.charAt(0) + "**" + username.substring(username.length() - 1) + "@" + domain;
}
/**
* 身份证脱敏(110101********1234)
*/
public static String maskIdCard(String idCard) {
if (isEmpty(idCard) || idCard.length() < 10) {
return idCard;
}
if (idCard.length() == 18) {
return idCard.substring(0, 6) + "********" + idCard.substring(14);
}
return idCard.substring(0, 6) + "****" + idCard.substring(idCard.length() - 4);
}
/**
* 姓名脱敏(张*三)
*/
public static String maskName(String name) {
if (isEmpty(name)) {
return name;
}
if (name.length() == 1) {
return "*";
}
if (name.length() == 2) {
return name.charAt(0) + "*";
}
return name.charAt(0) + "*" + name.substring(name.length() - 1);
}
}
3.2 实际使用场景
// 场景 1:用户信息脱敏
public class UserService {
public UserVO getUserVO(User user) {
UserVO vo = new UserVO();
vo.setId(user.getId());
vo.setName(StringUtils.maskName(user.getName()));
vo.setPhone(StringUtils.maskPhone(user.getPhone()));
vo.setEmail(StringUtils.maskEmail(user.getEmail()));
vo.setIdCard(StringUtils.maskIdCard(user.getIdCard()));
return vo;
}
}
// 场景 2:标签处理
public class ArticleService {
public void saveArticle(Article article) {
// 标签字符串转列表
String tagsStr = article.getTagsStr(); // "Java,Spring,MySQL"
List<String> tags = StringUtils.splitByComma(tagsStr);
article.setTags(tags);
// 内容摘要(最多 200 字)
String content = article.getContent();
article.setSummary(StringUtils.abbreviate(content, 200));
articleRepository.save(article);
}
}
// 场景 3:批量导入验证
public class ImportService {
public ImportResult validate(List<ImportData> dataList) {
List<String> errors = new ArrayList<>();
for (int i = 0; i < dataList.size(); i++) {
ImportData data = dataList.get(i);
// 必填项验证
if (StringUtils.isBlank(data.getName())) {
errors.add("第" + (i + 1) + "行:姓名不能为空");
}
// 手机号验证
if (!StringUtils.matches(data.getPhone(), "^1[3-9]\\d{9}$")) {
errors.add("第" + (i + 1) + "行:手机号格式错误");
}
// 邮箱验证
if (StringUtils.isNotBlank(data.getEmail()) &&
!StringUtils.matches(data.getEmail(), "^[\\w.-]+@[\\w.-]+\\.[\\w.-]+$")) {
errors.add("第" + (i + 1) + "行:邮箱格式错误");
}
}
return new ImportResult(errors.isEmpty(), errors);
}
}
4. JSON 处理工具类
4.1 JsonUtils 完整实现(基于 Jackson)
package com.example.common.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.*;
/**
* JSON 处理工具类(基于 Jackson)
*/
@Slf4j
public class JsonUtils {
private JsonUtils() {
throw new IllegalStateException("Utility class");
}
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
// 注册 Java 8 日期时间模块
objectMapper.registerModule(new JavaTimeModule());
// 忽略未知字段
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 空对象序列化为 null
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
// ==================== 对象转 JSON ====================
/**
* 对象转 JSON 字符串
*/
public static String toJson(Object obj) {
if (obj == null) {
return null;
}
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
log.error("对象转 JSON 失败", e);
return null;
}
}
/**
* 对象转格式化 JSON 字符串
*/
public static String toPrettyJson(Object obj) {
if (obj == null) {
return null;
}
try {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
log.error("对象转 JSON 失败", e);
return null;
}
}
/**
* Map 转 JSON 字符串
*/
public static String mapToJson(Map<String, Object> map) {
return toJson(map);
}
/**
* List 转 JSON 字符串
*/
public static String listToJson(List<?> list) {
return toJson(list);
}
// ==================== JSON 转对象 ====================
/**
* JSON 字符串转对象
*/
public static <T> T fromJson(String json, Class<T> clazz) {
if (StringUtils.isBlank(json)) {
return null;
}
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
log.error("JSON 转对象失败:{}", json, e);
return null;
}
}
/**
* JSON 字符串转对象(TypeReference)
*/
public static <T> T fromJson(String json, TypeReference<T> typeRef) {
if (StringUtils.isBlank(json)) {
return null;
}
try {
return objectMapper.readValue(json, typeRef);
} catch (IOException e) {
log.error("JSON 转对象失败:{}", json, e);
return null;
}
}
/**
* JSON 字符串转 List
*/
public static <T> List<T> jsonToList(String json, Class<T> clazz) {
return fromJson(json, new TypeReference<List<T>>() {});
}
/**
* JSON 字符串转 Map
*/
public static Map<String, Object> jsonToMap(String json) {
return fromJson(json, new TypeReference<Map<String, Object>>() {});
}
// ==================== 节点操作 ====================
/**
* 创建 ObjectNode
*/
public static ObjectNode createObjectNode() {
return objectMapper.createObjectNode();
}
/**
* 创建 ArrayNode
*/
public static ArrayNode createArrayNode() {
return objectMapper.createArrayNode();
}
/**
* 读取 JSON 节点
*/
public static JsonNode readTree(String json) {
if (StringUtils.isBlank(json)) {
return null;
}
try {
return objectMapper.readTree(json);
} catch (IOException e) {
log.error("读取 JSON 树失败", e);
return null;
}
}
/**
* 获取节点值(字符串)
*/
public static String getStringValue(JsonNode node, String fieldName) {
if (node == null || !node.has(fieldName)) {
return null;
}
JsonNode fieldNode = node.get(fieldName);
return fieldNode.isTextual() ? fieldNode.asText() : fieldNode.toString();
}
/**
* 获取节点值(整数)
*/
public static Integer getIntValue(JsonNode node, String fieldName) {
if (node == null || !node.has(fieldName)) {
return null;
}
return node.get(fieldName).asInt();
}
/**
* 获取节点值(长整型)
*/
public static Long getLongValue(JsonNode node, String fieldName) {
if (node == null || !node.has(fieldName)) {
return null;
}
return node.get(fieldName).asLong();
}
/**
* 获取节点值(布尔)
*/
public static Boolean getBooleanValue(JsonNode node, String fieldName) {
if (node == null || !node.has(fieldName)) {
return null;
}
return node.get(fieldName).asBoolean();
}
/**
* 获取数组节点
*/
public static ArrayNode getArrayNode(JsonNode node, String fieldName) {
if (node == null || !node.has(fieldName)) {
return null;
}
JsonNode fieldNode = node.get(fieldName);
return fieldNode.isArray() ? (ArrayNode) fieldNode : null;
}
// ==================== 工具方法 ====================
/**
* 判断是否是有效的 JSON
*/
public static boolean isValidJson(String json) {
if (StringUtils.isBlank(json)) {
return false;
}
try {
objectMapper.readTree(json);
return true;
} catch (IOException e) {
return false;
}
}
/**
* 比较两个 JSON 是否相等
*/
public static boolean jsonEquals(String json1, String json2) {
try {
JsonNode node1 = objectMapper.readTree(json1);
JsonNode node2 = objectMapper.readTree(json2);
return node1.equals(node2);
} catch (IOException e) {
return false;
}
}
/**
* JSON 去重(List)
*/
public static <T> List<T> deduplicateJsonList(List<T> list) {
if (list == null || list.isEmpty()) {
return list;
}
Set<String> seen = new HashSet<>();
List<T> result = new ArrayList<>();
for (T item : list) {
String json = toJson(item);
if (seen.add(json)) {
result.add(item);
}
}
return result;
}
}
4.2 实际使用场景
// 场景 1:HTTP 请求响应处理
@RestController
public class ApiController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
User user = userService.getById(id);
// 返回格式化 JSON
return JsonUtils.toPrettyJson(user);
}
@PostMapping("/user")
public Result createUser(@RequestBody String json) {
// JSON 转对象
User user = JsonUtils.fromJson(json, User.class);
userService.save(user);
return Result.success();
}
}
// 场景 2:动态字段处理
public class DynamicService {
public void saveDynamicData(String json) {
// 解析 JSON
JsonNode node = JsonUtils.readTree(json);
// 动态获取字段
String name = JsonUtils.getStringValue(node, "name");
Integer age = JsonUtils.getIntValue(node, "age");
Boolean active = JsonUtils.getBooleanValue(node, "active");
// 获取嵌套对象
JsonNode addressNode = node.get("address");
String city = JsonUtils.getStringValue(addressNode, "city");
// 获取数组
ArrayNode tagsNode = JsonUtils.getArrayNode(node, "tags");
List<String> tags = new ArrayList<>();
if (tagsNode != null) {
tagsNode.forEach(tag -> tags.add(tag.asText()));
}
// 保存数据
// ...
}
}
// 场景 3:第三方 API 对接
public class ThirdPartyService {
public UserInfo getUserInfo(String apiResponse) {
// 解析第三方返回的 JSON
Map<String, Object> map = JsonUtils.jsonToMap(apiResponse);
// 提取数据
UserInfo userInfo = new UserInfo();
userInfo.setId((String) map.get("id"));
userInfo.setName((String) map.get("name"));
userInfo.setEmail((String) map.get("email"));
return userInfo;
}
public List<Product> getProducts(String apiResponse) {
// JSON 转 List
return JsonUtils.fromJson(apiResponse, new TypeReference<List<Product>>() {});
}
}
(由于篇幅限制,这里展示前 4 个工具类,完整文章包含 11 个工具类)
5. 文件操作工具类
5.1 FileUtils 核心实现
package com.example.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
/**
* 文件操作工具类
*/
@Slf4j
public class FileUtils {
private FileUtils() {
throw new IllegalStateException("Utility class");
}
private static final int BUFFER_SIZE = 8192;
// ==================== 文件读取 ====================
/**
* 读取文件内容为字符串
*/
public static String readFileToString(String filePath) throws IOException {
return Files.readString(Paths.get(filePath));
}
/**
* 读取文件内容为字节数组
*/
public static byte[] readFileToBytes(String filePath) throws IOException {
return Files.readAllBytes(Paths.get(filePath));
}
/**
* 读取文件内容为行列表
*/
public static java.util.List<String> readLines(String filePath) throws IOException {
return Files.readAllLines(Paths.get(filePath));
}
// ==================== 文件写入 ====================
/**
* 写入字符串到文件
*/
public static void writeStringToFile(String filePath, String content) throws IOException {
Files.writeString(Paths.get(filePath), content);
}
/**
* 写入字节数组到文件
*/
public static void writeBytesToFile(String filePath, byte[] bytes) throws IOException {
Files.write(Paths.get(filePath), bytes);
}
/**
* 保存上传的文件
*/
public static String saveUploadedFile(MultipartFile file, String destDir) throws IOException {
if (file.isEmpty()) {
throw new IOException("上传文件为空");
}
// 创建目录
Path destPath = Paths.get(destDir);
if (!Files.exists(destPath)) {
Files.createDirectories(destPath);
}
// 生成文件名
String fileName = generateFileName(file.getOriginalFilename());
Path fullPath = destPath.resolve(fileName);
// 保存文件
Files.copy(file.getInputStream(), fullPath, StandardCopyOption.REPLACE_EXISTING);
return fullPath.toString();
}
// ==================== 文件操作 ====================
/**
* 复制文件
*/
public static void copyFile(String source, String dest) throws IOException {
Files.copy(Paths.get(source), Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
}
/**
* 移动文件
*/
public static void moveFile(String source, String dest) throws IOException {
Files.move(Paths.get(source), Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
}
/**
* 删除文件
*/
public static boolean deleteFile(String filePath) {
try {
return Files.deleteIfExists(Paths.get(filePath));
} catch (IOException e) {
log.error("删除文件失败:{}", filePath, e);
return false;
}
}
/**
* 删除目录(包括子文件)
*/
public static boolean deleteDirectory(String dirPath) throws IOException {
Path path = Paths.get(dirPath);
if (!Files.exists(path)) {
return false;
}
Files.walk(path)
.sorted((a, b) -> b.compareTo(a)) // 先删除子文件
.forEach(p -> {
try {
Files.delete(p);
} catch (IOException e) {
log.error("删除文件失败:{}", p, e);
}
});
return true;
}
// ==================== 文件信息 ====================
/**
* 获取文件大小(字节)
*/
public static long getFileSize(String filePath) throws IOException {
return Files.size(Paths.get(filePath));
}
/**
* 获取文件大小(格式化)
*/
public static String getFileSizeFormatted(String filePath) throws IOException {
return formatFileSize(getFileSize(filePath));
}
/**
* 格式化文件大小
*/
public static String formatFileSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.2f KB", size / 1024.0);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.2f MB", size / (1024.0 * 1024.0));
} else {
return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
/**
* 获取文件扩展名
*/
public static String getFileExtension(String fileName) {
if (fileName == null) {
return "";
}
int lastDot = fileName.lastIndexOf('.');
return lastDot > 0 ? fileName.substring(lastDot + 1).toLowerCase() : "";
}
/**
* 获取文件名(不含扩展名)
*/
public static String getFileNameWithoutExtension(String fileName) {
if (fileName == null) {
return "";
}
int lastDot = fileName.lastIndexOf('.');
int lastSep = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
String name = fileName.substring(lastSep + 1);
return lastDot > 0 ? name.substring(0, lastDot) : name;
}
// ==================== 压缩解压 ====================
/**
* 压缩文件为 ZIP
*/
public static void zipFiles(String[] sourceFiles, String zipFilePath) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
for (String sourceFile : sourceFiles) {
zipFile(zos, new File(sourceFile), new File(sourceFile).getName());
}
}
}
private static void zipFile(ZipOutputStream zos, File file, String fileName) throws IOException {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
zipFile(zos, f, fileName + "/" + f.getName());
}
}
} else {
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
try (FileInputStream fis = new FileInputStream(file)) {
fis.transferTo(zos);
}
zos.closeEntry();
}
}
/**
* 解压 ZIP 文件
*/
public static void unzipFile(String zipFilePath, String destDir) throws IOException {
Path destPath = Paths.get(destDir);
if (!Files.exists(destPath)) {
Files.createDirectories(destPath);
}
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
Path entryPath = destPath.resolve(entry.getName());
if (entry.isDirectory()) {
Files.createDirectories(entryPath);
} else {
Files.createDirectories(entryPath.getParent());
Files.copy(zis, entryPath, StandardCopyOption.REPLACE_EXISTING);
}
zis.closeEntry();
}
}
}
}
6. HTTP 请求工具类
6.1 HttpUtils 完整实现(基于 HttpClient)
package com.example.common.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
/**
* HTTP 请求工具类(基于 Java 11+ HttpClient)
*/
@Slf4j
public class HttpUtils {
private HttpUtils() {
throw new IllegalStateException("Utility class");
}
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
// ==================== GET 请求 ====================
/**
* GET 请求
*/
public static String get(String url) throws IOException, InterruptedException {
return get(url, null, null);
}
/**
* GET 请求(带参数)
*/
public static String get(String url, Map<String, String> params) throws IOException, InterruptedException {
return get(url, params, null);
}
/**
* GET 请求(带参数和请求头)
*/
public static String get(String url, Map<String, String> params, Map<String, String> headers)
throws IOException, InterruptedException {
String fullUrl = buildUrlWithParams(url, params);
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(fullUrl))
.GET()
.timeout(Duration.ofSeconds(30));
// 添加请求头
if (headers != null) {
headers.forEach(builder::header);
}
HttpRequest request = builder.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
log.debug("GET {} - Status: {}", fullUrl, response.statusCode());
if (response.statusCode() != 200) {
throw new IOException("HTTP GET failed: " + response.statusCode());
}
return response.body();
}
// ==================== POST 请求 ====================
/**
* POST 请求(JSON)
*/
public static String postJson(String url, String jsonBody) throws IOException, InterruptedException {
return post(url, jsonBody, "application/json");
}
/**
* POST 请求(表单)
*/
public static String postForm(String url, Map<String, String> formData) throws IOException, InterruptedException {
StringBuilder body = new StringBuilder();
if (formData != null) {
formData.forEach((key, value) -> {
if (body.length() > 0) {
body.append("&");
}
body.append(key).append("=").append(value);
});
}
return post(url, body.toString(), "application/x-www-form-urlencoded");
}
/**
* POST 请求(通用)
*/
public static String post(String url, String body, String contentType) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(body != null ? body : ""))
.timeout(Duration.ofSeconds(30))
.header("Content-Type", contentType)
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
log.debug("POST {} - Status: {}", url, response.statusCode());
if (response.statusCode() != 200 && response.statusCode() != 201) {
throw new IOException("HTTP POST failed: " + response.statusCode());
}
return response.body();
}
// ==================== 工具方法 ====================
/**
* 构建带参数的 URL
*/
private static String buildUrlWithParams(String url, Map<String, String> params) {
if (params == null || params.isEmpty()) {
return url;
}
StringBuilder sb = new StringBuilder(url);
boolean hasQuery = url.contains("?");
params.forEach((key, value) -> {
if (hasQuery) {
sb.append("&");
} else {
sb.append("?");
hasQuery = true;
}
sb.append(key).append("=").append(value);
});
return sb.toString();
}
/**
* 检查 URL 是否可访问
*/
public static boolean isUrlAccessible(String url) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.HEAD()
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<Void> response = httpClient.send(request, HttpResponse.BodyHandlers.discarding());
return response.statusCode() == 200;
} catch (Exception e) {
return false;
}
}
}
7-11. 其他工具类概览
由于篇幅限制,这里简要介绍其他工具类:
7. 加密解密工具类(CryptoUtils)
// MD5 加密
String md5 = CryptoUtils.md5("password");
// BCrypt 加密(推荐用于密码)
String hashed = CryptoUtils.bcryptHash("password");
boolean matches = CryptoUtils.bcryptCheck("password", hashed);
// AES 加密解密
String encrypted = CryptoUtils.aesEncrypt("data", "key");
String decrypted = CryptoUtils.aesDecrypt(encrypted, "key");
// Base64 编解码
String encoded = CryptoUtils.base64Encode("data");
String decoded = CryptoUtils.base64Decode(encoded);
8. Bean 转换工具类(BeanUtils)
// Map 转 Bean
User user = BeanUtils.mapToBean(map, User.class);
// Bean 转 Map
Map<String, Object> map = BeanUtils.beanToMap(user);
// Bean 复制
UserVO vo = BeanUtils.copyProperties(user, UserVO.class);
// List 转换
List<UserVO> voList = BeanUtils.copyList(userList, UserVO.class);
9. 验证工具类(ValidationUtils)
// 手机号验证
boolean valid = ValidationUtils.isValidPhone("13800138000");
// 邮箱验证
boolean valid = ValidationUtils.isValidEmail("test@example.com");
// 身份证验证
boolean valid = ValidationUtils.isValidIdCard("110101199001011234");
// URL 验证
boolean valid = ValidationUtils.isValidUrl("https://example.com");
// IP 地址验证
boolean valid = ValidationUtils.isValidIp("192.168.1.1");
10. 缓存工具类(CacheUtils)
// 设置缓存
CacheUtils.set("key", "value", 3600);
// 获取缓存
String value = CacheUtils.get("key");
// 删除缓存
CacheUtils.delete("key");
// 批量删除(pattern)
CacheUtils.deletePattern("user:*");
// 分布式锁
Lock lock = CacheUtils.getLock("lock:key");
lock.lock();
try {
// 业务逻辑
} finally {
lock.unlock();
}
11. Excel 处理工具类(ExcelUtils)
// 导出 Excel
ExcelUtils.export(dataList, "用户列表", response);
// 导入 Excel
List<User> users = ExcelUtils.importExcel(file.getInputStream(), User.class);
// 生成复杂报表
ExcelUtils.generateReport(templatePath, dataMap, outputPath);
12. 总结
12.1 工具类使用建议
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12.2 最佳实践
✅ 应该做的:
-
1. 统一工具类包路径(如 com.example.common.utils) -
2. 使用私有构造函数防止实例化 -
3. 添加完整的 JavaDoc 注释 -
4. 处理 null 值和边界情况 -
5. 记录关键日志 -
6. 编写单元测试
❌ 不应该做的:
-
1. 工具类中包含业务逻辑 -
2. 忽略异常处理 -
3. 返回 null 而不说明 -
4. 工具类之间循环依赖 -
5. 过度设计,方法过长
12.3 项目集成
<!-- Maven 依赖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common-utils</artifactId>
<version>1.0.0</version>
</dependency>
// Spring Boot 自动扫描
@SpringBootApplication(scanBasePackages = {"com.example.demo", "com.example.common"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
希望这篇文章能帮助你构建高效的工具类库!完整代码示例请关注项目仓库。
夜雨聆风