通过切面将请求日志记录到数据库
Posted 阿拉的梦想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过切面将请求日志记录到数据库相关的知识,希望对你有一定的参考价值。
通过切面将请求日志记录到数据库
1. 日志表
CREATE TABLE `sys_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`operation` varchar(50) DEFAULT NULL COMMENT '用户操作',
`method` varchar(200) DEFAULT NULL COMMENT '请求方法',
`params` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '请求参数',
`time` bigint NOT NULL COMMENT '执行时长(毫秒)',
`ip` varchar(64) DEFAULT NULL COMMENT 'IP地址',
`create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='日志表'
2. 自定义日志注解
import java.lang.annotation.*;
/**
* 日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog
String value() default "";
3. 日志实体类
import java.io.Serializable;
import java.util.Date;
@ApiModel
@Data
@TableName("sys_log")
public class SysLogEntity implements Serializable
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
// 用户名
@TableField("username")
private String username;
// 用户操作
@TableField("operation")
private String operation;
// 请求方法
@TableField("method")
private String method;
// 请求参数
@TableField("params")
private String params;
// 执行时长(毫秒)
@TableField("time")
private Long time;
// IP地址
@TableField("ip")
private String ip;
// 创建时间
@TableField("create_date")
private Date createDate;
/*@TableField("email")
private String email;*/
4. 定义日志切面
import com.alibaba.fastjson.JSON;
import com.demo.devops.common.anotations.SysLog;
import com.demo.devops.entity.SysLogEntity;
import com.demo.devops.service.SysLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 系统日志,切面处理类
*/
@Aspect
@Component
public class SysLogAspect
@Autowired
private SysLogService sysLogService;
@Pointcut("@annotation(com.demo.devops.common.anotations.SysLog)")
public void logPointCut()
@Around("logPointCut()")
@Transactional
public Object around(ProceedingJoinPoint point) throws Throwable
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = point.proceed();
// 执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
// 保存日志
saveSysLog(point, time);
return result;
@Transactional
public void saveSysLog(ProceedingJoinPoint joinPoint, long time)
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogEntity sysLog = new SysLogEntity();
SysLog syslog = method.getAnnotation(SysLog.class);
if (syslog != null)
// 注解上的描述
sysLog.setOperation(syslog.value());
// 请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
// 请求的参数
Object[] args = joinPoint.getArgs();
try
String params = JSON.toJSONString(args[0]);
sysLog.setParams(params);
catch (Exception e)
// 获取request
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
// 当前用户
DevOpsUserInfo user = UserInfoUtil.getUserinfoEntryViaServletCookies();
sysLog.setUsername(user.getUsername());
//sysLog.setEmail(user.getEmail());
sysLog.setTime(time);
sysLog.setCreateDate(new Date());
// 保存系统日志到数据库
sysLogService.save(sysLog);
5. 请求方IP地址获取工具类
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* IP地址
*/
public class IPUtils
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
/**
* 获取IP地址
*
* <p>使用nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request)
String ip = null;
try
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("Proxy-Client-IP");
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("WL-Proxy-Client-IP");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("HTTP_CLIENT_IP");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
ip = request.getRemoteAddr();
catch (Exception e)
logger.error("IPUtils ERROR ", e);
// //使用代理,则获取第一个IP地址
// if(StringUtils.isEmpty(ip) && ip.length() > 15)
// if(ip.indexOf(",") > 0)
// ip = ip.substring(0, ip.indexOf(","));
//
//
return ip;
6. 将日志注解配置到controller
加上注解@SysLog,经过切面拦截处理,就可以将日志保存到数据库了
@SysLog("模板删除")
@PostMapping("/delete/id")
public Result<Template> delete(@PathVariable Long id) throws BusinessException
if (id == null)
throw new BusinessException("id不能为空");
templateService.deleteTemplate(id);
return Result.success();
以上是关于通过切面将请求日志记录到数据库的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot @Aspect 切面编程实现访问请求日志记录