我遇到过这么一个需求,日志中需要有操作修改前的值和修改后的值。并且对修改后的值进行权重划分,而且只展示两个属性字段值,改变过的旧值则按json格式存入数据库中,在此之前都是没有新旧值存入,所以可以用springAop来实现,可能小编我的实力有限,不能利用aop来获取旧值,因为需求中的旧值需要从数据库中来获取,所以采用反射来实现,需要记录日志的地方调用这个日志方法就行了,废话不多说,下面来展示代码
@Component
@Slf4j
public class NewAndOldValueUtil {
// 注入LogInfoDao
@Resource
private LogInfoDao logInfoDao;
/* // 初始化id
private static AtomicLong counter;
@PostConstruct
void InitId(){
// 获取最后一个id
long id=logInfoDao.getlastId();
// 初始化AtomicLong
counter = new AtomicLong(id);
}*/
/**
* 获取变更内容
*
* @param old 更改前的Bean
* @param newBean 更改后的Bean
* @param logType 日志类型,修改和删除类型的日志
* @param <T>
* @return
*/
@Async
public <T> void getChangedFields(T old, T newBean, String logType) {
//TODO LoginUserContext
LoginUserRespVo user = LoginUserContext.getUser();
//获取当前时间,格式为yyyy-MM-dd HH:mm:ss
Date nowTime = new Date();
String date = DateUtil.format(nowTime, "yyyy-MM-dd HH:mm:ss");
//随机生成long
// long logid = counter.incrementAndGet();
long logid = SnowUtil.getSnowflakeNextId();
if (BeanUtil.isEmpty(newBean)||BeanUtil.isEmpty(old))
{
//记录删除日志,和新增日志
LogInfo logInfo = LogInfo.builder().logid(logid)
.logType(logType).schoolId("d418b9cd-5e48-409e-9978-1efa9973604d")
.userName("系统管理员3").userId("9debfafc-a5a1-4a65-a887-1b4676a0d31b")
.logdate(date).logstamp(nowTime)
.build();
logInfoDao.add(logInfo);
return;
}
Class<?> newBean1 = newBean.getClass();
//通过newBean的到对象
Object oldBean = null;
try {
oldBean = newBean1.newInstance();
} catch (Exception e) {
log.debug("newInstance error");
}
BeanUtil.copyProperties(old, oldBean);
Field[] fields = newBean.getClass().getDeclaredFields();
StringBuilder oldVal = new StringBuilder();
oldVal.append("{");
//获取oldVal长度
List<Object> list = new ArrayList<>();
//创建TreeMap对象并制定value的升序规则
TreeMap<Integer, String> treeMap = new TreeMap<>();
String data1;
String data2;
for (Field field : fields) {
field.setAccessible(true);
try {
Object oldValue = field.get(oldBean);
Object newValue = field.get(newBean);
String name = field.getName();
if (name.equals("loginPassword")){
oldValue=RSAUtil.decrypt((String) oldValue);
newValue=RSAUtil.decrypt((String) newValue);
}
if (!Objects.equals(newValue, oldValue)) {
String s = name.toUpperCase();
//TODO 日志数据权重
//判断字符串name包括字符串namStr
if (s.indexOf("NAME") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(1, (String) newValue);
} else if (s.indexOf("IP") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(2, (String) newValue);
} else if (s.indexOf("NOTE") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(3, (String) newValue);
} else if (s.indexOf("URL") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(4, (String) newValue);
} else if (s.indexOf("ID") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(5, (String) newValue);
} else if (s.indexOf("TIME") != -1&& StrUtil.isNotBlank((String) newValue)) {
treeMap.put(6, (String) newValue);
}else {
treeMap.put(7, " ");
}
if (oldValue != null&&oldValue!=""){
oldVal.append(name + ":" +
(name.equals("loginPassword")?RSAUtil.decrypt((String) oldValue):oldValue));
oldVal.append(",");
}
}
} catch (Exception e) {
System.out.println(e);
}
}
//获取前两个value值
Object[] values = treeMap.values().toArray();
if (oldVal.length()==1){
oldVal.delete(oldVal.length()-1,oldVal.length());
}else {
oldVal.delete(oldVal.length()-1,oldVal.length());
oldVal.append("}");
}
LogInfo logInfo = LogInfo.builder().logid(logid)
.logType(logType).schoolId("d418b9cd-5e48-409e-9978-1efa9973604d")
.userName("系统管理员3").userId("9debfafc-a5a1-4a65-a887-1b4676a0d31b")
.logdate(date).logstamp(nowTime)
.logdata1(treeMap.size()>=2?(String) values[0]:" ")
.logdata2(treeMap.size()>=2?(String) values[1]:" ")
.logdata3(oldVal.toString())
.build();
logInfoDao.add(logInfo);
}
}
以上是所有代码,各位可抽取其中重要的部分,要注意的是,因为传进来的两个对象不同,在使用糊涂工具的
copyProperties
时候,属性名字一定要一样,不然无法进行属性值拷贝,例如:
@Data
public class UserInfo {
// 用户ID
private UUID userId;
// 学校ID
private UUID schoolId;
// 登录Key
private String loginKey;
// 登录密码
private String loginPassword;
// 用户名
private String userName;
// 邮箱
private String eMail;
// 是否使用
private Integer isUse;
// 手机号
private String phone;
// 电话号码
private String telNo;
// 地址
private String address;
// 用户IP
private String userIp;
// 角色ID
private Long roleId;
// 用户备注
private String userMemo;
// 创建时间
private Date createTime;
// 创建用户
private String createUser;
// 更新时间
private Date updateTime;
// 更新用户
private String updateUser;
}
@Data
public class UserInfoReqUpdVo {
// 用户ID
private String userId;
// 学校ID
private String schoolId;
// 登录Key
private String loginKey;
// 登录密码
private String loginPassword;
public void setLoginPassword(String loginPassword) throws Exception {
if (loginPassword.length()>150){
this.loginPassword = loginPassword;
return;
}
String encrypt = RSAUtil.encrypt(loginPassword);
this.loginPassword = encrypt;
}
// 用户名
private String userName;
// 邮箱
private String eMail;
// 是否使用
private Integer isUse;
// 手机号
private String phone;
// 电话号码
private String telNo;
// 地址
private String address;
// 用户IP
private String userIp;
// 角色ID
private Long roleId;
// 用户备注
private String userMemo;
// 更新时间
private Date updateTime;
// 更新用户
private String updateUser;
//角色名
private String roleName;
//学校名
private String schoolName;
}
这两个是传入是实体类,只有这种情况才能进行属性拷贝