背景
接到一个需求一个员工有诸多信息 现在要记录修改时哪些信息被修改了并需要记录这些信息在一个字段中,同时后台又需要支持按照修改内容进行多选搜索。
一、分析思路
要记录每一个字段是否修改,按照常规写法会产生大量ifelse 同时代码可读性差 并且代码也不好维护 所以我使用了自定义注解+反射来解决问题
二、实现步骤
首先写一个自定义注解来标记字段的描述
package cn.nineox.health.common.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Description {
/**
* 字段描述
*/
public String filedName();
}
然后需要将源对象要和修改后的对象进行比对 需要遍历对象 这里我用到了反射
/**
* 信息修改组装字符串
*
* @param sourceBean
* @param targetBean
* @return
*/
public static String editContent(Object sourceBean, Object targetBean) {
Class sourceBeanClass = sourceBean.getClass();
Class targetBeanClass = targetBean.getClass();
// 获取对象的所有字段并存入字段集合中
Field[] sourceFields = sourceBeanClass.getDeclaredFields();
Field[] targetFields = targetBeanClass.getDeclaredFields();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < sourceFields.length; i++) {
Field sourceField = sourceFields[i];
Field targetField = targetFields[i];
// 没有注解的字段不处理
Description description = sourceField.getAnnotation(Description.class);
if (description == null) {
continue;
}
// 设置私有变量也可访问
sourceField.setAccessible(true);
targetField.setAccessible(true);
try {
// 获取简单名称 比如java.lang.String 的简单名称就是String
String fieldTypeName = sourceField.getType().getSimpleName();
// 信息修改的类型暂时只有Integer和String 后续有新的再增加
if (StringUtils.equals("String", fieldTypeName)) {
String sourceValue = (String) sourceField.get(sourceBean);
String targetValue = (String) targetField.get(targetBean);
// 不相等则证明是修改
if (!StringUtils.equalsIgnoreCase(sourceValue, targetValue)
&& (StringUtils.isNotEmpty(targetValue) || StringUtils.isNotEmpty(sourceValue))) {
// 将注解中的描述信息拼接到字符串中
stringBuffer.append(sourceField.getAnnotation(Description.class).filedName()).append(',');
}
}
if (StringUtils.equals("Integer", fieldTypeName)) {
Integer sourceValue = (Integer) sourceField.get(sourceBean);
Integer targetValue = (Integer) targetField.get(targetBean);
// 不相等则证明是修改
if (!ObjectUtil.equal(sourceValue, targetValue)) {
// 将注解中的描述信息拼接到字符串中
stringBuffer.append(sourceField.getAnnotation(Description.class).filedName()).append(',');
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
if (stringBuffer.length() > 0) {
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
}
return stringBuffer.toString();
}
然后实现多选的筛选操作
这里我用到了mysql中的FIND_IN_SET(a,b)函数 他能判断a是否在b中存在 其中b是用逗号分割的
<if test="query.editContentList != null and query.editContentList.size() > 0">
and (
<foreach collection="query.editContentList" item="item" open="(" close=")" separator="or">
FIND_IN_SET(#{item}, c.editContent)
</foreach>
)
</if>