前言:平时我们在做项目的时候,会对一些重要的功能操作记录日志,方便以后的跟踪,同时也会对某些功能的异常进行记录,方便我们进行查找,以下我们采用AOP的思想将项目中的日志进行统计,并存储在数据库中,同时也统计异常日志,以遍查询。
1.添加maven依赖
<--AOP的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<--JSON的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<--mysql-data-jpa的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<--lombok的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.连接数据库
#### database config start ####
spring:
datasource:
url: jdbc:mysql://localhost:3306/favorites?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
#### database config end ####
3.创建保存日志类
/**日志类
* @author song
*/
@Entity
@Data
public class LoggerRecord implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 操作方法的描述
*/
@Column(updatable = true)
private String description;
/**
* 操作所在的包
*/
@Column(updatable = true)
private String packageName;
/**
* 操作的类名
*/
@Column(updatable = true)
private String className;
/**
* 操作的方法名
*/
@Column(updatable = true)
private String methodName;
/**
* 操作方法的参数
*/
@Column(updatable = true)
private String requestParams;
/**
* 日志记录发生时间
*/
@Column(updatable = false)
private Date createdDate;
}
4.创建保存日志的接口
/**日志增删改的接口
* @author song
*/
@Component
public interface LoggerRecordRepository extends JpaRepository<LoggerRecord,Long> {
}
5.创建操作日志注解类LoggerManager
/**日志描述的注解
* @author song
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoggerManager {
String description() default "";
}
6.创建切面类记录操作日志
/**日志的AOP服务
* @author song
*/
@Aspect
@Service
public class LoggerAdvice {
@Resource
private LoggerRecordRepository loggerRecordRepository;
@Resource
private LoggerExceptionRecordRepository loggerExceptionRecordRepository;
protected Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 切点,在注解处切入
*/
@Pointcut("@annotation(com.song.common.aop.LoggerManager)")
public void AroundPointCut(){
}
/**
* 异常切入点,扫描所以webController包下
*/
@Pointcut("execution(* com.song.webController..*.*(..))")
public void exceptionPointCut(){
}
/**
* 环绕
*/
@Around(value = "AroundPointCut()")
public void aroundAdvice(JoinPoint joinPoint ){
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//获取该切点处的方法
Method method = AopUtil.getMethod(joinPoint);
//获取切点处的注解
LoggerManager loggerManager = method.getAnnotation(LoggerManager.class);
//获取请求的描述
String description = loggerManager.description();
//获取请求包名
Signature signature = joinPoint.getSignature();
//获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
//获取请求的参数
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, String> stringStringMap = AopUtil.converMap(parameterMap);
logger.info("执行===" + description + "===开始");
//打印方法名
logger.info("方法名:" + signature.toString());
//打印方法参数
logger.info("方法参数:" + JSON.toJSONString(stringStringMap));
logger.info("执行===" + description + "===结束");
//将日志保存
try {
LoggerRecord loggerRecord = new LoggerRecord();
loggerRecord.setDescription(description);
loggerRecord.setPackageName(signature.toString());
loggerRecord.setClassName(className);
loggerRecord.setMethodName(methodName);
loggerRecord.setRequestParams(JSON.toJSONString(stringStringMap));
loggerRecord.setCreatedDate(new Date());
loggerRecordRepository.save(loggerRecord);
} catch (Exception e) {
e.printStackTrace();
}
}
}
7.创建切面工具类
public class AopUtil {
/**
* 获取切点处的方法
* @param joinPoint
* @return
*/
public static Method getMethod(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method;
}
/**
// * 将参数数组转化为字符串
// * @param params 参数数组
// * @return 参数字符串
// */
public static String getStringOfParams(Object[] params) {
if (params.length <= 0 || params.length > 1024 || null == params) {
return "";
}
StringBuffer paramString = new StringBuffer("参数: ");
for (Object param : params) {
//将参数转换成字符串
String s = ToStringBuilder.reflectionToString(param);
paramString.append(s).append("||");
}
return paramString.toString();
}
/**
* 转换request 请求参数
* @param paramMap request获取的参数数组
*/
public static Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
}
8.在Controller层方法添加@类LoggerManager注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9F1VI9aB-1646300220208)(bf1314f4f52c6019b24f4d847e03c1a1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ePa0n7mi-1646300220210)(a229515ba414a53586f6cd6c2e4381e4.png)]
9.启动项目,查看日志
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zgGKs2bO-1646300220211)(dfe9be3d469c2dd60cb2a7e68b34a7fd.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ErVL7ji-1646300220213)(5adf49a4398b09a712b194083852bafb.png)]