1、表设计
CREATE TABLE `b_log_access` (
`fid` varchar(64) NOT NULL COMMENT '主键',
`request_name` varchar(100) DEFAULT NULL COMMENT '请求名称',
`request_url` varchar(200) DEFAULT NULL COMMENT '请求地址',
`request_parameter` longtext COMMENT '请求参数',
`request_type` varchar(50) DEFAULT NULL COMMENT '请求模块类型',
`request_result` longtext COMMENT '请求返回结果',
`request_appid` varchar(100) DEFAULT NULL COMMENT '请求应用id',
`request_key` varchar(100) DEFAULT NULL COMMENT '请求应用key例如密码等',
`request_secret` varchar(1000) DEFAULT NULL COMMENT '请求参数密钥',
`request_id` varchar(200) DEFAULT NULL COMMENT '请求关键id例如订单号等',
`return_status` varchar(20) DEFAULT '200' COMMENT '请求返回状态结果,默认:200成功',
`is_repeat` int(2) DEFAULT '0' COMMENT '失败是否重复请求;0:否,1:是',
`repeat_times` int(11) DEFAULT '0' COMMENT '针对请求失败重复请求次数',
`is_remove` int(2) DEFAULT '0' COMMENT '请求成功是否根据移除时间自动移除; 0:否;1:是',
`remove_seconds` int(11) DEFAULT '10' COMMENT '根据最后更新时间自动移除时间,单位(s)',
`create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`last_modifyer` varchar(64) DEFAULT 'N' COMMENT '记录最后修改人 关联b_user.fid',
`creater` varchar(64) DEFAULT 'N' COMMENT '记录创建人 关联b_user.fid',
`client_id` varchar(64) DEFAULT 'N' COMMENT '记录所属租户 关联b_client.fid',
PRIMARY KEY (`fid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
2、逻辑构思
1、 数据异步插入 b_log_access表 的方法;
2、每10s执行(请求失败重复请求、请求成功超时的请求)
3、查询请求失败的请求列表、查询请求成功的请求列表
4、超时时间算法函数
3、代码
package cn.ivg.service.impl;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import cn.invengo.common.utils.FastJsonUtils;
import cn.ivg.cscm.log.model.entity.LogAccessWithBLOBs;
import cn.ivg.cscm.log.service.IRepLogAccessService;
import cn.ivg.framework.comp.idGen.IdGenUtil;
import cn.ivg.model.LogAccessEx;
import cn.ivg.service.ILogAccessService;
import cn.ivg.service.RepeatCallback;
@Service
public class LogAccessServiceImpl implements ILogAccessService, InitializingBean {
static Logger log = LoggerFactory.getLogger(LogAccessServiceImpl.class);
/**
* 失败重复执行调用缓存类
*/
private Map<String, RepeatCallback> callbackMap = new ConcurrentHashMap<>();
/**
* 请求日志调度守护线程
*/
private Timer logAccessTimeSchedule = new Timer("Log_access_schedule");
@Autowired
private IRepLogAccessService repLogAccessService;
@Autowired
private Executor taskExecutor;
@Autowired
private IdGenUtil idGenUtil;
@Override
public void AsynRecordAccessLog(LogAccessEx record, boolean isprint) {
// TODO Auto-generated method stub
if (isprint) {
log.info(FastJsonUtils.toJSONString(record));
}
taskExecutor.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
record.setCreateDate(new Date());
record.setFid(idGenUtil.getId());
record.setLastUpdate(new Date());
repLogAccessService.insertSelective(record);
}
});
}
@Override
public void RegisterRepeatCallback(String requestType, RepeatCallback callback) {
// TODO Auto-generated method stub
if(Objects.isNull(callbackMap.get(requestType))){
callbackMap.put(requestType, callback);
}
}
@Override
public void afterPropertiesSet() throws Exception {
// 10秒执行一次请求及移除
logAccessTimeSchedule.schedule(new DealAccessLogTask(), 10 * 1000, 10 * 1000);
}
@Override
public List<LogAccessWithBLOBs> repeatCallList() {
// TODO Auto-generated method stub
LogAccessWithBLOBs record = new LogAccessWithBLOBs();
record.setIsRepeat(Constant.REPEAT_OK);
record.setReturnStatus(Constant.STATUS_ERRO);
return repLogAccessService.select(record);
}
@Override
public List<LogAccessWithBLOBs> removeList() {
// TODO Auto-generated method stub
LogAccessWithBLOBs record = new LogAccessWithBLOBs();
record.setIsRemove(Constant.REMOVE_OK);
record.setReturnStatus(Constant.STATUS_OK);
return repLogAccessService.select(record);
}
@Override
public long diffNow(Date date) {
// TODO Auto-generated method stub
return System.currentTimeMillis() - date.getTime();
}
/**
* 分类处理请求日志任务
*
* @author tao.tang
* @date 2019/01/23
*/
class DealAccessLogTask extends TimerTask {
@Override
public void run() {
try {
// 失败请求重复请求
List<LogAccessWithBLOBs> repeatList = repeatCallList();
for (LogAccessWithBLOBs repeat : repeatList) {
if (ObjectUtils.isEmpty(callbackMap.get(repeat.getRequestType()))) {
continue;
}
LogAccessEx repeatParam = new LogAccessEx();
BeanUtils.copyProperties(repeat, repeatParam);
//根据请求次数延长下一次重复调用时间
if (diffNow(repeatParam.getLastUpdate()) > repeatParam.getRepeatTimes() * Constant.REPEAT_BASE) {
repLogAccessService
.updateByPrimaryKeySelective(callbackMap.get(repeat.getRequestType()).excute(repeatParam));
}
}
// 处理已请求成功超时记录
List<LogAccessWithBLOBs> removeList = removeList();
for (LogAccessWithBLOBs remove : removeList) {
//超时移除日志
if (diffNow(remove.getLastUpdate()) > remove.getRemoveSeconds() * 1000) {
repLogAccessService.deleteByPrimaryKey(remove.getFid());
}
}
} catch (Exception e) {
log.error("定时器Log_access_schedule执行异常", e);
}
}
}
}