02.SpringBoot常用Utils工具类详解

发布于:2025-07-02 ⋅ 阅读:(29) ⋅ 点赞:(0)

文章目录

1. BeanUtils详解

1.1 什么是BeanUtils?

BeanUtils是一个非常重要的工具类,主要用于JavaBean之间的属性拷贝。在实际开发中,我们经常需要在不同的对象之间复制属性值,比如Entity转DTO、VO转DTO等场景。

1.2 主要的BeanUtils实现

1.2.1 Spring BeanUtils

Spring框架提供的BeanUtils,性能较好,是最常用的选择。

1.2.2 Apache Commons BeanUtils

Apache提供的BeanUtils,功能更强大但性能相对较差。

1.2.3 其他实现
  • Dozer
  • MapStruct(编译时生成代码,性能最佳)
  • ModelMapper

1.3 Spring BeanUtils详细使用

1.3.1 基本用法
import org.springframework.beans.BeanUtils;

/**
 * 用户实体类
 */
public class User {
    private Long id;
    private String username;
    private String email;
    private String phone;
    private Integer age;
    private Date createTime;
    
    // 构造方法
    public User() {}
    
    public User(Long id, String username, String email, String phone, Integer age) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.phone = phone;
        this.age = age;
        this.createTime = new Date();
    }
    
    // getter和setter方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public Date getCreateTime() { return createTime; }
    public void setCreateTime(Date createTime) { this.createTime = createTime; }
    
    @Override
    public String toString() {
        return "User{id=" + id + ", username='" + username + "', email='" + email + 
               "', phone='" + phone + "', age=" + age + ", createTime=" + createTime + '}';
    }
}

/**
 * 用户DTO类
 */
public class UserDTO {
    private Long id;
    private String username;
    private String email;
    private String phone;
    private Integer age;
    private String createTimeStr; // 注意:这个字段名不同
    
    // 构造方法
    public UserDTO() {}
    
    // getter和setter方法...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public String getCreateTimeStr() { return createTimeStr; }
    public void setCreateTimeStr(String createTimeStr) { this.createTimeStr = createTimeStr; }
    
    @Override
    public String toString() {
        return "UserDTO{id=" + id + ", username='" + username + "', email='" + email + 
               "', phone='" + phone + "', age=" + age + ", createTimeStr='" + createTimeStr + "'}";
    }
}

/**
 * 基本拷贝示例
 */
public class BeanUtilsExample {
    
    public static void main(String[] args) {
        // 创建源对象
        User user = new User(1L, "张三", "zhangsan@example.com", "13800138000", 25);
        System.out.println("源对象:" + user);
        
        // 创建目标对象
        UserDTO userDTO = new UserDTO();
        
        // 执行属性拷贝
        BeanUtils.copyProperties(user, userDTO);
        
        System.out.println("拷贝后的目标对象:" + userDTO);
        System.out.println("注意:createTime没有被拷贝,因为目标对象中对应的是createTimeStr");
    }
}
1.3.2 指定忽略属性
public class BeanUtilsIgnoreExample {
    
    public static void main(String[] args) {
        User user = new User(1L, "李四", "lisi@example.com", "13900139000", 30);
        UserDTO userDTO = new UserDTO();
        
        // 拷贝时忽略指定属性
        BeanUtils.copyProperties(user, userDTO, "email", "phone");
        
        System.out.println("忽略email和phone后的拷贝结果:" + userDTO);
        // 输出:UserDTO{id=1, username='李四', email='null', phone='null', age=30, createTimeStr='null'}
    }
}
1.3.3 批量拷贝(列表转换)
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class BeanUtilsBatchExample {
    
    /**
     * 批量拷贝方法
     */
    public static <T> List<T> copyList(List<?> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.isEmpty()) {
            return new ArrayList<>();
        }
        
        return sourceList.stream().map(source -> {
            try {
                T target = targetClass.newInstance();
                BeanUtils.copyProperties(source, target);
                return target;
            } catch (Exception e) {
                throw new RuntimeException("对象拷贝失败", e);
            }
        }).collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        // 创建用户列表
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "张三", "zhangsan@example.com", "13800138000", 25));
        userList.add(new User(2L, "李四", "lisi@example.com", "13900139000", 30));
        userList.add(new User(3L, "王五", "wangwu@example.com", "13700137000", 28));
        
        System.out.println("原始用户列表:");
        userList.forEach(System.out::println);
        
        // 批量转换为DTO
        List<UserDTO> userDTOList = copyList(userList, UserDTO.class);
        
        System.out.println("\n转换后的DTO列表:");
        userDTOList.forEach(System.out::println);
    }
}

1.4 自定义BeanUtils工具类

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * 自定义Bean拷贝工具类
 */
public class BeanCopyUtils {
    
    /**
     * 单个对象拷贝
     * @param source 源对象
     * @param targetSupplier 目标对象供应器
     * @param <T> 目标对象类型
     * @return 拷贝后的目标对象
     */
    public static <T> T copyBean(Object source, Supplier<T> targetSupplier) {
        if (source == null) {
            return null;
        }
        T target = targetSupplier.get();
        BeanUtils.copyProperties(source, target);
        return target;
    }
    
    /**
     * 单个对象拷贝(指定忽略属性)
     * @param source 源对象
     * @param targetSupplier 目标对象供应器
     * @param ignoreProperties 忽略的属性名
     * @param <T> 目标对象类型
     * @return 拷贝后的目标对象
     */
    public static <T> T copyBean(Object source, Supplier<T> targetSupplier, String... ignoreProperties) {
        if (source == null) {
            return null;
        }
        T target = targetSupplier.get();
        BeanUtils.copyProperties(source, target, ignoreProperties);
        return target;
    }
    
    /**
     * 列表对象拷贝
     * @param sourceList 源对象列表
     * @param targetSupplier 目标对象供应器
     * @param <T> 目标对象类型
     * @return 拷贝后的目标对象列表
     */
    public static <T> List<T> copyBeanList(List<?> sourceList, Supplier<T> targetSupplier) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new ArrayList<>();
        }
        
        List<T> targetList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            T target = copyBean(source, targetSupplier);
            targetList.add(target);
        }
        return targetList;
    }
    
    /**
     * 列表对象拷贝(指定忽略属性)
     * @param sourceList 源对象列表
     * @param targetSupplier 目标对象供应器
     * @param ignoreProperties 忽略的属性名
     * @param <T> 目标对象类型
     * @return 拷贝后的目标对象列表
     */
    public static <T> List<T> copyBeanList(List<?> sourceList, Supplier<T> targetSupplier, String... ignoreProperties) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new ArrayList<>();
        }
        
        List<T> targetList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            T target = copyBean(source, targetSupplier, ignoreProperties);
            targetList.add(target);
        }
        return targetList;
    }
}

/**
 * 使用示例
 */
public class BeanCopyUtilsExample {
    
    public static void main(String[] args) {
        // 单个对象拷贝
        User user = new User(1L, "张三", "zhangsan@example.com", "13800138000", 25);
        UserDTO userDTO = BeanCopyUtils.copyBean(user, UserDTO::new);
        System.out.println("单个对象拷贝:" + userDTO);
        
        // 单个对象拷贝(忽略属性)
        UserDTO userDTO2 = BeanCopyUtils.copyBean(user, UserDTO::new, "email", "phone");
        System.out.println("忽略属性拷贝:" + userDTO2);
        
        // 列表拷贝
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "张三", "zhangsan@example.com", "13800138000", 25));
        userList.add(new User(2L, "李四", "lisi@example.com", "13900139000", 30));
        
        List<UserDTO> userDTOList = BeanCopyUtils.copyBeanList(userList, UserDTO::new);
        System.out.println("列表拷贝:");
        userDTOList.forEach(System.out::println);
    }
}

1.5 BeanUtils的局限性和注意事项

1.5.1 深拷贝 vs 浅拷贝
import java.util.List;
import java.util.ArrayList;

/**
 * 演示BeanUtils的浅拷贝特性
 */
public class User {
    private Long id;
    private String username;
    private List<String> hobbies; // 引用类型
    private Address address; // 自定义引用类型
    
    // 构造方法和getter/setter...
    public User() {}
    
    public User(Long id, String username) {
        this.id = id;
        this.username = username;
        this.hobbies = new ArrayList<>();
        this.address = new Address();
    }
    
    // getter和setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
}

class Address {
    private String province;
    private String city;
    
    public Address() {}
    
    public Address(String province, String city) {
        this.province = province;
        this.city = city;
    }
    
    // getter和setter
    public String getProvince() { return province; }
    public void setProvince(String province) { this.province = province; }
    
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    
    @Override
    public String toString() {
        return "Address{province='" + province + "', city='" + city + "'}";
    }
}

public class ShallowCopyExample {
    
    public static void main(String[] args) {
        // 创建源对象
        User sourceUser = new User(1L, "张三");
        sourceUser.getHobbies().add("篮球");
        sourceUser.getHobbies().add("足球");
        sourceUser.setAddress(new Address("北京", "北京市"));
        
        // 拷贝对象
        User targetUser = new User();
        BeanUtils.copyProperties(sourceUser, targetUser);
        
        System.out.println("拷贝前:");
        System.out.println("源对象地址:" + sourceUser.getAddress());
        System.out.println("目标对象地址:" + targetUser.getAddress());
        System.out.println("地址对象是否相同:" + (sourceUser.getAddress() == targetUser.getAddress()));
        
        // 修改源对象的引用类型属性
        sourceUser.getAddress().setCity("上海市");
        sourceUser.getHobbies().add("游泳");
        
        System.out.println("\n修改源对象后:");
        System.out.println("源对象地址:" + sourceUser.getAddress());
        System.out.println("目标对象地址:" + targetUser.getAddress());
        System.out.println("目标对象的地址也被修改了!这就是浅拷贝的问题");
    }
}
1.5.2 类型转换问题
/**
 * 演示类型转换问题
 */
public class TypeConversionExample {
    
    static class SourceBean {
        private String id; // String类型
        private String age; // String类型
        private Date createTime;
        
        public SourceBean(String id, String age, Date createTime) {
            this.id = id;
            this.age = age;
            this.createTime = createTime;
        }
        
        // getter和setter...
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getAge() { return age; }
        public void setAge(String age) { this.age = age; }
        
        public Date getCreateTime() { return createTime; }
        public void setCreateTime(Date createTime) { this.createTime = createTime; }
    }
    
    static class TargetBean {
        private Long id; // Long类型
        private Integer age; // Integer类型
        private String createTime; // String类型
        
        // getter和setter...
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
        
        public String getCreateTime() { return createTime; }
        public void setCreateTime(String createTime) { this.createTime = createTime; }
        
        @Override
        public String toString() {
            return "TargetBean{id=" + id + ", age=" + age + ", createTime='" + createTime + "'}";
        }
    }
    
    public static void main(String[] args) {
        SourceBean source = new SourceBean("123", "25", new Date());
        TargetBean target = new TargetBean();
        
        // BeanUtils不会进行类型转换
        BeanUtils.copyProperties(source, target);
        
        System.out.println("拷贝结果:" + target);
        // 输出:TargetBean{id=null, age=null, createTime='null'}
        // 所有属性都为null,因为类型不匹配
        
        System.out.println("String类型的id无法直接拷贝到Long类型");
        System.out.println("需要手动进行类型转换");
    }
}

1.6 BeanUtils性能对比

import org.springframework.beans.BeanUtils;
import org.apache.commons.beanutils.BeanUtils as ApacheBeanUtils;

/**
 * BeanUtils性能测试
 */
public class BeanUtilsPerformanceTest {
    
    private static final int TEST_COUNT = 100000;
    
    public static void main(String[] args) throws Exception {
        User sourceUser = new User(1L, "张三", "zhangsan@example.com", "13800138000", 25);
        
        // Spring BeanUtils性能测试
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < TEST_COUNT; i++) {
            UserDTO target = new UserDTO();
            BeanUtils.copyProperties(sourceUser, target);
        }
        long springTime = System.currentTimeMillis() - startTime;
        System.out.println("Spring BeanUtils耗时:" + springTime + "ms");
        
        // Apache BeanUtils性能测试
        startTime = System.currentTimeMillis();
        for (int i = 0; i < TEST_COUNT; i++) {
            UserDTO target = new UserDTO();
            ApacheBeanUtils.copyProperties(target, sourceUser);
        }
        long apacheTime = System.currentTimeMillis() - startTime;
        System.out.println("Apache BeanUtils耗时:" + apacheTime + "ms");
        
        // 手动拷贝性能测试
        startTime = System.currentTimeMillis();
        for (int i = 0; i < TEST_COUNT; i++) {
            UserDTO target = new UserDTO();
            target.setId(sourceUser.getId());
            target.setUsername(sourceUser.getUsername());
            target.setEmail(sourceUser.getEmail());
            target.setPhone(sourceUser.getPhone());
            target.setAge(sourceUser.getAge());
        }
        long manualTime = System.currentTimeMillis() - startTime;
        System.out.println("手动拷贝耗时:" + manualTime + "ms");
        
        System.out.println("\n性能对比:");
        System.out.println("Spring BeanUtils vs 手动拷贝:" + (springTime / (double) manualTime) + " 倍");
        System.out.println("Apache BeanUtils vs 手动拷贝:" + (apacheTime / (double) manualTime) + " 倍");
    }
}

2. StringUtils详解

2.1 什么是StringUtils?

StringUtils是处理字符串的工具类,提供了大量便捷的字符串操作方法。主要有Apache Commons Lang的StringUtils和Spring的StringUtils。

2.2 Apache Commons StringUtils

2.2.1 基本判断方法
import org.apache.commons.lang3.StringUtils;

/**
 * StringUtils基本判断方法示例
 */
public class StringUtilsBasicExample {
    
    public static void main(String[] args) {
        String str1 = null;
        String str2 = "";
        String str3 = "   ";
        String str4 = "hello";
        String str5 = "Hello World";
        
        System.out.println("=== 空值判断 ===");
        // isEmpty: 判断字符串是否为null或空字符串
        System.out.println("StringUtils.isEmpty(null): " + StringUtils.isEmpty(str1)); // true
        System.out.println("StringUtils.isEmpty(\"\"): " + StringUtils.isEmpty(str2)); // true
        System.out.println("StringUtils.isEmpty(\"   \"): " + StringUtils.isEmpty(str3)); // false
        System.out.println("StringUtils.isEmpty(\"hello\"): " + StringUtils.isEmpty(str4)); // false
        
        // isNotEmpty: 判断字符串是否不为null且不为空字符串
        System.out.println("StringUtils.isNotEmpty(\"hello\"): " + StringUtils.isNotEmpty(str4)); // true
        
        // isBlank: 判断字符串是否为null、空字符串或只包含空白字符
        System.out.println("\n=== 空白判断 ===");
        System.out.println("StringUtils.isBlank(null): " + StringUtils.isBlank(str1)); // true
        System.out.println("StringUtils.isBlank(\"\"): " + StringUtils.isBlank(str2)); // true
        System.out.println("StringUtils.isBlank(\"   \"): " + StringUtils.isBlank(str3)); // true
        System.out.println("StringUtils.isBlank(\"hello\"): " + StringUtils.isBlank(str4)); // false
        
        // isNotBlank: 判断字符串是否不为空白
        System.out.println("StringUtils.isNotBlank(\"hello\"): " + StringUtils.isNotBlank(str4)); // true
        System.out.println("StringUtils.isNotBlank(\"   \"): " + StringUtils.isNotBlank(str3)); // false
        
        System.out.println("\n=== 实际应用场景 ===");
        // 在实际开发中的应用
        String username = getUserInput(); // 模拟用户输入
        if (StringUtils.isNotBlank(username)) {
            System.out.println("用户名有效:" + username.trim());
        } else {
            System.out.println("请输入有效的用户名");
        }
    }
    
    private static String getUserInput() {
        // 模拟用户输入,可能为空或包含空格
        return "  admin  ";
    }
}
2.2.2 字符串操作方法
/**
 * StringUtils字符串操作方法示例
 */
public class StringUtilsOperationExample {
    
    public static void main(String[] args) {
        String str = "Hello World Java Programming";
        
        System.out.println("=== 字符串截取和填充 ===");
        // 安全的截取字符串(不会抛出IndexOutOfBoundsException)
        System.out.println("substring(str, 0, 5): " + StringUtils.substring(str, 0, 5)); // "Hello"
        System.out.println("substring(str, 6, 11): " + StringUtils.substring(str, 6, 11)); // "World"
        System.out.println("substring(str, 100): " + StringUtils.substring(str, 100)); // "" (不会报错)
        
        // 左填充和右填充
        String shortStr = "123";
        System.out.println("leftPad(\"123\", 8, '0'): " + StringUtils.leftPad(shortStr, 8, '0')); // "00000123"
        System.out.println("rightPad(\"123\", 8, '*'): " + StringUtils.rightPad(shortStr, 8, '*')); // "123*****"
        System.out.println("center(\"123\", 10, '-'): " + StringUtils.center(shortStr, 10, '-')); // "---123----"
        
        System.out.println("\n=== 字符串重复和反转 ===");
        // 重复字符串
        System.out.println("repeat(\"abc\", 3): " + StringUtils.repeat("abc", 3)); // "abcabcabc"
        System.out.println("repeat(\"*\", 10): " + StringUtils.repeat("*", 10)); // "**********"
        
        // 反转字符串
        System.out.println("reverse(\"hello\"): " + StringUtils.reverse("hello")); // "olleh"
        
        System.out.println("\n=== 大小写转换 ===");
        String mixedCase = "hELLo WoRLd";
        System.out.println("capitalize(str): " + StringUtils.capitalize(mixedCase)); // "HELLo WoRLd"
        System.out.println("uncapitalize(str): " + StringUtils.uncapitalize(mixedCase)); // "hELLo WoRLd"
        System.out.println("swapCase(str): " + StringUtils.swapCase(mixedCase)); // "HellO wOrld"
        
        System.out.println("\n=== 实际应用示例 ===");
        // 格式化订单号
        String orderNumber = "123";
        String formattedOrderNumber = StringUtils.leftPad(orderNumber, 10, '0');
        System.out.println("订单号格式化:" + formattedOrderNumber); // "0000000123"
        
        // 生成分隔线
        String separator = StringUtils.repeat("=", 50);
        System.out.println(separator);
        System.out.println(StringUtils.center("系统公告", 50, '='));
        System.out.println(separator);
    }
}
2.2.3 字符串查找和替换
/**
 * StringUtils查找和替换方法示例
 */
public class StringUtilsSearchReplaceExample {
    
    public static void main(String[] args) {
        String text = "Java is great, Java is powerful, Java is everywhere";
        
        System.out.println("=== 字符串查找 ===");
        // 查找子字符串
        System.out.println("contains(text, \"Java\"): " + StringUtils.contains(text, "Java")); // true
        System.out.println("containsIgnoreCase(text, \"java\"): " + StringUtils.containsIgnoreCase(text, "java")); // true
        
        // 统计子字符串出现次数
        System.out.println("countMatches(text, \"Java\"): " + StringUtils.countMatches(text, "Java")); // 3
        System.out.println("countMatches(text, \"is\"): " + StringUtils.countMatches(text, "is")); // 3
        
        // 查找位置
        System.out.println("indexOf(text, \"great\"): " + StringUtils.indexOf(text, "great")); // 8
        System.out.println("lastIndexOf(text, \"Java\"): " + StringUtils.lastIndexOf(text, "Java")); // 45
        
        System.out.println("\n=== 字符串替换 ===");
        // 替换所有匹配项
        String replaced1 = StringUtils.replace(text, "Java", "Python");
        System.out.println("replace Java with Python: " + replaced1);
        
        // 只替换前n个匹配项
        String replaced2 = StringUtils.replace(text, "Java", "Python", 2);
        System.out.println("replace first 2 Java with Python: " + replaced2);
        
        // 忽略大小写替换
        String replaced3 = StringUtils.replaceIgnoreCase(text, "java", "C++");
        System.out.println("replaceIgnoreCase java with C++: " + replaced3);
        
        System.out.println("\n=== 批量替换 ===");
        // 批量替换
        String[] searchArray = {"Java", "great", "powerful"};
        String[] replaceArray = {"Python", "awesome", "amazing"};
        String batchReplaced = StringUtils.replaceEach(text, searchArray, replaceArray);
        System.out.println("批量替换结果: " + batchReplaced);
        
        System.out.println("\n=== 实际应用示例 ===");
        // 敏感词过滤
        String userInput = "这是一个该死的测试文本,包含一些脏话";
        String[] sensitiveWords = {"该死", "脏话"};
        String[] replacements = {"***", "**"};
        String filteredText = StringUtils.replaceEach(userInput, sensitiveWords, replacements);
        System.out.println("敏感词过滤后: " + filteredText);
        
        // URL参数替换
        String urlTemplate = "https://api.example.com/users/{userId}/posts/{postId}";
        String finalUrl = StringUtils.replace(urlTemplate, "{userId}", "123");
        finalUrl = StringUtils.replace(finalUrl, "{postId}", "456");
        System.out.println("URL模板替换: " + finalUrl);
    }
}
2.2.4 字符串分割和连接
import java.util.Arrays;

/**
 * StringUtils分割和连接方法示例
 */
public class StringUtilsSplitJoinExample {
    
    public static void main(String[] args) {
        System.out.println("=== 字符串分割 ===");
        String csv = "apple,banana,orange,grape";
        String[] fruits = StringUtils.split(csv, ",");
        System.out.println("split CSV: " + Arrays.toString(fruits));
        
        // 按多个分隔符分割
        String mixedSeparators = "apple,banana;orange:grape";
        String[] mixedFruits = StringUtils.split(mixedSeparators, ",;:");
        System.out.println("split by multiple separators: " + Arrays.toString(mixedFruits));
        
        // 分割并限制结果数量
        String longText = "one,two,three,four,five";
        String[] limitedSplit = StringUtils.split(longText, ",", 3);
        System.out.println("split with limit 3: " + Arrays.toString(limitedSplit));
        
        // 按空白字符分割
        String sentence = "Hello   world    java   programming";
        String[] words = StringUtils.split(sentence);
        System.out.println("split by whitespace: " + Arrays.toString(words));
        
        System.out.println("\n=== 字符串连接 ===");
        // 简单连接
        String[] animals = {"cat", "dog", "bird", "fish"};
        String joined1 = StringUtils.join(animals, ", ");
        System.out.println("join with comma: " + joined1);
        
        // 连接数组的部分元素
        String joined2 = StringUtils.join(animals, " | ", 1, 3);
        System.out.println("join partial array: " + joined2); // "dog | bird"
        
        // 连接集合
        java.util.List<String> list = Arrays.asList("red", "green", "blue");
        String joined3 = StringUtils.join(list, " - ");
        System.out.println("join list: " + joined3);
        
        System.out.println("\n=== 实际应用示例 ===");
        // 处理用户输入的标签
        String userTags = "Java, Spring,   MyBatis,  ,   Redis,";
        String[] tagArray = StringUtils.split(userTags, ",");
        // 清理空白和空字符串
        java.util.List<String> cleanTags = new java.util.ArrayList<>();
        for (String tag : tagArray) {
            String cleanTag = StringUtils.trim(tag);
            if (StringUtils.isNotBlank(cleanTag)) {
                cleanTags.add(cleanTag);
            }
        }
        String finalTags = StringUtils.join(cleanTags, ", ");
        System.out.println("清理后的标签: " + finalTags);
        
        // 构建SQL IN查询
        String[] userIds = {"1", "2", "3", "4", "5"};
        String inClause = "'" + StringUtils.join(userIds, "', '") + "'";
        String sql = "SELECT * FROM users WHERE id IN (" + inClause + ")";
        System.out.println("生成的SQL: " + sql);
    }
}
2.2.5 字符串去除和修剪
/**
 * StringUtils去除和修剪方法示例
 */
public class StringUtilsTrimExample {
    
    public static void main(String[] args) {
        System.out.println("=== 基本修剪操作 ===");
        String str1 = "   hello world   ";
        String str2 = "\t\n  hello world  \r\n";
        String str3 = null;
        
        // 安全的trim(处理null值)
        System.out.println("trim(\"   hello world   \"): '" + StringUtils.trim(str1) + "'");
        System.out.println("trim(null): '" + StringUtils.trim(str3) + "'"); // null
        System.out.println("trimToEmpty(null): '" + StringUtils.trimToEmpty(str3) + "'"); // ""
        System.out.println("trimToNull(\"   \"): " + StringUtils.trimToNull("   ")); // null
        
        // 去除所有空白字符
        System.out.println("deleteWhitespace(str): '" + StringUtils.deleteWhitespace(str2) + "'"); // "helloworld"
        
        System.out.println("\n=== 自定义字符去除 ===");
        String str4 = "xxxhello worldxxx";
        String str5 = "abc123def";
        
        // 去除指定字符
        System.out.println("strip(\"xxxhello worldxxx\", \"x\"): '" + StringUtils.strip(str4, "x") + "'");
        System.out.println("stripStart(\"xxxhello worldxxx\", \"x\"): '" + StringUtils.stripStart(str4, "x") + "'");
        System.out.println("stripEnd(\"xxxhello worldxxx\", \"x\"): '" + StringUtils.stripEnd(str4, "x") + "'");
        
        // 去除数字
        System.out.println("stripDigits(\"abc123def\"): '" + removeDigits(str5) + "'");
        
        System.out.println("\n=== 实际应用示例 ===");
        // 清理用户输入
        String userInput = "  admin@example.com  ";
        String cleanEmail = StringUtils.trimToEmpty(userInput).toLowerCase();
        System.out.println("清理后的邮箱: '" + cleanEmail + "'");
        
        // 清理文件路径
        String filePath = "///path//to///file.txt///";
        String cleanPath = StringUtils.strip(filePath, "/");
        System.out.println("清理后的路径: '" + cleanPath + "'");
    }
    
    private static String removeDigits(String str) {
        if (str == null) return null;
        return str.replaceAll("\\d", "");
    }
}
2.2.6 字符串比较
/**
 * StringUtils比较方法示例
 */
public class StringUtilsCompareExample {
    
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        String str3 = "hello";
        String str4 = null;
        String str5 = "";
        
        System.out.println("=== 基本比较 ===");
        // 安全的equals比较(处理null)
        System.out.println("equals(\"hello\", \"hello\"): " + StringUtils.equals(str1, str3)); // true
        System.out.println("equals(\"hello\", \"Hello\"): " + StringUtils.equals(str1, str2)); // false
        System.out.println("equals(null, null): " + StringUtils.equals(str4, str4)); // true
        System.out.println("equals(\"hello\", null): " + StringUtils.equals(str1, str4)); // false
        
        // 忽略大小写比较
        System.out.println("equalsIgnoreCase(\"hello\", \"Hello\"): " + StringUtils.equalsIgnoreCase(str1, str2)); // true
        
        // 比较任意一个
        System.out.println("equalsAny(\"hello\", \"world\", \"hello\", \"java\"): " + 
                         StringUtils.equalsAny(str1, "world", "hello", "java")); // true
        
        System.out.println("\n=== 字符串相似度 ===");
        String text1 = "programming";
        String text2 = "programing"; // 少了一个m
        String text3 = "program";
        
        // 计算编辑距离
        int distance1 = StringUtils.getLevenshteinDistance(text1, text2);
        int distance2 = StringUtils.getLevenshteinDistance(text1, text3);
        System.out.println("编辑距离 \"programming\" vs \"programing\": " + distance1); // 1
        System.out.println("编辑距离 \"programming\" vs \"program\": " + distance2); // 4
        
        // 获取相同前缀
        String prefix = StringUtils.getCommonPrefix("hello", "help", "healthy");
        System.out.println("共同前缀: '" + prefix + "'"); // "hel"
        
        System.out.println("\n=== 实际应用示例 ===");
        // 用户名验证
        String inputUsername = "Admin";
        String[] existingUsers = {"admin", "user1", "test"};
        
        boolean userExists = false;
        for (String existing : existingUsers) {
            if (StringUtils.equalsIgnoreCase(inputUsername, existing)) {
                userExists = true;
                break;
            }
        }
        System.out.println("用户名 '" + inputUsername + "' 是否存在: " + userExists);
        
        // 模糊搜索建议
        String searchTerm = "jav";
        String[] technologies = {"Java", "JavaScript", "Python", "C++", "Ruby"};
        System.out.println("搜索建议(包含 '" + searchTerm + "'):");
        for (String tech : technologies) {
            if (StringUtils.containsIgnoreCase(tech, searchTerm)) {
                System.out.println("  - " + tech);
            }
        }
    }
}

2.3 Spring StringUtils

import org.springframework.util.StringUtils;

/**
 * Spring StringUtils示例
 */
public class SpringStringUtilsExample {
    
    public static void main(String[] args) {
        System.out.println("=== Spring StringUtils基本方法 ===");
        
        String str1 = "hello,world,java";
        String str2 = "  hello world  ";
        String str3 = "user/profile/settings";
        
        // 判断是否有文本(相当于Apache的isNotBlank)
        System.out.println("hasText(\"  hello world  \"): " + StringUtils.hasText(str2)); // true
        System.out.println("hasText(\"   \"): " + StringUtils.hasText("   ")); // false
        System.out.println("hasText(null): " + StringUtils.hasText(null)); // false
        
        // 判断是否有长度(相当于Apache的isNotEmpty)
        System.out.println("hasLength(\"\"): " + StringUtils.hasLength("")); // false
        System.out.println("hasLength(\"hello\"): " + StringUtils.hasLength("hello")); // true
        
        // 字符串分割(返回数组)
        String[] tokens1 = StringUtils.commaDelimitedListToStringArray(str1);
        System.out.println("commaDelimitedListToStringArray: " + java.util.Arrays.toString(tokens1));
        
        // 字符串分割(指定分隔符)
        String[] tokens2 = StringUtils.delimitedListToStringArray(str3, "/");
        System.out.println("delimitedListToStringArray: " + java.util.Arrays.toString(tokens2));
        
        // 数组转逗号分隔字符串
        String[] array = {"apple", "banana", "orange"};
        String joined = StringUtils.arrayToCommaDelimitedString(array);
        System.out.println("arrayToCommaDelimitedString: " + joined);
        
        System.out.println("\n=== 路径和文件操作 ===");
        String filePath = "/path/to/file.txt";
        String fileName = "document.pdf";
        String extension = ".java";
        
        // 获取文件名
        System.out.println("getFilename(\"/path/to/file.txt\"): " + StringUtils.getFilename(filePath));
        
        // 获取文件扩展名
        System.out.println("getFilenameExtension(\"document.pdf\"): " + StringUtils.getFilenameExtension(fileName));
        
        // 去除文件扩展名
        System.out.println("stripFilenameExtension(\"document.pdf\"): " + StringUtils.stripFilenameExtension(fileName));
        
        // 清理路径
        String messyPath = "/path/../to/./file.txt";
        System.out.println("cleanPath: " + StringUtils.cleanPath(messyPath));
        
        System.out.println("\n=== 实际应用示例 ===");
        // 配置解析
        String configValue = "jdbc.driver, jdbc.url, jdbc.username, jdbc.password";
        String[] configKeys = StringUtils.commaDelimitedListToStringArray(configValue);
        System.out.println("配置项解析:");
        for (String key : configKeys) {
            System.out.println("  - " + key.trim());
        }
        
        // 文件上传处理
        String uploadFileName = "user_avatar.png";
        String fileExtension = StringUtils.getFilenameExtension(uploadFileName);
        if (StringUtils.hasText(fileExtension)) {
            if ("jpg,jpeg,png,gif".contains(fileExtension.toLowerCase())) {
                System.out.println("文件类型有效: " + fileExtension);
            } else {
                System.out.println("不支持的文件类型: " + fileExtension);
            }
        }
    }
}

3. CollectionUtils详解

3.1 什么是CollectionUtils?

CollectionUtils是用于处理集合(Collection)的工具类,提供了许多便捷的集合操作方法。主要有Apache Commons Collections和Spring的CollectionUtils。

3.2 Apache Commons CollectionUtils

3.2.1 基本集合操作
import org.apache.commons.collections4.CollectionUtils;
import java.util.*;

/**
 * CollectionUtils基本操作示例
 */
public class CollectionUtilsBasicExample {
    
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("a", "b", "c", "d");
        List<String> list2 = Arrays.asList("c", "d", "e", "f");
        List<String> emptyList = new ArrayList<>();
        List<String> nullList = null;
        
        System.out.println("=== 集合判断 ===");
        // 判断集合是否为空
        System.out.println("isEmpty(emptyList): " + CollectionUtils.isEmpty(emptyList)); // true
        System.out.println("isEmpty(nullList): " + CollectionUtils.isEmpty(nullList)); // true
        System.out.println("isEmpty(list1): " + CollectionUtils.isEmpty(list1)); // false
        
        // 判断集合是否不为空
        System.out.println("isNotEmpty(list1): " + CollectionUtils.isNotEmpty(list1)); // true
        
        // 获取集合大小(安全)
        System.out.println("size(list1): " + CollectionUtils.size(list1)); // 4
        System.out.println("size(nullList): " + CollectionUtils.size(nullList)); // 0
        
        System.out.println("\n=== 集合运算 ===");
        // 交集
        Collection<String> intersection = CollectionUtils.intersection(list1, list2);
        System.out.println("交集 list1 ∩ list2: " + intersection); // [c, d]
        
        // 并集
        Collection<String> union = CollectionUtils.union(list1, list2);
        System.out.println("并集 list1 ∪ list2: " + union); // [a, b, c, d, e, f]
        
        // 差集(list1中有但list2中没有的元素)
        Collection<String> subtract = CollectionUtils.subtract(list1, list2);
        System.out.println("差集 list1 - list2: " + subtract); // [a, b]
        
        // 对称差集(两个集合中不共同拥有的元素)
        Collection<String> disjunction = CollectionUtils.disjunction(list1, list2);
        System.out.println("对称差集: " + disjunction); // [a, b, e, f]
        
        System.out.println("\n=== 实际应用示例 ===");
        // 用户权限管理
        List<String> userPermissions = Arrays.asList("read", "write", "delete");
        List<String> requiredPermissions = Arrays.asList("read", "write");
        
        // 检查用户是否拥有所需权限
        boolean hasAllPermissions = CollectionUtils.containsAll(userPermissions, requiredPermissions);
        System.out.println("用户是否拥有所需权限: " + hasAllPermissions);
        
        // 找出缺少的权限
        Collection<String> missingPermissions = CollectionUtils.subtract(requiredPermissions, userPermissions);
        if (CollectionUtils.isNotEmpty(missingPermissions)) {
            System.out.println("缺少权限: " + missingPermissions);
        } else {
            System.out.println("权限充足");
        }
        
        // 商品标签管理
        List<String> productTags = Arrays.asList("electronics", "mobile", "smartphone", "android");
        List<String> searchTags = Arrays.asList("mobile", "ios");
        
        Collection<String> matchedTags = CollectionUtils.intersection(productTags, searchTags);
        System.out.println("匹配的标签: " + matchedTags);
        
        if (CollectionUtils.isNotEmpty(matchedTags)) {
            System.out.println("商品与搜索条件匹配");
        } else {
            System.out.println("商品与搜索条件不匹配");
        }
    }
}
3.2.2 集合转换和过滤
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import java.util.*;

/**
 * CollectionUtils转换和过滤示例
 */
public class CollectionUtilsTransformExample {
    
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<String> words = Arrays.asList("hello", "world", "java", "programming", "collection");
        
        System.out.println("=== 集合过滤 ===");
        // 过滤偶数
        Collection<Integer> evenNumbers = CollectionUtils.select(numbers, new Predicate<Integer>() {
            @Override
            public boolean evaluate(Integer number) {
                return number % 2 == 0;
            }
        });
        System.out.println("偶数: " + evenNumbers); // [2, 4, 6, 8, 10]
        
        // 使用Lambda表达式(Java 8+)
        List<Integer> oddNumbers = new ArrayList<>();
        CollectionUtils.select(numbers, n -> n % 2 == 1, oddNumbers);
        System.out.println("奇数: " + oddNumbers); // [1, 3, 5, 7, 9]
        
        // 过滤长度大于4的单词
        Collection<String> longWords = CollectionUtils.select(words, new Predicate<String>() {
            @Override
            public boolean evaluate(String word) {
                return word.length() > 4;
            }
        });
        System.out.println("长单词: " + longWords); // [hello, world, programming, collection]
        
        System.out.println("\n=== 集合转换 ===");
        // 数字平方转换
        Collection<Integer> squares = CollectionUtils.collect(numbers, new Transformer<Integer, Integer>() {
            @Override
            public Integer transform(Integer number) {
                return number * number;
            }
        });
        System.out.println("平方数: " + squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
        
        // 字符串转大写
        Collection<String> upperWords = CollectionUtils.collect(words, new Transformer<String, String>() {
            @Override
            public String transform(String word) {
                return word.toUpperCase();
            }
        });
        System.out.println("大写单词: " + upperWords);
        
        System.out.println("\n=== 组合操作 ===");
        // 先过滤再转换:获取偶数的平方
        Collection<Integer> evenSquares = CollectionUtils.collect(
            CollectionUtils.select(numbers, n -> n % 2 == 0),
            n -> n * n
        );
        System.out.println("偶数的平方: " + evenSquares); // [4, 16, 36, 64, 100]
        
        System.out.println("\n=== 实际应用示例 ===");
        // 用户数据处理
        List<User> users = createSampleUsers();
        
        // 过滤成年用户
        Collection<User> adults = CollectionUtils.select(users, user -> user.getAge() >= 18);
        System.out.println("成年用户数量: " + adults.size());
        
        // 提取用户名
        Collection<String> usernames = CollectionUtils.collect(users, User::getUsername);
        System.out.println("用户名列表: " + usernames);
        
        // 获取成年用户的邮箱
        Collection<String> adultEmails = CollectionUtils.collect(
            CollectionUtils.select(users, user -> user.getAge() >= 18),
            User::getEmail
        );
        System.out.println("成年用户邮箱: " + adultEmails);
    }
    
    private static List<User> createSampleUsers() {
        List<User> users = new ArrayList<>();
        users.add(new User(1L, "张三", "zhangsan@example.com", 25));
        users.add(new User(2L, "李四", "lisi@example.com", 17));
        users.add(new User(3L, "王五", "wangwu@example.com", 30));
        users.add(new User(4L, "赵六", "zhaoliu@example.com", 16));
        return users;
    }
    
    static class User {
        private Long id;
        private String username;
        private String email;
        private Integer age;
        
        public User(Long id, String username, String email, Integer age) {
            this.id = id;
            this.username = username;
            this.email = email;
            this.age = age;
        }
        
        // getters
        public Long getId() { return id; }
        public String getUsername() { return username; }
        public String getEmail() { return email; }
        public Integer getAge() { return age; }
        
        @Override
        public String toString() {
            return "User{id=" + id + ", username='" + username + "', email='" + email + "', age=" + age + '}';
        }
    }
}
3.2.3 集合统计和分组
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.Bag;
import java.util.*;

/**
 * CollectionUtils统计和分组示例
 */
public class CollectionUtilsStatisticsExample {
    
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "apple", "orange", "banana", "apple", "grape");
        List<Integer> scores = Arrays.asList(85, 92, 78, 96, 88, 92, 85, 78, 96);
        
        System.out.println("=== 元素计数 ===");
        // 使用Bag进行计数
        Bag<String> fruitBag = new HashBag<>(fruits);
        System.out.println("水果统计:");
        for (String fruit : fruitBag.uniqueSet()) {
            System.out.println("  " + fruit + ": " + fruitBag.getCount(fruit));
        }
        
        // 手动计数
        Map<Integer, Integer> scoreCount = new HashMap<>();
        for (Integer score : scores) {
            scoreCount.put(score, scoreCount.getOrDefault(score, 0) + 1);
        }
        System.out.println("\n分数统计: " + scoreCount);
        
        System.out.println("\n=== 集合比较 ===");
        List<String> list1 = Arrays.asList("a", "b", "c");
        List<String> list2 = Arrays.asList("a", "b", "c");
        List<String> list3 = Arrays.asList("a", "b", "d");
        
        // 集合相等比较
        System.out.println("isEqualCollection(list1, list2): " + CollectionUtils.isEqualCollection(list1, list2)); // true
        System.out.println("isEqualCollection(list1, list3): " + CollectionUtils.isEqualCollection(list1, list3)); // false
        
        // 获取基数(去重后的大小)
        System.out.println("fruits cardinality: " + CollectionUtils.cardinality("apple", fruits)); // 3
        
        System.out.println("\n=== 实际应用示例 ===");
        // 电商订单统计
        List<Order> orders = createSampleOrders();
        
        // 按状态分组统计
        Map<String, Integer> statusCount = new HashMap<>();
        for (Order order : orders) {
            statusCount.put(order.getStatus(), statusCount.getOrDefault(order.getStatus(), 0) + 1);
        }
        System.out.println("订单状态统计: " + statusCount);
        
        // 统计总金额
        double totalAmount = orders.stream().mapToDouble(Order::getAmount).sum();
        System.out.println("订单总金额: " + totalAmount);
        
        // 按金额范围分组
        Map<String, List<Order>> amountGroups = new HashMap<>();
        amountGroups.put("low", new ArrayList<>());    // 0-100
        amountGroups.put("medium", new ArrayList<>());  // 100-500
        amountGroups.put("high", new ArrayList<>());    // 500+
        
        for (Order order : orders) {
            if (order.getAmount() < 100) {
                amountGroups.get("low").add(order);
            } else if (order.getAmount() < 500) {
                amountGroups.get("medium").add(order);
            } else {
                amountGroups.get("high").add(order);
            }
        }
        
        System.out.println("订单金额分组:");
        for (Map.Entry<String, List<Order>> entry : amountGroups.entrySet()) {
            System.out.println("  " + entry.getKey() + ": " + entry.getValue().size() + " 个订单");
        }
    }
    
    private static List<Order> createSampleOrders() {
        List<Order> orders = new ArrayList<>();
        orders.add(new Order(1L, "pending", 89.99));
        orders.add(new Order(2L, "completed", 299.99));
        orders.add(new Order(3L, "pending", 159.99));
        orders.add(new Order(4L, "cancelled", 599.99));
        orders.add(new Order(5L, "completed", 79.99));
        orders.add(new Order(6L, "completed", 899.99));
        return orders;
    }
    
    static class Order {
        private Long id;
        private String status;
        private Double amount;
        
        public Order(Long id, String status, Double amount) {
            this.id = id;
            this.status = status;
            this.amount = amount;
        }
        
        public Long getId() { return id; }
        public String getStatus() { return status; }
        public Double getAmount() { return amount; }
        
        @Override
        public String toString() {
            return "Order{id=" + id + ", status='" + status + "', amount=" + amount + '}';
        }
    }
}

3.3 Spring CollectionUtils

import org.springframework.util.CollectionUtils;
import java.util.*;

/**
 * Spring CollectionUtils示例
 */
public class SpringCollectionUtilsExample {
    
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("a", "b", "c");
        List<String> list2 = Arrays.asList("c", "d", "e");
        List<String> emptyList = new ArrayList<>();
        List<String> nullList = null;
        
        System.out.println("=== 基本判断 ===");
        // 判断集合是否为空
        System.out.println("isEmpty(emptyList): " + CollectionUtils.isEmpty(emptyList)); // true
        System.out.println("isEmpty(nullList): " + CollectionUtils.isEmpty(nullList)); // true
        System.out.println("isEmpty(list1): " + CollectionUtils.isEmpty(list1)); // false
        
        System.out.println("\n=== 集合合并 ===");
        // 合并数组到集合
        String[] array = {"x", "y", "z"};
        List<String> mergedList = new ArrayList<>(list1);
        CollectionUtils.mergeArrayIntoCollection(array, mergedList);
        System.out.println("合并后的集合: " + mergedList); // [a, b, c, x, y, z]
        
        // 合并Properties
        Properties props1 = new Properties();
        props1.setProperty("key1", "value1");
        props1.setProperty("key2", "value2");
        
        Properties props2 = new Properties();
        props2.setProperty("key2", "newValue2"); // 会覆盖
        props2.setProperty("key3", "value3");
        
        CollectionUtils.mergePropertiesIntoMap(props1, props2);
        System.out.println("合并后的Properties: " + props2);
        
        System.out.println("\n=== 集合转换 ===");
        // 集合转数组
        String[] arrayFromList = list1.toArray(new String[0]);
        System.out.println("集合转数组: " + Arrays.toString(arrayFromList));
        
        System.out.println("\n=== 实际应用示例 ===");
        // 配置管理
        Properties defaultConfig = new Properties();
        defaultConfig.setProperty("timeout", "30");
        defaultConfig.setProperty("retries", "3");
        defaultConfig.setProperty("debug", "false");
        
        Properties userConfig = new Properties();
        userConfig.setProperty("timeout", "60"); // 用户自定义超时时间
        userConfig.setProperty("host", "localhost"); // 用户添加的配置
        
        // 合并配置(用户配置优先)
        Properties finalConfig = new Properties();
        CollectionUtils.mergePropertiesIntoMap(defaultConfig, finalConfig);
        CollectionUtils.mergePropertiesIntoMap(userConfig, finalConfig);
        
        System.out.println("最终配置:");
        for (Object key : finalConfig.keySet()) {
            System.out.println("  " + key + " = " + finalConfig.getProperty((String) key));
        }
        
        // 数据验证
        List<String> requiredFields = Arrays.asList("username", "email", "password");
        Map<String, String> formData = new HashMap<>();
        formData.put("username", "admin");
        formData.put("email", "admin@example.com");
        // 缺少password字段
        
        List<String> missingFields = new ArrayList<>();
        for (String field : requiredFields) {
            if (!formData.containsKey(field) || formData.get(field) == null || formData.get(field).trim().isEmpty()) {
                missingFields.add(field);
            }
        }
        
        if (CollectionUtils.isEmpty(missingFields)) {
            System.out.println("表单验证通过");
        } else {
            System.out.println("缺少必填字段: " + missingFields);
        }
    }
}

4. DateUtils详解

4.1 什么是DateUtils?

DateUtils是用于处理日期和时间的工具类。Java 8之前主要使用Apache Commons Lang的DateUtils,Java 8之后推荐使用新的时间API(LocalDate、LocalDateTime等)。

4.2 Apache Commons DateUtils

4.2.1 日期基本操作
import org.apache.commons.lang3.time.DateUtils;
import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;

/**
 * DateUtils基本操作示例
 */
public class DateUtilsBasicExample {
    
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    public static void main(String[] args) throws Exception {
        Date now = new Date();
        System.out.println("当前时间: " + sdf.format(now));
        
        System.out.println("\n=== 日期加减操作 ===");
        // 添加天数
        Date tomorrow = DateUtils.addDays(now, 1);
        Date yesterday = DateUtils.addDays(now, -1);
        System.out.println("明天: " + sdf.format(tomorrow));
        System.out.println("昨天: " + sdf.format(yesterday));
        
        // 添加小时
        Date nextHour = DateUtils.addHours(now, 1);
        Date prevHour = DateUtils.addHours(now, -1);
        System.out.println("一小时后: " + sdf.format(nextHour));
        System.out.println("一小时前: " + sdf.format(prevHour));
        
        // 添加月份
        Date nextMonth = DateUtils.addMonths(now, 1);
        Date lastMonth = DateUtils.addMonths(now, -1);
        System.out.println("下个月: " + sdf.format(nextMonth));
        System.out.println("上个月: " + sdf.format(lastMonth));
        
        // 添加年份
        Date nextYear = DateUtils.addYears(now, 1);
        System.out.println("明年: " + sdf.format(nextYear));
        
        System.out.println("\n=== 日期设置操作 ===");
        // 设置时间为当天开始(00:00:00)
        Date startOfDay = DateUtils.truncate(now, Calendar.DAY_OF_MONTH);
        System.out.println("今天开始: " + sdf.format(startOfDay));
        
        // 设置为当月开始
        Date startOfMonth = DateUtils.truncate(now, Calendar.MONTH);
        System.out.println("本月开始: " + sdf.format(startOfMonth));
        
        // 设置为当年开始
        Date startOfYear = DateUtils.truncate(now, Calendar.YEAR);
        System.out.println("今年开始: " + sdf.format(startOfYear));
        
        // 设置具体时间
        Date specificTime = DateUtils.setHours(now, 14);
        specificTime = DateUtils.setMinutes(specificTime, 30);
        specificTime = DateUtils.setSeconds(specificTime, 0);
        System.out.println("设置为14:30:00: " + sdf.format(specificTime));
        
        System.out.println("\n=== 实际应用示例 ===");
        // 计算生日是否在本月
        Date birthday = sdf.parse("1990-03-15 10:30:00");
        Date birthdayThisYear = DateUtils.setYears(birthday, Calendar.getInstance().get(Calendar.YEAR));
        Date startOfThisMonth = DateUtils.truncate(now, Calendar.MONTH);
        Date endOfThisMonth = DateUtils.addMonths(startOfThisMonth, 1);
        
        boolean birthdayThisMonth = birthdayThisYear.after(startOfThisMonth) && birthdayThisYear.before(endOfThisMonth);
        System.out.println("生日是否在本月: " + birthdayThisMonth);
        
        // 计算工作日(简单示例:排除周末)
        Date checkDate = DateUtils.addDays(now, 1);
        Calendar cal = Calendar.getInstance();
        cal.setTime(checkDate);
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        boolean isWorkday = dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY;
        System.out.println("明天是否为工作日: " + isWorkday);
    }
}
4.2.2 日期解析和格式化
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.Date;
import java.text.ParseException;

/**
 * DateUtils解析和格式化示例
 */
public class DateUtilsParseExample {
    
    public static void main(String[] args) throws ParseException {
        System.out.println("=== 日期解析 ===");
        
        // 解析多种格式的日期字符串
        String[] parsePatterns = {
            "yyyy-MM-dd",
            "yyyy/MM/dd",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy/MM/dd HH:mm:ss",
            "dd/MM/yyyy",
            "MM/dd/yyyy"
        };
        
        String[] dateStrings = {
            "2023-12-25",
            "2023/12/25",
            "2023-12-25 15:30:45",
            "2023/12/25 15:30:45",
            "25/12/2023",
            "12/25/2023"
        };
        
        for (String dateStr : dateStrings) {
            try {
                Date parsedDate = DateUtils.parseDate(dateStr, parsePatterns);
                System.out.println("解析 '" + dateStr + "' -> " + DateFormatUtils.format(parsedDate, "yyyy-MM-dd HH:mm:ss"));
            } catch (ParseException e) {
                System.out.println("无法解析: " + dateStr);
            }
        }
        
        System.out.println("\n=== 日期格式化 ===");
        Date now = new Date();
        
        // 常用格式化
        System.out.println("标准格式: " + DateFormatUtils.format(now, "yyyy-MM-dd HH:mm:ss"));
        System.out.println("日期格式: " + DateFormatUtils.format(now, "yyyy年MM月dd日"));
        System.out.println("时间格式: " + DateFormatUtils.format(now, "HH:mm:ss"));
        System.out.println("ISO格式: " + DateFormatUtils.ISO_DATETIME_FORMAT.format(now));
        System.out.println("RFC822格式: " + DateFormatUtils.SMTP_DATETIME_FORMAT.format(now));
        
        System.out.println("\n=== 实际应用示例 ===");
        // 用户输入的日期解析
        String userInput = "2023-12-25";
        try {
            Date userDate = DateUtils.parseDate(userInput, parsePatterns);
            System.out.println("用户输入日期: " + DateFormatUtils.format(userDate, "yyyy年MM月dd日"));
            
            // 检查是否是未来日期
            if (userDate.after(new Date())) {
                System.out.println("这是一个未来日期");
            } else {
                System.out.println("这是一个过去日期");
            }
        } catch (ParseException e) {
            System.out.println("日期格式错误,请使用正确格式");
        }
        
        // 日志文件名生成
        String logFileName = "app_" + DateFormatUtils.format(now, "yyyyMMdd_HHmmss") + ".log";
        System.out.println("日志文件名: " + logFileName);
    }
}
4.2.3 日期比较和判断
/**
 * DateUtils比较和判断示例
 */
public class DateUtilsCompareExample {
    
    public static void main(String[] args) throws ParseException {
        Date now = new Date();
        Date yesterday = DateUtils.addDays(now, -1);
        Date tomorrow = DateUtils.addDays(now, 1);
        Date sameDay = DateUtils.truncate(now, Calendar.DAY_OF_MONTH);
        
        System.out.println("=== 日期相等判断 ===");
        // 判断是否是同一天(忽略时分秒)
        System.out.println("今天和昨天是同一天: " + DateUtils.isSameDay(now, yesterday)); // false
        System.out.println("今天和今天是同一天: " + DateUtils.isSameDay(now, sameDay)); // true
        
        // 判断是否是同一时刻
        System.out.println("现在和截取后的时间相等: " + (now.getTime() == sameDay.getTime())); // false
        
        System.out.println("\n=== 日期范围判断 ===");
        // 创建日期范围
        Date startDate = DateUtils.parseDate("2023-01-01", "yyyy-MM-dd");
        Date endDate = DateUtils.parseDate("2023-12-31", "yyyy-MM-dd");
        Date testDate = DateUtils.parseDate("2023-06-15", "yyyy-MM-dd");
        
        boolean inRange = testDate.after(startDate) && testDate.before(endDate);
        System.out.println("测试日期是否在范围内: " + inRange);
        
        System.out.println("\n=== 年龄计算 ===");
        Date birthDate = DateUtils.parseDate("1990-05-15", "yyyy-MM-dd");
        long ageInMillis = now.getTime() - birthDate.getTime();
        long ageInDays = ageInMillis / (24 * 60 * 60 * 1000);
        int ageInYears = (int) (ageInDays / 365.25);
        System.out.println("年龄: " + ageInYears + " 岁");
        
        System.out.println("\n=== 实际应用示例 ===");
        // 会员有效期检查
        Date membershipExpiry = DateUtils.parseDate("2024-01-01", "yyyy-MM-dd");
        if (now.before(membershipExpiry)) {
            long daysLeft = (membershipExpiry.getTime() - now.getTime()) / (24 * 60 * 60 * 1000);
            System.out.println("会员有效,还剩 " + daysLeft + " 天");
        } else {
            System.out.println("会员已过期");
        }
        
        // 促销活动时间检查
        Date promotionStart = DateUtils.parseDate("2023-11-01 00:00:00", "yyyy-MM-dd HH:mm:ss");
        Date promotionEnd = DateUtils.parseDate("2023-11-30 23:59:59", "yyyy-MM-dd HH:mm:ss");
        
        if (now.after(promotionStart) && now.before(promotionEnd)) {
            System.out.println("促销活动进行中");
        } else if (now.before(promotionStart)) {
            System.out.println("促销活动尚未开始");
        } else {
            System.out.println("促销活动已结束");
        }
    }
}

4.3 Java 8+ 时间API工具类

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * Java 8+ 时间API工具类
 */
public class ModernDateTimeUtils {
    
    public static final DateTimeFormatter DEFAULT_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter DEFAULT_DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter CHINESE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    
    /**
     * 获取当前日期
     */
    public static LocalDate getCurrentDate() {
        return LocalDate.now();
    }
    
    /**
     * 获取当前时间
     */
    public static LocalDateTime getCurrentDateTime() {
        return LocalDateTime.now();
    }
    
    /**
     * 字符串转LocalDate
     */
    public static LocalDate parseDate(String dateStr) {
        return LocalDate.parse(dateStr, DEFAULT_DATE_FORMAT);
    }
    
    /**
     * 字符串转LocalDateTime
     */
    public static LocalDateTime parseDateTime(String dateTimeStr) {
        return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * LocalDate转字符串
     */
    public static String formatDate(LocalDate date) {
        return date.format(DEFAULT_DATE_FORMAT);
    }
    
    /**
     * LocalDateTime转字符串
     */
    public static String formatDateTime(LocalDateTime dateTime) {
        return dateTime.format(DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * 计算两个日期之间的天数差
     */
    public static long daysBetween(LocalDate startDate, LocalDate endDate) {
        return ChronoUnit.DAYS.between(startDate, endDate);
    }
    
    /**
     * 计算年龄
     */
    public static int calculateAge(LocalDate birthDate) {
        return Period.between(birthDate, LocalDate.now()).getYears();
    }
    
    /**
     * 获取月份的第一天
     */
    public static LocalDate getFirstDayOfMonth(LocalDate date) {
        return date.withDayOfMonth(1);
    }
    
    /**
     * 获取月份的最后一天
     */
    public static LocalDate getLastDayOfMonth(LocalDate date) {
        return date.withDayOfMonth(date.lengthOfMonth());
    }
    
    /**
     * 判断是否是工作日
     */
    public static boolean isWorkday(LocalDate date) {
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
    }
    
    /**
     * Date转LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }
    
    /**
     * LocalDateTime转Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    public static void main(String[] args) {
        System.out.println("=== Java 8+ 时间API示例 ===");
        
        LocalDate today = getCurrentDate();
        LocalDateTime now = getCurrentDateTime();
        
        System.out.println("今天: " + formatDate(today));
        System.out.println("现在: " + formatDateTime(now));
        System.out.println("中文格式: " + today.format(CHINESE_DATE_FORMAT));
        
        // 日期计算
        LocalDate birthday = parseDate("1990-05-15");
        int age = calculateAge(birthday);
        System.out.println("年龄: " + age + " 岁");
        
        // 月份操作
        LocalDate firstDay = getFirstDayOfMonth(today);
        LocalDate lastDay = getLastDayOfMonth(today);
        System.out.println("本月第一天: " + formatDate(firstDay));
        System.out.println("本月最后一天: " + formatDate(lastDay));
        
        // 工作日判断
        System.out.println("今天是工作日: " + isWorkday(today));
        
        // 时间范围
        LocalDate startDate = today.minusDays(30);
        long daysDiff = daysBetween(startDate, today);
        System.out.println("30天前到今天共 " + daysDiff + " 天");
        
        // 与Date的转换
        Date oldDate = new Date();
        LocalDateTime converted = dateToLocalDateTime(oldDate);
        System.out.println("Date转换为LocalDateTime: " + formatDateTime(converted));
    }
}

5. JsonUtils详解

5.1 什么是JsonUtils?

JsonUtils是用于处理JSON数据的工具类,主要基于Jackson、Gson、Fastjson等JSON库实现。在SpringBoot中,默认使用Jackson库。

5.2 基于Jackson的JsonUtils

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import java.util.List;
import java.util.Map;

/**
 * 基于Jackson的JSON工具类
 */
public class JsonUtils {
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 对象转JSON字符串
     */
    public static String toJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("对象转JSON失败", e);
        }
    }
    
    /**
     * 对象转格式化的JSON字符串
     */
    public static String toPrettyJson(Object obj) {
        try {
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("对象转JSON失败", e);
        }
    }
    
    /**
     * JSON字符串转对象
     */
    public static <T> T fromJson(String json, Class<T> clazz) {
        try {
            return objectMapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON转对象失败", e);
        }
    }
    
    /**
     * JSON字符串转List
     */
    public static <T> List<T> fromJsonToList(String json, Class<T> clazz) {
        try {
            CollectionType listType = objectMapper.getTypeFactory()
                    .constructCollectionType(List.class, clazz);
            return objectMapper.readValue(json, listType);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON转List失败", e);
        }
    }
    
    /**
     * JSON字符串转Map
     */
    public static Map<String, Object> fromJsonToMap(String json) {
        try {
            return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON转Map失败", e);
        }
    }
    
    /**
     * 对象转Map
     */
    public static Map<String, Object> objectToMap(Object obj) {
        return objectMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {});
    }
    
    /**
     * Map转对象
     */
    public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) {
        return objectMapper.convertValue(map, clazz);
    }
    
    /**
     * 读取JSON节点
     */
    public static JsonNode readTree(String json) {
        try {
            return objectMapper.readTree(json);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("解析JSON树失败", e);
        }
    }
    
    /**
     * 检查是否是有效的JSON
     */
    public static boolean isValidJson(String json) {
        try {
            objectMapper.readTree(json);
            return true;
        } catch (JsonProcessingException e) {
            return false;
        }
    }
    
    /**
     * 使用示例
     */
    public static void main(String[] args) {
        System.out.println("=== JSON工具类示例 ===");
        
        // 创建测试对象
        User user = new User(1L, "张三", "zhangsan@example.com", 25);
        
        // 对象转JSON
        String json = toJson(user);
        System.out.println("对象转JSON: " + json);
        
        // 格式化JSON
        String prettyJson = toPrettyJson(user);
        System.out.println("格式化JSON:\n" + prettyJson);
        
        // JSON转对象
        User parsedUser = fromJson(json, User.class);
        System.out.println("JSON转对象: " + parsedUser);
        
        // 对象转Map
        Map<String, Object> userMap = objectToMap(user);
        System.out.println("对象转Map: " + userMap);
        
        // Map转对象
        User userFromMap = mapToObject(userMap, User.class);
        System.out.println("Map转对象: " + userFromMap);
        
        // JSON数组处理
        List<User> userList = List.of(
            new User(1L, "张三", "zhangsan@example.com", 25),
            new User(2L, "李四", "lisi@example.com", 30)
        );
        String listJson = toJson(userList);
        System.out.println("List转JSON: " + listJson);
        
        List<User> parsedList = fromJsonToList(listJson, User.class);
        System.out.println("JSON转List: " + parsedList);
        
        // JSON节点读取
        JsonNode rootNode = readTree(json);
        System.out.println("读取用户名: " + rootNode.get("username").asText());
        System.out.println("读取年龄: " + rootNode.get("age").asInt());
        
        // JSON有效性检查
        System.out.println("有效JSON: " + isValidJson(json));
        System.out.println("无效JSON: " + isValidJson("{invalid json}"));
    }
    
    static class User {
        private Long id;
        private String username;
        private String email;
        private Integer age;
        
        public User() {}
        
        public User(Long id, String username, String email, Integer age) {
            this.id = id;
            this.username = username;
            this.email = email;
            this.age = age;
        }
        
        // getters and setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
        
        @Override
        public String toString() {
            return "User{id=" + id + ", username='" + username + "', email='" + email + "', age=" + age + '}';
        }
    }
}

5.3 配置化的JsonUtils

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 配置化的JSON工具类
 */
public class ConfigurableJsonUtils {
    
    private static final ObjectMapper objectMapper;
    
    static {
        objectMapper = new ObjectMapper();
        
        // 配置时间模块
        objectMapper.registerModule(new JavaTimeModule());
        
        // 配置序列化选项
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        // 配置反序列化选项
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
    }
    
    /**
     * 获取配置的ObjectMapper实例
     */
    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }
    
    /**
     * 对象转JSON(不包含null值)
     */
    public static String toJsonExcludeNull(Object obj) {
        try {
            ObjectMapper mapper = objectMapper.copy();
            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("JSON转换失败", e);
        }
    }
    
    /**
     * 对象转JSON(不包含空值)
     */
    public static String toJsonExcludeEmpty(Object obj) {
        try {
            ObjectMapper mapper = objectMapper.copy();
            mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("JSON转换失败", e);
        }
    }
    
    /**
     * 容错的JSON解析
     */
    public static <T> T fromJsonTolerant(String json, Class<T> clazz) {
        try {
            ObjectMapper mapper = objectMapper.copy();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
            return mapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException("JSON解析失败", e);
        }
    }
    
    public static void main(String[] args) {
        System.out.println("=== 配置化JSON工具类示例 ===");
        
        // 测试时间序列化
        UserWithTime user = new UserWithTime();
        user.setId(1L);
        user.setUsername("张三");
        user.setEmail(null); // null值
        user.setDescription(""); // 空字符串
        user.setCreateTime(LocalDateTime.now());
        
        System.out.println("包含null值: " + JsonUtils.toJson(user));
        System.out.println("排除null值: " + toJsonExcludeNull(user));
        System.out.println("排除空值: " + toJsonExcludeEmpty(user));
        
        // 测试容错解析
        String invalidJson = "{\"id\":1,\"username\":\"张三\",\"unknownField\":\"value\",\"age\":\"not_a_number\"}";
        try {
            UserWithTime parsed = fromJsonTolerant(invalidJson, UserWithTime.class);
            System.out.println("容错解析结果: " + parsed);
        } catch (Exception e) {
            System.out.println("解析失败: " + e.getMessage());
        }
    }
    
    static class UserWithTime {
        private Long id;
        private String username;
        private String email;
        private String description;
        private LocalDateTime createTime;
        private Integer age;
        
        // getters and setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        
        public LocalDateTime getCreateTime() { return createTime; }
        public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
        
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
        
        @Override
        public String toString() {
            return "UserWithTime{id=" + id + ", username='" + username + "', email='" + email + 
                   "', description='" + description + "', createTime=" + createTime + ", age=" + age + '}';
        }
    }
}

6. FileUtils详解

6.1 什么是FileUtils?

FileUtils是用于处理文件和目录操作的工具类,主要基于Apache Commons IO实现,提供了丰富的文件操作方法。

6.2 Apache Commons IO FileUtils

6.2.1 文件基本操作
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;

/**
 * FileUtils基本操作示例
 */
public class FileUtilsBasicExample {
    
    public static void main(String[] args) throws IOException {
        System.out.println("=== 文件读写操作 ===");
        
        File testFile = new File("test.txt");
        String content = "Hello, FileUtils!\n这是测试内容。\n中文支持测试。";
        
        // 写入文件
        FileUtils.writeStringToFile(testFile, content, StandardCharsets.UTF_8);
        System.out.println("文件写入成功: " + testFile.getAbsolutePath());
        
        // 读取文件
        String readContent = FileUtils.readFileToString(testFile, StandardCharsets.UTF_8);
        System.out.println("文件内容: " + readContent);
        
        // 按行读取
        List<String> lines = FileUtils.readLines(testFile, StandardCharsets.UTF_8);
        System.out.println("文件行数: " + lines.size());
        for (int i = 0; i < lines.size(); i++) {
            System.out.println("第" + (i + 1) + "行: " + lines.get(i));
        }
        
        System.out.println("\n=== 文件信息 ===");
        // 文件大小
        long fileSize = FileUtils.sizeOf(testFile);
        System.out.println("文件大小: " + fileSize + " 字节");
        System.out.println("文件大小(可读): " + FileUtils.byteCountToDisplaySize(fileSize));
        
        // 文件时间
        System.out.println("最后修改时间: " + new java.util.Date(testFile.lastModified()));
        
        System.out.println("\n=== 文件复制和移动 ===");
        File copyFile = new File("test_copy.txt");
        File moveFile = new File("test_moved.txt");
        
        // 复制文件
        FileUtils.copyFile(testFile, copyFile);
        System.out.println("文件复制成功: " + copyFile.getAbsolutePath());
        
        // 移动文件
        FileUtils.moveFile(copyFile, moveFile);
        System.out.println("文件移动成功: " + moveFile.getAbsolutePath());
        
        System.out.println("\n=== 目录操作 ===");
        File testDir = new File("testDir");
        File subDir = new File(testDir, "subDir");
        
        // 创建目录
        FileUtils.forceMkdir(subDir);
        System.out.println("目录创建成功: " + subDir.getAbsolutePath());
        
        // 复制文件到目录
        FileUtils.copyFileToDirectory(testFile, testDir);
        System.out.println("文件复制到目录成功");
        
        // 列出目录中的文件
        Collection<File> files = FileUtils.listFiles(testDir, new String[]{"txt"}, true);
        System.out.println("目录中的txt文件:");
        for (File file : files) {
            System.out.println("  " + file.getName());
        }
        
        // 计算目录大小
        long dirSize = FileUtils.sizeOfDirectory(testDir);
        System.out.println("目录大小: " + FileUtils.byteCountToDisplaySize(dirSize));
        
        System.out.println("\n=== 清理 ===");
        // 删除文件和目录
        FileUtils.deleteQuietly(testFile);
        FileUtils.deleteQuietly(moveFile);
        FileUtils.deleteDirectory(testDir);
        System.out.println("清理完成");
    }
}
6.2.2 高级文件操作
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.*;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;

/**
 * FileUtils高级操作示例
 */
public class FileUtilsAdvancedExample {
    
    public static void main(String[] args) throws IOException {
        System.out.println("=== 文件过滤 ===");
        
        // 创建测试文件结构
        createTestStructure();
        
        File rootDir = new File("fileTest");
        
        // 按扩展名过滤
        Collection<File> javaFiles = FileUtils.listFiles(rootDir, 
            new String[]{"java", "class"}, true);
        System.out.println("Java相关文件:");
        javaFiles.forEach(file -> System.out.println("  " + file.getName()));
        
        // 按大小过滤
        Collection<File> largeFiles = FileUtils.listFiles(rootDir, 
            new SizeFileFilter(100), // 大于100字节
            TrueFileFilter.INSTANCE);
        System.out.println("大文件:");
        largeFiles.forEach(file -> System.out.println("  " + file.getName() + 
            " (" + FileUtils.byteCountToDisplaySize(file.length()) + ")"));
        
        // 按修改时间过滤
        long oneHourAgo = System.currentTimeMillis() - (60 * 60 * 1000);
        Collection<File> recentFiles = FileUtils.listFiles(rootDir,
            new AgeFileFilter(oneHourAgo, false), // 最近一小时内修改的
            TrueFileFilter.INSTANCE);
        System.out.println("最近修改的文件:");
        recentFiles.forEach(file -> System.out.println("  " + file.getName()));
        
        // 组合过滤器
        IOFileFilter combinedFilter = new AndFileFilter(
            new SuffixFileFilter(".txt"),
            new SizeFileFilter(50, true) // 小于50字节的txt文件
        );
        Collection<File> filteredFiles = FileUtils.listFiles(rootDir, 
            combinedFilter, TrueFileFilter.INSTANCE);
        System.out.println("小txt文件:");
        filteredFiles.forEach(file -> System.out.println("  " + file.getName()));
        
        System.out.println("\n=== 文件监控 ===");
        // 文件迭代器
        Iterator<File> fileIterator = FileUtils.iterateFiles(rootDir, null, true);
        System.out.println("所有文件:");
        while (fileIterator.hasNext()) {
            File file = fileIterator.next();
            System.out.println("  " + file.getPath() + 
                " (" + FileUtils.byteCountToDisplaySize(file.length()) + ")");
        }
        
        System.out.println("\n=== 文件名操作 ===");
        String filePath = "/path/to/document.pdf";
        System.out.println("完整路径: " + filePath);
        System.out.println("文件名: " + FilenameUtils.getName(filePath));
        System.out.println("基础名: " + FilenameUtils.getBaseName(filePath));
        System.out.println("扩展名: " + FilenameUtils.getExtension(filePath));
        System.out.println("路径: " + FilenameUtils.getPath(filePath));
        System.out.println("父路径: " + FilenameUtils.getFullPath(filePath));
        
        // 路径标准化
        String messyPath = "/path/../to/./document.pdf";
        System.out.println("混乱路径: " + messyPath);
        System.out.println("标准化路径: " + FilenameUtils.normalize(messyPath));
        
        // 清理
        FileUtils.deleteDirectory(rootDir);
        System.out.println("\n清理完成");
    }
    
    private static void createTestStructure() throws IOException {
        File rootDir = new File("fileTest");
        FileUtils.forceMkdir(rootDir);
        
        // 创建不同类型的文件
        FileUtils.writeStringToFile(new File(rootDir, "test.txt"), 
            "这是一个文本文件", StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(rootDir, "README.md"), 
            "# 这是README文件\n这是一个较长的文件内容,用于测试文件大小过滤功能。", StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(rootDir, "Main.java"), 
            "public class Main { public static void main(String[] args) {} }", StandardCharsets.UTF_8);
        
        // 创建子目录
        File subDir = new File(rootDir, "subdir");
        FileUtils.forceMkdir(subDir);
        FileUtils.writeStringToFile(new File(subDir, "data.xml"), 
            "<root><data>test</data></root>", StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(subDir, "config.properties"), 
            "app.name=test\napp.version=1.0", StandardCharsets.UTF_8);
    }
}

6.3 文件工具类实战

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 实用文件工具类
 */
public class PracticalFileUtils {
    
    /**
     * 安全地读取文件内容
     */
    public static String readFileContent(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                return null;
            }
            return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("读取文件失败: " + filePath, e);
        }
    }
    
    /**
     * 安全地写入文件内容
     */
    public static boolean writeFileContent(String filePath, String content) {
        try {
            File file = new File(filePath);
            FileUtils.forceMkdirParent(file); // 确保父目录存在
            FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
            return true;
        } catch (IOException e) {
            System.err.println("写入文件失败: " + filePath + ", " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 备份文件
     */
    public static boolean backupFile(String filePath, String backupDir) {
        try {
            File sourceFile = new File(filePath);
            if (!sourceFile.exists()) {
                return false;
            }
            
            File backupDirectory = new File(backupDir);
            FileUtils.forceMkdir(backupDirectory);
            
            String timestamp = String.valueOf(System.currentTimeMillis());
            String backupName = FilenameUtils.getBaseName(filePath) + "_" + timestamp + 
                               "." + FilenameUtils.getExtension(filePath);
            File backupFile = new File(backupDirectory, backupName);
            
            FileUtils.copyFile(sourceFile, backupFile);
            return true;
        } catch (IOException e) {
            System.err.println("备份文件失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 压缩文件夹
     */
    public static boolean zipDirectory(String sourceDir, String zipFilePath) {
        try {
            File source = new File(sourceDir);
            if (!source.exists() || !source.isDirectory()) {
                return false;
            }
            
            FileUtils.forceMkdirParent(new File(zipFilePath));
            
            try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
                Path sourcePath = source.toPath();
                Files.walk(sourcePath)
                    .filter(path -> !Files.isDirectory(path))
                    .forEach(path -> {
                        try {
                            String entryName = sourcePath.relativize(path).toString();
                            ZipEntry entry = new ZipEntry(entryName);
                            zos.putNextEntry(entry);
                            Files.copy(path, zos);
                            zos.closeEntry();
                        } catch (IOException e) {
                            throw new RuntimeException("压缩文件失败", e);
                        }
                    });
            }
            return true;
        } catch (Exception e) {
            System.err.println("压缩目录失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 获取文件的MD5值
     */
    public static String getFileMD5(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return null;
            }
            
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            try (FileInputStream fis = new FileInputStream(file)) {
                byte[] buffer = new byte[8192];
                int length;
                while ((length = fis.read(buffer)) != -1) {
                    md.update(buffer, 0, length);
                }
            }
            
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            System.err.println("计算MD5失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 清理临时文件
     */
    public static int cleanupTempFiles(String tempDir, long maxAgeMillis) {
        try {
            File dir = new File(tempDir);
            if (!dir.exists() || !dir.isDirectory()) {
                return 0;
            }
            
            long cutoffTime = System.currentTimeMillis() - maxAgeMillis;
            int deletedCount = 0;
            
            File[] files = dir.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.lastModified() < cutoffTime) {
                        if (FileUtils.deleteQuietly(file)) {
                            deletedCount++;
                        }
                    }
                }
            }
            return deletedCount;
        } catch (Exception e) {
            System.err.println("清理临时文件失败: " + e.getMessage());
            return 0;
        }
    }
    
    /**
     * 监控目录变化
     */
    public static void watchDirectory(String dirPath) {
        try {
            Path path = Paths.get(dirPath);
            WatchService watchService = FileSystems.getDefault().newWatchService();
            path.register(watchService, 
                StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_DELETE,
                StandardWatchEventKinds.ENTRY_MODIFY);
            
            System.out.println("开始监控目录: " + dirPath);
            
            WatchKey key;
            while ((key = watchService.take()) != null) {
                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    Path filePath = (Path) event.context();
                    System.out.println("文件变化: " + kind.name() + " -> " + filePath);
                }
                key.reset();
            }
        } catch (Exception e) {
            System.err.println("目录监控失败: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) throws IOException {
        System.out.println("=== 实用文件工具类示例 ===");
        
        // 创建测试环境
        String testContent = "这是测试文件内容\n包含多行文本\n用于测试各种文件操作";
        String testFile = "practical_test.txt";
        
        // 写入文件
        boolean writeSuccess = writeFileContent(testFile, testContent);
        System.out.println("文件写入: " + (writeSuccess ? "成功" : "失败"));
        
        // 读取文件
        String content = readFileContent(testFile);
        System.out.println("文件内容: " + (content != null ? "读取成功" : "读取失败"));
        
        // 备份文件
        boolean backupSuccess = backupFile(testFile, "backup");
        System.out.println("文件备份: " + (backupSuccess ? "成功" : "失败"));
        
        // 计算MD5
        String md5 = getFileMD5(testFile);
        System.out.println("文件MD5: " + md5);
        
        // 创建测试目录结构并压缩
        File testDir = new File("zipTest");
        FileUtils.forceMkdir(testDir);
        FileUtils.writeStringToFile(new File(testDir, "file1.txt"), "文件1内容", StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(testDir, "file2.txt"), "文件2内容", StandardCharsets.UTF_8);
        
        boolean zipSuccess = zipDirectory("zipTest", "test.zip");
        System.out.println("目录压缩: " + (zipSuccess ? "成功" : "失败"));
        
        // 清理
        FileUtils.deleteQuietly(new File(testFile));
        FileUtils.deleteQuietly(new File("backup"));
        FileUtils.deleteQuietly(new File("zipTest"));
        FileUtils.deleteQuietly(new File("test.zip"));
        System.out.println("清理完成");
    }
}

7. ValidateUtils详解

7.1 什么是ValidateUtils?

ValidateUtils是用于数据验证的工具类,提供了多种验证方法,包括参数校验、格式验证、业务规则验证等。在实际开发中,数据验证是保证系统安全性和数据完整性的重要环节。

7.2 基本参数验证

import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.regex.Pattern;

/**
 * 基础验证工具类
 */
public class ValidateUtils {
    
    // 常用正则表达式
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
        "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Pattern ID_CARD_PATTERN = Pattern.compile(
        "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");
    private static final Pattern CHINESE_PATTERN = Pattern.compile("^[\\u4e00-\\u9fa5]+$");
    private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,20}$");
    
    /**
     * 验证字符串不为空
     */
    public static boolean isNotBlank(String str) {
        return StringUtils.hasText(str);
    }
    
    /**
     * 验证字符串为空
     */
    public static boolean isBlank(String str) {
        return !StringUtils.hasText(str);
    }
    
    /**
     * 验证集合不为空
     */
    public static boolean isNotEmpty(Collection<?> collection) {
        return collection != null && !collection.isEmpty();
    }
    
    /**
     * 验证对象不为空
     */
    public static boolean isNotNull(Object obj) {
        return obj != null;
    }
    
    /**
     * 验证邮箱格式
     */
    public static boolean isValidEmail(String email) {
        if (isBlank(email)) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email).matches();
    }
    
    /**
     * 验证手机号格式
     */
    public static boolean isValidPhone(String phone) {
        if (isBlank(phone)) {
            return false;
        }
        return PHONE_PATTERN.matcher(phone).matches();
    }
    
    /**
     * 验证身份证号格式
     */
    public static boolean isValidIdCard(String idCard) {
        if (isBlank(idCard)) {
            return false;
        }
        return ID_CARD_PATTERN.matcher(idCard).matches();
    }
    
    /**
     * 验证用户名格式(字母、数字、下划线,3-20位)
     */
    public static boolean isValidUsername(String username) {
        if (isBlank(username)) {
            return false;
        }
        return USERNAME_PATTERN.matcher(username).matches();
    }
    
    /**
     * 验证是否为中文
     */
    public static boolean isChinese(String str) {
        if (isBlank(str)) {
            return false;
        }
        return CHINESE_PATTERN.matcher(str).matches();
    }
    
    /**
     * 验证数字范围
     */
    public static boolean isInRange(Number number, Number min, Number max) {
        if (number == null || min == null || max == null) {
            return false;
        }
        double value = number.doubleValue();
        return value >= min.doubleValue() && value <= max.doubleValue();
    }
    
    /**
     * 验证字符串长度
     */
    public static boolean isLengthValid(String str, int minLength, int maxLength) {
        if (str == null) {
            return false;
        }
        int length = str.length();
        return length >= minLength && length <= maxLength;
    }
    
    /**
     * 验证密码强度(至少包含大写字母、小写字母、数字,长度8-20位)
     */
    public static boolean isStrongPassword(String password) {
        if (isBlank(password) || !isLengthValid(password, 8, 20)) {
            return false;
        }
        
        boolean hasUpper = password.matches(".*[A-Z].*");
        boolean hasLower = password.matches(".*[a-z].*");
        boolean hasDigit = password.matches(".*\\d.*");
        
        return hasUpper && hasLower && hasDigit;
    }
    
    /**
     * 验证URL格式
     */
    public static boolean isValidUrl(String url) {
        if (isBlank(url)) {
            return false;
        }
        try {
            new java.net.URL(url);
            return true;
        } catch (java.net.MalformedURLException e) {
            return false;
        }
    }
    
    /**
     * 验证IP地址格式
     */
    public static boolean isValidIpAddress(String ip) {
        if (isBlank(ip)) {
            return false;
        }
        String ipPattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
        return Pattern.matches(ipPattern, ip);
    }
    
    public static void main(String[] args) {
        System.out.println("=== 验证工具类示例 ===");
        
        // 邮箱验证
        System.out.println("邮箱验证:");
        System.out.println("  admin@example.com: " + isValidEmail("admin@example.com"));
        System.out.println("  invalid-email: " + isValidEmail("invalid-email"));
        
        // 手机号验证
        System.out.println("\n手机号验证:");
        System.out.println("  13800138000: " + isValidPhone("13800138000"));
        System.out.println("  12345678901: " + isValidPhone("12345678901"));
        
        // 密码强度验证
        System.out.println("\n密码强度验证:");
        System.out.println("  Password123: " + isStrongPassword("Password123"));
        System.out.println("  password: " + isStrongPassword("password"));
        System.out.println("  123456: " + isStrongPassword("123456"));
        
        // 用户名验证
        System.out.println("\n用户名验证:");
        System.out.println("  admin_123: " + isValidUsername("admin_123"));
        System.out.println("  ab: " + isValidUsername("ab")); // 太短
        System.out.println("  user@name: " + isValidUsername("user@name")); // 包含特殊字符
        
        // 数字范围验证
        System.out.println("\n数字范围验证:");
        System.out.println("  25 in (18, 60): " + isInRange(25, 18, 60));
        System.out.println("  15 in (18, 60): " + isInRange(15, 18, 60));
    }
}

7.3 业务验证工具类

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

/**
 * 业务验证工具类
 */
public class BusinessValidateUtils {
    
    /**
     * 验证用户注册信息
     */
    public static ValidationResult validateUserRegistration(UserRegistrationRequest request) {
        ValidationResult result = new ValidationResult();
        
        // 验证用户名
        if (ValidateUtils.isBlank(request.getUsername())) {
            result.addError("username", "用户名不能为空");
        } else if (!ValidateUtils.isValidUsername(request.getUsername())) {
            result.addError("username", "用户名格式不正确,只能包含字母、数字、下划线,长度3-20位");
        }
        
        // 验证邮箱
        if (ValidateUtils.isBlank(request.getEmail())) {
            result.addError("email", "邮箱不能为空");
        } else if (!ValidateUtils.isValidEmail(request.getEmail())) {
            result.addError("email", "邮箱格式不正确");
        }
        
        // 验证密码
        if (ValidateUtils.isBlank(request.getPassword())) {
            result.addError("password", "密码不能为空");
        } else if (!ValidateUtils.isStrongPassword(request.getPassword())) {
            result.addError("password", "密码强度不够,需包含大写字母、小写字母、数字,长度8-20位");
        }
        
        // 验证确认密码
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            result.addError("confirmPassword", "两次输入的密码不一致");
        }
        
        // 验证手机号
        if (ValidateUtils.isNotBlank(request.getPhone()) && !ValidateUtils.isValidPhone(request.getPhone())) {
            result.addError("phone", "手机号格式不正确");
        }
        
        // 验证年龄
        if (request.getAge() != null && !ValidateUtils.isInRange(request.getAge(), 1, 150)) {
            result.addError("age", "年龄必须在1-150之间");
        }
        
        return result;
    }
    
    /**
     * 验证订单信息
     */
    public static ValidationResult validateOrder(OrderRequest request) {
        ValidationResult result = new ValidationResult();
        
        // 验证商品列表
        if (ValidateUtils.isNotEmpty(request.getItems())) {
            for (int i = 0; i < request.getItems().size(); i++) {
                OrderItemRequest item = request.getItems().get(i);
                String prefix = "items[" + i + "]";
                
                if (item.getProductId() == null || item.getProductId() <= 0) {
                    result.addError(prefix + ".productId", "商品ID无效");
                }
                
                if (item.getQuantity() == null || item.getQuantity() <= 0) {
                    result.addError(prefix + ".quantity", "商品数量必须大于0");
                }
                
                if (item.getPrice() == null || item.getPrice().compareTo(java.math.BigDecimal.ZERO) <= 0) {
                    result.addError(prefix + ".price", "商品价格必须大于0");
                }
            }
        } else {
            result.addError("items", "订单商品列表不能为空");
        }
        
        // 验证收货地址
        if (ValidateUtils.isBlank(request.getShippingAddress())) {
            result.addError("shippingAddress", "收货地址不能为空");
        }
        
        // 验证联系电话
        if (ValidateUtils.isBlank(request.getContactPhone())) {
            result.addError("contactPhone", "联系电话不能为空");
        } else if (!ValidateUtils.isValidPhone(request.getContactPhone())) {
            result.addError("contactPhone", "联系电话格式不正确");
        }
        
        return result;
    }
    
    /**
     * 验证文件上传
     */
    public static ValidationResult validateFileUpload(String fileName, long fileSize, byte[] fileContent) {
        ValidationResult result = new ValidationResult();
        
        // 验证文件名
        if (ValidateUtils.isBlank(fileName)) {
            result.addError("fileName", "文件名不能为空");
            return result;
        }
        
        // 验证文件扩展名
        String extension = getFileExtension(fileName);
        List<String> allowedExtensions = Arrays.asList("jpg", "jpeg", "png", "gif", "pdf", "doc", "docx");
        if (!allowedExtensions.contains(extension.toLowerCase())) {
            result.addError("fileName", "不支持的文件类型,支持的类型:" + String.join(", ", allowedExtensions));
        }
        
        // 验证文件大小(10MB)
        long maxSize = 10 * 1024 * 1024;
        if (fileSize > maxSize) {
            result.addError("fileSize", "文件大小不能超过10MB");
        }
        
        // 验证文件内容
        if (fileContent == null || fileContent.length == 0) {
            result.addError("fileContent", "文件内容不能为空");
        }
        
        return result;
    }
    
    private static String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return "";
        }
        return fileName.substring(lastDotIndex + 1);
    }
    
    /**
     * 验证结果类
     */
    public static class ValidationResult {
        private boolean valid = true;
        private java.util.Map<String, String> errors = new java.util.HashMap<>();
        
        public void addError(String field, String message) {
            this.valid = false;
            this.errors.put(field, message);
        }
        
        public boolean isValid() {
            return valid;
        }
        
        public java.util.Map<String, String> getErrors() {
            return errors;
        }
        
        public String getErrorMessage() {
            if (valid) {
                return null;
            }
            return String.join("; ", errors.values());
        }
    }
    
    // 请求类示例
    static class UserRegistrationRequest {
        private String username;
        private String email;
        private String password;
        private String confirmPassword;
        private String phone;
        private Integer age;
        
        // getters and setters
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        
        public String getConfirmPassword() { return confirmPassword; }
        public void setConfirmPassword(String confirmPassword) { this.confirmPassword = confirmPassword; }
        
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
        
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
    }
    
    static class OrderRequest {
        private List<OrderItemRequest> items;
        private String shippingAddress;
        private String contactPhone;
        
        // getters and setters
        public List<OrderItemRequest> getItems() { return items; }
        public void setItems(List<OrderItemRequest> items) { this.items = items; }
        
        public String getShippingAddress() { return shippingAddress; }
        public void setShippingAddress(String shippingAddress) { this.shippingAddress = shippingAddress; }
        
        public String getContactPhone() { return contactPhone; }
        public void setContactPhone(String contactPhone) { this.contactPhone = contactPhone; }
    }
    
    static class OrderItemRequest {
        private Long productId;
        private Integer quantity;
        private java.math.BigDecimal price;
        
        // getters and setters
        public Long getProductId() { return productId; }
        public void setProductId(Long productId) { this.productId = productId; }
        
        public Integer getQuantity() { return quantity; }
        public void setQuantity(Integer quantity) { this.quantity = quantity; }
        
        public java.math.BigDecimal getPrice() { return price; }
        public void setPrice(java.math.BigDecimal price) { this.price = price; }
    }
    
    public static void main(String[] args) {
        System.out.println("=== 业务验证工具类示例 ===");
        
        // 测试用户注册验证
        UserRegistrationRequest userRequest = new UserRegistrationRequest();
        userRequest.setUsername("admin");
        userRequest.setEmail("admin@example.com");
        userRequest.setPassword("Password123");
        userRequest.setConfirmPassword("Password123");
        userRequest.setPhone("13800138000");
        userRequest.setAge(25);
        
        ValidationResult userResult = validateUserRegistration(userRequest);
        System.out.println("用户注册验证: " + (userResult.isValid() ? "通过" : "失败"));
        if (!userResult.isValid()) {
            System.out.println("错误信息: " + userResult.getErrorMessage());
        }
        
        // 测试文件上传验证
        ValidationResult fileResult = validateFileUpload("test.jpg", 1024 * 1024, new byte[]{1, 2, 3});
        System.out.println("文件上传验证: " + (fileResult.isValid() ? "通过" : "失败"));
        if (!fileResult.isValid()) {
            System.out.println("错误信息: " + fileResult.getErrorMessage());
        }
    }
}

8. EncryptUtils详解

8.1 什么是EncryptUtils?

EncryptUtils是用于加密和解密操作的工具类,提供了多种加密算法的实现,包括MD5、SHA、AES、RSA等常用加密方式。

8.2 常用加密算法实现

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 加密工具类
 */
public class EncryptUtils {
    
    private static final String AES_ALGORITHM = "AES";
    private static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";
    
    /**
     * MD5加密
     */
    public static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (Exception e) {
            throw new RuntimeException("MD5加密失败", e);
        }
    }
    
    /**
     * SHA-256加密
     */
    public static String sha256(String input) {
        try {
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            byte[] digest = sha.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (Exception e) {
            throw new RuntimeException("SHA-256加密失败", e);
        }
    }
    
    /**
     * 生成随机盐值
     */
    public static String generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);
        return bytesToHex(salt);
    }
    
    /**
     * 密码加盐哈希
     */
    public static String hashPasswordWithSalt(String password, String salt) {
        return sha256(password + salt);
    }
    
    /**
     * 验证密码
     */
    public static boolean verifyPassword(String password, String salt, String hashedPassword) {
        String computedHash = hashPasswordWithSalt(password, salt);
        return computedHash.equals(hashedPassword);
    }
    
    /**
     * 生成AES密钥
     */
    public static String generateAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
            keyGenerator.init(256);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException("生成AES密钥失败", e);
        }
    }
    
    /**
     * AES加密
     */
    public static String aesEncrypt(String plainText, String base64Key) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(base64Key);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }
    
    /**
     * AES解密
     */
    public static String aesDecrypt(String encryptedText, String base64Key) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(base64Key);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }
    
    /**
     * Base64编码
     */
    public static String base64Encode(String input) {
        return Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * Base64解码
     */
    public static String base64Decode(String encoded) {
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        return new String(decodedBytes, StandardCharsets.UTF_8);
    }
    
    /**
     * 字节数组转十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
    
    public static void main(String[] args) {
        System.out.println("=== 加密工具类示例 ===");
        
        String originalText = "Hello, 这是需要加密的文本!";
        System.out.println("原文: " + originalText);
        
        // MD5加密
        String md5Hash = md5(originalText);
        System.out.println("MD5: " + md5Hash);
        
        // SHA-256加密
        String sha256Hash = sha256(originalText);
        System.out.println("SHA-256: " + sha256Hash);
        
        // 密码加盐哈希
        String password = "MyPassword123";
        String salt = generateSalt();
        String hashedPassword = hashPasswordWithSalt(password, salt);
        System.out.println("\n密码加盐哈希:");
        System.out.println("密码: " + password);
        System.out.println("盐值: " + salt);
        System.out.println("哈希: " + hashedPassword);
        
        // 验证密码
        boolean isValid = verifyPassword(password, salt, hashedPassword);
        System.out.println("密码验证: " + (isValid ? "通过" : "失败"));
        
        // AES加密解密
        String aesKey = generateAESKey();
        String encrypted = aesEncrypt(originalText, aesKey);
        String decrypted = aesDecrypt(encrypted, aesKey);
        System.out.println("\nAES加密解密:");
        System.out.println("密钥: " + aesKey);
        System.out.println("加密: " + encrypted);
        System.out.println("解密: " + decrypted);
        
        // Base64编码解码
        String encoded = base64Encode(originalText);
        String decoded = base64Decode(encoded);
        System.out.println("\nBase64编码解码:");
        System.out.println("编码: " + encoded);
        System.out.println("解码: " + decoded);
    }
}

9. ReflectionUtils详解

9.1 什么是ReflectionUtils?

ReflectionUtils是用于反射操作的工具类,提供了便捷的反射方法,用于动态获取类信息、调用方法、访问字段等操作。

9.2 Spring ReflectionUtils使用

import org.springframework.util.ReflectionUtils;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射工具类示例
 */
public class ReflectionUtilsExample {
    
    /**
     * 获取类的所有字段(包括私有字段)
     */
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        ReflectionUtils.doWithFields(clazz, fields::add);
        return fields;
    }
    
    /**
     * 获取类的所有方法(包括私有方法)
     */
    public static List<Method> getAllMethods(Class<?> clazz) {
        List<Method> methods = new ArrayList<>();
        ReflectionUtils.doWithMethods(clazz, methods::add);
        return methods;
    }
    
    /**
     * 根据字段名获取字段值
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        try {
            Field field = ReflectionUtils.findField(obj.getClass(), fieldName);
            if (field == null) {
                throw new IllegalArgumentException("字段不存在: " + fieldName);
            }
            ReflectionUtils.makeAccessible(field);
            return ReflectionUtils.getField(field, obj);
        } catch (Exception e) {
            throw new RuntimeException("获取字段值失败", e);
        }
    }
    
    /**
     * 根据字段名设置字段值
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        try {
            Field field = ReflectionUtils.findField(obj.getClass(), fieldName);
            if (field == null) {
                throw new IllegalArgumentException("字段不存在: " + fieldName);
            }
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, obj, value);
        } catch (Exception e) {
            throw new RuntimeException("设置字段值失败", e);
        }
    }
    
    /**
     * 调用对象的方法
     */
    public static Object invokeMethod(Object obj, String methodName, Object... args) {
        try {
            Class<?>[] paramTypes = new Class<?>[args.length];
            for (int i = 0; i < args.length; i++) {
                paramTypes[i] = args[i].getClass();
            }
            
            Method method = ReflectionUtils.findMethod(obj.getClass(), methodName, paramTypes);
            if (method == null) {
                throw new IllegalArgumentException("方法不存在: " + methodName);
            }
            ReflectionUtils.makeAccessible(method);
            return ReflectionUtils.invokeMethod(method, obj, args);
        } catch (Exception e) {
            throw new RuntimeException("调用方法失败", e);
        }
    }
    
    /**
     * 创建对象实例
     */
    @SuppressWarnings("unchecked")
    public static <T> T createInstance(Class<T> clazz) {
        try {
            Constructor<T> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建实例失败", e);
        }
    }
    
    /**
     * 复制对象属性
     */
    public static void copyProperties(Object source, Object target) {
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();
        
        ReflectionUtils.doWithFields(sourceClass, field -> {
            ReflectionUtils.makeAccessible(field);
            Object value = ReflectionUtils.getField(field, source);
            
            Field targetField = ReflectionUtils.findField(targetClass, field.getName());
            if (targetField != null && targetField.getType().equals(field.getType())) {
                ReflectionUtils.makeAccessible(targetField);
                ReflectionUtils.setField(targetField, target, value);
            }
        });
    }
    
    /**
     * 检查类是否包含指定注解
     */
    public static boolean hasAnnotation(Class<?> clazz, Class<? extends java.lang.annotation.Annotation> annotationClass) {
        return clazz.isAnnotationPresent(annotationClass);
    }
    
    /**
     * 获取带有指定注解的字段
     */
    public static List<Field> getFieldsWithAnnotation(Class<?> clazz, Class<? extends java.lang.annotation.Annotation> annotationClass) {
        List<Field> annotatedFields = new ArrayList<>();
        ReflectionUtils.doWithFields(clazz, field -> {
            if (field.isAnnotationPresent(annotationClass)) {
                annotatedFields.add(field);
            }
        });
        return annotatedFields;
    }
    
    /**
     * 获取带有指定注解的方法
     */
    public static List<Method> getMethodsWithAnnotation(Class<?> clazz, Class<? extends java.lang.annotation.Annotation> annotationClass) {
        List<Method> annotatedMethods = new ArrayList<>();
        ReflectionUtils.doWithMethods(clazz, method -> {
            if (method.isAnnotationPresent(annotationClass)) {
                annotatedMethods.add(method);
            }
        });
        return annotatedMethods;
    }
    
    public static void main(String[] args) {
        System.out.println("=== 反射工具类示例 ===");
        
        // 创建测试对象
        TestUser user = new TestUser();
        user.setId(1L);
        user.setUsername("admin");
        user.setEmail("admin@example.com");
        user.setAge(25);
        
        System.out.println("原始对象: " + user);
        
        // 获取字段值
        Object username = getFieldValue(user, "username");
        System.out.println("获取用户名: " + username);
        
        // 设置字段值
        setFieldValue(user, "username", "new_admin");
        System.out.println("修改用户名后: " + user);
        
        // 调用方法
        Object result = invokeMethod(user, "getDisplayName");
        System.out.println("调用getDisplayName方法: " + result);
        
        // 获取所有字段
        List<Field> fields = getAllFields(TestUser.class);
        System.out.println("\n所有字段:");
        for (Field field : fields) {
            System.out.println("  " + field.getName() + " (" + field.getType().getSimpleName() + ")");
        }
        
        // 获取所有方法
        List<Method> methods = getAllMethods(TestUser.class);
        System.out.println("\n所有方法:");
        for (Method method : methods) {
            if (method.getDeclaringClass() == TestUser.class) { // 只显示当前类的方法
                System.out.println("  " + method.getName());
            }
        }
        
        // 创建新实例并复制属性
        TestUser newUser = createInstance(TestUser.class);
        copyProperties(user, newUser);
        System.out.println("\n复制后的新对象: " + newUser);
    }
    
    /**
     * 测试用户类
     */
    static class TestUser {
        private Long id;
        private String username;
        private String email;
        private Integer age;
        
        public TestUser() {}
        
        // getters and setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
        
        public String getDisplayName() {
            return username + " (" + email + ")";
        }
        
        @Override
        public String toString() {
            return "TestUser{id=" + id + ", username='" + username + "', email='" + email + "', age=" + age + '}';
        }
    }
}

10. 自定义工具类实践

10.1 综合工具类

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 综合工具类,整合常用功能
 */
public class CommonUtils {
    
    /**
     * 判断字符串是否为空或空白
     */
    public static boolean isBlank(String str) {
        return str == null || str.trim().isEmpty();
    }
    
    /**
     * 判断字符串是否不为空且不为空白
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }
    
    /**
     * 安全的字符串转换
     */
    public static String safeToString(Object obj) {
        return obj == null ? "" : obj.toString();
    }
    
    /**
     * 安全的数字转换
     */
    public static Integer safeToInteger(String str, Integer defaultValue) {
        try {
            return isBlank(str) ? defaultValue : Integer.parseInt(str.trim());
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
    
    /**
     * 安全的长整型转换
     */
    public static Long safeToLong(String str, Long defaultValue) {
        try {
            return isBlank(str) ? defaultValue : Long.parseLong(str.trim());
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
    
    /**
     * 安全的双精度浮点数转换
     */
    public static Double safeToDouble(String str, Double defaultValue) {
        try {
            return isBlank(str) ? defaultValue : Double.parseDouble(str.trim());
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
    
    /**
     * 对象拷贝
     */
    public static <T> T copyBean(Object source, Supplier<T> targetSupplier) {
        if (source == null) {
            return null;
        }
        T target = targetSupplier.get();
        BeanUtils.copyProperties(source, target);
        return target;
    }
    
    /**
     * 列表拷贝
     */
    public static <T> List<T> copyBeanList(List<?> sourceList, Supplier<T> targetSupplier) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new ArrayList<>();
        }
        return sourceList.stream()
                .map(source -> copyBean(source, targetSupplier))
                .collect(Collectors.toList());
    }
    
    /**
     * 获取文件扩展名
     */
    public static String getFileExtension(String fileName) {
        if (isBlank(fileName)) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex == -1 ? "" : fileName.substring(lastDotIndex + 1).toLowerCase();
    }
    
    /**
     * 生成随机字符串
     */
    public static String generateRandomString(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        java.util.Random random = new java.util.Random();
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }
    
    /**
     * 脱敏手机号
     */
    public static String maskPhone(String phone) {
        if (isBlank(phone) || phone.length() != 11) {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }
    
    /**
     * 脱敏邮箱
     */
    public static String maskEmail(String email) {
        if (isBlank(email) || !email.contains("@")) {
            return email;
        }
        String[] parts = email.split("@");
        String localPart = parts[0];
        String domainPart = parts[1];
        
        if (localPart.length() <= 2) {
            return email;
        }
        
        String maskedLocal = localPart.substring(0, 1) + "****" + localPart.substring(localPart.length() - 1);
        return maskedLocal + "@" + domainPart;
    }
    
    /**
     * 脱敏身份证号
     */
    public static String maskIdCard(String idCard) {
        if (isBlank(idCard) || idCard.length() != 18) {
            return idCard;
        }
        return idCard.substring(0, 6) + "********" + idCard.substring(14);
    }
    
    public static void main(String[] args) {
        System.out.println("=== 综合工具类示例 ===");
        
        // 字符串处理
        System.out.println("空字符串检查: " + isBlank("   "));
        System.out.println("安全转换: " + safeToInteger("abc", 0));
        
        // 数据脱敏
        System.out.println("手机号脱敏: " + maskPhone("13800138000"));
        System.out.println("邮箱脱敏: " + maskEmail("admin@example.com"));
        System.out.println("身份证脱敏: " + maskIdCard("110101199001011234"));
        
        // 随机字符串
        System.out.println("随机字符串: " + generateRandomString(10));
        
        // 文件扩展名
        System.out.println("文件扩展名: " + getFileExtension("test.jpg"));
    }
}

11. 总结与最佳实践

11.1 工具类使用原则

  1. 静态方法设计:工具类的方法应设计为静态方法,方便调用
  2. 线程安全:确保工具类的方法是线程安全的
  3. 异常处理:妥善处理可能出现的异常,提供有意义的错误信息
  4. 参数验证:对输入参数进行必要的验证
  5. 性能考虑:避免在工具类中进行耗时操作

11.2 开发建议

  1. 合理选择工具类:根据项目需求选择合适的工具类
  2. 统一工具类规范:在团队中建立统一的工具类使用规范
  3. 避免重复造轮子:优先使用成熟的工具类库
  4. 适当封装:对常用操作进行封装,提高代码复用性
  5. 文档完善:为自定义工具类编写详细的文档和示例

通过学习和掌握这些工具类,可以大大提高SpringBoot项目的开发效率,减少重复代码,提升代码质量。在实际开发中,建议根据项目需求选择合适的工具类,并建立团队统一的使用规范。


网站公告

今日签到

点亮在社区的每一天
去签到