Java前后端模拟定时器及其响应案例

先描述一下需求:云平台端(简称:cloud)发送通知(通过异步线程执行mqtt消息订阅对象处理),让手持机(简称:POS)主动上传日志文件到对应的服务器(oss),手持机上传成功后,会通过接口将上传信息(如:url,posId等)保存到数据库。为了cloud有更好的体验,避免处理有延迟和网络等复杂问题造成交互影响,cloud在指定pos发送消息后,页面会给一个10s的倒计时,防止用户同一时间内重复请求;后台将采用10s内每5s查询一次数据库(最多只查2次),查询范围是当前时间及5分钟以内的数据;如果查询出,则直接返回true,前端则直接去掉倒计时刷新回原可点击状态,否则返回false,前端倒计时10s后恢复原可点击状态;

一.前端应用

1.场景描述:

表格查询出POS设备记录,在表格列中新增操作列,点击设备的操作列,发送通知;

2.表格列格式化操作:

formatter: function (cellvalue, options, rowObject) {
                //终端状态(0-离线, 1-在线)
                var terCode = rowObject.terminalCode;
                var terId = rowObject.terminalId;
                var onlin = rowObject.onOffLine;
                var dealerId = rowObject.dealerId;
                if (onlin == 1) {
                    return '点此通知';
                }

                return '终端离线';
            }

3.异步通知上传:

// 异步调用通知pos端上传日志
function sendMsg(terminalCode, terminalId, dealerId) {

    // 校验必填数据
    if (typeof(terminalCode) == "undefined" || terminalCode == "" || terminalCode == "null") {
        return false;
    }
    if (typeof(dealerId) == "undefined" || dealerId == "" || dealerId == "null") {
        return false;
    }

    // 执行刷新状态和异步请求
    getMsgResponse(terminalCode, terminalId, dealerId);

}

// 刷新点击状态
function getMsgResponse(terCode, terId, dealerId) {

    // 可点击a标签
    var a1 = '点此通知';

    // 点击后倒计时10s
    var maxtime = 10;
    var desTimer = setInterval(function () {
        if (maxtime >= 0) {
            var seconds = Math.floor(maxtime % 60);
            var text = seconds + "s";
            // 立即刷新为不可点击
            var a0 = '请稍后...' + text + '';
            refreshStyle(a0, terId);
            --maxtime;
        } else {
            clearInterval(desTimer);
            // 立即刷新为可点击
            refreshStyle(a1, terId);
        }

    }, 1000);

    // 执行异步通知并获取消息反应
    $.ajax({
        url: sendPosMsgUrl,
        type: 'POST',
        dataType: 'json',
        data: {
            "terminalCode": terCode,
            "dealerId": dealerId
        },
        success: function (data) {
            // 提示异步执行结果
            if (data.successful) {
                // 数据库已上传则立即刷新为可点击
                if(data.resultValue.flag==11){
                    clearInterval(desTimer);
                    refreshStyle(a1, terId);
                }
                st.layer.alert(data.resultValue.msg, {icon: 1});
            } else {
                st.layer.error(data.errorInfo);
            }
        },
        error:function (data) {
            clearInterval(desTimer);
            refreshStyle(a1, terId);
        }
    });

}

// 刷新原有的样式
function refreshStyle(a, terId) {
    $("#opt" + terId).empty();
    $("#opt" + terId).html(a);
}

二.后端处理

后端主要是处理异步的请求,线程池处理通知线程后,执行主线程,5s/次等待后查询数据库,10s后返回异步处理结果;

1.异步发送通知:

   /**
	 * 定义访问标志: 11 10s内完成文件上传
	 */
	private final int TEN_FINSHED=11;
	/**
	 * 定义访问标志: 10 10s内未完成文件上传
	 */
	private final int TEN_UNFINSHED=10;

   /**
	 * @Description: 发送通知mqtt上传日志
	 * @author 
	 * @date 2019年01月25日 19:39:00
	 * @param bo
	 * @return
	 *
	 */
	@RequestMapping("/sendPosMsg")
	@ResponseBody
	public WrappedResult sendPosMsg(HttpServletRequest request,
									PosLogQueryBO bo) throws InterruptedException {
		UserInfo user = UserInfoUtil.getUserInfo(request);
		if (StringUtil.isNullOrEmpty(bo.getTerminalCode())) {
			return WrappedResult.failedWrappedResult("数据错误,终端编号不能为空");
		}
		if (null==bo.getDealerId()) {
			return WrappedResult.failedWrappedResult("数据错误,商户编号不能为空");
		}
		if (user.getUserType() != UserType.ADMIN.value()) {
			return WrappedResult.failedWrappedResult("权限错误,只有超级管理员才可以操作");
		}

		// 通知pos上传日志
		ThreadPool.addNotice(new GetPosLogNotice(bo.getTerminalCode()));

		// 10s后查询数据库,验证执行是否成功
		Map msgMap=new HashMap<>(2);
		if(posLogUploadService.queryPosLogExist(bo)){
			msgMap.put("flag",TEN_FINSHED);
			msgMap.put("msg","通知成功,请在日志文件下载页面查看");
		}else{
			msgMap.put("flag",TEN_UNFINSHED);
			msgMap.put("msg","通知已发出,请稍后在日志文件下载页面查看");
		}

		return WrappedResult.successWrapedResult(msgMap);
	}

 2.查询POS日志是否已上传的方法:

/**
	 * @Description: 查询POS日志是否已上传
	 * @author 
	 * @date 2019年02月16日 12:04:28
	 * @param bo
	 * @return
	 *
	 */
	@Override
	public Boolean queryPosLogExist(PosLogQueryBO bo)
			throws InterruptedException {

		int times = 0;
		int count;

		// 设置5分钟跨度的查询条件
		Date date = new Date();
		bo.setBgnTime(date);
		bo.setEndTime(DateUtil.getNowDealyDayTime(5, date));

		while (true) {
			// 等待5s后查询数据库
			Thread.sleep(5000);
			times++;
			// 总共查询两次数据库
			count = posLogUploadDao.queryPosLogExist(bo);
			if (times >= 2 || count > 0) {
				break;
			}
		}
		// 已存在
		if (count > 0) {
			return true;
		}

		return false;
	}

三.执行效果

1.web端页面点击通知后:

Java前后端模拟定时器及其响应案例_第1张图片

2.后台执行结果返回后的页面:

Java前后端模拟定时器及其响应案例_第2张图片

 Java前后端模拟定时器及其响应案例_第3张图片

你可能感兴趣的:(java随笔)