ApplicationEvent 监听事件实现异步保存日志
Posted 洛阳泰山
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ApplicationEvent 监听事件实现异步保存日志相关的知识,希望对你有一定的参考价值。
下面以spring boot项目为例
pom文件所需的依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
SpringUtil工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
@Component
public class SpringUtil implements ApplicationContextAware {
private static final Logger log = LoggerFactory.getLogger(SpringUtil.class);
private static ConfigurableApplicationContext context;
public SpringUtil() {
}
public static DefaultListableBeanFactory getBeanFactory() {
return (DefaultListableBeanFactory)context.getBeanFactory();
}
public static <T> T getBean(Class<T> clazz) {
return clazz == null ? null : context.getBean(clazz);
}
public static <T> T getBean(String beanId) {
return beanId == null ? null : (T) context.getBean(beanId);
}
public static <T> T getBean(String beanName, Class<T> clazz) {
if (null != beanName && !"".equals(beanName.trim())) {
return clazz == null ? null : context.getBean(beanName, clazz);
} else {
return null;
}
}
public static ApplicationContext getContext() {
return context == null ? null : context;
}
public static void publishEvent(ApplicationEvent event) {
if (context != null) {
try {
context.publishEvent(event);
} catch (Exception var2) {
log.error(var2.getMessage());
}
}
}
public static void registerBeanDefinition(String beanName, BeanDefinition definition) {
getBeanFactory().registerBeanDefinition(beanName, definition);
}
public void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
SpringUtil.context = (ConfigurableApplicationContext)context;
}
}
登录事件
LoginLogEvent类继承ApplicationEvent
import com.tarzan.cms.module.admin.model.log.LoginLog;
import org.springframework.context.ApplicationEvent;
/**
* 登录日志事件
*
* @author tarzan
* @version 1.0
* @date 2021年07月19日 09:41:28
*/
public class LoginLogEvent extends ApplicationEvent {
public LoginLogEvent(LoginLog source) {
super(source);
}
}
登录事件监听器
import com.tarzan.cms.common.event.LoginLogEvent;
import com.tarzan.cms.module.admin.model.log.LoginLog;
import com.tarzan.cms.module.admin.service.log.LoginLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* 登录日志事件监听
*
* @author tarzan
* @version 1.0
* @date 2021年04月19日 09:42:36
*/
@Slf4j
@AllArgsConstructor
@Component
public class LoginLogListener {
private LoginLogService loginLogService;
@Async
@Order
@EventListener(LoginLogEvent.class)
public void saveLoginLog(LoginLogEvent event) {
LoginLog loginLog = (LoginLog)event.getSource();
loginLogService.saveOrUpdate(loginLog);
}
}
登录时候,调用
SpringUtil.publishEvent(new LoginLogEvent(loginLog)) ,监听器监听到事件,开始保存日志
/**
* 提交登录
*
* @param request
* @param username
* @param password
* @param verification
* @param rememberMe
* @return
*/
@PostMapping("/login")
@ResponseBody
public ResponseVo login(HttpServletRequest request, String username, String password, String verification,
@RequestParam(value = "rememberMe", defaultValue = "0") Integer rememberMe) {
//判断验证码
if (!CaptchaUtil.ver(verification, request)) {
// 清除session中的验证码
CaptchaUtil.clear(request);
return ResultUtil.error("验证码错误!");
}
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
token.setRememberMe(1 == rememberMe);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
} catch (LockedAccountException e) {
token.clear();
return ResultUtil.error("用户已经被锁定不能登录,请联系管理员!");
} catch (AuthenticationException e) {
token.clear();
return ResultUtil.error("用户名或者密码错误!");
}
//更新最后登录时间
User user=(User) SecurityUtils.getSubject().getPrincipal();
userService.updateLastLoginTime(user);
//异步保存登录日志
String userType= request.getHeader(CoreConst.USER_TYPE_HEADER_KEY)==null?UserEnum.WEB.getName():request.getHeader(CoreConst.USER_TYPE_HEADER_KEY);
saveLoginLog(userType,user);
return ResultUtil.success("登录成功!");
}
/**
* 保存日志
*
* @param userInfo
* @return
*/
private void saveLoginLog(String userType,User userInfo) {
Date now = new Date();
LoginLog loginLog = new LoginLog();
loginLog.setCreateTime(now);
loginLog.setStartTime(now);
loginLog.setSourceIp(IpUtil.getIpAddr(WebUtil.getRequest()));
if (userType.equals(UserEnum.WEB.getName())) {
loginLog.setSource("PC登录");
} else if (userType.equals(UserEnum.APP.getName())) {
loginLog.setSource("APP登录");
}
loginLog.setName(userInfo.getNickname());
loginLog.setPhone(userInfo.getPhone());
loginLog.setLoginName(userInfo.getUsername());
SpringUtil.publishEvent(new LoginLogEvent(loginLog));
}
以上是关于ApplicationEvent 监听事件实现异步保存日志的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot 发布ApplicationEventPublisher和监听ApplicationEvent事件
Java:SpringBoot实现ApplicationEvent事件的监听和发布
ApplicationEvent 与ApplicationListener 异步化执行测试