今天我们来使用aop来实现简易版的日志记录,话不多说,直接来上手
-
创建日志表log
-
创建用户实体类,日志实体类
-
创建日志类接口
-
创建扫描注解
-
创建切面
-
测试接口
1.创建日志表log
CREATE TABLE `log` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`Executor` varchar(64) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL COMMENT '执行人',
`operation` varchar(64) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL COMMENT '操作描述',
`method` varchar(2048) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT '' COMMENT '执行方法路径',
`execution_duration` int(11) NULL DEFAULT NULL COMMENT '执行时间',
`ip` varchar(64) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL COMMENT 'ip地址',
`createtime` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 249 CHARACTER SET = gbk COLLATE = gbk_chinese_ci ROW_FORMAT = Dynamic;
2.创建用户实体和日志实体
- 用户实体类
/**用户测试实体*/
@Accessors(chain = true)
@Data
public class User {
private Integer id;
private String username;
private String password;
}
- 日志实体类
/**日志实体*/
@Accessors(chain = true)
@Data
public class Log {
/**主键*/
private Integer id;
/**执行人*/
private String executor;
/**方法描述*/
private String operation;
/**执行方法*/
private String method;
/**执行时长*/
private Long executionDuration;
/**ip*/
private String ip;
/**创建时间*/
private Date createtime;
}
3.创建日志类接口
@Mapper
public interface LogMapper {
@Insert("insert into log(id,Executor,operation,method,execution_duration,ip,createtime) " +
"values(null,#{executor},#{operation},#{method},#{executionDuration},#{ip},#{createtime})")
int insert(Log log);
}
4.创建扫描注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredPower {
String value();
}
5.创建切面
@Aspect//定义切面
@Component
@Order(1)//第一层切面
@Slf4j
public class LogAspect {
@Resource
private LogMapper logMapper;
//扫描RequiredLog注解
@Pointcut("@annotation(com.sise.annotation.RequiredLog)")
public void doPointCut() {
}
@Around("doPointCut()")
public Object around(ProceedingJoinPoint jp) throws Throwable {
try {
//记录方法执行前的时间
long t1 = System.currentTimeMillis();
//执行方法
Object result = jp.proceed();
//记录方法执行后的时间
long t2 = System.currentTimeMillis();
//保存用户行为日志
log(jp, (t2 - t1));
return result;
} catch (Throwable e) {
log.error(e.getMessage());
throw e;
}
}
private void log(ProceedingJoinPoint jp, long time) throws Exception {
//获取目标对象
Class<?> targetCls = jp.getTarget().getClass();
//获取目标方法签名信息(包含方法名,参数列表等信息)
MethodSignature ms = (MethodSignature) jp.getSignature();
//获取方法对象
Method interfaceMethod = ms.getMethod();
//获取方法名
String methodName = interfaceMethod.getName();
//拼接包名+类名+方法
String clsMethodName = targetCls.getName() + "." + methodName;
//获取注解RequiredLog
Method targetMethod =
targetCls.getMethod(methodName, ms.getParameterTypes());
RequiredLog requiredLog =
targetMethod.getAnnotation(RequiredLog.class);
//获取方法描述(注解值)
String operation = requiredLog.value();
//获取已登录的用户信息
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession(true);
User user = (User) session.getAttribute("user");
//如果是登录操作则获取登录时的用户名作为执行人
if(user==null&&operation.equals("登录")){
Object[] args = jp.getArgs();
for (Object object : args) {
if (object instanceof User) {
user = (User) object;
}
}
}
//初始化日志实体
Log entity = new Log()
.setExecutor(user == null ? "" : user.getUsername())//登录使用的用户名
.setOperation(operation)
.setMethod(clsMethodName)//method=类全名+方法名
.setIp(IPUtils.getIpAddr())
.setExecutionDuration(time)
.setCreatetime(new Date());
//插入日志
logMapper.insert(entity);
}
}
6.测试
-
创建测试接口
@RequestMapping("/test7") @RequiredLog("登录") public CallResult test7(@RequestBody User user,HttpSession session){ session.setAttribute("user",user); return CallResult.success(user); } @RequestMapping("/getUser") @RequiredLog("获取用户信息") public CallResult getUser(HttpSession session){ return CallResult.success(session.getAttribute("user")); }
-
模拟登录测试
登录测试日志信息插入成功
-
模拟操作测试
模拟操作日志插入成功