本文主要是介绍一款通用的数据编辑历史记录工具,用来解决用户编辑业务数据留痕的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
为了只在业务代码里只写一行代码我容易吗我? 最终使用效果:
// 记录编辑信息UserEditRecordBee.BASE_USER_EDIT.record(user);// 编辑用户userMapper.updateById(user);
UserEditRecordBee定义:
public enum UserEditRecordBee implements RecordBee {BASE_USER_EDIT("编辑用户基本信息");private String recordName;@Overridepublic String recordType() {return this.name().toLowerCase();}@Overridepublic String recordName() {return this.recordName;}
}
RecordBee 定义:
public interface RecordBee {String recordType();String recordName();default String idFieldName() {return "id";}default <T> void record(T newEntity) {Object id = ZYBeanUtils.getProperty(newEntity, idFieldName());if (ZYStrUtils.isNotNull(id)) {ZYEditRecordHelper.record(recordType(), String.valueOf(id), newEntity, recordName());}}default <T> void record(T newEntity, String businessId) {ZYEditRecordHelper.record(recordType(), businessId, newEntity, recordName());}default <T> void record(String businessId, T newEntity, T oldEntity) {ZYEditRecordHelper.record(recordType(), businessId, newEntity, oldEntity, recordName());}default <T> void record(String businessId, T newEntity, T oldEntity, String recordUserId, String recordUserName) {ZYEditRecordHelper.record(recordType(), businessId, newEntity, oldEntity, recordName(), recordUserId, recordUserName);}
}
ZYEditRecordHelper定义:
// InterestedClassAware接口参考本人博文:
// https://blog.csdn.net/qq_37148232/article/details/131821497?spm=1001.2014.3001.5501
// EasyApplicationRunner 接口参考本人博文:
// https://blog.csdn.net/qq_37148232/article/details/122296078?spm=1001.2014.3001.5501
public class ZYEditRecordHelper implements InterestedClassAware, EasyApplicationRunner {private static final Map<String, BaseMapper<?>> MAPPER_CONTAINER = new HashMap<>();private static final Map<String, Class<?>> MAPPER__CLASS_CONTAINER = new HashMap<>();private static EditRecordMapper editRecordMapper;private static EditRecordDetailMapper editRecordDetailMapper;@Autowiredpublic ZYEditRecordHelper(EditRecordMapper editRecordMapper, EditRecordDetailMapper editRecordDetailMapper) {ZYEditRecordHelper.editRecordMapper = editRecordMapper;ZYEditRecordHelper.editRecordDetailMapper = editRecordDetailMapper;}public static <T> void record(String recordType, String businessId, T newEntity, String recordName) {if (ZYStrUtils.isAnyNull(recordType, businessId, newEntity)) {return;}Class<?> aClass = newEntity.getClass();String entityClassName = aClass.getName();// 从缓存中找到entity对应的那个BaseMapperBaseMapper<?> baseMapper = MAPPER_CONTAINER.get(entityClassName);if (null == baseMapper) {return;}if (ZYStrUtils.isNotNull(businessId)) {// 利用BaseMapper获取到旧的数据记录行。T oldEntity = (T) baseMapper.selectById(businessId);// 记录新旧记录record(recordType, businessId, newEntity, oldEntity, recordName);}}public static <T> void record(String recordType, String businessId, T newEntity, T oldEntity, String recordName) {if (ZYStrUtils.isAnyNull(recordType, businessId, newEntity, oldEntity)) {return;}// 处理下是否有登录用户,没有默认系统修改LoginUser loginAreaUser = ZYUserHelper.getLoginAreaUser();String editUserId = "system";String editUserName = "system";if (null != loginAreaUser) {editUserId = loginAreaUser.getId();editUserName = loginAreaUser.getUserName();}// 处理编辑记录record(recordType, businessId, newEntity, oldEntity, recordName, editUserId, editUserName);}public static <T> void record(String recordType, String businessId, T newEntity, T oldEntity, String recordName, String recordUserId, String recordUserName) {if (ZYStrUtils.isAnyNull(recordType, businessId, newEntity, oldEntity, recordUserId)) {return;}// 编辑记录idString recordId = SnowFlake.nextKey();// 构建编辑详情List<EditRecordDetail> details = RecordDetailBuilder.buildEditRecordDetail(recordId, recordName, newEntity, oldEntity);// 保存记录if (!details.isEmpty()) {// 构建编辑记录EditRecord editRecord = new EditRecord();editRecord.setRecordType(recordType);editRecord.setBusinessId(businessId);editRecord.setId(recordId);editRecord.setRecordName(recordName);editRecord.setRecordUserId(recordUserId);editRecord.setRecordUserName(recordUserName);editRecord.setRecordTime(System.currentTimeMillis());// 保存记录editRecordMapper.insert(editRecord);editRecordDetailMapper.insertSplitBatch(details, 100);}}@Overridepublic boolean match(AnnotationMetadata annotationMetadata) {// 收集带@Mapper注解的return annotationMetadata.hasAnnotation(Mapper.class.getName());}@Overridepublic void setClasses(Set<Class<?>> classes) {for (Class<?> mapperClass : classes) {// 查找泛型上面的实体实名称Class<?> entityClass = ZYSpringUtils.findGenericClass(mapperClass, FIRST);if (null != entityClass) {MAPPER__CLASS_CONTAINER.put(entityClass.getName(), mapperClass);}}}@Overridepublic void doBusiness() {// 容器启动完成后,实体类对象的BaseMapper bean对象。缓存到map中MAPPER__CLASS_CONTAINER.forEach((entityName, mapperClass) -> {Object mapper = ZYSpringUtils.getBean(mapperClass);if (null != mapper) {MAPPER_CONTAINER.put(entityName, (BaseMapper<?>) mapper);}});}
}
RecordDetailBuilder,修改信息构建器,(与本人所有项目业务有关系,一些代码可能会没用)定义:
public class RecordDetailBuilder {public static <T> List<EditRecordDetail> buildEditRecordDetail(String recordId, String recordName, T newEntity, T oldEntity) {EntityWrapper<T> wrapper = EntityWrapper.ofCompareEntity(recordId, newEntity, oldEntity);// 解析对比不成功Tif (!wrapper.isNecessaryRecord()) {return Collections.emptyList();}// 如果是基本类型,直接new一个对象就可以了if (wrapper.isBaseClass()) {EditRecordDetail editRecordDetail = new EditRecordDetail();editRecordDetail.setId(SnowFlake.nextKey());editRecordDetail.setRecordId(recordId);editRecordDetail.setEditField(recordName);editRecordDetail.setEditFieldName(recordName);editRecordDetail.setNewValue(NameExchanger.singleExchange(newEntity));editRecordDetail.setOldValue(NameExchanger.singleExchange(oldEntity));return Collections.singletonList(editRecordDetail);} else {List<String> fieldNames = wrapper.getFieldNames();// 移除指定的不用记录的字段List<String> excludeFields = ExcludeFieldProvider.findExclude(wrapper.getEntityClass());if (ZYListUtils.isNotEmptyList(excludeFields)) {fieldNames.removeIf(excludeFields::contains);}return ZYListUtils.list2list(fieldNames, fieldName -> doBuildDetail(wrapper, fieldName));}}private static <T> EditRecordDetail doBuildDetail(EntityWrapper<T> wrapper, String fieldName) {EntityField entityField = wrapper.findEntityField(fieldName);if (null == entityField) {return null;}if (entityField.isExclude()) {return null;}// 基本字段不记录if (entityField.isBaseField()) {return null;}// 比对是否需要记录详情Object newFieldValue = wrapper.findNewFieldValue(fieldName);Object oldFieldValue = wrapper.findOldFieldValue(fieldName);if (!necessaryToRecord(newFieldValue, oldFieldValue)) {return null;}EditRecordDetail editRecordDetail = new EditRecordDetail();editRecordDetail.setId(SnowFlake.nextKey());editRecordDetail.setRecordId(wrapper.getRecordId());String newValue = NameExchanger.exchangeValue(entityField, newFieldValue);String oldValue = NameExchanger.exchangeValue(entityField, oldFieldValue);editRecordDetail.setNewValue(newValue);editRecordDetail.setOldValue(oldValue);editRecordDetail.setEditField(fieldName);editRecordDetail.setEditFieldName(entityField.getChinaName());return editRecordDetail;}private static boolean necessaryToRecord(Object newFieldValue, Object oldFieldValue) {if (ZYStrUtils.isAllNull(newFieldValue, oldFieldValue)) {return false;}if (ZYStrUtils.isAnyNull(newFieldValue, oldFieldValue)) {if (isDict(newFieldValue, oldFieldValue)) {return !toCheckDictIsAllNull(newFieldValue, oldFieldValue);} else {return true;}}if (newFieldValue instanceof DictColumn) {DictColumn newDict = (DictColumn) newFieldValue;DictColumn oldDict = (DictColumn) oldFieldValue;String newDictValue = newDict.getValue();String oldDictValue = oldDict.getValue();return necessaryToRecord(newDictValue, oldDictValue);}return !ZYBoolUtils.ignoreEquals(newFieldValue, oldFieldValue);}private static boolean toCheckDictIsAllNull(Object newFieldValue, Object oldFieldValue) {boolean isEmptyDictNew = null == newFieldValue || ZYStrUtils.isNull(((DictColumn) newFieldValue).getValue());boolean isEmptyDictOld = null == oldFieldValue || ZYStrUtils.isNull(((DictColumn) oldFieldValue).getValue());return isEmptyDictNew && isEmptyDictOld;}private static boolean isDict(Object newFieldValue, Object oldFieldValue) {boolean isDict = false;if (null != newFieldValue) {isDict = newFieldValue instanceof DictColumn;} else if (null != oldFieldValue) {isDict = oldFieldValue instanceof DictColumn;}return isDict;}
}
EntityWrapper,包装和预处理下编辑记录的新旧对象信息,定义
public class EntityWrapper<T> {private final static Map<String, Map<String, EntityField>> FIELD_CACHE = new HashMap<>();// 初始不成功private boolean necessaryRecord;// 是基本类型private boolean isBaseClass;private String recordId;// 字段新的属性值private Map<String, Object> newProperties;// 字段旧的属性值private Map<String, Object> oldProperties;private Map<String, EntityField> entityFields;private List<String> fieldNames = new ArrayList<>();private Class<?> entityClass;public EntityWrapper(String recordId, T newEntity, T oldEntity) {// 任一为空,不用记录this.necessaryRecord = null != newEntity && null != oldEntity;if (!necessaryRecord) {return;}// 记录idthis.recordId = recordId;// 是基本类型this.entityClass = newEntity.getClass();this.isBaseClass = isBaseClass(entityClass);if (isBaseClass) {return;}// 字段新的属性值this.newProperties = ZYBeanUtils.beanToMap(newEntity, false, false);if (this.newProperties.isEmpty()) {this.necessaryRecord = false;return;}// 字段旧的属性值this.oldProperties = ZYBeanUtils.beanToMap(oldEntity, false, false);if (this.oldProperties.isEmpty()) {this.necessaryRecord = false;return;}// 字段的属性定义this.entityFields = resolveEntityField(entityClass);this.fieldNames.addAll(entityFields.keySet());}private boolean isBaseClass(Class<?> entityClass) {return String.class.isAssignableFrom(entityClass)|| Date.class.isAssignableFrom(entityClass)|| Integer.class.isAssignableFrom(entityClass)|| Long.class.isAssignableFrom(entityClass)|| Boolean.class.isAssignableFrom(entityClass)|| Double.class.isAssignableFrom(entityClass);}public static <T> EntityWrapper<T> ofCompareEntity(String recordId, T newEntity, T oldEntity) {return new EntityWrapper<>(recordId, newEntity, oldEntity);}public EntityField findEntityField(String fieldName) {return entityFields.get(fieldName);}public Object findNewFieldValue(String fieldName) {return newProperties.get(fieldName);}public Object findOldFieldValue(String fieldName) {return oldProperties.get(fieldName);}private static Map<String, EntityField> resolveEntityField(Class<?> newClass) {String className = newClass.getName();Map<String, EntityField> entityFieldContainer = FIELD_CACHE.get(className);if (null == entityFieldContainer) {Map<String, Field> fieldMap = ZYReflectUtils.getFieldMap(newClass);entityFieldContainer = ZYMapUtils.map2mapValue(fieldMap, EntityField::new);FIELD_CACHE.put(className, entityFieldContainer);}return entityFieldContainer;}
}
NameExchanger,记录编辑记录时,用来将外键、字典、日期等转换成中文名称的转换器(与本人所有项目业务有关系,一些代码可能会没用)定义:
public class NameExchanger {public static String singleExchange(Object value) {return ZYStrUtils.isNotNull(value) ? String.valueOf(value) : "";}public static String exchangeValue(EntityField entityField, Object value) {if (ZYStrUtils.isNull(value)) {return "";}if (value instanceof String && !entityField.isJoin()) {return String.valueOf(value);}if (value instanceof Float || value instanceof Double) {BigDecimal decimal = new BigDecimal(String.valueOf(value));DecimalFormat decimalFormat = new DecimalFormat("#.##");return decimalFormat.format(decimal.doubleValue());}if (value instanceof Date) {return ZYDateUtils.formart((Date) value, "yyyy-MM-dd");}if (value instanceof Integer) {if (entityField.isIntBoolean()) {return ZYBoolUtils.int2bool((Integer) value) ? "是" : "否";} else {return String.valueOf(value);}}if (value instanceof Boolean) {boolean valueBool = (boolean) value;return valueBool ? "是" : "否";}// 是Long类型日期if (value instanceof Long) {if (entityField.isLongDate()) {return ZYDateUtils.formart((Long) value, "yyyy-MM-dd");} else {return String.valueOf(value);}}// 是关联字段if (entityField.isJoin()) {JoinNameProvider provider = ZYSpringUtils.getBean(entityField.getJoinBeanName(), JoinNameProvider.class);return null != provider ? provider.findJoinName(String.valueOf(value)) : "";}// 字典String dictName = exchangeDict(entityField, value);if (ZYStrUtils.isNotNull(dictName)) {return dictName;}return "";}private static String exchangeDict(EntityField entityField, Object value) {if (entityField.isDict() && value instanceof DictColumn) {DictColumn dictColumn = (DictColumn) value;String dictValue = dictColumn.getValue();String label = dictColumn.getLabel();if (ZYStrUtils.isNotNull(label)) {return label;} else if (ZYStrUtils.isNotNull(dictValue)) {return ZYDictHelper.dictName(entityField.dictType, dictValue);} else {return "";}}if (entityField.isDict() && value instanceof String) {return ZYDictHelper.dictName(entityField.dictType, String.valueOf(value));}if (value instanceof DictColumn) {DictColumn dictColumn = (DictColumn) value;String dictValue = dictColumn.getValue();String label = dictColumn.getLabel();if (ZYStrUtils.isNotNull(label)) {return label;} else if (ZYStrUtils.isNotNull(dictValue)) {return ZYDictHelper.dictName(ZYStrUtils.camelToUnderline(entityField.getFieldName()), dictValue);} else {return "";}}return null;}
}
这篇关于一款通用的数据编辑历史记录工具,用来解决用户编辑业务数据留痕的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!