代码结构如下图所示:
代码详情
MAVEN配制 子pom.xml中的引入
- 注:引包的版本号自已找吧,在父pom.xml中配制
<!-- spring-boot aop依赖配置引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
application.yml配制
- 注:本项目用的是springboot,所以差异性的配制请自行百度
spring:
aop:
auto: true #启动AOP配制用的
注解类:OperationLogDetail
package com.chnenergy.monitoring.supervison.api.service.logInfo.annotation;
import com.chnenergy.monitoring.supervison.api.service.logInfo.enums.OperationFun;
import com.chnenergy.monitoring.supervison.api.service.logInfo.enums.OperationType;
import com.chnenergy.monitoring.supervison.api.service.logInfo.enums.OperationUnit;
import java.lang.annotation.*;
//@OperationLogDetail(detail = "根据用n[{{tel}}]获取用户名",level = 3,operationUnit = OperationUnit.USER,operationType = OperationType.SELECT)
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLogDetail {
/**
* 方法描述,可使用占位符获取参数:{{tel}}
*/
String detail() default "";
/**
* 日志等级:自己定,此处分为1-9
*/
int level() default 0;
/**
* 操作类型(enum):主要是select,insert,update,delete
*/
OperationType operationType() default OperationType.UNKNOWN;
/**
* 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
*/
OperationUnit operationUnit() default OperationUnit.UNKNOWN;
/**
* 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
*/
OperationFun operationFun() default OperationFun.UNKNOWN;
}
切面类 LogAspect
package com.chnenergy.monitoring.supervison.api.service.logInfo.aop;
import com.alibaba.fastjson.JSON;
import com.chnenergy.monitoring.supervison.api.entity.OperationLog;
import com.chnenergy.monitoring.supervison.api.entity.UserLocalEntity;
import com.chnenergy.monitoring.supervison.api.service.SessionConstant;
import com.chnenergy.monitoring.supervison.api.service.UserService;
import com.chnenergy.monitoring.supervison.api.service.logInfo.annotation.OperationLogDetail;
import com.chnenergy.monitoring.supervison.api.util.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private UserService userService;
@Value("${logging.level.com.chnenergy}")
private String infoLevel;
private UserLocalEntity bean;
/**
* 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
* '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
* logging:
* level:
* com.chnenergy
*/
@Pointcut("@annotation(com.chnenergy.monitoring.supervison.api.service.logInfo.annotation.OperationLogDetail)")
public void operationLog() {
}
/**
* 环绕增强,相当于MethodInterceptor
*/
@Around("operationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object res = null;
long time = System.currentTimeMillis();
try {
res = joinPoint.proceed();
time = System.currentTimeMillis() - time;
return res;
} finally {
try {
//方法执行完成后增加日志
addOperationLog(joinPoint, res, time);
} catch (Exception e) {
logger.error("LogAspect 操作失败:{}" , e.getMessage());
e.printStackTrace();
}
}
}
private void addOperationLog(JoinPoint joinPoint, Object res, long time) {
OperationLog operationLog = new OperationLog();
HttpSession session = SessionUtil.getSession();
operationLog.setUserId("未知ID");
operationLog.setUserName("未知用户");
if (null != session) {
UserLocalEntity user = (UserLocalEntity) session.getAttribute(SessionConstant.USER_ENTITY);
if (null != user) {
operationLog.setUserId(user.getUserId());
operationLog.setUserName(user.getFirstName() + user.getLastName());
} else {
//用户的登陆操作,还没有来得及设置Session时进此判断
String userId = (String) session.getAttribute(SessionConstant.USER);
if (!StringUtils.isEmpty(userId)) {
String name = userService.findNameByUserId(userId);
operationLog.setUserName(name);
operationLog.setUserId(userId);
}
}
} else {
//登出时进入此逻辑
operationLog.setUserId(bean.getUserId());
operationLog.setUserName(bean.getFirstName() + bean.getLastName());
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
operationLog.setRunTime(time);
OperationLogDetail annotation = signature.getMethod().getAnnotation(OperationLogDetail.class);
if (annotation != null) {
operationLog.setLevel(annotation.level());
operationLog.setDescribe(getDetail(((MethodSignature) joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs(), annotation, operationLog));
operationLog.setOperationType(annotation.operationType().getValue());
operationLog.setOperationUnit(annotation.operationUnit().getValue());
operationLog.setOperationFun(annotation.operationFun().getValue());
operationLog.setCreateTime(new Date());
}
//TODO 这里保存日志
mongoTemplate.insert(operationLog);
// operationLogService.insert(operationLog);
//如果开启调试模式,则log上打印输出日志信息
if ("DEBUG".equals(infoLevel)) {
operationLog.setRunTime(time);
operationLog.setReturnValue(JSON.toJSONString(res));
operationLog.setArgs(JSON.toJSONString(joinPoint.getArgs()));
operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
logger.info("调试日志信息:{}", operationLog.toString());
}
// System.out.println("记录日志:" + operationLog.toString());
}
/**
* 对当前登录用户和占位符处理
*
* @param argNames 方法参数名称数组
* @param args 方法参数数组
* @param annotation 注解信息
* @return 返回处理后的描述
*/
private String getDetail(String[] argNames, Object[] args, OperationLogDetail annotation, OperationLog operationLog) {
String detail = "";
if (null == operationLog) {
//不按需要来记日志根据入参和返回值记录
Map<Object, Object> map = new HashMap<>(4);
for (int i = 0; i < argNames.length; i++) {
map.put(argNames[i], args[i]);
}
try {
detail = "'" + SessionUtil.getSessionAttribute(SessionConstant.USER) + "'=》" + annotation.detail();
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object k = entry.getKey();
Object v = entry.getValue();
detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
//需求方式记录日志信息
detail = operationLog.getUserName() + "对功能【" + annotation.operationUnit().getValue() + "-" + annotation.operationFun().getValue() + "】做如下操作:" + annotation.operationType().getValue();
String detailMunuel = annotation.detail();
if (StringUtils.isEmpty(annotation.detail())) {
detail += ",具体详情为为:" + detailMunuel;
}
}
return detail;
}
@Before("operationLog()")
public void doBeforeAdvice(JoinPoint joinPoint) {
if ("logoutop".equals(joinPoint.getSignature().getName())) {
bean = (UserLocalEntity) SessionUtil.getSession().getAttribute(SessionConstant.USER_ENTITY);
}
System.out.println("进入方法前执行.....");
}
/**
* 处理完请求,返回内容
*
* @param ret
*/
@AfterReturning(returning = "ret", pointcut = "operationLog()")
public void doAfterReturning(Object ret) {
System.out.println("方法的返回值 : " + ret);
}
/**
* 后置异常通知
*/
@AfterThrowing("operationLog()")
public void throwss(JoinPoint jp) {
System.out.println("方法异常时执行.....");
}
/**
* 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
*/
@After("operationLog()")
public void after(JoinPoint jp) {
System.out.println("方法最后执行.....");
}
}
枚举类
操作类型枚举OperationType
package com.chnenergy.monitoring.supervison.api.service.logInfo.enums;
public enum OperationType {
/**
* 操作类型
*/
UNKNOWN("unknown"),
DELETE("删除"),
SELECT("查询"),
UPDATE("修改"),
INSERT("增加"),
USERQUIT("退出"),
USERIN("登陆");
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
OperationType(String s) {
this.value = s;
}
}
功能枚举OperationUnit
package com.chnenergy.monitoring.supervison.api.service.logInfo.enums;
public enum OperationUnit {
/**
* 被操作的单元
*/
UNKNOWN("unknown"),
USER("用户管理"),
ALARM("报警处置"),
CREATESIGN("生成签报");
private String value;
OperationUnit(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
子菜单项枚举OperationFun
package com.chnenergy.monitoring.supervison.api.service.logInfo.enums;
public enum OperationFun {
/**
* 被操作的单元
*/
UNKNOWN("unknown"),
ALARMDEAL("报警处置"),
ALARMMERGE("报警合并"),
USERIN("用户登陆"),
USEROUT("用户退出");
private String value;
OperationFun(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
实体bean:OperationLog
package com.chnenergy.monitoring.supervison.api.entity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
@Document("cmss.log_info")
@Data
public class OperationLog {
private String id;
private Date createTime;
/**
* 日志等级
*/
private Integer level;
/**
* 被操作的对象
*/
private String operationUnit;
/**
* 被操作的功能
*/
private String operationFun;
/**
* 方法名
*/
private String method;
/**
* 参数
*/
private String args;
/**
* 操作人id
*/
private String userId;
/**
* 操作人
*/
private String userName;
/**
* 日志描述
*/
private String describe;
/**
* 操作类型
*/
private String operationType;
/**
* 方法运行时间
*/
private Long runTime;
/**
* 方法返回值
*/
private String returnValue;
@Override
public String toString() {
return "OperationLog{" +
"id='" + id + '\'' +
", createTime=" + createTime +
", level=" + level +
", operationUnit='" + operationUnit + '\'' +
", operationFun='" + operationFun+ '\''
", method='" + method + '\'' +
", args='" + args + '\'' +
", userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", describe='" + describe + '\'' +
", operationType='" + operationType + '\'' +
", runTime=" + runTime +
", returnValue='" + returnValue + '\'' +
'}';
}
}
使用中的示例
1. 用户登陆时的,放在了UserServiceImpl中的查询用户的方法上
@OperationLogDetail(detail = "通过用户ID[{{userId}}]获取用户名", level = 3, operationUnit = OperationUnit.USER, operationFun = OperationFun.USERIN, operationType = OperationType.SELECT)
2. 用户退出登陆时,放在 LogOutController中的退出方法上
@OperationLogDetail(detail = "用户退出操作", level = 3, operationUnit = OperationUnit.USER, operationFun = OperationFun.USEROUT, operationType = OperationType.USERQUIT)
结束语
大家试试吧,这些东西都是固定套路的,原理知道了,就是自己复制来复制去,AOP无非是spring加了层代理类,具体细节知识点,大家可以详细学习下,以上代码参考出处地址为:
https://www.cnblogs.com/wenjunwei/p/9639909.html