Skip to content

工具类 ​

这篇解决什么 ​

集合转换、时间区间、JSON 读写、取客户端 IP、从容器拿 Bean,业务里天天会碰到。读完能改 yudao-common 的 util 包,并先用 Hutool,而不是再贴一份新工具类。

对象拷贝走 VO 对象转换、数据翻译 的 BeanUtils。入参校验和时间格式走 参数校验、时间传参。分页条件拼 SQL 走 MyBatis 数据库。

默认端口 48080,管理端前缀 /admin-api。

怎么选 ​

package-info 写明:先查 Hutool;没有再封装,类名以 Utils 结尾,和 Hutool 的 Util 区分。依赖是 hutool-all 5.8.x,文档见 Hutool。

名称说明仓库路径
Hutool主工具库:CollUtil、StrUtil、DateUtil、HttpUtilyudao-common/pom.xml 的 hutool-all
util 包只补 Hutool 没有的能力ruoyi-office/yudao-framework/yudao-common/.../util/
Lombok生成 getter / setter / 构造,少写样板工程根 ruoyi-office/lombok.config

本文只列 collection、date、json、servlet、spring 五个包里真实存在的类。BeanUtils、PageUtils 见 VO / 分页篇。

先复用,再封装

空集合、字符串裁剪、日期加减,Hutool 已有就直接调。框架已有 CollectionUtils.convertList 这类方法时,复制一份到业务模块只会分叉。真要补能力,改对应 Utils,并写单测。

根目录 lombok.config 打开链式 setter,并让 toString / equals / hashCode 走父类:

名称说明仓库路径
lombok.accessors.chainsetXxx 返回 thisruoyi-office/lombok.config
lombok.tostring.callsupertoString 带上父字段同上
lombok.equalsandhashcode.callsuper相等比较带上父字段同上
config.stopBubbling不再向上找别的 Lombok 配置同上

集合 ​

四个类都在 cn.iocoder.yudao.framework.common.util.collection。空集合返回空 List / Map / Set,不返回 null。

名称说明仓库路径
CollectionUtilsconvertList / convertSet / convertMap / convertMultiMap、过滤、求和、diffList.../util/collection/CollectionUtils.java
MapUtilsfindAndThen、从 KeyValue 建 Map、取 BigDecimal.../util/collection/MapUtils.java
SetUtilsasSet,内部是 Hutool CollUtil.newHashSet.../util/collection/SetUtils.java
ArrayUtils数组合并、集合转数组、按下落标.../util/collection/ArrayUtils.java

UserController 批量回填部门、角色、岗位时,先抽 ID 再查表:

java
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
        convertList(list, AdminUserDO::getDeptId));
Set<Long> userIds = convertSet(list, AdminUserDO::getId);
Map<Long, RoleDO> roleMap = convertMap(
        CollUtil.removeNull(roleService.getRoleListFromCache(
                convertSet(userRoles, UserRoleDO::getRoleId))),
        RoleDO::getId);

convertMap 默认冲突保留先出现的值。一对多用 convertMultiMap(值是 List)或 convertMultiMap2(值是 Set)。新旧列表对账用 diffList,返回「新增 / 修改 / 删除」三段。

MapUtils.findAndThen 在 key 或 value 为 null 时直接跳过,适合列表翻译:

java
MapUtils.findAndThen(userMap, customerVO.getOwnerUserId(), user -> {
    customerVO.setOwnerUserName(user.getNickname());
});

这段在 CRM 客户列表,完整拼接见 VO 对象转换、数据翻译。

时间 ​

新代码用 LocalDate / LocalDateTime。和 Date 互转、默认时区常量放 DateUtils。

名称说明仓库路径
DateUtilsDate ↔ LocalDateTime、TIME_ZONE_DEFAULT、日期格式常量.../util/date/DateUtils.java
LocalDateTimeUtils区间、日/月起止、重叠、分片;内嵌 TimeRange.../util/date/LocalDateTimeUtils.java
名称说明仓库路径
TIME_ZONE_DEFAULTGMT+8DateUtils
FORMAT_YEAR_MONTH_DAYyyyy-MM-dd,VO 上 @JsonFormat 常用DateUtils
FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECONDyyyy-MM-dd HH:mm:ssDateUtils
EMPTY1970-01-01 零点,给唯一索引当非 null 占位LocalDateTimeUtils

字典类型删除时把 deletedTime 写成 EMPTY,避免唯一索引里出现多个 null:

java
dictType.setDeletedTime(LocalDateTimeUtils.EMPTY);

这段在 yudao-module-system-server 的 DictTypeServiceImpl。

判断「现在是否落在区间」用 isBetween;日/月边界用 beginOfDay、beginOfMonth、getDateTimeRange。会议室、考勤这类要算重叠或裁切时段,用 isOverlap、mergeTimeRanges、subtractTimeRanges。

接口上 LocalDate 必须带 @JsonFormat,LocalDateTime 默认毫秒。对照见 参数校验、时间传参。

JSON ​

业务里统一走 JsonUtils,不要再 new 一个 ObjectMapper。Web 启动后 YudaoJacksonAutoConfiguration 会 JsonUtils.init,和接口序列化共用同一套规则。

名称说明仓库路径
JsonUtilstoJsonString / parseObject / parseArray / convertObject.../util/json/JsonUtils.java
TimestampLocalDateTimeSerializer默认写成 epoch 毫秒;字段有 @JsonFormat 则按 pattern.../util/json/databind/
TimestampLocalDateTimeDeserializer毫秒读回 LocalDateTime同上
NumberSerializer超出 JS 安全整数的 Long 改写成字符串同上;注册在 YudaoJacksonAutoConfiguration
java
String json = JsonUtils.toJsonString(snapshot);
UserRespVO vo = JsonUtils.parseObject(json, UserRespVO.class);
List<UserRespVO> list = JsonUtils.parseArray(json, UserRespVO.class);

parseObject 失败会抛运行时异常并打日志。允许失败时用 parseObjectQuietly 或 parseMap,得到 null。Map / POJO 转目标类型用 convertObject,不要先 toJsonString 再 parse。

带 @JsonTypeInfo(use = Id.CLASS) 且 JSON 没有 class 字段时,用 parseObject2(Hutool JSONUtil)。

Servlet ​

ServletUtils 包一层 Hutool JakartaServletUtil,方便在非 Controller 参数里取当前请求。

名称说明仓库路径
ServletUtils写 JSON、UA、客户端 IP、读 Body、附件下载.../util/servlet/ServletUtils.java
CacheRequestBodyFilter缓存 JSON Body,才能重复读yudao-spring-boot-starter-web/.../CacheRequestBodyFilter.java

登录日志这样取 IP 和 UA,不必把 HttpServletRequest 一路往下传:

java
reqDTO.setUserAgent(ServletUtils.getUserAgent());
reqDTO.setUserIp(ServletUtils.getClientIP());

这段在 yudao-module-system-server 的 AdminAuthServiceImpl。getRequest() 靠 RequestContextHolder,异步线程里拿不到,要先取出再往后传。

getBody / getBodyBytes 只处理 Content-Type 以 application/json 开头的请求;表单读不到。写回包用 writeJSON,下载用 writeAttachment。

Spring ​

名称说明仓库路径
SpringUtils继承 Hutool SpringUtil,多一个 isProd().../util/spring/SpringUtils.java
SpringExpressionUtils解析 SpEL:切面参数,或容器里的 Bean.../util/spring/SpringExpressionUtils.java

getBean、getActiveProfile 来自父类。isProd() 判断当前 profile 是否等于 prod。静态方法、工具类里临时取 Bean 可以调它,常规 Service 仍用 @Resource。

java
if (SpringUtils.isProd()) {
    // 生产环境收紧日志或开关
}
BillCodeUtils coder = SpringUtils.getBean(BillCodeUtils.class);

切面上按方法参数算表达式(操作日志、租户忽略、脱敏开关)走 parseExpressions(joinPoint, ...)。例如 TenantIgnoreAspect 读 @TenantIgnore.enable()。和 Bean 工厂绑定时用 parseExpression(expr, variables)。

配置与操作 ​

优先用 yudao-common 已有工具,不要复制一份日期/JSON 工具。单据号走 BillCodeUtils Bean。

开启见 框架层。

相关篇 ​

联系我们

获取报价、演示和二开方案

微信咨询二维码

微信咨询

17156169080

添加时备注「RuoYi Office」

在线体验商业版