SpringBoot利用AOP写一个日志管理(Log)

2023-11-09

1. 需求

目前有这么个问题,有两个系统CSP和OMS,这俩系统共用的是同一套日志操作:Log;目前想区分下这俩系统的日志操作,那没办法了,只能重写一份Log的日志操作;

你也可以参照若依框架的日志系统实现。

2. 新建一张日志表

sys_oper_csp_log

/*
 Navicat Premium Data Transfer

 Date: 08/09/2022 09:21:45
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_oper_csp_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_oper_csp_log`;
CREATE TABLE `sys_oper_csp_log`  (
  `oper_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '模块标题',
  `business_type` int(2) NULL DEFAULT 0 COMMENT '业务类型(0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据)',
  `method` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '方法名称',
  `request_method` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求方式',
  `operator_type` int(1) NULL DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
  `oper_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作人员',
  `dept_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '部门名称',
  `oper_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求URL',
  `oper_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '主机地址',
  `oper_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作地点',
  `oper_param` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求参数',
  `json_result` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '返回参数',
  `status` int(1) NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)',
  `error_msg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '错误消息',
  `oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间',
  PRIMARY KEY (`oper_id`) USING BTREE,
  INDEX `idx_time`(`oper_time`, `title`, `oper_name`) USING BTREE
) ENGINE = InnoD CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'CSP系统操作日志记录';

3. 写相应的Controller层

package com.juepeiscm.csp.controller.csplog;

import com.juepeiscm.admin.api.domain.SysOperLog;
import com.juepeiscm.common.core.controller.BaseController;
import com.juepeiscm.common.core.domain.AjaxResult;
import com.juepeiscm.common.core.page.TableDataInfo;
import com.juepeiscm.common.enums.BusinessType;
import com.juepeiscm.common.utils.poi.ExcelUtil;
import com.juepeiscm.csp.annotation.CspLog;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;
import com.juepeiscm.csp.service.csplog.ISysOperCspLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 操作CSP系统日志
 * @Author: py.sun
 * @Date: 2022/9/7 14:51
 */
@RestController
@RequestMapping({"/csplog/opercsplog"})
public class SysOperCsplogController extends BaseController {
    @Autowired
    private ISysOperCspLogService operCspLogService;

    public SysOperCsplogController() {
    }

    /**
     * 查询操作日志列表
     * @param sysOperCspLog
     * @return
     */
    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
    @GetMapping({"/list"})
    public TableDataInfo list(SysOperCspLog sysOperCspLog) {
        this.startPage();
        List<SysOperCspLog> list = this.operCspLogService.selectOperLogList(sysOperCspLog);
        return this.getDataTable(list);
    }

    /**
     * 查询系统模块的分类
     * @param
     * @return
     */
    @GetMapping({"/listTitle"})
    public TableDataInfo listTitle() {
        this.startPage();
        List<String> list = this.operCspLogService.selectOperLogListTitle();
        return this.getDataTable(list);
    }

    @CspLog(
            title = "导出CSP系统日志",
            businessType = BusinessType.EXPORT
    )
    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
    @GetMapping({"/export"})
    public AjaxResult export(SysOperCspLog operLog) {
        List<SysOperCspLog> list = this.operCspLogService.selectOperLogList(operLog);
        ExcelUtil<SysOperCspLog> util = new ExcelUtil(SysOperLog.class);
        return util.exportExcel(list, "操作CSP系统日志");
    }

    @CspLog(
            title = "操作CSP系统日志",
            businessType = BusinessType.DELETE
    )
    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
    @DeleteMapping({"/{operIds}"})
    public AjaxResult remove(@PathVariable Long[] operIds) {
        return this.toAjax(this.operCspLogService.deleteOperLogByIds(operIds));
    }

    @CspLog(
            title = "清除CSP系统日志",
            businessType = BusinessType.CLEAN
    )
    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
    @DeleteMapping({"/clean"})
    public AjaxResult clean() {
        this.operCspLogService.cleanOperLog();
        return AjaxResult.success();
    }


}


Service接口层

package com.juepeiscm.csp.service.csplog;

import com.juepeiscm.admin.api.domain.SysOperLog;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;

import java.util.List;

/**
 * @Author: py.sun
 * @Date: 2022/9/7 15:02
 */
public interface ISysOperCspLogService {
    void insertOperlog(SysOperCspLog var1);

    List<SysOperCspLog> selectOperLogList(SysOperCspLog var1);

    List<String> selectOperLogListTitle();

    int deleteOperLogByIds(Long[] var1);

    SysOperLog selectOperLogById(Long var1);

    void cleanOperLog();
}


Service实现

package com.juepeiscm.csp.service.impl.csplog;

import com.juepeiscm.admin.api.domain.SysOperLog;
import com.juepeiscm.common.core.domain.AjaxResult;
import com.juepeiscm.common.core.domain.entity.SysDept;
import com.juepeiscm.common.core.domain.entity.SysUser;
import com.juepeiscm.common.core.domain.model.LoginUser;
import com.juepeiscm.common.exception.CustomException;
import com.juepeiscm.common.utils.SecurityUtils;
import com.juepeiscm.common.utils.ServletUtils;
import com.juepeiscm.common.utils.StringUtils;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;
import com.juepeiscm.csp.mapper.csplog.SysOperCspLogMapper;
import com.juepeiscm.csp.service.csplog.ISysOperCspLogService;
import com.juepeiscm.framework.web.service.TokenService;
import com.juepeiscm.uam.service.ISysDeptService;
import com.juepeiscm.uam.version.UamVersion;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author: py.sun
 * @Date: 2022/9/7 15:03
 */
@Service
public class SysOperCspLogServiceImpl implements ISysOperCspLogService {
    @Autowired
    private SysOperCspLogMapper operLogMapper;

    @Autowired
    private TokenService tokenService;

    @Reference(version = UamVersion.idV)
    public ISysDeptService deptService;

    @Override
    public void insertOperlog(SysOperCspLog sysOperCspLog) {
        try {
            this.operLogMapper.insertOperlog(sysOperCspLog);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("CSP系统日志插入失败,请联系管理员!!!");
        }

    }

    @Override
    public List<SysOperCspLog> selectOperLogList(SysOperCspLog sysOperCspLog) {
        return this.operLogMapper.selectOperLogList(sysOperCspLog);
    }

    @Override
    public List<String> selectOperLogListTitle() {
        return this.operLogMapper.selectOperLogListTitle();
    }

    @Override
    public int deleteOperLogByIds(Long[] operIds) {
        return this.operLogMapper.deleteOperLogByIds(operIds);
    }

    @Override
    public SysOperLog selectOperLogById(Long operId) {
        return this.operLogMapper.selectOperLogById(operId);
    }

    @Override
    public void cleanOperLog() {
        this.operLogMapper.cleanOperLog();
    }
}


Mapper接口

package com.juepeiscm.csp.mapper.csplog;

import com.juepeiscm.admin.api.domain.SysOperLog;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;

import java.util.List;

/**
 * @Author: py.sun
 * @Date: 2022/9/7 15:06
 */
public interface SysOperCspLogMapper {

    void insertOperlog(SysOperCspLog var1);

    List<SysOperCspLog> selectOperLogList(SysOperCspLog sysOperCspLog);

    List<String> selectOperLogListTitle();

    int deleteOperLogByIds(Long[] var1);

    SysOperLog selectOperLogById(Long var1);

    void cleanOperLog();
}


Mapper.xml(我用的是Mybatis)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.juepeiscm.csp.mapper.csplog.SysOperCspLogMapper">

    <resultMap type="SysOperCspLog" id="SysOperLogResult">
        <id     property="operId"         column="oper_id"        />
        <result property="title"          column="title"          />
        <result property="businessType"   column="business_type"  />
        <result property="method"         column="method"         />
        <result property="requestMethod"  column="request_method" />
        <result property="operatorType"   column="operator_type"  />
        <result property="operName"       column="oper_name"      />
        <result property="deptName"       column="dept_name"      />
        <result property="operUrl"        column="oper_url"       />
        <result property="operIp"         column="oper_ip"        />
        <result property="operLocation"   column="oper_location"  />
        <result property="operParam"      column="oper_param"     />
        <result property="jsonResult"     column="json_result"    />
        <result property="status"         column="status"         />
        <result property="errorMsg"       column="error_msg"      />
        <result property="operTime"       column="oper_time"      />
    </resultMap>

    <sql id="selectOperLogVo">
        select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time
        from sys_oper_csp_log
    </sql>

    <insert id="insertOperlog" parameterType="SysOperCspLog">
        insert into sys_oper_csp_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time)
        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, sysdate())
    </insert>

    <select id="selectOperLogList" parameterType="SysOperCspLog" resultMap="SysOperLogResult">
        <include refid="selectOperLogVo"/>
        <where>
            <if test="title != null and title != ''">
                AND title like concat('%', #{title}, '%')
            </if>
            <if test="businessType != null and businessType != ''">
                AND business_type = #{businessType}
            </if>
            <if test="businessTypes != null and businessTypes.length > 0">
                AND business_type in
                <foreach collection="businessTypes" item="businessType" open="(" separator="," close=")">
                    #{businessType}
                </foreach>
            </if>
            <if test="status != null">
                AND status = #{status}
            </if>
            <if test="operName != null and operName != ''">
                AND oper_name like concat('%', #{operName}, '%')
            </if>
            <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
                and date_format(oper_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
            </if>
            <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
                and date_format(oper_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
            </if>
        </where>
        order by oper_id desc
    </select>

    <delete id="deleteOperLogByIds" parameterType="Long">
        delete from sys_oper_csp_log where oper_id in
        <foreach collection="array" item="operId" open="(" separator="," close=")">
            #{operId}
        </foreach>
    </delete>

    <select id="selectOperLogById" parameterType="Long" resultMap="SysOperLogResult">
        <include refid="selectOperLogVo"/>
        where oper_id = #{operId}
    </select>

    <select id="selectOperLogListTitle" resultType="java.lang.String">
        select distinct(title)  from sys_oper_csp_log
    </select>

    <update id="cleanOperLog">
        truncate table sys_oper_csp_log
    </update>

</mapper>

CspLog

定义一个日志管理的名称:CspLog

package com.juepeiscm.csp.annotation;

import com.juepeiscm.common.enums.BusinessType;
import com.juepeiscm.common.enums.OperatorType;

import java.lang.annotation.*;

/**
 * CSP系统的日志管理
 * @Author: py.sun
 * @Date: 2022/9/7 14:42
 * @Target表示注解可以使用到哪些地方,可以是类,方法,或者是属性上,定义在ElementType枚举中:
 * @Retention作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中:
 *
 * 我们的@CspLog注解,可以作用在方法和参数上,将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射性地读取。该注解是通过AOP进行解析的
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CspLog {
    /**
     * 模块
     * @return
     */
    String title() default "";

    /**
     * 功能
     * @return
     */
    BusinessType businessType() default BusinessType.OTHER;

    /**
     * 操作人类别
     * @return
     */
    OperatorType operatorType() default OperatorType.MANAGE;

    /**
     * 是否保存请求的参数
     * @return
     */
    boolean isSaveRequestData() default true;
}

实体类SysOperCspLog

package com.juepeiscm.csp.domain.csplog;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.juepeiscm.common.annotation.Excel;
import com.juepeiscm.common.core.domain.BaseEntity;

import java.util.Date;

/**
 * @Author: py.sun
 * @Date: 2022/9/7 15:04
 */
public class SysOperCspLog extends BaseEntity {
    private static final long serialVersionUID = 1L;
    @Excel(
            name = "操作序号",
            cellType = Excel.ColumnType.NUMERIC
    )
    private Long operId;
    @Excel(
            name = "操作模块"
    )
    private String title;
    @Excel(
            name = "业务类型",
            readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据"
    )
    private Integer businessType;
    private Integer[] businessTypes;
    @Excel(
            name = "请求方法"
    )
    private String method;
    @Excel(
            name = "请求方式"
    )
    private String requestMethod;
    @Excel(
            name = "操作类别",
            readConverterExp = "0=其它,1=后台用户,2=手机端用户"
    )
    private Integer operatorType;
    @Excel(
            name = "操作人员"
    )
    private String operName;
    @Excel(
            name = "部门名称"
    )
    private String deptName;
    @Excel(
            name = "请求地址"
    )
    private String operUrl;
    @Excel(
            name = "操作地址"
    )
    private String operIp;
    @Excel(
            name = "操作地点"
    )
    private String operLocation;
    @Excel(
            name = "请求参数"
    )
    private String operParam;
    @Excel(
            name = "返回参数"
    )
    private String jsonResult;
    @Excel(
            name = "状态",
            readConverterExp = "0=正常,1=异常"
    )
    private Integer status;
    @Excel(
            name = "错误消息"
    )
    private String errorMsg;
    @JsonFormat(
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    @Excel(
            name = "操作时间",
            width = 30.0D,
            dateFormat = "yyyy-MM-dd HH:mm:ss"
    )
    private Date operTime;

    public SysOperCspLog() {
    }

    public Long getOperId() {
        return this.operId;
    }

    public void setOperId(Long operId) {
        this.operId = operId;
    }

    public String getTitle() {
        return this.title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Integer getBusinessType() {
        return this.businessType;
    }

    public void setBusinessType(Integer businessType) {
        this.businessType = businessType;
    }

    public Integer[] getBusinessTypes() {
        return this.businessTypes;
    }

    public void setBusinessTypes(Integer[] businessTypes) {
        this.businessTypes = businessTypes;
    }

    public String getMethod() {
        return this.method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getRequestMethod() {
        return this.requestMethod;
    }

    public void setRequestMethod(String requestMethod) {
        this.requestMethod = requestMethod;
    }

    public Integer getOperatorType() {
        return this.operatorType;
    }

    public void setOperatorType(Integer operatorType) {
        this.operatorType = operatorType;
    }

    public String getOperName() {
        return this.operName;
    }

    public void setOperName(String operName) {
        this.operName = operName;
    }

    public String getDeptName() {
        return this.deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public String getOperUrl() {
        return this.operUrl;
    }

    public void setOperUrl(String operUrl) {
        this.operUrl = operUrl;
    }

    public String getOperIp() {
        return this.operIp;
    }

    public void setOperIp(String operIp) {
        this.operIp = operIp;
    }

    public String getOperLocation() {
        return this.operLocation;
    }

    public void setOperLocation(String operLocation) {
        this.operLocation = operLocation;
    }

    public String getOperParam() {
        return this.operParam;
    }

    public void setOperParam(String operParam) {
        this.operParam = operParam;
    }

    public String getJsonResult() {
        return this.jsonResult;
    }

    public void setJsonResult(String jsonResult) {
        this.jsonResult = jsonResult;
    }

    public Integer getStatus() {
        return this.status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getErrorMsg() {
        return this.errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public Date getOperTime() {
        return this.operTime;
    }

    public void setOperTime(Date operTime) {
        this.operTime = operTime;
    }
}


10. 定义日志管理的切面

大家一定要记住哈,所有针对实体的SysOperCspLog赋值操作必须在这里main执行。

package com.juepeiscm.csp.controller.utils;

import com.alibaba.fastjson.JSON;
import com.juepeiscm.common.core.domain.entity.SysDept;
import com.juepeiscm.common.core.domain.model.LoginUser;
import com.juepeiscm.common.enums.BusinessStatus;
import com.juepeiscm.common.enums.HttpMethod;
import com.juepeiscm.common.utils.ServletUtils;
import com.juepeiscm.common.utils.StringUtils;
import com.juepeiscm.common.utils.ip.IpUtils;
import com.juepeiscm.common.utils.spring.SpringUtils;
import com.juepeiscm.csp.annotation.CspLog;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;
import com.juepeiscm.framework.aspectj.LogAspect;
import com.juepeiscm.framework.manager.AsyncManager;
import com.juepeiscm.framework.web.service.TokenService;
import com.juepeiscm.uam.service.ISysDeptService;
import com.juepeiscm.uam.version.UamVersion;
import org.apache.dubbo.config.annotation.Reference;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

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

/**
 * @Author: py.sun
 * @Date: 2022/9/7 16:31
 * 操作日志记录处理
 */
@Aspect
@Component
public class CspLogAspect {
    private static final Logger log = LoggerFactory.getLogger(CspLog.class);

    @Reference(version = UamVersion.idV)
    public ISysDeptService deptService;

    public CspLogAspect() {
    }

    //把@CspLog配置为切入点。   配置织入点
    @Pointcut("@annotation(com.juepeiscm.csp.annotation.CspLog)")
    public void logPointCut() {
    }

    //拦截异常操作
    // 处理完请求后执行该方法。也就是用@CspLog注解的方法,执行完后,调用handleLog方法,处理返回结果。
    @AfterReturning(
            pointcut = "logPointCut()",
            returning = "jsonResult"
    )
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        this.handleLog(joinPoint, (Exception)null, jsonResult);
    }

    @AfterThrowing(
            value = "logPointCut()",
            throwing = "e"
    )
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        this.handleLog(joinPoint, e, (Object)null);
    }

    // 如果函数抛出了异常,也是执行handleLog方法,不过和正常返回的参数不一样,此处是为了处理异常。
    protected void handleLog(JoinPoint joinPoint, Exception e, Object jsonResult) {
        try {
            // 获得注解
            CspLog controllerLog = this.getAnnotationLog(joinPoint);
            if (controllerLog == null) {
                return;
            }

            // 获取当前的用户
            LoginUser loginUser = ((TokenService) SpringUtils.getBean(TokenService.class)).getLoginUser(ServletUtils.getRequest());
            // *========数据库日志=========*//
            SysOperCspLog operLog = new SysOperCspLog();
            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
            // 请求的地址
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
            operLog.setOperIp(ip);
            // 返回参数
            operLog.setJsonResult(JSON.toJSONString(jsonResult));
            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
            if (loginUser != null) {
                operLog.setOperName(loginUser.getUsername());
            }

            // 获取当前登录用户的部门名称
            SysDept sysDept = deptService.selectDeptIdByUserIdAndAppId(loginUser.getUser().getUserId(), "oms");
            if(sysDept != null && StringUtils.isNotEmpty(sysDept.getDeptName())){
                    operLog.setDeptName(sysDept.getDeptName());
            }

            if (e != null) {
                operLog.setStatus(BusinessStatus.FAIL.ordinal());
                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
            }

            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");
            // 设置请求方式
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            // 处理设置注解上的参数
            this.getControllerMethodDescription(joinPoint, controllerLog, operLog);
            // 保存数据库
            AsyncManager.me().execute(AsyncFactoryCsp.recordOper(operLog));
        } catch (Exception var10) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", var10.getMessage());
            var10.printStackTrace();
        }

    }

    public void getControllerMethodDescription(JoinPoint joinPoint, CspLog log, SysOperCspLog operLog) throws Exception {
        operLog.setBusinessType(log.businessType().ordinal());
        operLog.setTitle(log.title());
        operLog.setOperatorType(log.operatorType().ordinal());
        if (log.isSaveRequestData()) {
            this.setRequestValue(joinPoint, operLog);
        }

    }

    private void setRequestValue(JoinPoint joinPoint, SysOperCspLog operLog) throws Exception {
        String requestMethod = operLog.getRequestMethod();
        if (!HttpMethod.PUT.name().equals(requestMethod) && !HttpMethod.POST.name().equals(requestMethod)) {
            Map<?, ?> paramsMap = (Map)ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
        } else {
            String params = this.argsArrayToString(joinPoint.getArgs());
            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
        }

    }

    private CspLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method method = methodSignature.getMethod();
        return method != null ? (CspLog)method.getAnnotation(CspLog.class) : null;
    }

    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for(int i = 0; i < paramsArray.length; ++i) {
                if (StringUtils.isNotNull(paramsArray[i]) && !this.isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    params = params + jsonObj.toString() + " ";
                }
            }
        }

        return params.trim();
    }

    public boolean isFilterObject(Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else {
            Iterator iter;
            if (Collection.class.isAssignableFrom(clazz)) {
                Collection collection = (Collection)o;
                iter = collection.iterator();
                if (iter.hasNext()) {
                    return iter.next() instanceof MultipartFile;
                }
            } else if (Map.class.isAssignableFrom(clazz)) {
                Map map = (Map)o;
                iter = map.entrySet().iterator();
                if (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry)iter.next();
                    return entry.getValue() instanceof MultipartFile;
                }
            }

            return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse || o instanceof BindingResult;
        }
    }
}


AsyncFactoryCsp

package com.juepeiscm.csp.controller.utils;
import com.juepeiscm.common.utils.ip.AddressUtils;
import com.juepeiscm.common.utils.spring.SpringUtils;
import com.juepeiscm.csp.domain.csplog.SysOperCspLog;
import com.juepeiscm.csp.service.csplog.ISysOperCspLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.TimerTask;

/**
 * @Author: py.sun
 * @Date: 2022/9/7 16:47
 */
public class AsyncFactoryCsp {
    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");

    public AsyncFactoryCsp() {
    }

    public static TimerTask recordOper(final SysOperCspLog operLog) {
        return new TimerTask() {
            public void run() {
                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
                ((ISysOperCspLogService) SpringUtils.getBean(ISysOperCspLogService.class)).insertOperlog(operLog);
            }
        };
    }
}


12. 写一个Controller的Demo来执行一条日志试试

在这里插入代码片package com.juepeiscm.csp.controller.order;

import com.alibaba.fastjson.JSON;
import com.juepeiscm.admin.api.service.ISysDictDataService;
import com.juepeiscm.common.annotation.RepeatSubmit;
import com.juepeiscm.common.core.controller.BaseController;
import com.juepeiscm.common.core.domain.AjaxResult;
import com.juepeiscm.common.core.domain.entity.SysDictData;
import com.juepeiscm.common.core.page.TableDataInfo;
import com.juepeiscm.common.enums.BusinessType;
import com.juepeiscm.common.exception.BaseException;
import com.juepeiscm.common.utils.StringUtils;
import com.juepeiscm.common.utils.poi.ExcelUtil;
import com.juepeiscm.csp.annotation.CspLog;
import com.juepeiscm.csp.domain.order.CspGodownEntry;
import com.juepeiscm.csp.domain.order.CspGodownEntryDetails;
import com.juepeiscm.csp.service.common.MenuLogService;
import com.juepeiscm.csp.service.data.ICspGoodsdataService;
import com.juepeiscm.csp.service.order.ICspGodownEntryService;
import com.juepeiscm.csp.vo.GodownEntryExcel;
import com.juepeiscm.csp.vo.GoodsDataForGodownEntryDetails;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库订单Controller
 *
 * @author juepeiscm
 * @date 2021-07-23
 */
@Api(tags = "入库订单接口")
@RestController
@RequestMapping("/order/godownEntry")
public class CspGodownEntryController extends BaseController {

    private static final Logger logger = LoggerFactory.getLogger(CspGodownEntryController.class);

    @Autowired
    private ICspGodownEntryService cspGodownEntryService;
    @Autowired
    private ICspGoodsdataService goodsDataService;
    @Autowired
    private MenuLogService menuLogService;
    @Autowired
    private ISysDictDataService sysDictDataService;

    /**
     * 新增入库订单Demo
     */
    @PreAuthorize("@ss.hasPermi('order:godownEntry:add')")
    @ApiOperation(value = "新增入库订单")
    @CspLog(title = "入库订单demo4", businessType = BusinessType.INSERT)
    @PostMapping("/addOrder")
    @RepeatSubmit
    public AjaxResult addDemo(@RequestBody @Valid CspGodownEntry godownEntry) {
        try {
            return toAjax(cspGodownEntryService.insertOmsGodownEntry(godownEntry));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("新增失败,请联系管理员");
        }
    }
}

测试下,看看数据库内容

在这里插入图片描述

如果大家还有什么疑问,请留言!!!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot利用AOP写一个日志管理(Log) 的相关文章

  • 不同帐户上的 Spring Boot、JmsListener 和 SQS 队列

    我正在尝试开发一个 Spring Boot 1 5 应用程序 该应用程序需要侦听来自两个不同 AWS 帐户的 SQS 队列 是否可以使用 JmsListener 注解创建监听器 我已检查权限是否正确 我可以使用 getQueueUrl 获取
  • Junit:如何测试从属性文件读取属性的方法

    嗨 我有课ReadProperty其中有一个方法ReadPropertyFile返回类型的Myclass从属性文件读取参数值并返回Myclass目的 我需要帮助来测试ReadPropertyFile方法与JUnit 如果可能的话使用模拟文件
  • 如何循环遍历所有组合,例如48 选择 5 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在java中从大小为n的集合中迭代生成k个元素子集 https stackoverflow com questions 4504974 how to iteratively generate k
  • 如何使用assertEquals 和 Epsilon 在 JUnit 中断言两个双精度数?

    不推荐使用双打的assertEquals 我发现应该使用带有Epsilon的形式 这是因为双打不可能100 严格 但无论如何我需要比较两个双打 预期结果和实际结果 但我不知道该怎么做 目前我的测试如下 Test public void te
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 在 Jar 文件中运行 ANT build.xml 文件

    我需要使用存储在 jar 文件中的 build xml 文件运行 ANT 构建 该 jar 文件在类路径中可用 是否可以在不分解 jar 文件并将 build xml 保存到本地目录的情况下做到这一点 如果是的话我该怎么办呢 Update
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 内部类的构造函数引用在运行时失败并出现VerifyError

    我正在使用 lambda 为内部类构造函数创建供应商ctx gt new SpectatorSwitcher ctx IntelliJ建议我将其更改为SpectatorSwitcher new反而 SpectatorSwitcher 是我正
  • 当 OnFocusChangeListener 应用于包装的 EditText 时,TextInputLayout 没有动画

    不能比标题说得更清楚了 我有一个由文本输入布局包裹的 EditText 我试图在 EditText 失去焦点时触发一个事件 但是 一旦应用了事件侦听器 TextInputLayout 就不再对文本进行动画处理 它只是位于 editText
  • 如何对不同的参数类型使用相同的java方法?

    我的问题 我有 2 个已定义的记录 创建对象请求 更新对象请求 必须通过实用方法进行验证 由于这两个对象具有相同的字段 因此可以对这两种类型应用相同的验证方法 现在我只是使用两种方法进行重载 但它很冗长 public record Crea
  • 在我的 Spring Boot 示例中无法打开版本 3 中的 Swagger UI

    我在 Spring Boot 示例中打开 swagger ui 时遇到问题 当我访问 localhost 8080 swagger ui 或 localhost 8080 root api name swagger ui 时出现这种错误 S
  • Java 和 Python 可以在同一个应用程序中共存吗?

    我需要一个 Java 实例直接从 Python 实例数据存储中获取数据 我不知道这是否可能 数据存储是否透明 唯一 或者每个实例 如果它们确实可以共存 都有其单独的数据存储 总结一下 Java 应用程序如何从 Python 应用程序的数据存
  • 获取文件的总大小(以字节为单位)[重复]

    这个问题在这里已经有答案了 可能的重复 java 高效获取文件大小 https stackoverflow com questions 116574 java get file size efficiently 我有一个名为 filenam
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • Spring Boot 无法更新 azure cosmos db(MongoDb) 上的分片集合

    我的数据库中存在一个集合 documentDev 其分片键为 dNumber 样本文件 id 12831221wadaee23 dNumber 115 processed false 如果我尝试使用以下命令通过任何查询工具更新此文档 db
  • Spring Rest 和 Jsonp

    我正在尝试让我的 Spring Rest 控制器返回jsonp但我没有快乐 如果我想返回 json 但我有返回的要求 完全相同的代码可以正常工作jsonp我添加了一个转换器 我在网上找到了用于执行 jsonp 转换的源代码 我正在使用 Sp

随机推荐

  • v-model绑定checkbox无法动态更新视图

    在vue2中使用v model绑定checkbox
  • Python爬虫(入门+进阶)学习笔记 1-6 浏览器抓包及headers设置(案例一:爬取知乎)

    爬虫的一般思路 抓取网页 分析请求 解析网页 寻找数据 储存数据 多页处理 本节课主要讲授如何通过谷歌浏览器开发者工具分析真实请求的方法 寻找真实请求的三个步骤 分析 使用谷歌浏览器开发者工具分析网页的请求 测试 测试URL请求中每个参数的
  • echarts实现颜色渐变的环状图(包括自定义各种配置项的属性)

    实现效果 实现代码 option color new echarts graphic LinearGradient 1 1 0 0 offset 0 color F2A635 offset 0 9 color ffffff new echa
  • 为Qt应用程序的用户添加帮助文档

    qt5 简单文本查看器例子 Qt Assistant支持交互式帮助 并使您能够向Qt应用程序的用户显示客户文档 以下示例说明如何将Qt Assistant用作应用程序的帮助查看器 使用Qt Assistant作为应用程序的自定义help查看
  • Oracle V$SESSION详解

    V SESSION是APPS用户下面对于SYS V SESSION 视图的同义词 在本视图中 每一个连接到数据库实例中的session都拥有一条记录 包括用户session及后台进程如DBWR LGWR arcchiver等等 V SESS
  • 大数据环境下的“隐形隐私”保护问题

    导语 隐形隐私 泄漏问题一直我们乃至全球最难解决的问题 数据安全不止是一个企业发展的核心关键 更关系到企业单位的生死存亡 企业单位重要客户信息泄露并在市面上大肆流通发生之后我们在想尽各种方法亡羊补牢 可是我们数据安全难道不是要从最一开始就做
  • 针对初学者,解决一些问题【Kali】手把手教你设置Kali源地址以及更新源和安装所有工具命令

    文章目录 一 设置添加修改源地址 1 首先在命令提示符中输入以下命令打开源列表文件 2 按i进入编辑模式 3 在下面源地址中至少选择一个复制粘贴进去 4 添加进入以后按ESC键退出编辑模式 按 输入wq保存退出 二 更新源命令 三 软件包操
  • TCP为什么需要三次握手

    tcp为什么要第三次握手 time wait是做什么的 tcp有几种状态 画出所有的状态转换图 晚上看到的面试题 TCP三次握手的印象很深 但为什么需要3次握手 还是想不起来了 简单而言 如果不是三次握手的话 那么到底需要几次握手最佳呢 2
  • 关于毕业求职的就业经验-写给我亲爱的校友们

    提示 希望下面的文章对大家能有所帮助 文章目录 前言 一 毕业季的几种选择 1 考研 2 就业 3 其他 二 到了毕业季应该怎么去找到自己心怡的工作 三 需要掌握的基本技能 以我嵌入式开发角度 四 该怎么去跳槽到更好的公司 五 未来规划 1
  • SPARK安装

    首先是结论 最终我没能在win10上运行起来spark 官方给的quickstart http spark apache org docs latest api python getting started quickstart html
  • Matlab学习1.0

    1 Matlab通用命令 1 常用命令 cd 显示 or改变当前文件夹 dir 显示当前文件夹下的文件 clc 清空工作窗中显示的内容 load 加载指定文件的变量 diary 日志文件命令 调用DOS命令 home 光标移动到窗口最左上角
  • 网络安全知识库

    0x00 前言 本篇用来整理所有的零散的知识 作为一个技能树或者技能表来进行引导 CTF 加解密合集 CTF Web合集 0x01 Http 1 http头 1 1 本地访问识别 如何伪造http头 让后端认为是本地访问 0x02 Web
  • Python爬虫反反爬:CSS反爬加密彻底破解!

    刚开始搞爬虫的时候听到有人说爬虫是一场攻坚战 听的时候也没感觉到特别 但是经过了一段时间的练习之后 深以为然 每个网站不一样 每次爬取都是重新开始 所以 爬之前谁都不敢说会有什么结果 前两天 应几个小朋友的邀请 动心思玩了一下大众点评的数据
  • css动画效果之transition(动画过渡效果属性)

  • pandas dataframe 读取 xlsx 文件

    refer to https medium com kasiarachuta reading and writingexcel files in python pandas 8f0da449cc48 dframe pd read excel
  • github代码推送总是失败

    github代码推送问题 因为github仓库代码的推送总是失败 所以改了一个方案采用ssh的方式来进行代码的推送 并记录操作步骤 方案 https方式换成ssh方式 git ssh 生成 假如已经生成的话 可以略过此步骤 ssh keyg
  • Android启动service的方法

    在 Android 中启动 service 的方法如下 创建 service 的类 并在 AndroidManifest xml 文件中注册该 service 使用 Intent 类来启动 service 例如 Intent intent
  • [转]公司管理混乱,从哪里入手?

    案例分析 我们是一个40人左右的小公司 规模虽小 但管理起来感觉力不从心 经常碰到工人抵抗 情绪化 上班迟到 旷工 不服从管理 即使勉强接受 也不会用心去做 草草应付了事 每次都提议是否弄个规章制度 但也是白纸一张 到了月底 实施不了 因为
  • 使用OpenGL 立方体贴图

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 OpenGL 立方体贴图 二 使用步骤 1 代码 2 着色器程序 运行结果 注意 源码下载 参考 前言 对于室外3D 场景 通常可以通过在地平线上创造一些逼真的效果 来
  • SpringBoot利用AOP写一个日志管理(Log)

    1 需求 目前有这么个问题 有两个系统CSP和OMS 这俩系统共用的是同一套日志操作 Log 目前想区分下这俩系统的日志操作 那没办法了 只能重写一份Log的日志操作 你也可以参照若依框架的日志系统实现 2 新建一张日志表 sys oper