使用SpringBoot AOP 记录操作日志并保存到数据库

第一步: 创建日志表
在这里插入图片描述
第二步: 添加aop依赖

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

第三步: 自定义日志注解及代码实现
在这里插入图片描述
自定义一个名为LogAnno的注解

package com.minapp.admin.annotation;

import java.lang.annotation.*;

/**
 * @Description: 日志注解
 * @Param:
 * @return:
 * @Author: XQD
 * @Date:2021/3/9 10:33
 */
@Target(ElementType.METHOD)  //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) // 注解在哪个阶段执行 运行时可见
public @interface LogAnno {
    // 记录日志的操作类型
    String operateType();
}

使用aop实现日志,数据表中有自己的业务字段,自行更改

package com.minapp.admin.aop;

import com.alibaba.fastjson.JSON;
import com.minapp.admin.annotation.LogAnno;
import com.minapp.admin.controller.BaseController;
import com.minapp.admin.entity.TdAdminOperLog;
import com.minapp.admin.mapper.TdAdminOperLogMapper;
import com.minapp.admin.utils.HttpContextUtil;
import com.minapp.admin.utils.HttpMethod;
import com.minapp.admin.utils.ServletUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

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


/**
 * @ClassName: LogAopAspect
 * @Description: AOP实现日志  aop环绕通知类
 * @Authror: XQD
 * @Date: 2021/3/9 10:36
 */
@Order(3)  // 标记支持AspectJ的切面排序
@Component
@Aspect
public class LogAopAspect extends BaseController {

    @Autowired
    private TdAdminOperLogMapper operLogMapper;

    @Pointcut("@annotation(com.minapp.admin.annotation.LogAnno)")
    public void operLogPoinCut() {

    }

    @AfterReturning(value = "operLogPoinCut()", returning = "keys")
    public Object aroundAdvice(JoinPoint joinPoint, Object keys) {

        // 1.方法执行前的处理,相当于前置通知
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法
        Method method = methodSignature.getMethod();
        // 获取方法上面的注解
        LogAnno logAnno = method.getAnnotation(LogAnno.class);
        // 获取操作描述的属性值
        String operateType = logAnno.operateType();
        TdAdminOperLog adminOperLog = new TdAdminOperLog();
        String token = getToken();
        String[] tokenArray = token.split("-");
        String loginId = tokenArray[1];

        adminOperLog.setOperateor(loginId);
        adminOperLog.setOperateProjectId(projectId(token));
        String className = joinPoint.getTarget().getClass().getName();
        String signatureName = methodSignature.getName();
        adminOperLog.setOperateMethod(className + "." + signatureName + "()");
        String requestMethod = ServletUtils.getRequest().getMethod();
        if ("PUT".equals(requestMethod) || "POST".equals(requestMethod)) {
            String params = argsArrayToString(joinPoint.getArgs());
            adminOperLog.setParams(StringUtils.substring(params, 0, 2000));
        } else {
            // 获取RequestAttributes
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            // 从获取RequestAttributes中获取HttpServletRequest的信息
            HttpServletRequest request = (HttpServletRequest) requestAttributes
                    .resolveReference(RequestAttributes.REFERENCE_REQUEST);
            // 请求的参数
            Map<String, String> rtnMap = converMap(request.getParameterMap());
            adminOperLog.setParams(StringUtils.substring(JSON.toJSONString(rtnMap), 0, 2000));
        }
        // 接口返回值参数
        adminOperLog.setOperateResult(JSON.toJSONString(keys));
        adminOperLog.setOperateType(operateType);
        String ip = HttpContextUtil.getIpAddress();
        adminOperLog.setOperateIp(ip);
        Object result = null;
        operLogMapper.insert(adminOperLog);// 添加日志记录
        return result;
    }

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

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    if (jsonObj != null) {
                        params += jsonObj.toString() + " ";
                    }
                }
            }
        }
        return params.trim();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
     */
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}

获取ip工具类

package com.minapp.admin.utils;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @ClassName: HttpContextUtil
 * @Description: TODO
 * @Authror: XQD
 * @Date: 2021/3/9 11:07
 */
public class HttpContextUtil {
    public static HttpServletRequest getRequest() {
        return  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
    }

    /**
     * @Description:  获取IP地址的方法
     * @Param: []
     * @return: java.lang.String
     * @Author: XQD
     * @Date:2021/3/9 11:22
     */
    public static String getIpAddress() {
        HttpServletRequest request = getRequest();
        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;
    }
}

客户端工具类

package com.minapp.admin.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;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * 客户端工具类
 * 
 * @author ruoyi
 */
public class ServletUtils
{
    /**
     * 获取String参数
     */
    public static String getParameter(String name)
    {
        return getRequest().getParameter(name);
    }



    /**
     * 获取request
     */
    public static HttpServletRequest getRequest()
    {
        return getRequestAttributes().getRequest();
    }

    /**
     * 获取response
     */
    public static HttpServletResponse getResponse()
    {
        return getRequestAttributes().getResponse();
    }

    /**
     * 获取session
     */
    public static HttpSession getSession()
    {
        return getRequest().getSession();
    }

    public static ServletRequestAttributes getRequestAttributes()
    {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }
    /**
     * 将字符串渲染到客户端
     *
     * @param response 渲染对象
     * @param string 待渲染的字符串
     * @return null
     */
    public static String renderString(HttpServletResponse response, String string)
    {
        try
        {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }



}

实现方式
在这里插入图片描述
数据库记录
在这里插入图片描述

  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
你可以通过Spring AOP实现这个功能。具体步骤如下: 1. 创建一个实体类,用于保存错误日志信息,包括用户信息、请求url、方法、参数、异常信息等。 2. 创建一个切面类,使用@Aspect注解标注,该切面类中定义一个@Before通知,用于捕获Controller中抛出的异常,并将异常信息和其他相关信息保存数据库中。 3. 在切面类中通过@Pointcut注解指定切入点,即对哪些Controller中的方法进行切面处理。 4. 在切面类中使用@Autowired注解注入实体类对应的Repository,然后在@Before通知中调用Repository中的方法将错误信息保存数据库中。 具体实现细节可以参考以下代码: ```java @Aspect @Component public class ErrorLogAspect { @Autowired private ErrorLogRepository errorLogRepository; @Pointcut("execution(* com.example.demo.controller..*.*(..))") public void logPointcut() {} @Before("logPointcut()") public void logError(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); ErrorLog errorLog = new ErrorLog(); errorLog.setUserId(request.getHeader("userId")); // 从请求头中获取用户信息 errorLog.setUrl(request.getRequestURI()); // 获取请求url errorLog.setMethod(joinPoint.getSignature().toShortString()); // 获取方法名 errorLog.setArgs(Arrays.toString(joinPoint.getArgs())); // 获取方法参数 errorLog.setExceptionMessage(getExceptionMessage(joinPoint)); // 获取异常信息 errorLogRepository.save(errorLog); // 保存错误日志数据库 } private String getExceptionMessage(JoinPoint joinPoint) { Throwable ex = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ExceptionHandler.class).value(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); return sw.toString(); } } ``` 其中,ErrorLog是保存错误日志信息的实体类,ErrorLogRepository是对应的Repository。在logError方法中,通过JoinPoint获取方法名、方法参数等信息,通过RequestContextHolder获取请求信息,最后将错误日志保存数据库中。getExceptionMessage方法用于获取异常信息。在Controller中,需要使用@ExceptionHandler注解来捕获异常,并将异常信息保存数据库中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值