From dae71bad1bc9562869ff6520943029044298ad5e Mon Sep 17 00:00:00 2001 From: s_hongshibo Date: Wed, 12 Aug 2026 15:15:04 +0800 Subject: [PATCH] docs: enrich README feature documentation - data mask: detailed table + examples for @EmailDataMask/@MobileDataMask/ @IdCardDataMask, and clarify masking only affects output, not comparison - add built-in comparator section (DefaultDiffComparator, BigDecimalEffectiveDiffComparator) - add structured diff result section (diffResult / DiffResult / Diff API) - add output prefix + custom ToStringStyle section - add misc behavior notes (static/transient skipped, reflection cache) - fix typo: DiffUtil -> DiffUtils --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 12f429e..2a45c27 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ private String name; ``` ##### 手动忽略 -调用工具类DiffUtil 时传递排除比较的字段名。 +调用工具类DiffUtils 时传递排除比较的字段名。 ```java -DiffResult diffResult = DiffUtil.diff(obj1, obj2, "name"); +DiffResult diffResult = DiffUtils.diff(obj1, obj2, "name"); ``` #### 自定义比较器 @@ -51,6 +51,17 @@ public class MyComparator implements DiffComparable { private String name; ``` +#### 内置比较器 +库内置了几个可直接复用的比较器,无需自己实现: + +- `DefaultDiffComparator`:默认比较器,使用 `equals` 比较。 +- `BigDecimalEffectiveDiffComparator`:`BigDecimal` 忽略尾零的有效值比较,`1.0` 与 `1.00` 视为相等。 + +```java +@DiffCompare(using = BigDecimalEffectiveDiffComparator.class) +private BigDecimal money; +``` + #### 自定义类型属性 支持自定义成员变量需要使用注解标识。会自动解析到属性 可以加注解`@DiffBean`来标识。 @@ -155,7 +166,69 @@ public class DateTimeDiffFormatter implements DiffFormatter { 使用示例代码详见:`com.openquartz.javaobjdiff.test.DiffUtilTest` #### 脱敏支持 -使用注解可以支持对应的属性脱敏。\ -`@EmailDataMask`可以支持邮箱脱敏。\ -`@IdCardDataMask`可以支持身份证号脱敏。\ -`@MobileDataMask`可以支持手机号脱敏。 \ No newline at end of file +对于手机号、邮箱、身份证号等敏感字段,在输出差异结果时支持自动脱敏展示,避免敏感信息在 diff 结果中明文泄露。 + +支持以下三种内置脱敏注解: + +| 注解 | 适用字段 | 脱敏规则 | 示例 | +| --- | --- | --- | --- | +| `@EmailDataMask` | 邮箱 | 前缀仅保留首字母,其余用 `*` 替代,保留 `@` 及域名 | `wangtest1111@126.com` → `***********w@126.com` | +| `@MobileDataMask` | 手机号 / 座机 | 手机号保留前 3 位与后 4 位;座机保留区号与后 4 位 | `17000000056` → `170****0056`;`010-12345678` → `010-****5678` | +| `@IdCardDataMask` | 身份证号 | 保留前 6 位与后 4 位(仅对 18 位生效) | `321556199301152110` → `321556********2110` | + +用法示例: + +```java +public class User { + @MobileDataMask + private String mobile; + + @EmailDataMask + private String email; + + @IdCardDataMask + private String idCard; +} +``` + +diff 输出示例: + +``` +User[mobile=170****0056, email=***********w@126.com, idCard=321556********2110] -> User[mobile=171****0056, email=*********l@126.com, idCard=301556********2110] +``` + +> **注意**:脱敏仅作用于 `DiffResult.toString()` / `Diff.getFormatValue()` 等**输出展示**环节,字段的比较逻辑仍基于原始值。两个对象该字段原始值不同,即使脱敏后的展示串相同,仍会被判定为有差异。 + +#### 结构化 diff 结果 +`DiffUtils.diff(...)` 返回格式化的字符串;如果需要以编程方式获取结构化结果,使用 `DiffUtils.diffResult(...)`: + +```java +DiffResult result = DiffUtils.diffResult(person1, person2); + +boolean diff = result.isDiff(); // 是否存在差异 +int count = result.getNumberOfDiffs(); // 差异数量 +List> diffs = result.getDiffs(); // 差异列表(不可修改) + +for (Diff d : result) { // DiffResult 实现了 Iterable> + String field = d.getFieldName(); // 字段路径,如 address.country + String name = d.getActualName(); // 展示名(别名优先) + Object left = d.getLeft(); // 左侧(旧)值 + Object right = d.getRight(); // 右侧(新)值 + Object formatLeft = d.getFormatValue(left); // 格式化/脱敏后的展示值 +} +``` + +#### 输出前缀与自定义样式 +```java +// 为输出中的所有字段添加前缀 +String diff = DiffUtils.diff(source, target, "user", "excludeField1", "excludeField2"); + +// 使用自定义 ToStringStyle +String diff = DiffUtils.diff(source, target, new MyToStringStyle(), "excludeField1"); +``` + +#### 其他行为说明 +- `static`、`transient` 字段不参与比较。 +- 字段反射结果按 `Class` 缓存,频繁比较同一类型的对象时性能更好。 +- 默认使用 `equals` / 引用相等进行比较,可通过 `@DiffIgnore`、`@DiffCompare`、`@DiffBean`、`@DiffFormat` 等注解覆盖默认行为。 +