文章目录
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 工具类使用原则
- 静态方法设计:工具类的方法应设计为静态方法,方便调用
- 线程安全:确保工具类的方法是线程安全的
- 异常处理:妥善处理可能出现的异常,提供有意义的错误信息
- 参数验证:对输入参数进行必要的验证
- 性能考虑:避免在工具类中进行耗时操作
11.2 开发建议
- 合理选择工具类:根据项目需求选择合适的工具类
- 统一工具类规范:在团队中建立统一的工具类使用规范
- 避免重复造轮子:优先使用成熟的工具类库
- 适当封装:对常用操作进行封装,提高代码复用性
- 文档完善:为自定义工具类编写详细的文档和示例
通过学习和掌握这些工具类,可以大大提高SpringBoot项目的开发效率,减少重复代码,提升代码质量。在实际开发中,建议根据项目需求选择合适的工具类,并建立团队统一的使用规范。