首页 > 其他分享 >AOP记录日志操作

AOP记录日志操作

时间:2022-11-15 12:56:12浏览次数:40  
标签:name 记录 private AOP 日志 public String

AOP的定义

AOP通过 预编译方式 和 运行期动态代理 实现,在不修改源代码的情况下,给程序动态统一添加功能的一种技术,简称AOP,一句话总结:在不改变原有代码的条件下,对功能进行扩展

公式:AOP=切入点表达式 + 通知方法

AOP的一些概念

  • 1.连接点:在执行正常的业务过程中满足了切入点表达式时进入切面的点.(织入)多个

  • 2.通知: 在切面中执行的具体的业务 (方法)

    (1)前置通知: 目标方法执行之前执行
    (2)后置通知: 目标方法执行之后执行
    (3)异常通知: 目标方法执行之后抛出异常时执行
    (4)最终通知: 不管什么时候都需要执行的方法

    说明:上面的四大通知类型不能控制目标方法是否执行,一般适用上面的四大通知类型,都是用来记录程序的执行状态.

    (5)环绕通知:在目标方法执行前后都要执行的通知方法.控制目标方法是否执行,并且环绕通知的功能最为强大

  • 3.切入点:能够进入切面的一个判断 (if判断 一个)

    切入点表达式说明:
    1)bean(bean的id) 类名首字母小写 匹配一个类
    2).within(包名.类名) 按包路径匹配类 匹配多个类

    上述表达式时粗粒度的控制,按类匹配

    3)execution(返回值类型 包名.类名.方法名[参数列表])
    4)@annotation(包名.注解名) 按注解进行拦截

使用AOP记录日志操作

  • 1、自定义注解
/**
 * 标记需要做业务日志的方法
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BussinessLog {
    /**
     * 业务的名称,例如:"修改菜单"
     */
    String value() default "";
    /**
     * 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
     */
    String key() default "id";
    /**
     * 字典(用于查找key的中文名称和字段的中文名称)
     */
    String dict() default Dict.SYSTEM_DICT;
    /**
     * request参数默认为json
     * @return
     */
    String type() default ParaType.JSON;
}
  • 2、AOP相关配置类
/**
 * 日志记录
 */
@Aspect
@Component
public class LogAop {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private final String POINT_CUT ="execution(public * net.ruixin.dao.*.*(..))";

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut(value = "@annotation(net.ruixin.service.plat.log.aop.BussinessLog)")
    public void cutService() {
    }
    @Pointcut(POINT_CUT)
    public void cutDao() {
    }
    //切面 配置通知
    @Around("cutService()")
    public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
        //先执行业务
        Object result = point.proceed();
        try {
            handle(point);
        } catch (Exception e) {
            log.error("日志记录出错!", e);
        }
        return result;
    }

    private void handle(ProceedingJoinPoint point) throws Exception {
        //从切面织入点处通过反射机制获取织入点处的方法
        Signature sig = point.getSignature();
        MethodSignature msig;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        //获取切入点所在的方法
        String methodName = currentMethod.getName();

        //如果当前用户未登录,不做日志
        ShiroUser user = ShiroKit.getUser();
        if (null == user) {
            return;
        }

        //获取拦截方法的参数
        String className = point.getTarget().getClass().getName();
          //获取当前用户操作信息
//        Object[] params = point.getArgs();

        //获取操作名称
        BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);
        String bussinessName = annotation.value();
        String key = annotation.key();
        String dictClass = annotation.dict();
        String paraType = annotation.type();

        //如果涉及到修改,比对变化
        String msg;
        if (Objects.equals(paraType, ParaType.ATTRIBUTE)) {
            if (bussinessName.contains("修改")) {
                Object obj1 = LogObjectHolder.me().get();
                Map<String, String> obj2 = HttpKit.getRequestParameters();
                msg = Contrast.contrastObj(dictClass, key, obj1, obj2);
            } else {
                Map<String, String> parameters = HttpKit.getRequestParameters();
                AbstractDictMap dictMap = DictMapFactory.createDictMap(dictClass);
                msg = Contrast.parseMutiKey(dictMap, key, parameters);
            }
        } else {
            //如何使用json数据,需要特殊转换处理
            Map<String, String> parameters = HttpKit.getRequestParameters();
            msg = "日志名称:"+bussinessName + "; 操作数据: " +parameters.toString();
        }
        // 保存操作日志
        LogManager.me().executeLog(LogTaskFactory.bussinessLog(user, bussinessName, className, methodName, msg));
    }
}
  • 3、使用自定义注解
    @ResponseBody
    @RequestMapping(value = "/delSysOrgan")
    @BussinessLog(value = "机构删除")
    public AjaxReturn delSysOrgan(Long id, Long newOrganId) {
        organService.delSysOrgan(id, newOrganId);
        return success();
    }
  • 4、日志实体类
@Table(name = "SYS_LOG_OPERATION")
@Entity
@DynamicInsert
@DynamicUpdate
public class OperationLog extends BaseDomain {
    @Id
    @SequenceGenerator(name = "seq_sys_log", sequenceName = "SEQ_SYS_LOG_LOGIN", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_sys_log")
    private Long id;

    /**
     * 日志类型
     */
    @Column(name = "LOG_TYPE")
    private String logType;
    /**
     * 日志名称
     */
    @Column(name = "LOG_NAME")
    private String logName;
    /**
     * 用户id
     */
    @Column(name = "USER_ID")
    private Long userId;

    /**
     * 用户名
     */
    @Column(name = "USER_NAME")
    private String userName;

    /**
     * 类名称
     */
    @Column(name = "CLASS_NAME")
    private String className;
    /**
     * 方法名称
     */
    @Column(name = "METHOD")
    private String method;
    /**
     * 创建时间
     */
    @Column(name = "CREATE_TIME")
    private Date createTime;
    /**
     * 是否成功
     */
    @Column(name = "SUCCESS")
    private String success;
}

标签:name,记录,private,AOP,日志,public,String
From: https://www.cnblogs.com/d111991/p/16892059.html

相关文章