Aop切面 自定义注解记录操作日志保存到mysql

需求

公司要求记录操作日志,这里使用的aop正常返回通知以及自定义注解实现的需求,话不多说,直接贴代码。

1.首先创建实体类,接收参数保存到数据库


import lombok.Data;

import javax.persistence.Table;
import java.io.Serializable;

/**
 * 操作日志
 */
@Table(name = "operation_log")
@Data
public class OperationLog implements Serializable {

    private static final long serialVersionUID = 1;

     /**
     * 系统模块
     */
    private  String  systemModule;
     /**
     * 操作类型:  1:新增   2:修改  3:删除
     */
    private  Integer  operationType;
     /**
     * 用户id
     */
    private  Long  userId;
     /**
     * 用户姓名
     */
    private  String  userName;
     /**
     * 用户IP地址
     */
    private  String  ipAddress;
     /**
     * 操作描述
     */
    private  String  operationDescription;

    /**
     * 入参
     */
    private String requParam;

    /**
     *出参
     */
    private String respParam;

    /**
     *请求地址
     */
    private String url;

    /**
     *调用方法
     */
    private String method;
}

2.定义常量,也就是操作类型

/**
 * 新增
 */
public static final String  SAVE = "新增";

/**
 * 修改
 */
public static final String  UPDATE = "修改";

/**
 * 删除
 */
public static final String  DEL = "删除";

/**
 * 导入
 */
public static final String  IMPORT = "导入";

/**
 * 导出
 */
public static final String  EXPORT = "导出";

3.自定义做操日志注解@OperLog


import java.lang.annotation.*;

/**
 * 自定义注解 保存操作日志
 */
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented
public @interface OperLog {
    String systemModule() default ""; // 系统模块
    String operationType() default "";  // 操作类型  1:新增   2:修改  3:删除
    String operationDescription() default "";  // 操作描述
}

4.AOP



import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 切面 保存操作日志
 */
@Aspect
@Component
public class OperationLogAop {

    @Autowired
    private OperationLogFrontService operationLogFrontService;


    /**
     * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
     */
    @Pointcut("@annotation(com.xxxx.user.aspect.OperLog)")
    public void operLogPoinCut() {
    }


    /**
     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
     *
     * @param joinPoint 切入点
     */
    @AfterReturning(value = "operLogPoinCut()",returning = "keys")
    public void saveOperLog(JoinPoint  joinPoint,Object keys) throws Throwable {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //获取当前登录的用户信息
        UserDTO  userDTO  = getUserDTO(request);
        OperationLog operlog = new OperationLog();
        try {
            operlog.setId(IdTemplate.nextId()); // 主键ID

            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
            // 获取操作
            OperLog opLog = method.getAnnotation(OperLog.class);
            if (opLog != null) {
                String systemModule = opLog.systemModule();
                String operationType = opLog.operationType();
                String operationDescription = opLog.operationDescription();
                operlog.setSystemModule(systemModule); // 操作模块
                operlog.setOperationType(OperationTypeEnum.getCodeByDesc(operationType)); // 操作类型
                operlog.setOperationDescription(operationDescription); // 操作描述
            }
            //获取ip
            String ip = IpAdrressUtil.getIpAdrress(request);

            // 请求的参数
            Map<String, String> rtnMap = converMap(request.getParameterMap());
            // 将参数所在的数组转换成json
            String params = JSON.toJSONString(rtnMap);

            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName;

            operlog.setMethod(methodName); // 请求方法
            operlog.setRequParam(params);//入参
            operlog.setRespParam(JSON.toJSONString(keys));//出参
            operlog.setIpAddress(ip == null ? "" : ip); // 请求IP
            operlog.setUrl(request.getRequestURI()); // 请求URI
            operlog.setCreateTime(new Date()); // 创建时间
            operlog.setModifyTime(new Date()); // 修改时间
            if(userDTO != null){
                operlog.setUserId(userDTO.getId()); // 请求用户ID
                operlog.setUserName(userDTO.getName()); // 请求用户名称
                operlog.setCreator(userDTO.getId()); // 创建人
                operlog.setModifier(userDTO.getId()); // 修改人
            }
            operationLogFrontService.save(operlog);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 转换request 请求参数
     *
     * @param paramMap request获取的参数数组
     */
    public Map<String, String> converMap(Map<String, String[]> paramMap) {


        Map<String, String> rtnMap = new HashMap<String, String>();
        for (String key : paramMap.keySet()) {
            rtnMap.put(key, paramMap.get(key)[0]);
        }
        return rtnMap;
    }


    private UserDTO getUserDTO(HttpServletRequest request) {
        return LoginUserInfoUtil.getUserDTO(request);
    }
}

实际应用

@ApiOperation("根据id删除")
@PostMapping("/del")
@OperLog(systemModule = "XX模块",operationType = Const.DEL, operationDescription = "删除xx信息")
public AjaxResult<String> del(@NotNull(title = "id") Long id) {

   return relUserRoleFrontService.del(id);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值