异步管理类
采用单例模式的静态饥饿加载,利用空间换时间,提高效率
使用异步延迟任务线程池
通过其内直接创建饥一个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;
}