通过自定义注解优雅的实现审计日志

本文介绍了如何在SpringBoot项目中使用Maven引入相关依赖,创建自定义注解`AuditAnno`,并利用切面编程(AOP)实现对API方法的审计日志记录,包括创建切面类`AuditAopConfig`,处理增删改操作的审计逻辑,以及通过Dubbo获取服务实例以进行数据库操作。
摘要由CSDN通过智能技术生成

一、引入对应的maven jar

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二、编写自定义注解

package com.al.api.aop.annotation;

import java.lang.annotation.*;

/**
 * @Description TODD
 * @Author zhuzhibin
 * @Date 2021/1/13 14:02
 * @Version 1.0
 **/

@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuditAnno {

    String value() default "";//执行的方法名称

    String moduleName() default ""; //模块名称

    String moduleCode() default ""; //模块code

    String operationType() default "";//操作类型

}

三、创建切面类

package com.al.api.aop;

import cn.hutool.http.HttpUtil;
import com.al.api.aop.annotation.AuditAnno;
import com.al.api.utils.AdminInfoContext;
import com.al.base.dto.region.AuditLogDTO;
import com.al.base.service.region.AuditLogService;
import com.al.common.utils.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * @ClassName AuditAop
 * @Description TODO
 * @Author Administrator
 * @Date 2021/1/13 14:03
 * @Version 1.0
 */
@Slf4j
@Aspect
@Component
public class AuditAopConfig {

    @Reference(check = false)
    private AuditLogService auditLogService;

    // 操作类型
    ThreadLocal<String> operateType = new ThreadLocal<>();
    // 模块名称
    ThreadLocal<String> moduleName = new ThreadLocal<>();
    // 模块code
    ThreadLocal<String> moduleCode = new ThreadLocal<>();
    // 功能模块
    ThreadLocal<String> methodName = new ThreadLocal<>();
    // ip信息
    ThreadLocal<String> Ip = new ThreadLocal<>();
    // 操作信息实体
    ThreadLocal<AuditLogDTO> ald = new ThreadLocal<>();

    @Pointcut("execution(public * com.al.api.modules.*.controller.*.create(..)) && " +
            "@annotation(com.al.api.aop.annotation.AuditAnno)")
    public void add_log(){}

    @Pointcut("execution(public * com.al.api.modules.*.controller.*.update(..)) && " +
            "@annotation(com.al.api.aop.annotation.AuditAnno)")
    public void update_log(){}

    @Pointcut("execution(public * com.al.api.modules.*.controller.*.del(..)) && " +
            "@annotation(com.al.api.aop.annotation.AuditAnno)")
    public void del_log(){}




    /**
     * @Author zhuzhibin
     * @Description //TODO 编辑操作的审计日志记录
     * @Date
     * @Param
     * @return
     **/
    @Before("update_log()")
    public void updateLog(JoinPoint joinPoint){
        AuditLogDTO auditLogDTO = new AuditLogDTO();
        try{
            logPre(joinPoint);//注解中对应的参数
            auditLogDTO.setType(operateType.get());
            auditLogDTO.setModuleName(moduleName.get());
            auditLogDTO.setModuleCode(moduleCode.get());
            auditLogDTO.setMethod(methodName.get());
            String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
            JSONObject jsonObject = JSONObject.parseObject(args);
            auditLogDTO.setDataNow(args);
            String dataId = jsonObject.get("id").toString();
            String moduleCode = auditLogDTO.getModuleCode();
            //根据 tableName \ id
            String result = auditLogService.selectObjById(dataId, moduleCode);
            auditLogDTO.setDataOld(JSON.toJSONString(result));
            getIp();
            auditLogDTO.setIp(Ip.get());//操作的ip
            auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
            ald.set(auditLogDTO);
            auditLogService.add(ald.get());
        }catch (Exception e){
            log.error("编辑审计出现错误。"+e);
        }

    }


    /**
     * @Author zhuzhibin
     * @Description //TODO 新增操作的审计日志记录
     * @Date  
     * @Param 
     * @return 
     **/
    @AfterReturning(returning = "obj",pointcut = "add_log()")
    public void addLog(JoinPoint joinPoint,Object obj){
        JSONObject json = JSONObject.parseObject(JSON.toJSONString(obj));
        if("success".equals(json.get("msg"))){
            AuditLogDTO auditLogDTO = new AuditLogDTO();
            try{
                logPre(joinPoint);//注解中对应的参数
                auditLogDTO.setType(operateType.get());
                auditLogDTO.setModuleName(moduleName.get());
                auditLogDTO.setModuleCode(moduleCode.get());
                auditLogDTO.setMethod(methodName.get());
                String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
                auditLogDTO.setDataNow(args);
                auditLogDTO.setDataOld(null);//新增设置为null,删除设置为最后,修改的时候 时候需要进行查询
                getIp();
                auditLogDTO.setIp(Ip.get());//操作的ip
                auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
                ald.set(auditLogDTO);
                auditLogService.add(ald.get());
            }catch (Exception e){
                log.error("新增审计出现错误。"+e);
            }
        }
    }



    /**
     * @Author zhuzhibin
     * @Description //TODO 删除操作的审计日志记录
     * @Date
     * @Param
     * @return
     **/
    @Before("del_log()")
    public void delLog(JoinPoint joinPoint) throws Throwable {
        try{
            AuditLogDTO auditLogDTO = new AuditLogDTO();
            logPre(joinPoint);//注解中对应的参数
            auditLogDTO.setType(operateType.get());
            auditLogDTO.setModuleName(moduleName.get());
            auditLogDTO.setModuleCode(moduleCode.get());
            auditLogDTO.setMethod(methodName.get());
            String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
            auditLogDTO.setDataNow(null);
            auditLogDTO.setDataOld(args);//新增设置为null,删除设置为最后,修改的时候 时候需要进行查询
            getIp();
            auditLogDTO.setIp(Ip.get());//操作的ip
            auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
            ald.set(auditLogDTO);
            auditLogService.add(ald.get());
        }catch (Exception e){
            log.error("删除审计出现错误。"+e);
        }
    }

    /**
     * @Author zhuzhibin
     * @Description //TODO 获取请求过来的ip
     * @Date  
     * @Param 
     * @return 
     **/
    private void getIp(){
        //获取请求对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = HttpUtil.getClientIP(request);
        Ip.set(ip);
    }

    /**
     * @Author zhuzhibin
     * @Description //TODO 获取自定义注解的参数
     * @Date
     * @Param
     * @return
     **/
    private void logPre(JoinPoint pjp) throws Exception {
        for (Method method : Class.forName(pjp.getTarget().getClass().getName()).getMethods()) {
            if (method.getName().equals(pjp.getSignature().getName())) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == pjp.getArgs().length) {
                    //获取注解信息
                    operateType.set(method.getAnnotation(AuditAnno.class).operationType());
                    moduleName.set(method.getAnnotation(AuditAnno.class).moduleName());
                    moduleCode.set(method.getAnnotation(AuditAnno.class).moduleCode());
                    methodName.set(method.getAnnotation(AuditAnno.class).value());
                    break;
                }
            }
        }
    }
    /**
     * @Author zhuzhibin
     * @Description //TODO 从dubbo 中 获取对应的bean
     * @Date  
     * @Param 
     * @return 
     **/
    public static <T> T getDubboBean(Class<T> requiredType){
        ReferenceAnnotationBeanPostProcessor dubboContext = SpringUtil.getBean(ReferenceAnnotationBeanPostProcessor.class);
        Collection<ReferenceBean<?>> referenceBeans = dubboContext.getReferenceBeans();
        for (ReferenceBean<?> referenceBean : referenceBeans) {
            Class<?> objectType = referenceBean.getObjectType();
            if(objectType == requiredType){
                return (T)referenceBean.getObject();
            }
        }
        return null;
    }

}

四、通过spring application 获取对应的 service 服务类 为了修改审计日志的时候 进行调用【由于我使用的是dubbo 服务化注解的方式,所以使用了 动态sql 进行实现。】

1、
List<LinkedHashMap<String,Object>> selectObjById(@Param("id") String id, @Param("tableName") String tableName);
2、
<select id="selectObjById" parameterType="java.lang.String" resultType="java.util.LinkedHashMap">
    SELECT
        *
    FROM
        ${tableName}
    WHERE
        id = #{id}
</select>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值