本人是个刚刚学习的,我现在在做一个用户管理的系统,,想实现可以记录用户操作 然后将操作记录到数据库里的 一个方法 比如就是新增了一个用户 ,那我想记录的就是 是谁操作的 操作的哪个表 哪个列 新的数据是啥 旧的数据是啥 还有就是操作时间之类的 也搜到过说使用aop加自定义注解可以实现 但是我没看懂 希望有兄弟姐妹叔叔阿姨们指点一下 谢谢
我觉得你可以看看这个文章
http://t.csdn.cn/vUbYY
沒看懂就多看几片类似的文章,就是aop日志收集
最近做了一个简单的, 注解层面上的一个
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Record {
/**
* 字段名
*/
String name() default "";
/**
* 日期格式, 如: yyyy-MM-dd
*/
String dateFormat() default "";
/**
* 字典的类型值
*/
long dictParentId() default 0;
}
@Async
@Override
public <T> void update(Integer module, Long entity, T oldT, T newT, SysUser user) {
BasRecord record = new BasRecord(RecordConst.UPDATE, user);
List<BasRecordInfo> recordInfos = new ArrayList<BasRecordInfo>();
Field[] oldFields = oldT.getClass().getDeclaredFields();
for (Field oldField : oldFields) {
try {
oldField.setAccessible(true);
String fieldName = oldField.getName();
com.annotation.Record annotation = oldField.getDeclaredAnnotation(com.annotation.Record.class);
// 若字段包含Record注解, 则参与比较
if (annotation != null) {
Field newField = newT.getClass().getDeclaredField(fieldName);
newField.setAccessible(true);
// 获取旧字段值
Object oldFieldObj = oldField.get(oldT);
// 获取新字段值
Object newFieldObj = newField.get(newT);
String oldFieldVal = null;
String newFieldVal = null;
if (oldFieldObj == null) { // 若旧字段为空
if (newFieldObj == null) // 若新字段为空, 则直接跳过
continue;
// 若新字段不为空,则一定不同
newFieldVal = newFieldObj.toString();
if (newFieldObj instanceof Date date) {
newFieldVal = DateUtil.format(date, annotation.dateFormat());
}
if (annotation.dictParentId() != 0) {
newFieldVal = dictService.getValue(annotation.dictParentId(), Long.parseLong(newFieldVal));
}
} else {// 若旧字段不为空
if (newFieldObj == null) {// 若新字段为空,则直接进行比较
oldFieldVal = oldFieldObj.toString();
if (oldFieldObj instanceof Date date) {
oldFieldVal = DateUtil.format(date, annotation.dateFormat());
}
if (annotation.dictParentId() != 0) {
oldFieldVal = dictService.getValue(annotation.dictParentId(), Long.parseLong(oldFieldVal));
}
} else {// 若新字段也为空,则直接进行比较
oldFieldVal = oldFieldObj.toString();
newFieldVal = newFieldObj.toString();
if (oldFieldVal.equals(newFieldVal)) // 若新旧字段相同则跳过
continue;
if (oldFieldObj instanceof Date oldDate && newFieldObj instanceof Date newDate) {
oldFieldVal = DateUtil.format(oldDate, annotation.dateFormat());
newFieldVal = DateUtil.format(newDate, annotation.dateFormat());
}
if (annotation.dictParentId() != 0) {
oldFieldVal = dictService.getValue(annotation.dictParentId(), Long.parseLong(oldFieldVal));
newFieldVal = dictService.getValue(annotation.dictParentId(), Long.parseLong(newFieldVal));
}
}
}
recordInfos.add(new BasRecordInfo(annotation.name(), oldFieldVal, newFieldVal));
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (CollectionUtils.isNotEmpty(recordInfos)) {
record.setRecordInfos(recordInfos);
stringRedisTemplate.opsForZSet().add(RECORD + module + "_" + entity, JSON.toJSONString(record), System.currentTimeMillis());
}
}
这里的module是模块id, entity是具体数据id, oldT是未更新前的数据, 可以从数据库拿(一定要注意是更新前的), newT就是传那个了, 不过这种方法有个局限, 例如引用外键时修改时我们传输的为展示字段, 例如userId为表外键, 你就需要把注解放在userName上而不是userId上,userName就是连表查询的用户名字段, 并且在你传值过来时也要把userName赋值
如果使用过.NET MVC,Spring等框架,那么您一定对过滤器(Filter),拦截器(Interceptor),中间件(MiddleWare)等有所耳闻。而这些实现的核心思想就是AOP(Aspect Oriented Programming)——面向切面编程。AOP在项目中的主要的应用是事务控制,日志记录,安全控制,异常处理,缓存,埋点,性能统计等。