如何用Javers提交含Map属性对象并审计MongoDB文档字段变更?
解决MongoDB文档审计中Document属性的细粒度变更追踪问题
核心问题分析
当前问题的根源是Javers默认将Document类型视为整体黑盒对象,审计时只会标记整个data属性变更,而非内部具体条目;同时直接提交Document无法利用@TypeName和@Id生成要求的MyRecord/333格式全局ID,需要从Javers的类型处理逻辑入手解决。
方案一:自定义Javers类型适配器解析Document内部字段
通过编写Document的Json类型适配器,让Javers将其解析为可遍历的键值对结构,从而追踪内部条目的变更:
1. 编写Document类型适配器
import org.bson.Document; import org.javers.core.json.JsonTypeAdapter; import java.util.Map; public class DocumentTypeAdapter implements JsonTypeAdapter<Document> { @Override public Document fromJson(String json) { return Document.parse(json); } @Override public String toJson(Document document) { return document.toJson(); } @Override public Class<Document> getValueType() { return Document.class; } // 关键:将Document转换为Map,让Javers识别内部字段 @Override public Map<String, Object> toValueObject(Document document) { return document; } }
2. 注册适配器到Javers配置
import org.javers.core.Javers; import org.javers.core.JaversBuilder; Javers javers = JaversBuilder.javers() .registerJsonTypeAdapter(new DocumentTypeAdapter()) .build();
配置完成后,Javers会将data属性下的每个键值对当作独立属性处理,审计时会显示具体变更的条目(比如data.username),而非整个data属性。
方案二:替换Document为Map<String, Object>(更简便)
如果业务允许,直接将RecordDto中的data字段类型改为Map<String, Object>,Javers原生支持Map的结构化比较,无需额外适配器:
修改RecordDto类
import jakarta.persistence.Id; import lombok.Data; import org.javers.core.metamodel.annotation.TypeName; import java.util.Map; @TypeName("MyRecord") @Data public class RecordDto { @Id private Long recordId; private Map<String, Object> data; }
Spring Data MongoDB默认支持Map与Document的自动转换,存入数据库时会自动转为Document结构,完全不影响MongoDB的存储逻辑,但Javers能直接识别Map内部的每个字段,实现细粒度审计。
全局ID生成保障
无论采用哪种方案,RecordDto上的@TypeName("MyRecord")和@Id标注的recordId都会让Javers自动生成MyRecord/333格式的全局ID,完全满足提交时的标识需求,无需直接提交Document对象。
注意事项
- 确保
data中的值仅为int、long、string等Javers支持的基本类型,避免复杂类型导致的比较异常。 - 测试时可通过
javers.compare(oldRecord, newRecord)查看变更详情,确认具体条目变更是否被正确追踪。
内容的提问来源于stack exchange,提问作者babu babu
相关产品推荐
相关产品推荐

