操作日志

作为一个小外包...,记录一下工作中常用的一些方法(tools),以便后续使用。
如果有小伙伴看,欢迎指点。切记:不要指指点点。

操作日志表结构

-- mysql 8.0 操作日志表结构
CREATE TABLE `sys_op_log`
(
    `id`            varchar(40) NOT NULL COMMENT '主键',
    `op_user_id`    varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '操作人id\n',
    `op_user_name`  varchar(65) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '操作人账号',
    `url`           varchar(255)                                                 DEFAULT NULL COMMENT '访问路径',
    `ip`            varchar(255)                                                 DEFAULT NULL COMMENT '客户端ip',
    `module`        varchar(255)                                                 DEFAULT NULL COMMENT '所属模块',
    `type`          varchar(255)                                                 DEFAULT NULL COMMENT '请求类型',
    `status`        tinyint                                                      DEFAULT NULL COMMENT '1成功,0失败',
    `title`         varchar(255)                                                 DEFAULT NULL COMMENT '日志标题',
    `message`       text COMMENT '成功或失败的信息',
    `op_time`       datetime                                                     DEFAULT NULL COMMENT '操作时间',
    `request_param` varchar(2000)                                                DEFAULT NULL COMMENT '请求参数\n',
    `request_body`  varchar(2000)                                                DEFAULT NULL COMMENT '请求body',
    `create_time`   datetime                                                     DEFAULT NULL COMMENT '创建时间',
    `create_by`     varchar(40)                                                  DEFAULT NULL COMMENT '创建人',
    `update_time`   datetime                                                     DEFAULT NULL COMMENT '更新时间',
    `update_by`     varchar(40)                                                  DEFAULT NULL COMMENT '更新人',
    PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='系统操作日志表';

注解:

package log;

import java.lang.annotation.*;

/**
 * @author OutResource Boy
 * @date 2023/8/17 22:43
 */
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpLog {
    /**
     * 操作模块
     */
    String module() default "";
    /**
     * 操作标题
     */
    String title() default "";

    /**
     * 是否使用了body参数
     */
    boolean useBody() default false;
    /**
     * 注解:body参数位于方法的第几位
     */
    int bodyIndex() default 0;

}

opLog status 相关常量

package log;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * opLog status 相关常量
 * @author OutResource Boy
 * @date 2023/8/18 10:58
 */
@AllArgsConstructor
public enum OpLogEnum {
    /**
     * 成功
     */
    SUCCESS(1, "成功"),
    /**
     * 失败
     */
    FAIL(0, "失败");
    @Getter
    private final Integer FLAG;
    @Getter
    private final String DESC;
}

Aspect

package log;

import java.util.Date;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import utils.GlobalWebVarUtil;
import utils.SnowFlakeIdGenerateUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @author OutResource Boy
 * 来自:ruoyi
 * 重要依赖:hu-tool
 * @date 2023/8/17 22:43
 */
@Aspect
@Component
public class OpLogAspect {

    /**
     * 处理完请求后执行
     *
     * @param opLog      操作日志
     * @param jsonResult json结果
     */
    @AfterReturning(pointcut = "@annotation(opLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, OpLog opLog, Object jsonResult) {
        handleLog(joinPoint, opLog, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param e     异常
     * @param opLog 操作日志
     */
    @AfterThrowing(pointcut = "@annotation(opLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, OpLog opLog, Exception e) {
        handleLog(joinPoint, opLog, e, null);
    }

    /**
     * 处理日志
     *
     * @param joinPoint  连接点
     * @param opLog      操作日志注解
     * @param e          异常
     * @param jsonResult json结果
     */
    private void handleLog(JoinPoint joinPoint, OpLog opLog, Exception e, Object jsonResult) {
        try {
            // 记录到数据库时,return的数据 或者 异常的 限制长度
            int msgMaxSize = 500;

            // 1、生成日志Id
            String id = SnowFlakeIdGenerateUtils.getSnowFlakeId();
            // 2、操作人Id:这个需要获取当前登录的用户,这里不设置
            String opId = StrUtil.EMPTY;
            // 3、和操作人Id一样
            String opName = StrUtil.EMPTY;
            // 4、获取请求Uri
            HttpServletRequest request = GlobalWebVarUtil.getRequest();
            String requestUri = request.getRequestURI();
            // 5、获取请求者IP地址
            String ip = ServletUtil.getClientIP(request);
            // 6、获取请求模块
            String module = opLog.module();
            // +1、请求方式
            String requestMethod = request.getMethod();
            // 7、获取请求主题
            String title = opLog.title();
            // 8、获取请求Param参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            //  处理成json串
            String requestParam = JSONUtil.toJsonPrettyStr(parameterMap);
            // 9、获取Body参数--> 这个不能从request中获取,因为request的body只能被读取一次,所有采用从方法的形参中读取
            String bodyParam = StrUtil.EMPTY;
            if (opLog.useBody()) {
                Object[] args = joinPoint.getArgs();
                bodyParam = JSONUtil.toJsonPrettyStr(args[opLog.bodyIndex()]);
            }
            // 10、处理记录的message、状态
            String message;
            int status;
            if (ObjectUtil.isNull(e)) {
                status = OpLogEnum.SUCCESS.getFLAG();
                String resString = JSONUtil.toJsonPrettyStr(jsonResult);
                message = StrUtil.length(resString) > msgMaxSize ? StrUtil.sub(resString, 0, msgMaxSize) : resString;
            } else {
                status = OpLogEnum.FAIL.getFLAG();
                String resString = JSONUtil.toJsonPrettyStr(e);
                message = StrUtil.length(resString) > msgMaxSize ? StrUtil.sub(resString, 0, msgMaxSize) : resString;
            }
            // 记录日志
            SysOpLog sysOpLog = new SysOpLog();
            sysOpLog.setId(id);
            sysOpLog.setOpId(opId);
            sysOpLog.setOpName(opName);
            sysOpLog.setUrl(requestUri);
            sysOpLog.setIp(ip);
            sysOpLog.setModule(module);
            sysOpLog.setType(requestMethod);
            sysOpLog.setStatus(status);
            sysOpLog.setTitle(title);
            sysOpLog.setMessage(message);
            sysOpLog.setOpTime(new Date());
            sysOpLog.setRequestParam(requestParam);
            sysOpLog.setRequestBody(bodyParam);
            // --- 下面这几个我觉得放在mybatis拦截器里面比较好,这里就不设置了 --- //
            sysOpLog.setCreateTime(new Date());
            sysOpLog.setCreateBy("");
            sysOpLog.setUpdateTime(new Date());
            sysOpLog.setUpdateBy("");
        }catch (Exception exp){
            // 打一下异常..
        }

    }

}

其他小工具

package utils;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;

/**
 * 雪花id生成工具
 *
 * @author OutResource Boy
 * @date 2023/6/28 17:06
 */
public class SnowFlakeIdGenerateUtils {
    public static String getSnowFlakeId(){
        //参数1为终端ID, 参数2为数据中心ID
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        return snowflake.nextIdStr();
    }
}
package utils;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

/**
 * 获取Request
 * @author OutResource Boy
 * @date 2023/07/07
 */
public class GlobalWebVarUtil {
    /**
     * 得到HttpServletRequest对象
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return requestAttributes != null ? ((ServletRequestAttributes) requestAttributes).getRequest() : null;
    }

    /**
     * 设置父线程requestAttributes共享 当异步执行的DAO方法需要记录日志时,需要先调用此方法设置
     */
    public static void setParentRequestShare() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            RequestContextHolder.setRequestAttributes(requestAttributes, true);
        }
    }

}

完整代码在这:GIT

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容