java记录用户的操作信息

本人是个刚刚学习的,我现在在做一个用户管理的系统,,想实现可以记录用户操作 然后将操作记录到数据库里的 一个方法 比如就是新增了一个用户 ,那我想记录的就是 是谁操作的 操作的哪个表 哪个列 新的数据是啥 旧的数据是啥 还有就是操作时间之类的 也搜到过说使用aop加自定义注解可以实现 但是我没看懂 希望有兄弟姐妹叔叔阿姨们指点一下 谢谢

我觉得你可以看看这个文章
http://t.csdn.cn/vUbYY

沒看懂就多看几片类似的文章,就是aop日志收集

最近做了一个简单的, 注解层面上的一个

  1. 建立一个字段上面的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Record {

    /**
     * 字段名
     */
    String name() default "";

    /**
     * 日期格式, 如: yyyy-MM-dd
     */
    String dateFormat() default "";

    /**
     * 字典的类型值
     */
    long dictParentId() default 0;

}
  1. 在实体字段上加上这个注解, 字典类型以redis举例是使用hash储存, dictParentId是他的key, 用于储存或传输的为hkey, 具体文字就为value了, 例如性别: key=0(或"sex"等等类型随你传), hkey=1, value="男"
  2. 具体的就是通过反射进行比较了
@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在项目中的主要的应用是事务控制,日志记录,安全控制,异常处理,缓存,埋点,性能统计等。