使用自定义注解获取操作日志打印并且存储

前言

在做项目得时候需要日志记录,就是操作了那个接口得功能记录以及成功情况和操作id
就在这样的情况下,我做了一个全局日志配置
写的不是很好,大佬忽喷~~~

废话不多说,直接开干

首先我们得去创建一个存储日志得表,我这里存储得东西不duo

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `url` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求得url',
  `method_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求得方法',
  `http_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'http请求类型',
  `clazz_method` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求方法全名称',
  `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求ip',
  `request_args` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '请求得参数',
  `response_result` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '返回得状态信息',
  `create_by` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 87 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '日志表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

我们要创建表对应得实体类字段

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_log")
public class Log  {
    //主键
    private Long id;
    //请求得url
    private String url;
    //请求得方法
    private String methodName;
    //http请求类型
    private String httpMethod;
    //请求方法全名称
    private String clazzMethod;
    //请求ip
    private String ip;
    //请求得参数
    private String requestArgs;
    // 返回得信息
    private String responseResult;
    //创建时间
    private Date createTime;
    // 创建人
    private String createBy;

}

接下来我们要去创建表对应得mapper层稍后用来存储数据库操作使用

@Mapper
public interface LogMapper extends BaseMapper<Log> {
}

再去创建一个注解用来标注,该接口需要使用日志记录功能

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface  SystemLog {
    String businessName();
}

注意 : 接下里是重点了,我们使用Aop来获取日志

/**
 * @Description: 日志
 * @Author: 沐光
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    /**
     * @description 定义切入点 后面只要方法上面加上@SystemLog 都需要进行日志打印
     * @author 沐光
     */
    @Pointcut("@annotation(com.muguang.annotation.SystemLog)")
    public void pt(){}

    public Map<String, String> stringMap = new HashMap<>();

    @Autowired
    private LogMapper logMapper;

    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable{
        Object ret ;
        try {
            handleBefore(joinPoint);
            ret = joinPoint.proceed();
            handleAfter(ret);
        } finally {
            // 结束后换行 System.lineSeparator():获取系统换行符
            log.info("=======End=======" + System.lineSeparator());
            setSqlLogResult(stringMap);
        }
        return ret;
    }

    /**
     * description 处理打印前的获取信息
     * @author 沐光
     * @param joinPoint
     */
    private void handleBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        // 使用RequestAttributes实现类来获取request请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        // 获取被增强方法上的注解对象
        SystemLog systemLog = getSystemLog(joinPoint);
        // 获取sql语句
//        String sql = getSqlStr(joinPoint);
        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}",request.getRequestURL());
        // 打印描述信息
        log.info("BusinessName   : {}", systemLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), ((MethodSignature) joinPoint.getSignature()).getName());
        // 打印请求的 IP
        log.info("IP             : {}",request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", joinPoint.getArgs());

        stringMap.put("url", request.getRequestURL().toString());
        stringMap.put("methodName", systemLog.businessName());
        stringMap.put("httpMethod", request.getMethod());
        stringMap.put("clazzMethod", joinPoint.getSignature().getDeclaringTypeName()+"."+((MethodSignature) joinPoint.getSignature()).getName());
        stringMap.put("ip", request.getRemoteHost());
        stringMap.put("requestArgs", joinPoint.getArgs().toString());
        // 这里获取操作人得方法,大家可以修改一下,因为我这里使用得SpringSecurity框架里面得东西,所有大家根据自己得实际情况来
        // stringMap.put("createBy", SecurityUtils.getUserId().toString());
    }

    /**
     * @description 把aop拦截得MultipartFile类型文件转换为String类型
     * args[i] instanceof ServletRequest || args[i] instanceof ServletResponse ||
     * @author 沐光
     */
    private String filterArgs(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        byte[] imageByte = null;
        String base64EncoderImg = "";
        Object[] arguments = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if ( args[i] instanceof MultipartFile){
                imageByte = ((MultipartFile) args[i]).getBytes();
                BASE64Encoder base64Encoder = new BASE64Encoder();
                base64EncoderImg = base64Encoder.encode(imageByte);
                base64EncoderImg = base64EncoderImg.replaceAll("[\\s\t\n\r]", "");
                return base64EncoderImg;
            }
            arguments[i] = args[i];
        }
        return JSON.toJSONString(arguments);
    }

    /**
     * description 获取方法上注解里面得信息
     * @author 沐光
     */
    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        SystemLog systemLog = methodSignature.getMethod().getAnnotation(SystemLog.class);
        return systemLog;
    }

    /**
     * description 处理打印后的获取信息
     * @author 沐光
     * @param ret
     */
    private void handleAfter(Object ret) {
        // 打印出参
        log.info("Response       : {}", JSON.toJSONString(ret));
        stringMap.put("responseResult", JSON.toJSONString(ret));
    }

    /**
     * description 把日志信息存入数据库中
     * @param map 日志信息map
     * @return void
     * @author 沐光
     */
    private void setSqlLogResult(Map<String, String> map){
        map.put("createTime", Utils.getTime());
        Log log = JSONObject.toJavaObject(JSONObject.parseObject(JSON.toJSONString(map)), Log.class);
        logMapper.insert(log);
    }

    /**
     * @description 获取sql语句日志
     * @author 沐光
     */
//    private String getSqlStr(ProceedingJoinPoint joinPoint) {
//        Signature signature = joinPoint.getSignature();
//        if (signature instanceof MethodSignature){
//            MethodSignature methodSignature = (MethodSignature) signature;
//            Class<?> clazz = methodSignature.getDeclaringType();
//            String methodName = methodSignature.getName();
//            Object[] args = joinPoint.getArgs();
//            // 讲args转为map便于解析
//            HashMap<String, Object> paramMap = new HashMap<>();
//            for (int i = 0; i < args.length; i++) {
//                paramMap.put("arg"+i, args[i]);
//            }
//            // 获取sql语句
//            String sql = SqlHelper.getSql(clazz, methodName, paramMap);
//        }
//    }
}

这样就可以把我们得操作日志记录在数据库里面了,写的并不是很好,希望大佬忽喷,也能给出一点意见。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这是一个比较具体的问题,我可以为您提供一些思路和建议。 首先,您需要定义一个注解,用来标记需要记录到数据库的方法。可以定义一个类似于下面的注解: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface LogToDatabase { String value() default ""; } ``` 其中,`@Retention` 注解用来指定注解的生命周期,这里设为 `RUNTIME`,表示在运行期间保留注解信息;`@Target` 注解用来指定注解的作用目标,这里设为 `METHOD`,表示注解可以用在方法上。`@interface` 关键字表示这是一个注解的定义。 注解上面的 `value()` 方法表示注解的一个属性,可以用来存储一些额外的信息。在这个例子中,我们可以用它来记录操作的类型,比如增删改查。 接下来,您需要编写一个切面(Aspect),用来实现对标记了注解的方法进行拦截和记录。可以定义一个类似于下面的切面: ```java @Aspect @Component public class LogToDatabaseAspect { private final Logger logger = LoggerFactory.getLogger(LogToDatabaseAspect.class); @Autowired private JdbcTemplate jdbcTemplate; @Around("@annotation(logToDatabase)") public Object logToDatabase(ProceedingJoinPoint joinPoint, LogToDatabase logToDatabase) throws Throwable { // 获取方法名和参数 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 执行方法 Object result = joinPoint.proceed(args); // 记录日志到数据库 String operationType = logToDatabase.value(); String sql = "INSERT INTO operation_log (operation_type, method_name, parameters, result) VALUES (?, ?, ?, ?)"; jdbcTemplate.update(sql, operationType, methodName, Arrays.toString(args), result.toString()); // 返回结果 return result; } } ``` 这个切面使用 Spring AOP 实现,使用了 `@Around` 注解来指定拦截的方法。在方法执行前后,会执行切面中的代码。在这个例子中,我们将会记录操作日志到数据库中。 最后,您需要在需要记录操作日志的方法上标记注解,比如: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @LogToDatabase("insert") @Override public void addUser(User user) { userDao.addUser(user); } @LogToDatabase("delete") @Override public void deleteUser(int userId) { userDao.deleteUser(userId); } @LogToDatabase("update") @Override public void updateUser(User user) { userDao.updateUser(user); } @LogToDatabase("select") @Override public User getUser(int userId) { return userDao.getUser(userId); } } ``` 这样,当调用这些方法时,切面就会拦截它们,并将操作日志记录到数据库中。 希望这些思路和建议能够帮助您完成您的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值