新增趋势对比功能
This commit is contained in:
parent
1ea65f9ca3
commit
1c90190a4e
|
|
@ -0,0 +1,63 @@
|
|||
package com.ruoyi.framework.config;
|
||||
|
||||
import com.ruoyi.common.utils.Threads;
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 线程池配置
|
||||
*
|
||||
* @author ruoyi
|
||||
**/
|
||||
@Configuration
|
||||
public class ThreadPoolConfig
|
||||
{
|
||||
// 核心线程池大小
|
||||
private int corePoolSize = 50;
|
||||
|
||||
// 最大可创建的线程数
|
||||
private int maxPoolSize = 200;
|
||||
|
||||
// 队列最大长度
|
||||
private int queueCapacity = 1000;
|
||||
|
||||
// 线程池维护线程所允许的空闲时间
|
||||
private int keepAliveSeconds = 300;
|
||||
|
||||
@Bean(name = "threadPoolTaskExecutor")
|
||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
||||
{
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setMaxPoolSize(maxPoolSize);
|
||||
executor.setCorePoolSize(corePoolSize);
|
||||
executor.setQueueCapacity(queueCapacity);
|
||||
executor.setKeepAliveSeconds(keepAliveSeconds);
|
||||
// 线程池对拒绝任务(无线程可用)的处理策略
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行周期性或定时任务
|
||||
*/
|
||||
@Bean(name = "scheduledExecutorService")
|
||||
protected ScheduledExecutorService scheduledExecutorService()
|
||||
{
|
||||
return new ScheduledThreadPoolExecutor(corePoolSize,
|
||||
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy())
|
||||
{
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t)
|
||||
{
|
||||
super.afterExecute(r, t);
|
||||
Threads.printException(r, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.ruoyi.framework.interceptor.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.http.HttpHelper;
|
||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
||||
|
||||
/**
|
||||
* 判断请求url和数据是否和上一次相同,
|
||||
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
||||
{
|
||||
public final String REPEAT_PARAMS = "repeatParams";
|
||||
|
||||
public final String REPEAT_TIME = "repeatTime";
|
||||
|
||||
// 令牌自定义标识
|
||||
@Value("${token.header}")
|
||||
private String header;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
|
||||
{
|
||||
String nowParams = "";
|
||||
if (request instanceof RepeatedlyRequestWrapper)
|
||||
{
|
||||
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
|
||||
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
|
||||
}
|
||||
|
||||
// body参数为空,获取Parameter的数据
|
||||
if (StringUtils.isEmpty(nowParams))
|
||||
{
|
||||
nowParams = JSON.toJSONString(request.getParameterMap());
|
||||
}
|
||||
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
||||
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
||||
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
|
||||
|
||||
// 请求地址(作为存放cache的key值)
|
||||
String url = request.getRequestURI();
|
||||
|
||||
// 唯一值(没有消息头则使用请求地址)
|
||||
String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
|
||||
|
||||
// 唯一标识(指定key + url + 消息头)
|
||||
String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
|
||||
|
||||
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
|
||||
if (sessionObj != null)
|
||||
{
|
||||
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
|
||||
if (sessionMap.containsKey(url))
|
||||
{
|
||||
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
|
||||
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, Object> cacheMap = new HashMap<String, Object>();
|
||||
cacheMap.put(url, nowDataMap);
|
||||
redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否相同
|
||||
*/
|
||||
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
|
||||
{
|
||||
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
|
||||
String preParams = (String) preMap.get(REPEAT_PARAMS);
|
||||
return nowParams.equals(preParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两次间隔时间
|
||||
*/
|
||||
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)
|
||||
{
|
||||
long time1 = (Long) nowMap.get(REPEAT_TIME);
|
||||
long time2 = (Long) preMap.get(REPEAT_TIME);
|
||||
if ((time1 - time2) < interval)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.ruoyi.framework.manager;
|
||||
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.ruoyi.common.utils.Threads;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
|
||||
/**
|
||||
* 异步任务管理器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class AsyncManager
|
||||
{
|
||||
/**
|
||||
* 操作延迟10毫秒
|
||||
*/
|
||||
private final int OPERATE_DELAY_TIME = 10;
|
||||
|
||||
/**
|
||||
* 异步操作任务调度线程池
|
||||
*/
|
||||
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
|
||||
|
||||
/**
|
||||
* 单例模式
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.ruoyi.framework.manager.factory;
|
||||
|
||||
import java.util.TimerTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.utils.LogUtils;
|
||||
import com.ruoyi.common.utils.ServletUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.ip.AddressUtils;
|
||||
import com.ruoyi.common.utils.ip.IpUtils;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.system.domain.SysLogininfor;
|
||||
import com.ruoyi.system.domain.SysOperLog;
|
||||
import com.ruoyi.system.service.ISysLogininforService;
|
||||
import com.ruoyi.system.service.ISysOperLogService;
|
||||
import eu.bitwalker.useragentutils.UserAgent;
|
||||
|
||||
/**
|
||||
* 异步工厂(产生任务用)
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
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();
|
||||
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 (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue