外观
通用工具
本页入口均位于 com.own.constant.util。集合、文件和脱敏编码分别见集合与分页、文件与图片、脱敏与编码。
从具体任务选择即可:整理字符串用文本与参数,计算报文校验值用CRC,关联任务日志用 TraceId,在单进程内同步通知监听器用进程内事件。时间、标识和静态 YAML 的兼容行为放在各自小节中供查询。
文本与参数
java
import com.own.constant.util.CharacterUtil;
import com.own.constant.util.NumberUtil;
import com.own.constant.util.ParamUtil;
import java.util.Map;
System.out.println(CharacterUtil.fullWidthToHalfWidth("ABC123")); // ABC123
System.out.println(NumberUtil.completeDigitsStart(12, 5)); // 00012
System.out.println(ParamUtil.sort(Map.of("b", "2", "a", "1"))); // a=1&b=2| 入口 | 行为与边界 |
|---|---|
| CharacterUtil.fullWidthToHalfWidth(String/Character) | 转换全角 ASCII 字母、数字和标点,不转换全角空格;null 抛异常 |
| EmojiUtil.filter(text) | 空白原样返回;按正则移除代理字符范围,可能删除非 Emoji 的补充字符,不是完整 Emoji 解析 |
| DataUtil.getPrintLength(text) | U+0000..U+00FF 计 1,其他 UTF-16 code unit 计 2;空白为 0,不是精确显示宽度 |
| ParamUtil.sort(map) | key 字典序拼接 key=value&...,不做 URL 编码;null value 拼为 null |
| ParamUtil.sortObject(map) | 对 value 调用 toString,null value 抛异常 |
| ParamUtil.mergeParams(value, values) | 合并到新 HashSet,不保序;忽略单值 null,集合内的 null 保留 |
| NumberUtil.checkNumberLimit(number, floor, ceil) | 限制数值,但不验证 floor 小于等于 ceil |
| NumberUtil.completeDigitsStart/End(content, length[, filler]) | 左/右补位,默认 0;超过长度不截断,null content 抛异常 |
HTTP/URL 与表单格式
判断协议、编码参数和验证输入是不同操作:识别 HTTP/HTTPS scheme 用 HttpUtil.isHttpUrl,编码单个参数值用 UrlUtil.specialUrlEncode。这两者都不能证明一个地址适合被服务端下载。
HttpUtil.isHttp/isHttps/isUrl 只检查小写前缀,不 trim。isHttpUrl 则 trim 后通过 URI scheme 忽略大小写识别 HTTP/HTTPS,空值或非法 URI 返回 false;它不要求 host,http:test 也可返回 true,不能据此直接允许服务端下载。
UrlUtil.specialUrlEncode(text) 对整个文本执行 UTF-8 表单编码,再调整空格、星号和波浪号;适用于单个参数值,直接传完整 URL 会把 :/?& 等也编码。
FormUtil.isPhone 只要求 11 位数字且首位为 1;isEmail 使用简化邮箱正则。FormUtil.isUrl 当前把输入当作正则、固定表达式当作待匹配文本,普通 URL 常返回 false,非法正则还会抛异常,不应用作 URL 验证。只需识别协议可改用上面的 isHttpUrl;完整地址或下载来源校验还需应用自行实现。
十六进制与 CRC
DataUtil.hexStringToBytes 将偶数长度文本按两位转成一个字节;null/空字符串返回 null。它不校验非法字符,奇数长度会因读取末尾下一字符而抛 StringIndexOutOfBoundsException,不会忽略末位。调用前应自行校验长度和字符。
Crc8Util 则使用 CRC-8/MAXIM 的反射多项式 0x8C、初始值 0,提供明确的报文校验入口:
java
import com.own.constant.util.Crc8Util;
System.out.println(Crc8Util.calcCrcHex("313233343536373839")); // A1calcCrc(byte[]/String) 返回 0..255,calcCrcHex 返回两位大写十六进制。字符串参数是十六进制文本,允许空白,非法字符抛 IllegalArgumentException;奇数长度将末位按低 4 位处理,例如 ABC 对应 AB 0C。null/空输入的 CRC 为 0。CRC 用于校验报文差错,不提供消息认证。
时间、随机值与标识
| 工具 | 当前规则 |
|---|---|
| TimeUtil.unitConvert(time, unit) | DAYS/HOURS/MINUTES/SECONDS 转为毫秒;其他单位原值返回,MICROSECONDS/NANOSECONDS 不会正确折算 |
| TimeUtil.DEFAULT_ZONE_ID | Asia/Shanghai,只是常量,不修改 JVM 默认时区 |
| RandomUtil.getRandomString(n[, template]) | 从模板随机取字符,默认数字加大小写字母;n 小于等于 0 为空串,null 模板抛异常 |
| UUIDToLongUtil.to(String/UUID) | UUID 高低 64 位异或后清除符号位,返回非负 long;有损映射,不能保证不碰撞 |
时间乘法不检查 long 溢出。随机字符使用 java.util.Random,不能作为 Token 或密钥生成器;空模板且 n 大于 0 会失败,模板中重复字符会影响概率。
TraceId 与线程边界
TraceIdUtil.get() 读取 SLF4J MDC 的 traceId,不存在或空白时生成 UUID 并写入;set(object) 写入 toString,传 null 时生成新 UUID。MDC 的实际存储依赖应用日志实现。
java
import com.own.constant.ConstantCommon;
import com.own.constant.util.TraceIdUtil;
import org.slf4j.MDC;
String previous = MDC.get(ConstantCommon.TRACE_ID);
try {
TraceIdUtil.set("job-demo");
System.out.println(TraceIdUtil.get());
} finally {
if (previous == null) {
MDC.remove(ConstantCommon.TRACE_ID);
} else {
MDC.put(ConstantCommon.TRACE_ID, previous);
}
}该工具不提供请求拦截器、线程间复制或自动清理。已有 Base 的 HTTP 和异步任务链路时,优先沿用其上下文生命周期,避免泄漏到线程池的下一项任务。
按 key 同步调用
SynchronizedUtil.exec(String/Integer, Runnable) 在进程内按 key 获取临时锁,两种 key 使用独立 Map。任务异常原样传播,finally 删除锁映射。
当前实现会在仍有线程等待旧锁时移除映射,后来的调用可能取得新锁,导致同 key 并行。因此它不能提供严格的串行执行保证;需要临界区一致性时使用生命周期明确的锁,或按场景接入 Store 锁。
进程内事件
EventEmitsUtil<T> 收集可序列化 Consumer,以 Lambda 实现类和方法名作为监听标识。下面的完整类演示长期和一次性监听:
java
package example;
import com.own.constant.util.EventEmitsUtil;
public class EventExample {
static void always(String value) {
System.out.println("always:" + value);
}
static void first(String value) {
System.out.println("once:" + value);
}
public static void main(String[] args) {
var events = new EventEmitsUtil<String>();
events.on(EventExample::always);
events.once(EventExample::first);
events.emit("A");
events.emit("B");
events.clear();
}
}输出依次为 always:A、once:A、always:B。off(consumer) 同时删除长期与一次性同标识项;clear() 删除全部监听。
执行是同步的:先长期,再执行未与长期同标识的一次性监听,最后清空一次性 Map。同一类同一方法的不同实例或捕获值可能被视为同一监听,相同标识会覆盖旧项;同一 Map 内没有执行顺序保证。
两个 Map 均无并发保护,emit 期间注册/删除可能触发并发修改异常。监听异常直接传播,并且可能阻止一次性 Map 清空,使已执行项在下次再次执行。该容器没有持久化、重试或跨进程投递。
监听器类型与标识解析
LambdaUtils.getLambdaMethodIdentity(Serializable) 依赖反射读取 writeReplace();普通对象或不可解析 Lambda 抛 BusinessException("无法解析 lambda")。注册方法接收 com.own.constant.function.SerializableConsumer<T>,不是任意 Consumer 实现。
读取静态 YAML
Spring 应用需要使用启动参数、外部配置或绑定对象时,优先使用 Spring Environment 或显式绑定的属性对象。下面的工具适用于维护已有的 classpath YAML 读取逻辑。
PropertiesYamlUtil.get(key) 在首次使用类时读取 classpath 的 application.yml,随后读取逗号分隔的 spring.profiles.include 文件和单个 spring.profiles.active 文件,后加载覆盖先加载。
缺少主文件或引用的 profile 文件可能导致类初始化失败;key 缺失时抛 NullPointerException。该工具不等价于 Spring Environment,不处理其完整配置来源或多 active profile 语义,也不支持刷新。