日志Aop切面配置笔记

最近在学习搭建框架,在这里分享下一些技术搭建,当做自己笔记,不好勿喷。
直接进入主题,对于系统的一些敏感操作,如修改、删除用户等需要增加日志模块,记录用户的操作。但是我们不可能每个模块都写原生代码,构建对象保存到数据库,所以这里就开始用到了aop日志切面,下面是我配置的简单例子。

  1. 日志类

import cn.ffcs.base.MyBaseModel;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import com.baomidou.mybatisplus.annotation.*;

/**
 * <p>
 * 用户操作日志
 * </p>
 *
 * @author 86188
 * @since 2021-04-16
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_sm_userlog")
public class TSmUserlog extends MyBaseModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "ID", type = IdType.AUTO)
    private Long id;

    /**
     * 操作人id
     */
    @TableField("OPERATE_USER_ID")
    private Long operateUserId;

    /**
     * 操作人
     */
    @TableField("OPERATE_USER_NAME")
    private String operateUserName;

    /**
     * 操作模块
     */
    @TableField("OPERATE_MODULE")
    private String operateModule;

    /**
     * 操作类
     */
    @TableField("OPERATE_CLASS")
    private String operateClass;

    /**
     * 操作方法
     */
    @TableField("OPERATE_METHOD")
    private String operateMethod;

    /**
     * 操作类型
     */
    @TableField("OPERATE_NAME")
    private String operateName;

    /**
     * 操作内容
     */
    @TableField("OPERATE_CONTENT")
    private String operateContent;

    /**
     * 操作时间
     */
    @TableField("OPERATE_TIME")
    private Date operateTime;

    /**
     * 请求数据
     */
    @TableField("REQUEST_DATA")
    private String requestData;

    /**
     * 响应数据
     */
    @TableField("RESPONSE_DATA")
    private String responseData;

    /**
     * 响应code
     */
    @TableField("RESPONSE_CODE")
    private String responseCode;

    /**
     * 响应信息
     */
    @TableField("RESPONSE_MESSAGE")
    private String responseMessage;

    /**
     * 删除状态
     */
    @TableField(value="STATUS", fill = FieldFill.INSERT)
    @TableLogic
    private String status;


}

  1. 响应类
/**
 * 访问结果Response
 */
@Data
public class Result<T> {

    // http 状态码
    private int code;

    // 返回信息
    private String msg;

    // 返回的数据
    private T data;

    //返回失败或者成功
    private boolean success;

  

}

  1. 定义操作模块
/**
 * 定义模块名称枚举
 *
 * @author 天真热
 * @create 2021-04-15 9:43
 * @desc
 **/
public enum OperateModule {
    T_LOGIN("登录"),
    T_SM_USER("用户管理"),
    T_SM_ROLE("角色管理"),
    T_SM_AUTHORITY("权限管理");

    private String moudoleName;

    private OperateModule(String moudoleName) {
        this.moudoleName = moudoleName;
    }


    /**
     * 返回模块名称
     *
     * @return
     */
    public String getMoudoleName() {
        return moudoleName;
    }

}

  1. 定义操作行为
/**
 * 定义操作类型枚举
 *
 * @author 天真热
 * @create 2021-04-15 9:44
 * @desc
 **/
public enum OperateType {
    LOGIN("登录"),
    CREATE("新增"),
    MODIFY("修改"),
    DELETE("删除"),
    SHOW("查看");

    private String typeName;

    private OperateType(String typeName) {
        this.typeName = typeName;
    }


    /**
     * 返回模块名称
     *
     * @return
     */
    public String getTypeName() {
        return typeName;
    }

}

  1. 自定义日志注解
/**
 * 自定义注解@UserActionLog
 *
 * @author 天真热
 * @create 2021-04-15 9:42
 * @desc
 **/

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface UserActionLog {
    /**
     * 操作描述 业务名称business
     *
     * @return
     */
    String description() default "";

    /**
     * 操作模块
     *
     * @return
     */
    OperateModule module();

    /**
     * 操作类型 create modify delete
     *
     * @return
     */
    OperateType opType();




}

  1. 自定义日志操作
/**
 * 切面
 *
 * @author 天真热
 * @create 2021-04-15 9:45
 * @desc
 **/
@Aspect
@Component
public class WebLogAspect {
    @Resource
    private ITSmUserlogService userlogService;
    @Resource
    private ITSmUserService userService;

    private Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * 获取@UserActionLog 注解上信息
     *
     * @param joinPoint
     * @return map
     * @throws Exception
     */
    public static Map<String, Object> getControllerAnnotationValue(JoinPoint joinPoint) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //获取切入点类名
        String targetName = joinPoint.getTarget().getClass().getName();
        map.put("targetName", targetName);
        //获取切入点方法名
        String methodName = joinPoint.getSignature().getName();
        map.put("methodName", methodName);
        //获取切入点参数列表
        Object[] arguments = joinPoint.getArgs();
        //获取切入点类对象
        Class targetClass = Class.forName(targetName);
        //获取切入点类对象的所有方法
        Method[] methods = targetClass.getMethods();

        //遍历类方法
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                //返回Class对象数组
                Class[] classes = method.getParameterTypes();
                if (classes.length == arguments.length) {
                    //操作描述
                    String description = method.getAnnotation(UserActionLog.class).description();
                    //模块名
                    String module = method.getAnnotation(UserActionLog.class).module().name();
                    //操作类型
                    String opType = method.getAnnotation(UserActionLog.class).opType().name();
                    map.put("module", module);
                    map.put("opType", opType);
                    map.put("business", description);
                    break;
                }
            }
        }
        return map;
    }

    /**
     * 定义一个切入点.
     * 第一个 * 代表任意修饰符及任意返回值.
     * 第二个 * 任意包名
     * 第三个 * 定义在web包或者子包
     * 第四个 * 任意方法
     * .. 匹配任意数量的参数.
     */
    @Pointcut("execution(public * cn.tzr..*.controller..*.*(..))  && @annotation(cn.ffcs.config.aop.userlog.UserActionLog)")
    public void webLog() {
    }

    @Around("webLog()")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
//        logger.info("环绕通知开始........");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        //获取token
        String shortToken = request.getHeader(Constant.SHORT_TOKEN);
        if (CommonStringUtils.isEmpty(shortToken)) {
            //前后端不分离的情况下,需要考虑地址栏带token的情况
            if (Constant.IS_URL_TOKEN) {
                shortToken = request.getParameter(Constant.SHORT_TOKEN);
            }
        }

        //解析token获取用户
        String username = JWTUtil.getUsername(shortToken);
        if(username==null){
            //没登录
            return null;
        }
        TSmUserDTO userDTO = userService.getByUsername(username);
        String nickname = userDTO.getNickname();
        //获取切入点的参数列表
        Object[] args = joinPoint.getArgs();
        //获取切入点的入参名称列表
        String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        Map<String, Object> params = new HashMap<>();
        //获取所有参数对象
        for (int i = 0; i < args.length; i++) {
            if (null != args[i]) {
                if (args[i] instanceof BindingResult) {
                    params.put(paramNames[i], "bindingResult");
                } else {
                    params.put(paramNames[i], args[i]);
                }
            } else {
                params.put(paramNames[i], "无");
            }
        }


        //获取@controllerLog 注解上信息
        Map<String, Object> values = getControllerAnnotationValue(joinPoint);
        String opType = values.get("opType").toString();//操作类型
        String module = values.get("module").toString();//操作模块
        String business = values.get("business").toString();//业务

        //切面获取返回值
        Object returnValue = joinPoint.proceed();
        Result result = new Result();
        if (returnValue instanceof Result) {
            result = (Result) returnValue;
        }

        TSmUserlogDTO userlogDTO = new TSmUserlogDTO();

        userlogDTO.setOperateModule(OperateModule.valueOf(module).getMoudoleName());//操作模块
        userlogDTO.setOperateName(OperateType.valueOf(opType).getTypeName());//操作类型
        userlogDTO.setOperateContent(business);//操作内容
        userlogDTO.setRequestData(JSONObject.fromObject(params).toString());//数据
        userlogDTO.setOperateUserId(userDTO.getId());//操作人id
        userlogDTO.setOperateUserName(userDTO.getNickname());//操作人名称
        userlogDTO.setOperateTime(new Date());//操作时间
        userlogDTO.setResponseCode(CommonStringUtils.toString(result.getCode()));//响应码
        userlogDTO.setResponseMessage(result.getMsg());//响应信息
        String responseData = null;
        try {
            responseData = CommonStringUtils.toString(JSONObject.fromObject(result.getData()));//响应数据
        } catch (Exception e) {
            responseData = CommonStringUtils.toString(result.getData());//响应数据
        }
        if (responseData.length() > 450) {
            responseData = responseData.substring(0, 450)+"......";
        }
        userlogDTO.setResponseData(responseData);//响应数据

        userlogDTO.setOperateClass(CommonStringUtils.toString(values.get("targetName")));
        userlogDTO.setOperateMethod(CommonStringUtils.toString(values.get("methodName")));

        userlogService.save(userlogDTO);
        return returnValue;
    }

    @AfterReturning("webLog()")
    public void doAfterReturning(JoinPoint joinPoint) {
        // 处理完请求,返回内容
        logger.info("WebLogAspect.doAfterReturning()");
    }

}

  1. 需要记录日志的地方加上 @UserActionLog即可,如下
/**
     * 保存用户
     *
     * @return
     */
    @PostMapping("/user/save")
    @UserActionLog(description = "保存用户", module = OperateModule.T_SM_USER, opType = OperateType.CREATE)
    public Result save(@RequestBody JSONObject data) {
        return null;
    }

基本能直接套用、亲测有效!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值