Compare 模块设计文档
1. 模块概述
Compare 模块是一个基于 Java 反射机制的对象差异比较组件,提供了灵活的对象属性比较功能,支持自定义比较规则、字段映射和国际化展示。该模块适用于需要记录对象变更、生成变更日志或展示数据差异的场景。
1.1 主要功能特性
- 基于注解的对象属性比较
- 支持多种比较规则(字符串映射、枚举映射、注解映射)
- 支持国际化字段名称展示
- 支持对象列表比较
- 支持自定义忽略字段或类
- 缓存机制提高性能
- 与 Spring Boot 无缝集成
2. 架构设计
2.1 整体架构
Compare 模块采用了清晰的分层架构设计,主要包含以下几个部分:
- 注解层:提供
@CompareProperty、@CompareIgnore、@CompareMapping等注解,用于标记需要比较的字段和配置比较规则 - 核心功能层:
CompareCore类实现核心的对象比较逻辑 - 工具层:
CompareUtil提供便捷的工具方法,采用单例模式管理CompareCore实例 - 国际化层:
CompareI18n提供国际化支持,使比较结果可以根据用户语言进行展示 - 配置层:
CompareProperties和CompareAutoConfiguration提供自动配置支持 - 数据模型层:
CompareNode用于存储字段的比较信息
2.2 模块结构
├── annotation/ # 注解定义
│ ├── CompareProperty.java # 标记需要比较的字段
│ ├── CompareIgnore.java # 标记需要忽略的类或字段
│ └── CompareMapping.java # 定义映射规则
├── config/ # 配置相关
│ ├── CompareAutoConfiguration.java # 自动配置类
│ └── CompareProperties.java # 配置属性类
├── enums/ # 枚举定义
│ └── CompareRule.java # 比较规则枚举
├── CompareCore.java # 核心比较实现类
├── CompareNode.java # 比较节点数据模型
├── CompareUtil.java # 工具类
└── CompareI18n.java # 国际化支持类
3. 核心类与接口
3.1 CompareCore
CompareCore 是整个模块的核心实现类,负责实现对象和列表的比较功能。
主要方法:
compareObj(Object beforeObj, Object afterObj):比较两个对象的差异compareList(List<?> beforeList, List<?> afterList, String mappingKey):基于映射规则比较两个列表compareListByIndex(List<?> beforeList, List<?> afterList):按索引顺序比较两个列表formatCompareDiff(CompareNode before, CompareNode after):将字段差异格式化为字符串
关键特性:
- 使用反射获取对象属性
- 支持缓存反射结果提高性能
- 实现多种比较规则的处理逻辑
- 支持字段值映射转换
3.2 CompareNode
CompareNode 是一个数据模型类,用于存储字段的比较信息。
主要字段:
fieldKey:字段名称fieldValue:字段值fieldDesc:字段描述(支持国际化)
3.3 CompareUtil
CompareUtil 是一个工具类,提供获取 CompareCore 实例的静态方法,采用了单例模式和缓存机制。
主要方法:
forClazz(Class<?> clazz):获取指定类对应的CompareCore实例
关键特性:
- 维护
CompareCore实例池,避免重复创建 - 提供类和字段的有效性校验
3.4 CompareI18n
CompareI18n 提供国际化支持,负责获取字段的多语言描述。
主要方法:
getMessage(String i18nKey):获取指定键的国际化消息
关键特性:
- 支持从请求头获取语言偏好
- 支持通过配置文件自定义国际化资源
4. 注解说明
4.1 @CompareProperty
标记一个字段是否需要进行比较,并可配置比较规则。
主要属性:
value():字段名称(用于国际化展示)ruleType():映射规则类型(STR、ENUM、MAPPING)ruleStr():字符串规则数组,格式如{"1->男", "2->女"}ruleEnum():枚举规则类ruleMappings():映射规则数组
4.2 @CompareIgnore
标记一个类或字段是否需要被忽略比较。
4.3 @CompareMapping
定义映射规则,用于 @CompareProperty 的 ruleMappings 属性。
主要属性:
source():源值target():目标值
5. 配置说明
5.1 CompareProperties
配置类,用于设置模块的相关属性。
主要配置项:
primaryLanguage:主语言,默认为 "zh"messageSourceBasename:国际化文件前缀,默认为 "compare"
5.2 CompareAutoConfiguration
自动配置类,用于集成 Spring Boot 应用。
主要功能:
- 自动加载
CompareProperties配置 - 创建
CompareI18n实例 - 打印模块启动 Banner
6. 枚举说明
6.1 CompareRule
定义比较规则类型的枚举。
枚举值:
STR:使用字符串规则进行比较ENUM:使用枚举规则进行比较MAPPING:使用映射规则进行比较
7. 核心功能实现机制
7.1 对象比较流程
- 通过
CompareUtil.forClazz()获取CompareCore实例 - 调用
compareObj()方法比较两个对象 - 使用反射获取对象的属性信息
- 根据注解配置处理字段值的映射转换
- 比较转换后的字段值,生成差异描述
- 将所有差异描述合并为最终结果
7.2 列表比较机制
模块支持两种列表比较模式:
- 基于映射规则的列表比较:通过指定映射键,根据键值匹配两个列表中的对象进行比较
- 按索引顺序的列表比较:直接按列表索引顺序比较对应位置的对象
7.3 国际化处理
- 通过
CompareI18n类获取字段的国际化描述 - 支持从 HTTP 请求头的
Accept-Language获取用户语言偏好 - 支持通过配置文件自定义国际化资源
7.4 性能优化
- 使用静态缓存存储类的字段信息,避免重复反射操作
- 使用实例池管理
CompareCore实例,避免重复创建 - 支持忽略不需要比较的字段或类,减少比较操作
8. 类图描述
classDiagram
class CompareCore {
-static final Map<Class<?>, List<Field>> CLAZZ_FIELD_CACHE
-static final String BLANK_STR
-static final String BLANK_FILED_VALUE
-static final String SPLITTER_ARROW
-static final String DEFUALT_IGNORE_FIELDS[]
+compareObj(Object beforeObj, Object afterObj)
+compareList(List<?> beforeList, List<?> afterList, String mappingKey)
+compareListByIndex(List<?> beforeList, List<?> afterList)
+formatCompareDiff(CompareNode before, CompareNode after)
-getCompareNodeMap(T obj)
-getFieldFromCache(Class<?> objClazz)
-mapFiledValue(Object fieldValue, Field field)
-isJdkType(Class<?> clazz)
+parseStrRuleToMap(String[] input)
+praseStrToPair(String str)
}
class CompareNode {
-String fieldKey
-Object fieldValue
-String fieldDesc
+getFieldKey()
+setFieldKey(String fieldKey)
+getFieldValue()
+setFieldValue(Object fieldValue)
+getFieldDesc()
+setFieldDesc(String fieldDesc)
}
class CompareUtil {
-static final Map<Class<?>, CompareCore> INSTANCE_POOL
-CompareUtil()
+forClazz(Class<?> clazz)
}
class CompareI18n {
-static final ResourceBundleMessageSource messageSource
-static CompareProperties compareProperties
+setApplicationContext(ApplicationContext applicationContext)
+getMessage(String i18nKey)
}
class CompareProperty {
+String value()
+CompareRule ruleType()
+String[] ruleStr()
+Class<? extends Enum<? extends Function>> ruleEnum()
+CompareMapping[] ruleMappings()
}
class CompareIgnore {
}
class CompareMapping {
+String source()
+String target()
}
class CompareRule {
<<enumeration>>
STR
ENUM
MAPPING
}
class CompareProperties {
-static final String PREFIX
-String primaryLanguage
-String messageSourceBasename
+getPrimaryLanguage()
+setPrimaryLanguage(String primaryLanguage)
+getMessageSourceBasename()
+setMessageSourceBasename(String messageSourceBasename)
}
class CompareAutoConfiguration {
+String getDefaultBanner()
+void postConstruct()
+CompareI18n compareI18n()
}
CompareUtil --> CompareCore
CompareCore --> CompareNode
CompareCore --> CompareI18n
CompareProperty --> CompareRule
CompareProperty --> CompareMapping
CompareI18n --> CompareProperties
CompareAutoConfiguration --> CompareI18n
CompareAutoConfiguration --> CompareProperties
9. 流程图
9.1 对象比较流程
flowchart TB
A["开始比较"] --> B["获取对象的字段信息"]
B --> C{"字段是否有@CompareProperty注解"}
C -->|"否"| E["跳过此字段"]
C -->|"是"| D{"字段是否有@CompareIgnore注解"}
D -->|"是"| E
D -->|"否"| F["处理字段值映射"]
F --> G{"字段类型是否为JDK基础类型"}
G -->|"否"| E
G -->|"是"| H["创建CompareNode"]
H --> I["比较前后对象的相同字段"]
I --> J{"字段值是否不同"}
J -->|"否"| L["跳过此字段"]
J -->|"是"| K["格式化差异描述"]
K --> M["继续比较下一个字段"]
L --> M
E --> M
M --> N{"所有字段比较完成"}
N -->|"否"| B
N -->|"是"| O["返回比较结果"]
10. 使用示例
10.1 基本使用示例
1. 定义需要比较的类
public class User {
@CompareProperty("user.id")
private Long id;
@CompareProperty("user.name")
private String name;
@CompareProperty(value = "user.status", ruleStr = {"0->禁用", "1->启用"})
private Integer status;
@CompareIgnore
private String password;
// getter and setter
}
2. 执行对象比较
// 获取CompareCore实例
CompareCore compareCore = CompareUtil.forClazz(User.class);
// 创建两个用户对象
User beforeUser = new User();
beforeUser.setId(1L);
beforeUser.setName("张三");
beforeUser.setStatus(1);
beforeUser.setPassword("123456");
User afterUser = new User();
afterUser.setId(1L);
afterUser.setName("李四");
afterUser.setStatus(0);
afterUser.setPassword("123456");
// 比较对象差异
String diff = compareCore.compareObj(beforeUser, afterUser);
System.out.println(diff);
// 输出: [用户姓名] 修改前:张三 ——> 修改后:李四
// [用户状态] 修改前:启用 ——> 修改后:禁用
10.2 列表比较示例
基于映射规则的列表比较
List<User> beforeList = Arrays.asList(beforeUser);
List<User> afterList = Arrays.asList(afterUser);
// 基于id字段比较列表
String diff = compareCore.compareList(beforeList, afterList, "id");
按索引顺序的列表比较
String diff = compareCore.compareListByIndex(beforeList, afterList);
10.3 自定义枚举规则示例
// 定义枚举映射规则
public enum StatusEnum implements Function<Object, String> {
ENABLED(1, "启用"),
DISABLED(0, "禁用");
private final Integer code;
private final String desc;
StatusEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
@Override
public String apply(Object o) {
Integer status = (Integer) o;
for (StatusEnum e : values()) {
if (e.code.equals(status)) {
return e.desc;
}
}
return "未知";
}
}
// 使用枚举规则
public class User {
@CompareProperty(value = "user.status", ruleType = CompareRule.ENUM, ruleEnum = StatusEnum.class)
private Integer status;
}
10.4 使用@CompareMapping示例
public class User {
@CompareProperty(value = "user.status", ruleType = CompareRule.MAPPING, ruleMappings = {
@CompareMapping(source = "0", target = "禁用"),
@CompareMapping(source = "1", target = "启用")
})
private Integer status;
}
11. 注意事项
-
性能考虑:
- 对于频繁比较的对象,模块已实现缓存机制提高性能
- 对于不需要比较的字段,建议使用
@CompareIgnore注解忽略
-
数据类型支持:
- 目前主要支持 JDK 基础类型的比较
- 对于复杂对象类型,需要确保正确配置比较规则
-
国际化配置:
- 需要创建对应的国际化资源文件(如
compare_zh.properties) - 字段描述的键名应与
@CompareProperty注解的value属性一致
- 需要创建对应的国际化资源文件(如
-
Spring Boot 集成:
- 模块已实现自动配置,只需添加依赖即可使用
- 可通过
application.properties或application.yml自定义配置项
12. 配置项参考
在 application.properties 文件中可配置以下属性:
# 设置主语言
spring.ai.framework.compare.primary-language=zh
# 设置国际化资源文件前缀
spring.ai.framework.compare.message-source-basename=compare
在 application.yml 文件中可配置以下属性:
framework:
compare:
primary-language: zh
message-source-basename: compare
13. 总结
Compare 模块提供了一个灵活、强大的对象差异比较解决方案,通过简单的注解配置,即可实现复杂的对象比较需求。该模块适用于需要记录数据变更、生成操作日志或展示数据差异的场景,与 Spring Boot 框架无缝集成,使用方便,扩展性强。