乐于分享
好东西不私藏

SpringBoot 高效工具类大全

SpringBoot 高效工具类大全

SpringBoot 高效工具类大全


目录

  1. 1. 引言:为什么需要工具类
  2. 2. 日期时间工具类
  3. 3. 字符串处理工具类
  4. 4. JSON 处理工具类
  5. 5. 文件操作工具类
  6. 6. HTTP 请求工具类
  7. 7. 加密解密工具类
  8. 8. Bean 转换工具类
  9. 9. 验证工具类
  10. 10. 缓存工具类
  11. 11. Excel 处理工具类
  12. 12. 总结

1. 引言:为什么需要工具类

1.1 工具类的价值

┌─────────────────────────────────────────────────────────────┐
│              工具类的核心价值                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ✅ 提高开发效率                                            │
│     - 避免重复造轮子                                        │
│     - 一行代码完成复杂操作                                  │
│                                                             │
│  ✅ 保证代码质量                                            │
│     - 统一处理边界情况                                      │
│     - 经过充分测试验证                                      │
│                                                             │
│  ✅ 降低维护成本                                            │
│     - 集中管理通用逻辑                                      │
│     - 修改一处,全局生效                                    │
│                                                             │
│  ✅ 提升代码可读性                                          │
│     - 语义化的方法名                                        │
│     - 减少样板代码                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 工具类设计原则

原则
说明
示例
单一职责
每个工具类只做一类事
DateUtils 只处理日期
静态方法
无需实例化,直接调用
DateUtils.format()
私有构造
防止被实例化
private DateUtils() {}
线程安全
支持并发调用
使用 ThreadLocal
异常处理
明确的异常策略
抛出或返回 null
文档完善
清晰的注释说明
JavaDoc 完整

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 工具类使用建议

场景
推荐工具类
日期处理
DateUtils
字符串操作
StringUtils
JSON 处理
JsonUtils
文件操作
FileUtils
HTTP 请求
HttpUtils
密码加密
CryptoUtils
对象转换
BeanUtils
数据验证
ValidationUtils
缓存操作
CacheUtils
Excel 处理
ExcelUtils

12.2 最佳实践

✅ 应该做的

  1. 1. 统一工具类包路径(如 com.example.common.utils)
  2. 2. 使用私有构造函数防止实例化
  3. 3. 添加完整的 JavaDoc 注释
  4. 4. 处理 null 值和边界情况
  5. 5. 记录关键日志
  6. 6. 编写单元测试

❌ 不应该做的

  1. 1. 工具类中包含业务逻辑
  2. 2. 忽略异常处理
  3. 3. 返回 null 而不说明
  4. 4. 工具类之间循环依赖
  5. 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);
    }
}

希望这篇文章能帮助你构建高效的工具类库!完整代码示例请关注项目仓库。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » SpringBoot 高效工具类大全

猜你喜欢

  • 暂无文章