表设计
登录日志
逻辑:在登录或者退出时创建记录日志的任务,交给线程池执行。
代码分析
注入线程池 bean
/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService()
{
return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
{
@Override
protected void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r, t);
Threads.printException(r, t);
}
};
}
登录
com.ruoyi.web.controller.system.SysLoginController#login
com.ruoyi.framework.web.service.SysLoginService#login
com.ruoyi.framework.manager.AsyncManager#execute
退出(LogoutSuccessHandler接口onLogoutSuccess方法,处理用户登出成功请求)
com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl#onLogoutSuccess
com.ruoyi.framework.manager.AsyncManager#execute
LogoutSuccessHandler配置
class: com.ruoyi.framework.config.SecurityConfig
/**
* 退出处理类
*/
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
......
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
......
}
任务执行
//异步操作任务调度线程池
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
/**
* 执行任务
*
* @param task 任务
*/
public void execute(TimerTask task)
{
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
创建任务
/**
* 记录登录信息
*
* @param username 用户名
* @param status 状态
* @param message 消息
* @param args 列表
* @return 任务task
*/
public static TimerTask recordLogininfor(final String username, final String status, final String message,
final Object... args)
{
......
return new TimerTask()
{
@Override
public void run()
{
.......
// 插入数据
SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
}
};
}
操作日志
使用:在方法上使用注解@Log就可以实现记录操作日志的功能
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user)
{
......
return toAjax(userService.insertUser(user));
}
逻辑:AOP实现,通过后置通知,异常通知来创建记录日志的任务,交给线程池执行。
代码分析
调用栈
com.ruoyi.framework.aspectj.LogAspect#doAfterReturning
com.ruoyi.framework.aspectj.LogAspect#doAfterThrowing
com.ruoyi.framework.aspectj.LogAspect#handleLog
com.ruoyi.framework.manager.AsyncManager#execute
核心类: com.ruoyi.framework.aspectj.LogAspect
/**
* 操作日志记录处理
*
* @author ruoyi
*/
@Aspect
@Component
public class LogAspect
{
// 配置织入点
@Pointcut("@annotation(com.ruoyi.common.annotation.Log)")
public void logPointCut()
{
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
{
handleLog(joinPoint, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e)
{
handleLog(joinPoint, e, null);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
{
......
// 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
......
}
创建任务
/**
* 操作日志记录
*
* @param operLog 操作日志信息
* @return 任务task
*/
public static TimerTask recordOper(final SysOperLog operLog)
{
return new TimerTask()
{
@Override
public void run()
{
// 远程查询操作地点
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
// 执行插入操作
SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
}
};
}