springboot+AOP操作日志代码

pom.xml文件

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

自定义注解记录系统操作日志

package com.central.user.aop;
import java.lang.annotation.*;
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog
{
    /**
     * 模块标题
     */
    String title() default "";
    /**
     * 日志内容
     */
    String content() default "";
}

AOP工具类

@Aspect
@Component
public class OperLogAspect {

    @Autowired
    private IOperLogService operLogService;

    //为了记录方法的执行时间
    ThreadLocal<Long> startTime = new ThreadLocal<>();
    @Pointcut("@annotation(com.central.user.aop.MyLog)")//在注解的位置切入代码
    public void operLogPoinCut() {
    }

    @Before("operLogPoinCut()")
    public void beforMethod(JoinPoint point){
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 设置操作异常切入点记录异常日志 扫描所有DevelopController包下操作
     * @Pointcut("execution(* com.central.user.controller..*.*(..))")扫描所有包
     */
    @Pointcut("execution(* com.central.user.controller..DevelopController.*(..))")//扫描某个controller
    public void operExceptionLogPoinCut() {
    }

    /**
     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
     *
     * @param joinPoint 切入点
     * @param result      返回结果
     */
    @AfterReturning(value = "operLogPoinCut()", returning = "result")
    public void saveOperLog(JoinPoint joinPoint, Object result) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
            // 获取操作
            MyLog myLog = method.getAnnotation(MyLog.class);

            Synchronous operlog = new Synchronous();
            if (myLog != null) {
                operlog.setTitle(myLog.title());//设置模块名称
                operlog.setContent(myLog.content());//设置日志内容
            }
            // 将入参转换成json
            String params = argsArrayToString(joinPoint.getArgs());
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName + "()";
            operlog.setMethod(methodName); //设置请求方法
            operlog.setRequestMethod(request.getMethod());//设置请求方式
            operlog.setRequestParam(params); // 请求参数
            if(!"GET".equals(request.getMethod())) {
                operlog.setResponseResult(JSON.toJSONString(result)); // 返回结果
            }
            operlog.setTenantId(request.getParameter("tenantId")); 
            operlog.setIp(getIp(request)); // IP地址
            operlog.setRequestUrl(request.getRequestURI()); // 请求URI
            operlog.setOperTime(new Date()); // 时间
            operlog.setStatus(0);//操作状态(0正常 1异常)
            Long takeTime = System.currentTimeMillis() - startTime.get();//记录方法执行耗时时间(单位:毫秒)
            operlog.setTakeTime(takeTime);
            //插入数据库
            operLogService.saveIOperLog(operlog);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
     */
    @AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        Synchronous operlog = new Synchronous();
        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName + "()";
            // 获取操作
            MyLog myLog = method.getAnnotation(MyLog.class);
            if (myLog != null) {
                operlog.setTitle(myLog.title());//设置模块名称
                operlog.setContent(myLog.content());//设置日志内容
            }
            // 将入参转换成json
            String params = argsArrayToString(joinPoint.getArgs());
            operlog.setMethod(methodName); //设置请求方法
            operlog.setRequestMethod(request.getMethod());//设置请求方式
            operlog.setRequestParam(params); // 请求参数
            operlog.setTenantId(request.getParameter("tenantId")); // 获取应用标识
            operlog.setIp(getIp(request)); // IP地址
            operlog.setRequestUrl(request.getRequestURI()); // 请求URI
            operlog.setOperTime(new Date()); // 时间
            operlog.setStatus(1);//操作状态(0正常 1异常)
            operlog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));//记录异常信息
            //插入数据库
            operLogService.saveIOperLog(operlog);
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }

    /**
     * 转换异常信息为字符串
     */
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "\n");
        }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
        message = substring(message,0 ,2000);
        return message;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray)
    {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0)
        {
            for (Object o : paramsArray)
            {
                if (o != null)
                {
                    try
                    {
                        Object jsonObj = JSON.toJSON(o);
                        params += jsonObj.toString() + " ";
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }
        return params.trim();
    }

    //字符串截取
    public static String substring(String str, int start, int end) {
        if (str == null) {
            return null;
        } else {
            if (end < 0) {
                end += str.length();
            }

            if (start < 0) {
                start += str.length();
            }

            if (end > str.length()) {
                end = str.length();
            }

            if (start > end) {
                return "";
            } else {
                if (start < 0) {
                    start = 0;
                }

                if (end < 0) {
                    end = 0;
                }
                return str.substring(start, end);
            }
        }
    }

    /**
     * 转换request 请求参数
     * @param paramMap request获取的参数数组
     */
    public Map<String, String> converMap(Map<String, String[]> paramMap) {
        Map<String, String> returnMap = new HashMap<>();
        for (String key : paramMap.keySet()) {
            returnMap.put(key, paramMap.get(key)[0]);
        }
        return returnMap;
    }

    //根据HttpServletRequest获取访问者的IP地址
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

日志管理实体类

@Data
public class Synchronous extends Model<Synchronous> {

    private static final long serialVersionUID = 1L;

    /**
     * 日志主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 模块标题
     */
    private String title;
    /**
     * 日志内容
     */
    private String content;
    /**
     * 方法名称
     */
    private String method;
    /**
     * 请求方式
     */
    private String requestMethod;
    /**
     * 应用标识
     */
    private String tenantId;
    /**
     * 请求URL
     */
    private String requestUrl;
    /**
     * 请求IP地址
     */
    private String ip;
    /**
     * 请求参数
     */
    private String requestParam;
    /**
     * 方法响应参数
     */
    private String responseResult;
    /**
     * 操作状态(0正常 1异常)
     */
    private Integer status;
    /**
     * 错误消息
     */
    private String errorMsg;
    /**
     * 操作时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date operTime;
    /**
     * 方法执行耗时(单位:毫秒)
     */
    private Long takeTime;
}

mysql数据库脚本

CREATE TABLE `sys_synchronous_log` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `title` varchar(50) DEFAULT '' COMMENT '模块标题',
  `content` varchar(100) DEFAULT NULL COMMENT '日志内容',
  `method` varchar(100) DEFAULT '' COMMENT '方法名称',
  `request_method` varchar(10) DEFAULT '' COMMENT '请求方式',
  `tenant_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '应用系统标识',
  `request_url` varchar(255) DEFAULT '' COMMENT '请求URL',
  `ip` varchar(128) DEFAULT '' COMMENT '请求IP地址',
  `request_param` varchar(2000) DEFAULT '' COMMENT '请求参数',
  `response_result` varchar(2000) DEFAULT '' COMMENT '方法响应参数',
  `status` int DEFAULT NULL COMMENT '操作状态(0正常 1异常)',
  `error_msg` varchar(2000) DEFAULT NULL COMMENT '错误消息',
  `oper_time` datetime DEFAULT NULL COMMENT '操作时间',
  `take_time` bigint DEFAULT NULL COMMENT '方法执行耗时(单位:毫秒)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='同步接口操作日志记录';

达梦数据库脚本

CREATE TABLE "USER_CENTER"."SYS_SYNCHRONOUS_LOG"
(
"ID" BIGINT IDENTITY(1, 1) NOT NULL,
"TITLE" VARCHAR(500) DEFAULT '',
"CONTENT" VARCHAR(500),
"METHOD" VARCHAR(500) DEFAULT '',
"REQUEST_METHOD" VARCHAR(500) DEFAULT '',
"TENANT_ID" VARCHAR(500) DEFAULT '',
"REQUEST_URL" VARCHAR(500) DEFAULT '',
"IP" VARCHAR(500) DEFAULT '',
"REQUEST_PARAM" VARCHAR(4000) DEFAULT '',
"RESPONSE_RESULT" VARCHAR(4000) DEFAULT '',
"STATUS" INT,
"ERROR_MSG" VARCHAR(4000),
"OPER_TIME" TIMESTAMP(0),
"TAKE_TIME" BIGINT,
NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;

COMMENT ON TABLE "USER_CENTER"."SYS_SYNCHRONOUS_LOG" IS '同步接口操作日志记录';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."CONTENT" IS '日志内容';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."ERROR_MSG" IS '错误消息';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."ID" IS '日志主键';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."IP" IS '请求IP地址';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."METHOD" IS '方法名称';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."OPER_TIME" IS '操作时间';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."REQUEST_METHOD" IS '请求方式';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."REQUEST_PARAM" IS '请求参数';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."REQUEST_URL" IS '请求URL';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."RESPONSE_RESULT" IS '方法响应参数';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."STATUS" IS '操作状态(0正常 1异常)';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."TAKE_TIME" IS '方法执行耗时(单位:毫秒)';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."TENANT_ID" IS '应用系统标识';
COMMENT ON COLUMN "USER_CENTER"."SYS_SYNCHRONOUS_LOG"."TITLE" IS '模块标题';


CREATE UNIQUE  INDEX "INDEX189491221572200" ON "USER_CENTER"."SYS_SYNCHRONOUS_LOG"("ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;

mapper层

@Mapper
public interface IOperLogMapper {
    int saveIOperLog(Synchronous synchronous);
}

service层

public interface IOperLogService {
    int saveIOperLog(Synchronous synchronous);
}

service实现层

@Service
public class IOperLogServiceImpl implements IOperLogService {
    @Autowired
    IOperLogMapper iOperLogMapper;
    @Override
    public int saveIOperLog(Synchronous synchronous) {
        return iOperLogMapper.saveIOperLog(synchronous);
    }

controller层

@RestController
@RequestMapping("/ssss")
public class DevelopController {
    @Autowired
    DevelopService developService;
    @PostMapping("/saveUserData")
    @MyLog(title = "新增用户账号", content = "新增用户账号")
   public ResponseResult saveUserData(@RequestBody SysUser sysUser){
        return developService.saveUserData(sysUser);
    }
    }

sql插入语句

<insert id="saveIOperLog">
	insert into sys_synchronous_log
	<trim prefix="(" suffix=")" suffixOverrides=",">
		<if test="title != null">
			title,
		</if>
		<if test="content != null">
			content,
		</if>
		<if test="method != null">
			method,
		</if>
		<if test="requestMethod != null">
			request_method,
		</if>
		<if test="tenantId != null">
			tenant_id,
		</if>
		<if test="requestUrl != null">
			request_url,
		</if>
		<if test="ip != null">
			ip,
		</if>
		<if test="requestParam != null">
			request_param,
		</if>
		<if test="responseResult != null">
			response_result,
		</if>
		<if test="status != null">
			status,
		</if>
		<if test="errorMsg != null">
			error_msg,
		</if>
		<if test="operTime != null">
			oper_time,
		</if>
		<if test="takeTime != null">
			take_time,
		</if>
	</trim>
	<trim prefix="values (" suffix=")" suffixOverrides=",">
		<if test="title != null">
			#{title},
		</if>
		<if test="content != null">
			#{content},
		</if>
		<if test="method != null">
			#{method},
		</if>
		<if test="requestMethod != null">
			#{requestMethod},
		</if>
		<if test="tenantId != null">
			#{tenantId},
		</if>
		<if test="requestUrl != null">
			#{requestUrl},
		</if>
		<if test="ip != null">
			#{ip},
		</if>
		<if test="requestParam != null">
			#{requestParam},
		</if>
		<if test="responseResult != null">
			#{responseResult},
		</if>
		<if test="status != null">
			#{status},
		</if>
		<if test="errorMsg != null">
			#{errorMsg},
		</if>
		<if test="operTime != null">
			#{operTime},
		</if>
		<if test="takeTime != null">
			#{takeTime},
		</if>
	</trim>
</insert>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值