记录业务操作日志可能需要比较前后信息变更,方便记录,实现简单工具方便比较信息;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Compare {
/**
* 字段名称
*/
String value();
/**
* 内容转换
*/
CompareContent[] content() default {};
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CompareContent {
/**
* 值
*/
String value();
/**
* 值描述
*/
String valueDesc();
}
@Getter
@Setter
public class CompareNode {
/**
* 字段
*/
private String fieldKey;
/**
* 字段值
*/
private Object fieldValue;
/**
* 字段名称
*/
private String fieldName;
}
public class CompareUtils<T> {
private static final String COMMA = ",";
/**
* 属性比较
*
* @param source 源数据对象
* @param target 目标数据对象
* @return 对应属性值的比较变化
*/
public String compare(T source, T target) {
return compare(source, target, null);
}
/**
* 属性比较
*
* @param source 源数据对象
* @param target 目标数据对象
* @param ignoreCompareFields 忽略比较的字段
* @return 对应属性值的比较变化
*/
public String compare(T source, T target, List<String> ignoreCompareFields) {
if (Objects.isNull(source) && Objects.isNull(target)) {
return "";
}
Map<String, CompareNode> sourceMap = this.getFiledValueMap(source);
Map<String, CompareNode> targetMap = this.getFiledValueMap(target);
if (sourceMap.isEmpty() && targetMap.isEmpty()) {
return "";
}
// 如果源数据为空,则只显示目标数据,不显示属性变化情况
if (sourceMap.isEmpty()) {
return doEmpty(targetMap, ignoreCompareFields);
}
// 如果源数据为空,则显示属性变化情况
String s = doCompare(sourceMap, targetMap, ignoreCompareFields);
if (!s.endsWith(COMMA)) {
return s;
}
return s.substring(0, s.length() - 1);
}
private String doEmpty(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
StringBuilder sb = new StringBuilder();
Collection<CompareNode> values = targetMap.values();
int size = values.size();
int current = 0;
for (CompareNode node : values) {
current++;
Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
continue;
}
if (!o.toString().isEmpty()) {
sb.append("[").append(node.getFieldName()).append(":").append(o).append("]");
if (current < size) {
sb.append(COMMA);
}
}
}
return sb.toString();
}
private String doCompare(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap,
List<String> ignoreCompareFields) {
StringBuilder sb = new StringBuilder();
Set<String> keys = sourceMap.keySet();
int size = keys.size();
int current = 0;
for (String key : keys) {
current++;
CompareNode sn = sourceMap.get(key);
CompareNode tn = targetMap.get(key);
if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
continue;
}
String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
// 只有两者属性值不一致时, 才显示变化情况
if (!sv.equals(tv)) {
sb.append(String.format("%s:从 [%s] -> 变为 [%s]", sn.getFieldName(), sv, tv));
if (current < size) {
sb.append(COMMA);
}
}
}
return sb.toString();
}
private Map<String, CompareNode> getFiledValueMap(T t) {
if (Objects.isNull(t)) {
return Collections.emptyMap();
}
Field[] fields = t.getClass().getDeclaredFields();
if (fields.length == 0) {
return Collections.emptyMap();
}
Map<String, CompareNode> map = new LinkedHashMap<>();
for (Field field : fields) {
Compare compareAnnotation = field.getAnnotation(Compare.class);
if (Objects.isNull(compareAnnotation)) {
continue;
}
String fieldKey = field.getName();
String fieldName = compareAnnotation.value();
Object fieldValue;
try {
fieldValue = FieldUtils.readField(field, t, true);
} catch (IllegalAccessException e) {
continue;
}
// 值内容转换
CompareContent[] content = compareAnnotation.content();
List<CompareContent> compareContents = Arrays.asList(content);
Map<String, String> valueConvert = compareContents.stream()
.collect(Collectors.toMap(CompareContent::value, CompareContent::valueDesc, (key1, key2) -> key1));
if (Objects.nonNull(valueConvert.get(String.valueOf(fieldValue)))) {
fieldValue = valueConvert.get(String.valueOf(fieldValue));
}
CompareNode node = new CompareNode();
node.setFieldKey(fieldKey);
node.setFieldName(fieldName);
node.setFieldValue(fieldValue);
map.put(field.getName(), node);
}
return map;
}
}
使用示例:
public class Test {
public static void main(String[] args) {
CompareTest test1 = new CompareTest("测试1", "0");
CompareTest test2 = new CompareTest("测试2", "1");
String compare = new CompareUtils<CompareTest>().compare(test1, test2);
System.out.println("对象信息内容变化:\n" + compare);
}
}
@Data
@AllArgsConstructor
class CompareTest {
@Compare(value = "名称")
private String name;
@Compare(value = "内容",
content = {@CompareContent(value = "0", valueDesc = "零"), @CompareContent(value = "1", valueDesc = "壹")})
private String value;
}
运行后输出信息变化:
对象信息内容变化:
名称:从 [测试1] -> 变为 [测试2],内容:从 [零] -> 变为 [壹]