SpringBoot使用LogAspect的切面日志

目录

1、引入依赖

2、切面方法

3、Log类

 4、LogAspect类

5、SysLog实体类

6、服务类和服务实现类

7、实际调用


1、引入依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <scope>test</scope>
</dependency>
<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
</dependencies>

2、切面方法

切面方法说明如下:

@Aspect 作用是把当前类标识为一个切面供容器读取
@Pointcut (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
@Before 标识一个前置增强方法,相当于BeforeAdvice的功能
@AfterReturning 后置增强,相当于AfterReturningAdvice,方法退出时执行
@AfterThrowing 异常抛出增强,相当于ThrowsAdvice
@After final增强,不管是抛出异常或者正常退出都会执行
@Around 环绕增强,相当于MethodInterceptor

3、Log类

package com.shucha.deveiface.biz.aspect;

import java.lang.annotation.*;

/**
 * @author tqf
 * @Description 自定义拦截日志
 * @Version 1.0
 * @since 2022-08-08 15:28
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

    /**
     * 操作描述  查询、新增、修改、删除等
     * @return
     */
    String menu() default "";

    /**
     * 接口名称 不需要填写  可以通过request.getRequestURL().toString(); 获取
     * @return
     */
    String operation() default "";

    /**
     * 是否记录请求参数数据, 默认true: 记录; false:不记录
     *
     * @return
     */
    boolean isData() default true;
}

 4、LogAspect类

package com.shucha.deveiface.biz.aspect;



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sdy.common.model.Response;
import com.sdy.mvc.controller.BaseController;
import com.sdy.mvc.utils.HttpUtil;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import feign.Request;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author tqf
 * @Description 日志切面类
 * @Version 1.0
 * @since 2022-08-08 15:28
 */
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {

    @Autowired
    private SysLogService sysLogService;

    private final ThreadLocal<Long> startTime = new ThreadLocal<>();

    // 配置织入点
    @Pointcut("@annotation(Log)")
    public void logPointCut() {
    }

    @Before("logPointCut()")
    private void before() {
        startTime.set( System.currentTimeMillis());
    }

    /**
     * 处理完请求后执行
     * @param joinPoint
     * @param res
     * @throws Exception
     */
    @AfterReturning(returning = "res", pointcut = "logPointCut()")
    public void afterReturning(JoinPoint joinPoint, Response res) throws Exception {
        long nowTime = System.currentTimeMillis();
        HttpServletRequest request = getRequest();
        handleLog(joinPoint, null, res, nowTime, request);
    }

    /**
     * 拦截异常操作
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) throws Exception {
        // 从上下文中获取reqeust
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        // HttpServletRequest request = getRequest();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        handleLog(joinPoint, e, null, System.currentTimeMillis(), request);
    }

    protected void handleLog(final JoinPoint joinPoint, final Exception e, Response jsonResult, Long nowTime, HttpServletRequest request) throws Exception {
        Log controllerLog = getAnnotationLog(joinPoint);
        ProceedingJoinPoint point = (ProceedingJoinPoint)joinPoint;
        if (controllerLog == null) {
            return;
        }
        // 数据库日志
        SysLog sysLog = new SysLog();
        // 接口地址
        String requestUrl = request.getRequestURL().toString();
        // 请求的IP地址
        String ip = HttpUtil.getIpAddr(request);
        sysLog.setIp(ip);
        // 获取操作内容
        String content = controllerLog.menu();

        // 获取请求参数
        String requestData = "";
        if(controllerLog.isData()){
            requestData = getRequestParams(point,request);
        }
        if (jsonResult == null) {
            content = content + "--出现服务异常!";
        }
        if (jsonResult != null && !jsonResult.getSuccess()) {
            content = content + "--执行失败!";
        }
        sysLog.setContent(content)
            .setType(content)
            .setCreateTime(new Date())
            .setRequestUrl(requestUrl)
            .setRequestData(requestData);
        // 保存数据库
        sysLogService.save(sysLog);
    }

    /**
     * 是否存在注解,如果存在就获取
     */
    private Log getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }

    private HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes.getRequest();
    }

    /**
     * 获取请求参数 json格式返回
     * @param request
     * @return
     */
    private String getParameterName(HttpServletRequest request){
        // 增加查询日志  获取所有查询的参数名称和值 json格式存储
        Map map = new HashMap();
        Enumeration paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = (String) paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                String paramValue = paramValues[0];
                if (paramValue.length() != 0) {
                    map.put(paramName, paramValue);
                }
            }
        }
        return JSON.toJSONString(map);
    }

    /**
     * 获取请求参数
     * @param request
     * @return
     */
    public String getRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
        MethodSignature methodSignature = (MethodSignature)point.getSignature();
        Method method = methodSignature.getMethod();
        String queryString = null;
        String requestMethod = request.getMethod();
        if (requestMethod.equals(Request.HttpMethod.POST.name())) {
            //参数值
            Object[] args = ArrayUtils.toArray(point.getArgs());
            queryString = JSON.toJSONString(args[0], SerializerFeature.WriteMapNullValue);
        }
        else {
            // 增加查询日志  获取所有查询的参数名称和值 json格式存储
            Map map = new HashMap();
            Enumeration paramNames = request.getParameterNames();
            while (paramNames.hasMoreElements()) {
                String paramName = (String) paramNames.nextElement();
                String[] paramValues = request.getParameterValues(paramName);
                if (paramValues.length == 1) {
                    String paramValue = paramValues[0];
                    if (paramValue.length() != 0) {
                        map.put(paramName, paramValue);
                    }
                }
            }
            queryString = JSON.toJSONString(map);
        }
        return queryString;
    }

}

5、SysLog实体类

package com.shucha.deveiface.biz.model;

import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sdy.common.model.BaseModel;
import com.sdy.common.utils.DateUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.util.Date;

/**
 * <p>
 * 用户操作日志
 * </p>
 *
 * @author tqf
 * @since 2022-08-08 15:25
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class SysLog extends BaseModel {
    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @ApiModelProperty(value = "主键")
    @TableId
    private Long id;

    /**
     * 操作用户id
     */
    @ApiModelProperty(value = "操作用户id")
    private Long userId;

    @ApiModelProperty(value = "请求参数")
    private String requestData;

    @ApiModelProperty(value = "请求接口地址")
    private String requestUrl;

    /**
     * IP地址
     */
    @ApiModelProperty(value = "IP地址")
    private String ip;

    /**
     * 操作内容
     */
    @ApiModelProperty(value = "操作内容")
    private String content;

    /**
     * 操作类型
     */
    @ApiModelProperty(value = "操作类型")
    private String type;

    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
    private Date createTime;

}

创建表和插入数据

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` int(11) NULL DEFAULT NULL COMMENT '操作用户id',
  `ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT 'IP地址',
  `content` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作内容',
  `request_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '请求接口地址',
  `request_data` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '请求参数',
  `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作类型\r\n0:登陆\r\n1:新增用户\r\n2:开户\r\n3:用户基本信息编辑\r\n4:用户资源编辑\r\n5:新增角色\r\n6编辑角色\r\n7:角色权限编辑\r\n8:角色关联用户编辑\r\n9:新增菜单\r\n10:菜单编辑\r\n11:日志查询',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_user_id`(`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '操作日志信息' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES (1, NULL, '192.168.0.111', '查询数据', 'http://192.168.0.111:50041/test/getData', '{}', '查询数据', '2022-08-08 17:21:51');
INSERT INTO `sys_log` VALUES (2, NULL, '192.168.0.111', '新增数据发发发', NULL, NULL, NULL, NULL);
INSERT INTO `sys_log` VALUES (3, NULL, '192.168.0.111', '新增数据', 'http://192.168.0.111:50041/test/saveData', '{\"content\":\"新增数据发发发\",\"createTime\":null,\"id\":2,\"ip\":\"192.168.0.111\",\"requestData\":null,\"requestUrl\":null,\"type\":null,\"userId\":null}', '新增数据', '2022-08-08 17:22:12');

SET FOREIGN_KEY_CHECKS = 1;

6、服务类和服务实现类

package com.shucha.deveiface.biz.service;

import com.sdy.mvc.service.BaseService;
import com.shucha.deveiface.biz.model.SysLog;

/**
 * <p>
 * 用户操作日志 服务类
 * </p>
 *
 * @author cgj
 * @since 2021-07-13
 */
public interface SysLogService extends BaseService<SysLog> {

}
package com.shucha.deveiface.biz.service.impl;

import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.shucha.deveiface.biz.mapper.SysLogMapper;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 用户操作日志 服务实现类
 * </p>
 *
 * @author cgj
 * @since 2021-07-13
 */
@Slf4j
@Service
public class SysLogServiceImpl extends BaseServiceImpl<SysLog> implements SysLogService {
    @Autowired
    private SysLogMapper sysLogMapper;
}

7、实际调用

package com.shucha.deveiface.web.controller;

import com.sdy.common.model.Response;
import com.shucha.deveiface.biz.aspect.Log;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-08-08 15:23
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private SysLogService logService;

    @Log(menu = "查询数据")
    @GetMapping("/getData")
    public Response test(){
        return Response.success("请求成功");
    }

    @Log(menu = "新增数据")
    @PostMapping("/saveData")
    public Response saveData(@RequestBody SysLog sysLog){
        logService.save(sysLog);
        return Response.success();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码奴生来只知道前进~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值