工具类库 (Utils)
概述
ruoyi-common-core 的工具类库提供了丰富的工具方法,覆盖字符串处理、日期时间、反射操作、网络地址、文件处理、数据流处理等多个方面。这些工具类采用静态方法设计,线程安全,高度可复用。
目录结构
text
utils/
├── StringUtils.java # 字符串增强工具
├── DateUtils.java # 日期时间工具
├── ObjectUtils.java # 对象操作工具
├── StreamUtils.java # Stream流处理工具
├── TreeBuildUtils.java # 树形结构构建工具
├── ValidatorUtils.java # 参数校验工具
├── SpringUtils.java # Spring上下文工具
├── ServletUtils.java # Servlet请求响应工具
├── ThreadUtils.java # 线程处理工具
├── MapstructUtils.java # 对象映射工具
├── MessageUtils.java # 国际化消息工具
├── file/
│ ├── FileUtils.java # 文件处理工具
│ └── FileTypeUtils.java # 文件类型工具
├── ip/
│ ├── AddressUtils.java # IP地址解析工具
│ └── RegionUtils.java # IP区域定位工具
├── reflect/
│ └── ReflectUtils.java # 反射操作工具
├── regex/
│ ├── RegexPatterns.java # 正则表达式模式
│ ├── RegexPatternPool.java # 正则模式池
│ ├── RegexValidator.java # 正则校验器
│ └── RegexUtils.java # 正则工具
└── sql/
└── SqlUtil.java # SQL安全工具
核心工具类
1. 字符串工具 (StringUtils)
扩展了 Apache Commons Lang3 的 StringUtils,提供更多实用方法。
基础操作
java
// 空值处理
String result = StringUtils.blankToDefault("", "默认值");
boolean isEmpty = StringUtils.isEmpty("");
boolean isNotEmpty = StringUtils.isNotEmpty("hello");
// 字符串截取
String sub = StringUtils.substring("hello world", 6); // "world"
String sub2 = StringUtils.substring("hello world", 0, 5); // "hello"
// 格式化 - 支持 {} 占位符
String msg = StringUtils.format("Hello {}, age {}", "Tom", 25);
// 结果: "Hello Tom, age 25"
分割与转换
java
// 字符串转集合
Set<String> set = StringUtils.stringToSet("a,b,c", ",");
List<String> list = StringUtils.stringToList("a, b, c", ",", true, true);
// 分割并转换类型
List<Integer> ids = StringUtils.splitToList("1,2,3", Integer::valueOf);
List<Long> userIds = StringUtils.splitToList("100;200;300", ";", Long::valueOf);
命名转换
java
// 驼峰与下划线转换
String underscore = StringUtils.camelToUnderscore("userName"); // "user_name"
String camel = StringUtils.underscoreToCamelCase("user_name"); // "userName"
String pascal = StringUtils.underscoreToPascalCase("user_name"); // "UserName"
模式匹配
java
// URL匹配
boolean match = StringUtils.isMatch("/api/*", "/api/user"); // true
boolean matchAny = StringUtils.matchesAny("/api/user",
Arrays.asList("/api/*", "/admin/*")); // true
// 检查是否包含任意字符串
boolean contains = StringUtils.containsAnyIgnoreCase("Hello", "hello", "world"); // true
字符串映射转换
java
// 单值映射
Map<String, String> statusMap = Map.of("1", "启用", "0", "禁用");
String result = StringUtils.convertWithMapping("1", statusMap); // "启用"
// 多值映射
String result2 = StringUtils.convertWithMapping("1,0", ",", statusMap); // "启用,禁用"
// 反向映射
String key = StringUtils.convertWithReverseMapping("启用", ",", statusMap); // "1"
实用功能
java
// 左补零
String padded = StringUtils.leftPadWithZero(123, 5); // "00123"
// URL编码/解码
String encoded = StringUtils.urlEncode("中文参数");
String decoded = StringUtils.urlDecode("%E4%B8%AD%E6%96%87");
// 向逗号分隔字符串添加元素(自动去重)
String result = StringUtils.addToCommaString("a,b", "c"); // "a,b,c"
2. 日期时间工具 (DateUtils)
提供全面的日期时间处理功能,支持多种格式和转换。
获取当前时间
java
// 获取当前时间
Date now = DateUtils.getNowDate();
String date = DateUtils.getDate(); // yyyy-MM-dd
String time = DateUtils.getTime(); // yyyy-MM-dd HH:mm:ss
String compact = DateUtils.dateTimeNow(); // yyyyMMddHHmmss
// 路径格式日期
String path = DateUtils.datePath(); // yyyy/MM/dd
格式化与解析
java
// 格式化
String formatted = DateUtils.formatDate(new Date()); // yyyy-MM-dd
String dateTime = DateUtils.formatDateTime(new Date()); // yyyy-MM-dd HH:mm:ss
// 使用枚举格式
String custom = DateUtils.parseDateToStr(DateTimeFormat.DATE_COMPACT, new Date());
// 解析多种格式
Date parsed = DateUtils.parseDate("2023-07-22");
Date parsed2 = DateUtils.parseDate("2023/07/22 15:30:45");
时间差计算
java
Date start = DateUtils.parseDate("2023-07-01");
Date end = DateUtils.parseDate("2023-07-22");
// 计算时间差
long days = DateUtils.difference(start, end, TimeUnit.DAYS); // 21
long hours = DateUtils.difference(start, end, TimeUnit.HOURS);
// 格式化时间差
String diff = DateUtils.getDatePoor(end, start); // "21天 0小时 0分钟"
String detail = DateUtils.getTimeDifference(end, start); // "21天"
类型转换
java
// LocalDateTime 转 Date
Date date = DateUtils.toDate(LocalDateTime.now());
// LocalDate 转 Date
Date date2 = DateUtils.toDate(LocalDate.now());
日期范围校验
java
// 校验日期范围不超过30天
try {
DateUtils.validateDateRange(startDate, endDate, 30, TimeUnit.DAYS);
} catch (ServiceException e) {
// 处理范围超限
}
3. Stream流处理工具 (StreamUtils)
简化集合的流式处理操作。
过滤与查找
java
List<User> users = getUserList();
// 过滤
List<User> activeUsers = StreamUtils.filter(users, user -> "1".equals(user.getStatus()));
// 查找第一个
User firstAdmin = StreamUtils.findFirst(users, user -> "admin".equals(user.getRole()));
// 查找任意一个
Optional<User> anyActive = StreamUtils.findAny(users, user -> "1".equals(user.getStatus()));
转换操作
java
// 转换为List
List<String> names = StreamUtils.toList(users, User::getName);
List<Long> ids = StreamUtils.toList(users, User::getId);
// 转换为Set
Set<String> roleSet = StreamUtils.toSet(users, User::getRole);
// 拼接
String nameStr = StreamUtils.join(users, User::getName); // 逗号分隔
String customJoin = StreamUtils.join(users, User::getName, " | "); // 自定义分隔符
映射操作
java
// 转为Map (key-value相同类型)
Map<Long, User> userMap = StreamUtils.toIdentityMap(users, User::getId);
// 转为Map (key-value不同类型)
Map<Long, String> idNameMap = StreamUtils.toMap(users, User::getId, User::getName);
分组操作
java
// 按单一条件分组
Map<String, List<User>> roleGroups = StreamUtils.groupByKey(users, User::getRole);
// 按两个条件分组
Map<String, Map<String, List<User>>> deptRoleGroups =
StreamUtils.groupBy2Key(users, User::getDeptCode, User::getRole);
// 分组为Map
Map<String, Map<Long, User>> groups =
StreamUtils.group2Map(users, User::getDeptCode, User::getId);
排序
java
// 排序
List<User> sorted = StreamUtils.sorted(users,
Comparator.comparing(User::getCreateTime).reversed());
Map合并
java
Map<String, Integer> map1 = Map.of("a", 1, "b", 2);
Map<String, Integer> map2 = Map.of("b", 3, "c", 4);
// 合并Map
Map<String, Integer> merged = StreamUtils.merge(map1, map2,
(v1, v2) -> (v1 == null ? 0 : v1) + (v2 == null ? 0 : v2));
// 结果: {a=1, b=5, c=4}
4. 树形结构构建工具 (TreeBuildUtils)
构建和操作树形数据结构。
构建树形结构
java
List<Menu> menuList = getMenuList();
// 自动识别根节点构建
List<Tree<Long>> tree = TreeBuildUtils.build(menuList, (menu, treeNode) -> {
treeNode.setId(menu.getId());
treeNode.setParentId(menu.getParentId());
treeNode.setName(menu.getName());
treeNode.putExtra("url", menu.getUrl());
});
// 指定根节点构建
List<Tree<Long>> tree2 = TreeBuildUtils.build(menuList, 0L, (menu, treeNode) -> {
// 节点解析逻辑
});
树形操作
java
// 获取所有叶子节点
List<Tree<Long>> leafNodes = TreeBuildUtils.getLeafNodes(tree);
// 获取所有子节点(包括自身)
List<Tree<Long>> allNodes = TreeBuildUtils.getAllNodes(rootNode);
// 查找指定节点
Tree<Long> node = TreeBuildUtils.findNodeById(tree, 123L);
// 获取树的最大深度
int depth = TreeBuildUtils.getMaxDepth(tree);
5. 反射工具 (ReflectUtils)
扩展 HuTool 的反射工具,支持多级属性访问。
多级属性访问
java
User user = getUser();
// 获取多级属性
String profileName = ReflectUtils.invokeGetter(user, "profile.name");
String companyName = ReflectUtils.invokeGetter(user, "profile.company.name");
// 设置多级属性
ReflectUtils.invokeSetter(user, "profile.name", "张三");
ReflectUtils.invokeSetter(user, "profile.company.name", "ABC公司");
安全访问
java
// 安全获取属性(遇到null不抛异常)
String name = ReflectUtils.getPropertySafely(user, "profile.name");
// 检查是否具有属性路径
boolean hasProperty = ReflectUtils.hasProperty(user, "profile.name");
6. 对象工具 (ObjectUtils)
扩展 HuTool 的对象工具,提供安全的对象访问。
安全属性访问
java
User user = getUser(); // 可能为null
// 安全获取属性
String name = ObjectUtils.getIfNotNull(user, User::getName);
// 带默认值的安全获取
String name2 = ObjectUtils.getIfNotNull(user, User::getName, "未知用户");
7. Spring上下文工具 (SpringUtils)
访问Spring容器和Bean管理。
Bean操作
java
// 获取Bean
UserService userService = SpringUtils.getBean(UserService.class);
UserService userService2 = SpringUtils.getBean("userService");
// 检查Bean是否存在
boolean exists = SpringUtils.containsBean("userService");
// 检查是否单例
boolean singleton = SpringUtils.isSingleton("userService");
// 获取Bean类型
Class<?> type = SpringUtils.getType("userService");
// 获取别名
String[] aliases = SpringUtils.getAliases("userService");
AOP代理
java
// 获取AOP代理对象
UserService proxy = SpringUtils.getAopProxy(userServiceImpl);
环境信息
java
// 获取应用上下文
ApplicationContext context = SpringUtils.context();
// 判断是否虚拟线程环境
boolean isVirtual = SpringUtils.isVirtual();
8. Servlet工具 (ServletUtils)
处理HTTP请求响应的实用工具。
参数获取
java
// 获取请求参数
String userName = ServletUtils.getParameter("userName");
String userName2 = ServletUtils.getParameter("userName", "默认值");
// 类型转换
Integer pageNum = ServletUtils.getParameterToInt("pageNum");
Integer pageSize = ServletUtils.getParameterToInt("pageSize", 10);
Boolean active = ServletUtils.getParameterToBool("active");
// 获取所有参数
Map<String, String[]> allParams = ServletUtils.getParams(request);
Map<String, String> paramMap = ServletUtils.getParamMap(request);
请求响应对象
java
// 获取当前请求响应对象
HttpServletRequest request = ServletUtils.getRequest();
HttpServletResponse response = ServletUtils.getResponse();
HttpSession session = ServletUtils.getSession();
请求头处理
java
// 获取请求头
String userAgent = ServletUtils.getHeader(request, "User-Agent");
Map<String, String> headers = ServletUtils.getHeaders(request);
响应处理
java
// 渲染JSON响应
ServletUtils.renderString(response, "{\"success\": true}");
// 判断Ajax请求
boolean isAjax = ServletUtils.isAjaxRequest(request);
客户端信息
java
// 获取客户端IP
String clientIP = ServletUtils.getClientIP();
// URL编码解码
String encoded = ServletUtils.urlEncode("中文");
String decoded = ServletUtils.urlDecode("%E4%B8%AD%E6%96%87");
9. 线程工具 (ThreadUtils)
线程池管理和异常处理。
线程池优雅关闭
java
ExecutorService executor = Executors.newFixedThreadPool(10);
// 优雅关闭(默认120秒超时)
ThreadUtils.shutdownGracefully(executor);
// 自定义超时时间
ThreadUtils.shutdownGracefully(executor, 60);
异常处理
java
// 在ThreadPoolExecutor的afterExecute中使用
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
ThreadUtils.logException(r, t);
}
线程休眠
java
// 安全休眠(自动处理中断异常)
ThreadUtils.sleep(1000); // 1秒
ThreadUtils.sleepSeconds(5); // 5秒
// 获取线程信息
String threadInfo = ThreadUtils.getCurrentThreadInfo();
10. 文件工具 (FileUtils & FileTypeUtils)
文件处理和类型判断。
文件下载响应头
java
@GetMapping("/download")
public void download(HttpServletResponse response) {
String fileName = "用户数据.xlsx";
// 设置下载响应头(自动处理文件名编码)
FileUtils.setAttachmentResponseHeader(response, fileName);
// 文件内容写入响应流
// ...
}
文件类型判断
java
// 按扩展名判断
boolean isImage = FileTypeUtils.isImage("jpg");
boolean isDocument = FileTypeUtils.isDocument("pdf");
boolean isVideo = FileTypeUtils.isVideo("mp4");
// 按File对象判断
File file = new File("demo.png");
boolean isImage2 = FileTypeUtils.isImage(file);
String fileType = FileTypeUtils.getFileType(file); // "图片"
// 检查是否允许的类型
boolean allowed = FileTypeUtils.isAllowed("exe"); // false
URL编码工具
java
// 百分号编码
String encoded = FileUtils.percentEncode("文件名.txt");
11. IP地址工具 (AddressUtils & RegionUtils)
IP地址解析和地理位置定位。
IP地址解析
java
// 获取IP地理位置
String location = AddressUtils.getRealAddressByIp("8.8.8.8");
// 可能返回: "美国|北美|美国|美国|谷歌"
String location2 = AddressUtils.getRealAddressByIp("192.168.1.1");
// 返回: "内网IP"
String location3 = AddressUtils.getRealAddressByIp("invalid-ip");
// 返回: "XX XX"
离线IP定位
java
// 使用ip2region库进行离线定位
String cityInfo = RegionUtils.getCityInfo("202.108.22.5");
// 返回格式: "中国|华北|北京市|北京市|联通"
网络工具
java
// IP类型判断
boolean isIPv4 = NetUtils.isIpv4("192.168.1.1"); // true
boolean isIPv6 = NetUtils.isIpv6("2001:db8::1"); // true
// 内网判断
boolean isInner = NetUtils.isInnerIP("192.168.1.1"); // true
boolean isInnerV6 = NetUtils.isInnerIpv6("fe80::1"); // true
12. 正则工具 (Regex Utils)
正则表达式相关工具。
预定义模式
java
// 使用预编译模式池
Pattern i18nPattern = RegexPatternPool.I18N_KEY;
Pattern accountPattern = RegexPatternPool.ACCOUNT;
Pattern statusPattern = RegexPatternPool.BINARY_STATUS;
校验器
java
// 国际化键格式校验
boolean valid = RegexValidator.isValidI18nKey("user.profile.name"); // true
// 账号格式校验
boolean validAccount = RegexValidator.isValidAccount("admin123"); // true
// 状态值校验
boolean validStatus = RegexValidator.isValidStatus("1"); // true
// 字典类型校验
boolean validDict = RegexValidator.isValidDictType("sys_user_sex"); // true
提取工具
java
// 从字符串中提取匹配部分
String result = RegexUtils.extractFromString(
"用户ID: 12345", "(\\d+)", "未找到");
// 返回: "12345"
13. SQL安全工具 (SqlUtil)
防止SQL注入的安全工具。
ORDER BY安全校验
java
// 校验排序参数
String orderBy = "name asc, create_time desc";
String safeOrderBy = SqlUtil.escapeOrderBySql(orderBy);
// 检查是否安全
boolean isSafe = SqlUtil.isValidOrderBySql("name asc"); // true
boolean isUnsafe = SqlUtil.isValidOrderBySql("name; drop table"); // false
SQL关键字过滤
java
try {
SqlUtil.filterKeyword("select * from user");
// 抛出异常: 参数存在SQL注入风险
} catch (IllegalArgumentException e) {
// 处理SQL注入风险
}
14. 参数校验工具 (ValidatorUtils)
手动触发Bean Validation校验。
基本校验
java
User user = new User();
user.setName(""); // 违反@NotBlank约束
try {
// 校验对象(抛出异常)
ValidatorUtils.validate(user);
} catch (ConstraintViolationException e) {
// 处理校验失败
System.out.println(e.getMessage());
}
// 校验并返回结果(不抛异常)
Set<ConstraintViolation<User>> violations = ValidatorUtils.validateAndReturn(user);
分组校验
java
// 使用校验分组
ValidatorUtils.validate(user, AddGroup.class);
ValidatorUtils.validate(user, EditGroup.class);
属性校验
java
// 校验单个属性
ValidatorUtils.validateProperty(user, "email");
// 校验属性值
ValidatorUtils.validateValue(User.class, "email", "invalid-email");
便捷方法
java
// 检查是否通过校验
boolean isValid = ValidatorUtils.isValid(user);
// 获取错误信息
String errors = ValidatorUtils.getValidationErrors(user);
// 返回: "name: 不能为空; email: 邮箱格式错误"
15. 对象映射工具 (MapstructUtils)
基于 MapStruct Plus 的对象映射工具。
基本映射
java
// 对象转换
UserVo userVo = MapstructUtils.convert(user, UserVo.class);
// 列表转换
List<UserVo> userVos = MapstructUtils.convert(userList, UserVo.class);
// 属性赋值
UserVo vo = new UserVo();
MapstructUtils.convert(user, vo); // 将user属性赋值给vo
Map映射
java
// Map转对象
Map<String, Object> map = Map.of("name", "张三", "age", 25);
User user = MapstructUtils.convert(map, User.class);
16. 国际化消息工具 (MessageUtils)
国际化消息处理。
消息获取
java
// 获取国际化消息
String message = MessageUtils.message("user.not.found");
// 带参数的消息
String message2 = MessageUtils.message("user.login.success", "张三");
// 消息不存在时返回键本身
String message3 = MessageUtils.message("nonexistent.key"); // 返回: "nonexistent.key"
使用最佳实践
1. 性能优化
大数据量处理
java
// 使用Stream工具处理大量数据时,注意内存使用
List<UserVo> vos = StreamUtils.toList(users, user -> {
// 避免在转换函数中进行复杂操作
return MapstructUtils.convert(user, UserVo.class);
});
// 分批处理大数据量
List<List<User>> batches = Lists.partition(users, 1000);
for (List<User> batch : batches) {
// 分批处理
}
缓存利用
java
// 正则模式使用预编译版本
Pattern pattern = RegexPatternPool.I18N_KEY; // 而不是 Pattern.compile()
// 反射操作缓存Method对象
// ReflectUtils内部已实现缓存
2. 异常处理
安全的工具方法使用
java
// 使用安全版本的方法
String name = ObjectUtils.getIfNotNull(user, User::getName, "未知");
String profileName = ReflectUtils.getPropertySafely(user, "profile.name");
// 或者使用try-catch
try {
String name = ReflectUtils.invokeGetter(user, "profile.name");
} catch (Exception e) {
log.warn("获取用户档案名称失败", e);
// 设置默认值或其他处理
}
3. 字符串处理优化
大量字符串拼接
java
// 使用Stream工具进行拼接
String result = StreamUtils.join(users, User::getName, ",");
// 而不是循环拼接
StringBuilder sb = new StringBuilder();
for (User user : users) {
if (sb.length() > 0) sb.append(",");
sb.append(user.getName());
}
字符串映射批量转换
java
// 批量转换
List<String> statusLabels = StreamUtils.toList(statusCodes,
code -> StringUtils.convertWithMapping(code, statusMap));
4. 日期时间处理
时区注意事项
java
// 使用系统默认时区的转换
Date date = DateUtils.toDate(LocalDateTime.now());
// 如果需要特定时区,使用原生API
ZonedDateTime zdt = LocalDateTime.now().atZone(ZoneId.of("Asia/Shanghai"));
Date date2 = Date.from(zdt.toInstant());
5. 线程安全
工具类都是线程安全的
java
// 所有工具类方法都是静态的,线程安全
// 可以在多线程环境中安全使用
CompletableFuture.supplyAsync(() -> {
return StringUtils.format("用户{}, 时间{}", userName, DateUtils.getTime());
});
扩展指南
1. 自定义工具类
java
// 遵循相同的设计模式
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CustomUtils {
// 静态方法
public static String customMethod(String input) {
// 实现逻辑
return result;
}
// 重载方法提供便利
public static String customMethod(String input, String defaultValue) {
return StringUtils.isNotBlank(input) ? customMethod(input) : defaultValue;
}
}
2. 扩展现有工具
java
// 通过继承扩展(如果需要)
public class EnhancedStringUtils extends StringUtils {
public static String customFormat(String template, Object... args) {
// 自定义格式化逻辑
return format(template, args);
}
}
常见问题
Q: 为什么某些工具方法返回不可变集合?
A: 为了防止意外修改,某些场景下返回不可变集合。如需修改,请创建新的可变集合。
Q: 如何处理大数据量的Stream操作?
A: 考虑使用并行流、分批处理或者调整JVM堆内存设置。
Q: 正则表达式性能如何优化?
A: 使用 RegexPatternPool 中的预编译模式,避免重复编译。
Q: 反射操作的性能影响?
A: ReflectUtils 内部有缓存机制,但仍建议在性能敏感场景中谨慎使用。
Q: 如何添加新的文件类型支持?
A: 修改 FileTypeUtils 中的扩展名集合常量,或者使用继承的方式扩展。