操作日志

作為一個小外包...,記錄一下工作中常用的一些方法(tools),以便后續(xù)使用。
如果有小伙伴看,歡迎指點。切記:不要指指點點。

操作日志表結構

-- 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 '請求參數(shù)\n',
    `request_body`  varchar(2000)                                                DEFAULT NULL COMMENT '請求body',
    `create_time`   datetime                                                     DEFAULT NULL COMMENT '創(chuàng)建時間',
    `create_by`     varchar(40)                                                  DEFAULT NULL COMMENT '創(chuàng)建人',
    `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='系統(tǒng)操作日志表';

注解:

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參數(shù)
     */
    boolean useBody() default false;
    /**
     * 注解:body參數(shù)位于方法的第幾位
     */
    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 {

    /**
     * 處理完請求后執(zhí)行
     *
     * @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 {
            // 記錄到數(shù)據(jù)庫時,return的數(shù)據(jù) 或者 異常的 限制長度
            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參數(shù)
            Map<String, String[]> parameterMap = request.getParameterMap();
            //  處理成json串
            String requestParam = JSONUtil.toJsonPrettyStr(parameterMap);
            // 9、獲取Body參數(shù)--> 這個不能從request中獲取,因為request的body只能被讀取一次,所有采用從方法的形參中讀取
            String bodyParam = StrUtil.EMPTY;
            if (opLog.useBody()) {
                Object[] args = joinPoint.getArgs();
                bodyParam = JSONUtil.toJsonPrettyStr(args[opLog.bodyIndex()]);
            }
            // 10、處理記錄的message、狀態(tài)
            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(){
        //參數(shù)1為終端ID, 參數(shù)2為數(shù)據(jù)中心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共享 當異步執(zhí)行的DAO方法需要記錄日志時,需要先調用此方法設置
     */
    public static void setParentRequestShare() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            RequestContextHolder.setRequestAttributes(requestAttributes, true);
        }
    }

}

完整代碼在這:GIT

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容