背景
记录日志是一种重要步骤,可以提高系统的可靠性、安全性和性能,并为故障排查、业务分析和合规要求提供支持。在Spring Boot中,使用日志框架如Logback、Log4j等进行日志记录,可以灵活配置、方便使用,并提供丰富的日志级别和输出格式。
但是一般情况下Logback、Log4j等进行日志记录会把日志记录在text文本中,而且会定期删除。
我们可能会需要很多其他的功能:
- 很久之前的日志。
- 日志数据的统计和分析整理。
- 数据的关联和追踪
- 日志的安全性和隐私性
- 日志数据的备份和恢复
- 数据的共享
这些都得我们想一种新的记录日志的方式。比如 我们在业务中可以将很重要的日志记录在数据库中。
准备
可以参考我上一篇AOP文章来配置环境
目的
自定义日志记录,然后将记录的日志存储在数据库。由注解 @Log 来自定义标注要记录那些方法或者类。
步骤
1、创建一个注解类 Log
创建一个可以定义在类和方法上的注解。
/**
* 自定义操作日志记录注解
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
/**
* 模块
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
public OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
}
2、创建一个切面类
一个简单的记录系统接口的日志切面类,供大家参考:
@Component
@Aspect
public class LogAspect {
@Autowired
private RedisCache redisCache;
@Autowired
private LogAspect logAspect;
@Value("${token.header}")
private String header;
/**
* 定义一个开关 可以随时关闭这个切面
*/
@Value("${aspect.switch}")
private Boolean aBoolean;
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doBefore(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handle(joinPoint, jsonResult, null);
}
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
handle(joinPoint, null, e);
}
private void handle(JoinPoint joinPoint, Object jsonResult, Exception e) {
try {
if (aBoolean) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HashMap<String, Object> map = new HashMap<>();
// 获取请求的URL
map.put("url", request.getRequestURL().toString());
// 获取请求的方法
map.put("method", request.getMethod());
// 获取请求的IP地址
map.put("ip", request.getRemoteAddr());
// 获取请求的参数
Object[] args = joinPoint.getArgs();
String params = "";
try {
if (args != null && args.length > 0) {
for (Object arg : args) {
if (arg instanceof MultipartFile[]) {
params = "files";
}
}
if (!params.equals("files")) {
params = JSON.toJSONString(args[0]);
}
}
} catch (Exception e1) {
params = "参数解析失败";
}
map.put("params", params);
// 获取当前的用户
String token = request.getHeader(header);
String userId = "";
if (ObjectUtils.isNotEmpty(token)) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtils.isNotEmpty(loginUser)) {
userId = loginUser.getUserId().toString();
}
}
map.put("userId", userId);
//记录错误信息
if (e != null) {
map.put("errorMsg", StringUtils.substring(e.getMessage(), 0, 2000));
}
//当前时间
map.put("time", DateUtils.getTime());
// 是否需要保存result,参数和值
if (StringUtils.isNotNull(jsonResult)) {
map.put("result", StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
}
// 异步 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(map));
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
3、使用
/**
* 新增商品
*/
@Log(title = "新增商品", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody YdCommAttr ydCommAttr)
{
return toAjax(ydCommAttrService.insertYdCommAttr(ydCommAttr));
}
参考:
觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა