异步日志的实现

2023-11-10

异步管理类

采用单例模式的静态饥饿加载,利用空间换时间,提高效率
使用异步延迟任务线程池

通过其内直接创建饥一个static对象,形成饥饿加载,以达到记录日志时的单例模式

import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.common.utils.Threads;

/**
 * 异步任务管理器
 * 
 * 
 */
public class AsyncManager{
	
    /**
     * 操作延迟10毫秒
     */
    private final int OPERATE_DELAY_TIME = 10;

    /**
     * 异步操作任务调度线程池
     */
    private ScheduledExecutorService executor =Executors.newScheduledThreadPool(5);

    /**
     * 单例模式
     */
    private AsyncManager(){}

    private static AsyncManager me = new AsyncManager();

    public static AsyncManager me(){
        return me;
    }

    /**
     * 执行任务
     * 
     * @param task 任务
     */
    public void execute(TimerTask task){
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }

    /**
     * 停止任务线程池
     */
    public void shutdown(){
        Threads.shutdownAndAwaitTermination(executor);
    }
}

异步工厂类

调用静态方法传入具体参数,拼接字符串写入Log,具体参数写入数据库

通过匿名内部类重写TimerTask的run()方法,实现子线程进行的Log日志打印及数据库日志记录任务

返回一个任务。

import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.common.constant.Constants;
import com.common.utils.LogUtils;
import com.common.utils.ServletUtils;
import com.common.utils.ip.AddressUtils;
import com.common.utils.ip.IpUtils;
import com.common.utils.spring.SpringUtils;
import com.clues.domain.SysLogininfor;
import com.clues.domain.SysOperLog;
import com.clues.service.ISysLogininforService;
import com.clues.service.ISysOperLogService;
import eu.bitwalker.useragentutils.UserAgent;
/**
 * 异步工厂(产生任务用)
 * 
 * 
 */
public class AsyncFactory {
	private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");

	/**
	 * 记录登录信息
	 * 
	 * @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) {
		final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
		final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
		return new TimerTask() {
			@Override
			public void run() {
				String address = AddressUtils.getRealAddressByIP(ip);
				StringBuilder s = new StringBuilder();
				s.append(LogUtils.getBlock(ip));
				s.append(address);
				s.append(LogUtils.getBlock(username));
				s.append(LogUtils.getBlock(status));
				s.append(LogUtils.getBlock(message));
				// 打印信息到日志
				sys_user_logger.info(s.toString(), args);
				// 获取客户端操作系统
				String os = userAgent.getOperatingSystem().getName();
				// 获取客户端浏览器
				String browser = userAgent.getBrowser().getName();
				// 封装对象
				SysLogininfor logininfor = new SysLogininfor();
				logininfor.setUserName(username);
				logininfor.setIpaddr(ip);
				logininfor.setLoginLocation(address);
				logininfor.setBrowser(browser);
				logininfor.setOs(os);
				logininfor.setMsg(message);
				// 日志状态
				if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) {
					logininfor.setStatus(Constants.SUCCESS);
				} else if (Constants.LOGIN_FAIL.equals(status)) {
					logininfor.setStatus(Constants.FAIL);
				}
				// 插入数据
				SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
			}
		};
	}

	/**
	 * 操作日志记录
	 * 
	 * @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);
			}
		};
	}
}

登录校验

通过传入的uuid加上key在redis中得到验证码,操作成功后删除在redis中的缓存。
对得到的验证码数据进行判定,如果为空,进行日志写入验证码已过期,并抛出异常;如果验证码不匹配,则写入验证错误,并抛出异常。
验证码匹配后,对用户名以及密码进行判定,不匹配或者出现其他错误,则进行日志错误登录写入。
验证成功后,进行日志登陆成功写入,并返回该用户的taken给前端。

import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.common.constant.Constants;
import com.common.core.domain.model.LoginUser;
import comcommon.core.redis.RedisCache;
import com.common.exception.CustomException;
import com.common.exception.user.CaptchaException;
import com.common.exception.user.CaptchaExpireException;
import com.common.exception.user.UserPasswordNotMatchException;
import com.common.utils.MessageUtils;
import com.framework.manager.AsyncManager;
import com.framework.manager.factory.AsyncFactory;

/**
 * 登录校验方法
 * 
 * 
 */
@Component
public class SysLoginService {
    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.captcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.captcha.error")));
            throw new CaptchaException();
        }
        // 用户验证
        Authentication authentication = null;
        try {
            /**
             *获取用户对象的时候,会去调用下面的这个方法查询用户对象
             * UserDetailsServiceImpl.loadUserByUsername
             */
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            System.out.println("username "+username+" -----password "+password);
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }catch (Exception e) {
            e.printStackTrace();
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new CustomException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return tokenService.createToken(loginUser);
    }
}

登录

/**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异步日志的实现 的相关文章

  • 如何在测试套件中定义 JUnit 方法规则?

    我有一个类 它是 JUnit 测试类的 JUnit 套件 我想定义一个规则on the suite 这是可以做到的 但需要做一些工作 您还需要定义自己的 Suite 运行程序和测试运行程序 然后在测试运行程序中重写 runChild 使用以
  • 如何打印整个字符串池?

    我想打印包含文字的整个字符串池String使用添加的对象intern 就在垃圾收集之前 JDK有没有隐式的方法来进行这样的操作 我们如何检查字符串池 EDIT The comment suggests that there may be a
  • 有没有好的方法来解析用户代理字符串?

    我有一个Java接收模块User Agent来自最终用户浏览器的字符串的行为需要略有不同 具体取决于浏览器类型 浏览器版本甚至操作系统 例如 FireFox 7 0 Win7 Safari 3 2 iOS9 我明白了User Agent由于
  • Google Inbox 类似 RecyclerView 项目打开动画

    目前 我正在尝试实现 Google Inbox 例如RecyclerView行为 我对电子邮件打开动画很好奇 我的问题是 该怎么做 我的意思是 他们使用了哪种方法 他们用过吗ItemAnimator dispatchChangeStarti
  • 服务器到 Firebase HTTP POST 结果为响应消息 200

    使用 Java 代码 向下滚动查看 我使用 FCM 向我的 Android 发送通知消息 当提供正确的服务器密钥令牌时 我收到如下所示的响应消息 之后从 FCM 收到以下响应消息 Response 200 Success Message m
  • 使用 java 按电子邮件发送日历邀请

    我正在尝试使用 java 发送每封电子邮件的日历邀请 收件人收到电子邮件 但不会显示接受或拒绝的邀请 而是将该事件自动添加到他的日历中 我正在使用 ical4j jar 构建活动 邀请 private Calendar getInvite
  • 使用 Guava 联合两个 ImmutableEnumSets

    我想联合两个ImmutableEnumSets来自番石榴 这是我的尝试 public final class OurColors public enum Colors RED GREEN BLUE YELLOW PINK BLACK pub
  • 具有多种值类型的 Java 枚举

    基本上我所做的是为国家编写一个枚举 我希望不仅能够像国家一样访问它们 而且还能够访问它们的缩写以及它们是否是原始殖民地 public enum States MASSACHUSETTS Massachusetts MA true MICHI
  • 打印包含 JBIG2 图像的 PDF

    请推荐一些库 帮助我打印包含 JBIG2 编码图像的 PDF 文件 PDFRenderer PDFBox别帮我 这些库可以打印简单的 PDF 但不能打印包含 JBIG2 图像的 PDF PDFRenderer尝试修复它 根据 PDFRedn
  • jmap - 组织和堆操作会给 jvm 带来开销吗?

    正如标题所述 需要多少开销jmap histo and jmap heap分别带到jvm 如果一个内存敏感的 Java 进程处于OutOfMemory 例如 大约 96 的堆已满 并且无法通过 full gc 清除 其中一项操作是否有可能将
  • 从 Java 日历迁移到 Joda 日期时间

    以前 当我第一次设计股票应用相关软件时 我决定使用java util Date表示股票的日期 时间信息 后来我体会到了大部分方法java util Date已弃用 因此 很快 我重构了所有代码以利用java util Calendar 然而
  • Apache Commons CLI:替代已弃用的 OptionBuilder?

    IntelliJ 显示此示例代码中不推荐使用 OptionBuilderhttp commons apache org proper commons cli usage html http commons apache org proper
  • 如何使用 Mockito 和 Junit 模拟 ZonedDateTime

    我需要模拟一个ZonedDateTime ofInstant 方法 我知道SO中有很多建议 但对于我的具体问题 到目前为止我还没有找到任何简单的解决办法 这是我的代码 public ZonedDateTime myMethodToTest
  • 不兼容的类型:在 java netbeans 中对象无法转换为 String

    我试图在我的项目中使用对象数组 但出现错误 incompatible types Object cannot be converted to String 在这一行 ST1 new String emt1 emt2 emt3 emt4 现在
  • 将 RSA 密钥从 BigIntegers 转换为SubjectPublicKeyInfo 形式

    WARNING 最初的问题是关于 PKCS 1 编码密钥 而问题中的实际示例需要SubjectPublicKeyInfo X 509 编码密钥 我目前正致力于在 java 中从头开始实现 RSA 算法 特别是密钥生成方面 现在我的代码可以给
  • 如何在android sdk上使用PowerMock

    我想为我的 android 项目编写一些单元测试和仪器测试 然而 我遇到了一个困扰我一段时间的问题 我需要模拟静态方法并伪造返回值来测试项目 经过一些论坛的调查 唯一的方法是使用PowerMock来模拟静态方法 这是我的 gradle 的一
  • 我想要一个 Java 阿拉伯语词干分析器

    我正在寻找阿拉伯语的 Java 词干分析器 我找到了一个名为 AraMorph 的库 但它的输出是无法控制的 并且它会形成不需要的单词 还有其他阿拉伯语词干分析器吗 这是新的阿拉伯语词干分析器 Assem 的阿拉伯语轻词干分析器 http
  • 从java中的字符串数组中删除空值

    java中如何从字符串数组中删除空值 String firstArray test1 test2 test4 我需要像这样没有 null 空 值的 firstArray String firstArray test1 test2 test4
  • Spring Boot MSSQL Kerberos 身份验证

    目前在我的春季靴子中application properties文件中 我指定以下行来连接到 MSSql 服务器 spring datasource url jdbc sqlserver localhost databaseName spr
  • Java 推断泛型类型

    我正在寻找类似的推断捕获泛型类型的概念 类似于以下方法片段 但不是捕获泛型类型的类 public

随机推荐

  • 采矿权EXCEL文件坐标串矢量化和信息提取

    解决思路 1 采矿权文件坐标格式规则 百度出来的规则 2 将规则输入chatgpt中 让其给出arcpy的代码 如下结果 不得不说 chatgpt确实很强大 事半功倍 检查测试下了代码 xy坐标互换了下 解析坐标时列值有点不正确 index
  • springboot实现单文件上传和多文件上传(注释详细,最新版本)

    关于文件 我一般都是存在oss里面的 因为比赛可能要用到 所以又去学了一下存在服务器里面 关于这里 我是存本地目录的 单文件上传 首先创建一个springBoot项目 这个就不说了 然后创建一个文件上传的html页面
  • 超实用的python技巧:python读写Excel表格的实例代码(简单实用)

    本文来源于公众号 csdn2299 喜欢可以关注公众号 程序员学府 这篇文章主要介绍了python读写Excel表格的方法 本文通过实例代码给大家介绍的非常详细 具有一定的参考借鉴价值 需要的朋友可以参考下 安装两个库 pip instal
  • 前端vue项目一键换肤主题技术方案

    一 技术核心 通过切换 css 选择器的方式实现主题样式的切换 在组件中保留不变的样式 将需要变化的样式进行抽离 提供多种样式 给不同的主题定义一个对应的 CSS 选择器 根据不同主题通过切换CSS选择器设置不同的样式 二 实现方法 提取公
  • 数学建模之Python-随机森林算法

    理论 代码 coding utf 8 author Administrator step1 调用包 import pandas as pd from sklearn model selection import train test spl
  • Arduino UNO R3

    Arduino 常见型号 当然还有 LilyPad 附图 最常见的自然是UNO 最新版是第三版R3 国内也有一些改进的板子 我用的是一般的板子 拿到货也只能默默了 简介 The Uno is a microcontroller board
  • SyntaxError: unexpected EOF while parsing

    报错在eval 函数 正确代码段 with open COCO train json r as f data f readline data data strip split del data 0 del data 1 for i in d
  • 华为HCIA(五)

    Vlan id 在802 1Q中 高级ACL不能匹配用户名和源MAC 2 4G频段被分为14个交叠的 错列的20MHz信道 信道编码从1到14 邻近的信道之间存在一定的重叠范围 STA通过Probe获取SSID信息 Snmp报文 网络管理设
  • Java-1.1

    题目描述 编写程序 显示Welcome to Java Welcome to Computer Science Programming is fun 代码 public class PrintfMessage public static v
  • 首次访问(域名)过程

    1 解析出域名对应的ip地址 先知道默认的网关 使用arp协议获取默认网关的mac地址 组织数据发送给默认网关 ip还是dns服务器的ip但是mac地址是默认网关的mac地址 默认网关拥有转发数据的能力把数据转发给路由器 路由器根据自己的路
  • 网络编程之字节序

    字节序 计算机数据表示存在两种字节顺序 网络字节顺序NBO Network Byte Order 与主机字节顺序HBO Host Byte Order 或者是大端模式和小端模式 网络字节序 大端模式 网络字节顺序NBO 按从高到低的顺序存储
  • 普通人学Python有意义吗?

    普通人学Python有意义吗 Python作为一种跨平台的计算机程序设计语言 近些年来越来越受到企业和IT从业者的青睐 那么 普通人是否需要学习Python呢 学会Python有什么意义呢 今天小编就和大家聊一聊这个话题 Python有效提
  • 拿手机干什么

    前段时间在知乎网上收集了一下人们主要拿手机干什么 收到的反馈是 除了记事本 短信聊天 QQ聊天 回复邮件 发微博 回复帖子需要简短敲字外 大部分就是索取信息 看来无线移动上网 屏幕增大 键盘消失是需求大趋势 因为索取信息比提交数据要多 提交
  • wayland 之opengl es

    EGL 是 OpenGL ES 渲染 API 和本地窗口系统 native platform window system 之间的一个中间接口层 它主要由系统制造商实现 使用 EGL 绘图的基本步骤 Display EGLDisplay 是对
  • html里link使用方法,html的link标签怎么使用?

    html的link标签怎么使用 link标签是放在与之间的 把link放入这对符号中间 lt gt 写成这样 然后在link后面添加属性和属性对应的值 新手同学看到这里估计一头雾水 别担心 如乐老师举个例子你就懂了 比如 这段代码的作用是给
  • logback 不同类的日志打印在不同的文件中

    在Spring Boot中 您可以使用Logback为不同的类配置不同的日志文件 以下是一个基本的 logback xml 配置示例 展示了如何为两个类 com example Class1 和 com example Class2 配置不
  • MySql:局域网和权限用户管理

    MySql 5 6 XP 5 7 win7 添加用户和设置局域访问权限操作 请在 http sourceforge net 下载MySql Control Center 不是安装版本 use mysql select from user u
  • OPEN CV 环境配置 VS 2022(超详细+图解)

    先来说明一下写这篇博客的初衷吧 由于前段时间在和一位大佬的交流之中 他提出了一个建议 说叫我平时可以自己做一些嵌入式开发项目什么的 有极大的利处 我就跟着bi站的老师 华清创客学院 开始学习 但是老师的教程是用虚拟机创建一个linux系统
  • 人事管理系统 数据流图_大学毕业设计-宾馆管理系统

    目录 第一章 绪论 1 1 1概述 1 第二章 宾馆管理系统系统分析 1 2 1可行性分析 1 2 2 需求分析 2 第三章 系统概要设计 2 3 1 功能需求 2 3 2 主要功能 3 3 3 系统开发目的 3 3 4 运行环境 3 3
  • 异步日志的实现

    异步日志的实现 异步管理类 异步工厂类 登录校验 登录 异步管理类 采用单例模式的静态饥饿加载 利用空间换时间 提高效率 使用异步延迟任务线程池 通过其内直接创建饥一个static对象 形成饥饿加载 以达到记录日志时的单例模式 import