feat(新增-记录日志): 记录日志环绕通知

Signed-off-by: bunny <1319900154@qq.com>
This commit is contained in:
bunny 2024-03-26 21:07:44 +08:00
parent 9fc4afebc2
commit 7b060d309c
20 changed files with 316 additions and 32 deletions

View File

@ -9,6 +9,7 @@
<outputRelativeToContentRoot value="true" />
<module name="spzx-model" />
<module name="common-util" />
<module name="common-log" />
<module name="common-service" />
<module name="spzx-manager" />
</profile>
@ -16,6 +17,7 @@
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="common-log" options="-parameters" />
<module name="common-service" options="-parameters" />
<module name="common-util" options="-parameters" />
<module name="spzx-manager" options="-parameters" />

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/spzx-common/common-log/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spzx-common/common-service/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spzx-common/common-util/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spzx-common/src/main/java" charset="UTF-8" />

View File

@ -19,6 +19,7 @@
<module>spzx-common</module>
<module>spzx-model</module>
<module>spzx-manager</module>
<module>spzx-common/common-log</module>
</modules>
<properties>

View File

@ -0,0 +1,48 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu</groupId>
<artifactId>spzx-parent-v2</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>common-log</artifactId>
<packaging>jar</packaging>
<name>common-log</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>spzx-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
package com.atguigu.log.annotation;
import com.atguigu.log.aspect.LogAspect;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 开启动类中开启包扫描也可以
// 如果不想这样写可以按照下面定义一个切面类
// 之后在SpringBoot中加入这个注解让其扫描到
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(value = LogAspect.class)
public @interface EnableLogAspect {
}

View File

@ -0,0 +1,24 @@
package com.atguigu.log.annotation;
import com.atguigu.log.enums.OperatorType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log { // 自定义操作日志记录注解
String title(); // 模块名称
OperatorType operatorType() default OperatorType.MANAGE; // 操作人类别
int businessType(); // 业务类型0其它 1新增 2修改 3删除
boolean isSaveRequestData() default true; // 是否保存请求的参数
boolean isSaveResponseData() default true; // 是否保存响应的参数
}

View File

@ -0,0 +1,47 @@
package com.atguigu.log.aspect;
import com.atguigu.exception.BunnyException;
import com.atguigu.log.annotation.Log;
import com.atguigu.log.service.AsyncOperaLogService;
import com.atguigu.log.utils.LogUtil;
import com.atguigu.spzx.model.entity.system.SysOperLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class LogAspect {
@Autowired
private AsyncOperaLogService asyncOperaLogService;
@Around(value = "@annotation(sysLog)")
public Object doAroundAdvice(ProceedingJoinPoint joinPoint, Log sysLog) {
// 构建前置参数
SysOperLog sysOperLog = new SysOperLog();
LogUtil.beforeHandleLog(sysLog, joinPoint, sysOperLog);
Object proceed = null;
try {
proceed = joinPoint.proceed();
// 执行业务方法
LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 0, null);
// 构建响应结果参数
} catch (Throwable e) { // 代码执行进入到catch中
// 业务方法执行产生异常
LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 1, e.getMessage());
throw new BunnyException(e.getMessage());
}
// 保存日志数据
asyncOperaLogService.saveSysOperaLog(sysOperLog);
// 返回执行结果
return proceed;
}
}

View File

@ -0,0 +1,8 @@
package com.atguigu.log.enums;
// 操作人类别
public enum OperatorType {
OTHER,// 其他
MANAGE,// 后台用户
MOBILE// 手机端用户
}

View File

@ -0,0 +1,8 @@
package com.atguigu.log.service;
import com.atguigu.spzx.model.entity.system.SysOperLog;
// 保存日志数据
public interface AsyncOperaLogService {
void saveSysOperaLog(SysOperLog sysOperLog);
}

View File

@ -0,0 +1,62 @@
package com.atguigu.log.utils;
import com.alibaba.fastjson.JSON;
import com.atguigu.context.BaseContext;
import com.atguigu.log.annotation.Log;
import com.atguigu.spzx.model.entity.system.SysOperLog;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.util.Arrays;
public class LogUtil {
// 操作执行之后调用
public static void afterHandleLog(Log sysLog, Object proceed,
SysOperLog sysOperLog, int status,
String errorMsg) {
if (sysLog.isSaveResponseData()) {
sysOperLog.setJsonResult(JSON.toJSONString(proceed));
}
sysOperLog.setStatus(status);
sysOperLog.setErrorMsg(errorMsg);
}
// 操作执行之前调用
public static void beforeHandleLog(Log sysLog,
ProceedingJoinPoint joinPoint,
SysOperLog sysOperLog) {
// 设置操作模块名称
sysOperLog.setTitle(sysLog.title());
sysOperLog.setOperatorType(sysLog.operatorType().name());
// 获取目标方法信息
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
sysOperLog.setMethod(method.getDeclaringClass().getName());
// 获取请求相关参数
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
sysOperLog.setRequestMethod(request.getMethod());
sysOperLog.setOperUrl(request.getRequestURI());
sysOperLog.setOperIp(request.getRemoteAddr());
// 设置请求参数
if (sysLog.isSaveRequestData()) {
String requestMethod = sysOperLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = Arrays.toString(joinPoint.getArgs());
sysOperLog.setOperParam(params);
}
}
sysOperLog.setOperName(BaseContext.getSysUser().getName());
}
}

View File

@ -21,7 +21,8 @@ public class GlobalExceptionHandler {
@ResponseBody
public Result<Object> exceptionHandler(BunnyException exception) {
log.error("GlobalExceptionHandler===>自定义异常信息:{}", exception.getMessage());
return Result.error(exception.getCode(), exception.getMessage());
Integer code = exception.getCode() != null ? exception.getCode() : 500;
return Result.error(null, code, exception.getMessage());
}
// 运行时异常信息
@ -29,7 +30,8 @@ public class GlobalExceptionHandler {
@ResponseBody
public Result<Object> exceptionHandler(RuntimeException exception) {
log.error("GlobalExceptionHandler===>运行时异常信息:{}", exception.getMessage());
return Result.error(500, "出错了啦");
return Result.error(null, 500, "出错了啦");
}
// 捕获系统异常
@ -37,7 +39,8 @@ public class GlobalExceptionHandler {
@ResponseBody
public Result<Object> error(Exception exception) {
log.error("GlobalExceptionHandler===>系统异常信息:{}", exception.getMessage());
return Result.error(exception.getMessage());
return Result.error(null, 500, exception.getMessage());
}
// 特定异常处理
@ -45,7 +48,7 @@ public class GlobalExceptionHandler {
@ResponseBody
public Result<Object> error(ArithmeticException exception) {
log.error("GlobalExceptionHandler===>特定异常信息:{}", exception.getMessage());
return Result.error(null, exception.getMessage());
return Result.error(null, 500, exception.getMessage());
}
// spring security异常

View File

@ -29,6 +29,11 @@
<artifactId>common-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common-log</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- spring boot web开发所需要的起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -1,5 +1,6 @@
package com.atguigu.spzx.manger;
import com.atguigu.log.annotation.EnableLogAspect;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
@ -14,6 +15,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableCaching// 开启缓存注解
@EnableScheduling
@ComponentScan("com.atguigu")
@EnableLogAspect// 开启切面类
@MapperScan("com.atguigu.spzx.manger.mapper")
@Slf4j
public class MangerApplication {

View File

@ -1,5 +1,7 @@
package com.atguigu.spzx.manger.controller;
import com.atguigu.log.annotation.Log;
import com.atguigu.log.enums.OperatorType;
import com.atguigu.spzx.manger.service.CategoryService;
import com.atguigu.spzx.model.entity.product.Category;
import com.atguigu.spzx.model.vo.result.Result;
@ -19,6 +21,8 @@ public class CategoryController {
@Autowired
private CategoryService categoryService;
@Log(title = "根据parentId获取下级节点", businessType = 0, operatorType = OperatorType.MANAGE)
@Operation(summary = "根据parentId获取下级节点", description = "根据parentId获取下级节点")
@GetMapping(value = "findCategoryList/{parentId}")
public Result<List<Category>> findByParentId(@PathVariable Long parentId) {

View File

@ -1,5 +1,7 @@
package com.atguigu.spzx.manger.controller;
import com.atguigu.log.annotation.Log;
import com.atguigu.log.enums.OperatorType;
import com.atguigu.spzx.manger.service.CategoryBrandService;
import com.atguigu.spzx.manger.service.ProductService;
import com.atguigu.spzx.model.dto.product.ProductDto;
@ -46,6 +48,7 @@ public class ProductController {
return Result.success();
}
@Log(title = "查询商品详情", businessType = 0, operatorType = OperatorType.MANAGE)
@Operation(summary = "查询商品详情", description = "查询商品详情")
@GetMapping("getById/{id}")
public Result<Product> getById(@PathVariable Long id) {
@ -76,7 +79,7 @@ public class ProductController {
@Operation(summary = "商品上下架", description = "商品上下架")
@GetMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable Long id, @PathVariable Integer status) {
public Result<Product> updateStatus(@PathVariable Long id, @PathVariable Integer status) {
productService.updateStatus(id, status);
return Result.build(null, ResultCodeEnum.SUCCESS);
}

View File

@ -0,0 +1,14 @@
package com.atguigu.spzx.manger.mapper;
import com.atguigu.spzx.model.entity.system.SysOperLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysOperaLogMapper {
/**
* 异步执行保存日志操作
*
* @param sysOperaLog SysOperaLog
*/
void insert(SysOperLog sysOperaLog);
}

View File

@ -0,0 +1,25 @@
package com.atguigu.spzx.manger.service.impl;
import com.atguigu.log.service.AsyncOperaLogService;
import com.atguigu.spzx.manger.mapper.SysOperaLogMapper;
import com.atguigu.spzx.model.entity.system.SysOperLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncOperaLogServiceImpl implements AsyncOperaLogService {
@Autowired
private SysOperaLogMapper sysOperaLogMapper;
/**
* 异步执行保存日志操作
*
* @param sysOperaLog SysOperLog
*/
@Async
@Override
public void saveSysOperaLog(SysOperLog sysOperaLog) {
sysOperaLogMapper.insert(sysOperaLog);
}
}

View File

@ -2,7 +2,6 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.atguigu.spzx.manger.mapper.OrderInfoMapper">
<!-- 查询指定日期产生的订单数据 -->
<select id="selectOrderStatistics" resultType="com.atguigu.spzx.model.entity.order.OrderStatistics">
select DATE_FORMAT(oi.create_time, '%Y-%m-%d') orderDate,

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.atguigu.spzx.manger.mapper.SysOperaLogMapper">
<!-- 异步执行保存日志操作 -->
<insert id="insert">
insert into sys_oper_log (id, title, method, request_method, operator_type, oper_name, oper_url, oper_ip,
oper_param, json_result, status, error_msg)
values (#{id}, #{title}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{operUrl}, #{operIp},
#{operParam}, #{jsonResult}, #{status}, #{errorMsg})
</insert>
</mapper>

View File

@ -7,42 +7,40 @@ import lombok.Data;
@Data
@Schema(description = "SysOperLog")
public class SysOperLog extends BaseEntity {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
@Schema(description = "模块标题")
private String title;
@Schema(description = "模块标题")
private String title;
@Schema(description = "方法名称")
private String method;
@Schema(description = "方法名称")
private String method;
@Schema(description = "请求方式")
private String requestMethod;
@Schema(description = "请求方式")
private String requestMethod;
private Integer businessType; // 业务类型0其它 1新增 2修改 3删除
private Integer businessType ; // 业务类型0其它 1新增 2修改 3删除
@Schema(description = "操作类别0其它 1后台用户 2手机端用户")
private String operatorType;
@Schema(description = "操作类别0其它 1后台用户 2手机端用户")
private String operatorType;
@Schema(description = "操作人员")
private String operName;
@Schema(description = "操作人员")
private String operName;
@Schema(description = "请求URL")
private String operUrl;
@Schema(description = "请求URL")
private String operUrl;
@Schema(description = "主机地址")
private String operIp;
@Schema(description = "主机地址")
private String operIp;
@Schema(description = "请求参数")
private String operParam;
@Schema(description = "请求参数")
private String operParam;
@Schema(description = "返回参数")
private String jsonResult;
@Schema(description = "返回参数")
private String jsonResult;
@Schema(description = "操作状态0正常 1异常")
private Integer status;
@Schema(description = "错误消息")
private String errorMsg;
@Schema(description = "操作状态0正常 1异常")
private Integer status;
@Schema(description = "错误消息")
private String errorMsg;
}