怎么感觉web倒计时交互不该像老师这样写,我感觉这样不太合适,难道我的想法错误?

来源:5-3 计时交互

键盘兔

2016-09-08 12:44

关于课程:

《Java高并发秒杀API之web层》

怎么感觉web倒计时交互不该像老师这样写,我感觉这样不太合适,难道我的想法错误?

一、controller里的 /time/now 这个方法完全没有必要,获取秒杀地址Exposer里就包含了当前系统时间

下面看Exposer的属性:

public class Exposer {

	// 是否要暴露的,表示是否开启秒杀
	private boolean exposed;
	// md5加密措施
	private String md5;
	// 秒杀的id
	private long seckillId;
	// 系统当前时间 毫秒
	private long now;
	// 秒杀开始时间 毫秒
	private long start;
	// 秒杀结束时间 毫秒
	private long end;
	.......

倒计时交互流程我觉得应该是下面这样:

在详情页jsp通过“/{seckillId}/exposer"直接获取这个Exposer 的封装json对象SeckillResult<Exposer>。

判断exposed属性,

1.如果是false,则拿now分别比较start和end,如果在start前面则开始倒计时,如果在end后面则显示秒杀结束。

2.如果是true,则处于秒杀有效时间内,显示秒杀按钮。

获取的Exposer对象中的数据,已经是服务端执行了业务逻辑才放入的,直接可以拿来用。我不明白为什么jsp里还要写这么多逻辑,jsp最大的作用只是用来展示。而且对于以后维护也不方便,需要服务端和客户端都要改。


二、另外关于异常处理,我也感觉不合理。比如在SeckillController的方法executeSeckill中:

try {     
SeckillExecution execution = seckillService.executeSeckill(seckillId, userPhone, md5);
return new SeckillResult<SeckillExecution>(true,execution);    
}catch (RepeatkillException e){    
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.REPEAT_KILL);    
return new SeckillResult<SeckillExecution>(false,execution);    
}catch (SeckillCloseException e){    
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.END);    
return new SeckillResult<SeckillExecution>(false,execution);    
}catch (Exception e){    
logger.error(e.getMessage(),e);    
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);    
return new SeckillResult<SeckillExecution>(false,execution);    
}

catch到异常就应该把秒杀失败的标志,以及错误信息返回给前段就行了,为什么是SeckillResult<SeckillExecution>(false,execution);  其中false我可以理解,但是execution有什么用,SeckillResult不是有(boolean success, String error)的构造器吗?一个String的信息就行,需要传对象过去吗?

三、还有SeckillResult的boolean success,SeckillExecution 的 int state,Exposer的boolean exposed;我觉得概念设计的很混乱,老师讲解的也不是很清楚。

我认为,SeckillResult有boolean success和String error表示是否执行成功和异常信息就好,Exposer的boolean exposed表示秒杀是否开启。SeckillExecution 的 int state完全没有必要,枚举应该用在异常类里(可以给父类SeckillException加一个state的属性),这些信息只会在秒杀失败的时候返回给前段,直接捕捉异常,得到异常的message以字符转返回就行了,秒杀失败的时候根本不需要返回SeckillResult对象。

感觉有些混乱和冗余。

以上只是我个人的一些想法,希望大家可以看一下我想的对不对,如果有不对指正。如果本课的老师可以看到,真诚希望可以解疑,拜谢。


另外:

这是我参考老师的代码,按照自己的理解写的seckil.js逻辑代码,我感觉这样更好理解一些,经测试可以实现功能。

//存放主要的交互逻辑js代码
//javaScript模块化,可以模拟java的分包。
//seckill 对象有属性 URL(URL本身可能还有别的属性),属性也可以为函数,因为在script中函数也是对象。
//调用方法类似:seckill.detail.init(params);
var seckill = {
	// :(冒号)对象表达法 冒号在这里用来分割对象的属性和属性值。
	// 秒杀相关ajax的url
	URL : {
		nowUrl : function () {
			return '/seckill/seckill/time/now';
		},
		exposerUrl : function (seckillId) {
			return "/seckill/seckill/" + seckillId + "/exposer";
		},
		seckillUrl : function (seckillId, md5) {
			return "/seckill/seckill/" + seckillId + "/" + md5 + "/execution";
		}

	},
	// 校验手机号
	validatePhone : function (phone) {
		// if(phone){}表示不为空,isNaN(phone)表示非数字
		if (phone && phone.length == 11 && !isNaN(phone)) {
			return true;
		} else {
			return false;
		}
	},
	seckillView : function (seckillId) {
		$
		.post(
			seckill.URL.exposerUrl(seckillId), {},
			function (result) {

			if (result && result['success']) { // 请求成功
				var exposer = result['data'];
				var seckillId = exposer['seckillId'];
				var seckillBox = $('#seckill-box');
				if (exposer['exposed']) { // 可以秒杀
					var md5 = exposer['md5'];
					var killUrl = seckill.URL.seckillUrl(
							seckillId, md5);

					seckillBox
					.html('<button class="btn btn-primary btn-lg" id="killBtn">开始秒杀</button>'); // 按钮

					// 绑定点击事件(绑定一次)
					$("#killBtn")
					.one(
						'click',
						function () {
						// 执行秒杀的请求操作
						$(this).addClass(
							'disabled');
						// 发送秒杀的请求
						$
						.post(
							killUrl, {},
							function (
								result) {
							if (result
								 && result['success']) {
								var seckillExecution = result['data'];
								var state = seckillExecution['state'];
								var stateInfo = seckillExecution['stateInfo'];
								// 显示秒杀结果
								seckillBox
								.html('<span class="label label-success">'
									 + stateInfo
									 + '</span>');
							}
						})
					})
				} else { // 不可以秒杀
					var now = exposer['now'];
					var start = exposer['start'];
					var end = exposer['end'];
					if (now < start) { // 还未开始 倒计时

						seckill.countdown(seckillId, now,
							start, seckillBox);

					} else { // 已经结束(exposed为false只能是未开始或者结束)
						seckillBox.html('秒杀结束');
					}
				}

			} else { // 请求失败
				console.log("result:" + result);
			}
		})

	},
	// 倒计时处理
	countdown : function (seckillId, now, start, seckillBox) {
		// 计时事件绑定
		var killTime = new Date(Number(start) + 1000); // 加一秒的时间偏移。(运算计时的消耗时间,后来细想应该是减去消耗时间,但是因为无法知道消耗的时间多少,减多了会提前显示出点击按钮,并不合理,所以最好不加不减。)
		// jquery倒计时插件,监听时间变化循环回调函数
		seckillBox.countdown(killTime, function (event) {
			// 格式化时间
			var format = event.strftime('秒杀计时: %D天  %H小时  %M分钟  %S秒');
			// 更新倒计时节点组件
			seckillBox.html(format);
		}).on('finish.countdown', function () { // 倒计时结束的回调函数
			// 倒计时结束,以防倒计时误差,需要重新请求exposer,判断是否已经开始,来显示秒杀按钮或者更正倒计时
			seckill.seckillView(seckillId);
		});
	},

	// 详情页秒杀逻辑
	detail : {
		// 详情页初始化
		init : function (params) {
			// ******1。手机验证和登录,2。计时交互
			// *******规划我们的交互流程
			// 利用jquery的cookie插件在cookie中查找手机号
			var killPhone = $.cookie('killPhone');
			// 访问参数中对应的数据(javascript的访问方式)
			var seckillId = params['seckillId'];
			var startTime = params['startTime'];
			var endTime = params['endTime'];
			// 验证手机号
			if (!seckill.validatePhone(killPhone)) { // 未登录
				// 获取弹出层对象
				var killPhoneModal = $("#killPhoneModal");
				// 显示弹出层
				killPhoneModal.modal({
					show : true, // 显示弹出层
					backdrop : 'static', // 禁止位置关闭
					keyboard : false
					// 关闭键盘事件
				});
				// 为手机号的提交按钮绑定点击事件
				$('#submitPhone')
				.click(
					function () {
					// 获取用户输入的手机号
					var inputPhone = $('#killPhone').val();
					// 提交的电话号码有效
					if (seckill.validatePhone(inputPhone)) {
						// 电话写入cookie
						// {expires:7,path:'/seckill'}表示这个cookie的有效期为7天,
						// 只有访问本域名下/seckill路径才会在request中带上这个数据到cookie
						$.cookie('killPhone', inputPhone, {
							expires : 7,
							path : '/seckill'
						})
						// 刷新页面
						window.location.reload();
					} else { // 提交的电话号码无效
						// 显示手机号输入错误的提示信息(先隐藏节点,再写入数据,再显示出来,添加缓慢出现的显示效果)
						$('#killPhoneMessage')
						.hide()
						.html(
							'<label class="label label-danger">手机号错误!</label>')
						.show(500);
					}
				});
			}
			// 已经登录
			seckill.seckillView(seckillId);

		}
	}

}


写回答 关注

2回答

  • 天弈九幽
    2016-09-19 22:49:48

    一,用/time/now可以减轻服务器负担,exposer还得每一秒都查询数据库

    其余不知道

  • 键盘兔
    2016-09-11 19:05:15
    //存放主要的交互逻辑js代码  
    //javaScript模块化,可以模拟java的分包。
    //seckill 对象有属性 URL(URL本身可能还有别的属性),属性也可以为函数,因为在script中函数也是对象。
    //调用方法类似:seckill.detail.init(params);
    var seckill = {
    	// :(冒号)对象表达法 冒号在这里用来分割对象的属性和属性值。
    	// 秒杀相关ajax的url
    	URL : {
    		nowUrl : function() {
    			return '/seckill/seckill/time/now';
    		},
    		exposerUrl : function(seckillId) {
    			return "/seckill/seckill/" + seckillId + "/exposer";
    		},
    		seckillUrl : function(seckillId, md5) {
    			return "/seckill/seckill/" + seckillId + "/" + md5 + "/execution";
    		}
    
    	},
    	// 校验手机号
    	validatePhone : function(phone) {
    		// if(phone){}表示不为空,isNaN(phone)表示非数字
    		if (phone && phone.length == 11 && !isNaN(phone)) {
    			return true;
    		} else {
    			return false;
    		}
    	},
    	seckillView : function(seckillId) {
    		$
    				.post(
    						seckill.URL.exposerUrl(seckillId),
    						{},
    						function(result) {
    
    							if (result && result['success']) {// 请求成功
    								var exposer = result['data'];
    								var seckillId = exposer['seckillId'];
    								var seckillBox = $('#seckill-box');
    								if (exposer['exposed']) {// 可以秒杀
    									var md5 = exposer['md5'];
    									var killUrl = seckill.URL.seckillUrl(
    											seckillId, md5);
    
    									seckillBox
    											.html('<button class="btn btn-primary btn-lg" id="killBtn">开始秒杀</button>');// 按钮
    
    									// 绑定点击事件(绑定一次)
    									$("#killBtn")
    											.one(
    													'click',
    													function() {
    														// 执行秒杀的请求操作
    														$(this).addClass(
    																'disabled');
    														// 发送秒杀的请求
    														$
    																.post(
    																		killUrl,
    																		{},
    																		function(
    																				result) {
    																			if (result
    																					&& result['success']) {
    																				var seckillExecution = result['data'];
    																				var state = seckillExecution['state'];
    																				var stateInfo = seckillExecution['stateInfo'];
    																				// 显示秒杀结果
    																				seckillBox
    																						.html('<span class="label label-success">'
    																								+ stateInfo
    																								+ '</span>');
    																			}
    																		})
    													})
    								} else {// 不可以秒杀
    									var now = exposer['now'];
    									var start = exposer['start'];
    									var end = exposer['end'];
    									if (now < start) {// 还未开始 倒计时
    
    										seckill.countdown(seckillId, now,
    												start, seckillBox);
    
    									} else {// 已经结束(exposed为false只能是未开始或者结束)
    										seckillBox.html('秒杀结束');
    									}
    								}
    
    							} else {// 请求失败
    								console.log("result:" + result);
    							}
    						})
    
    	},
    	// 倒计时处理
    	countdown : function(seckillId, now, start, seckillBox) {
    		// 计时事件绑定
    		var killTime = new Date(Number(start) + 1000); // 加一秒的时间偏移。(运算计时的消耗时间,后来细想应该是减去消耗时间,但是因为无法知道消耗的时间多少,减多了会提前显示出点击按钮,并不合理,所以最好不加不减。)
    		// jquery倒计时插件,监听时间变化循环回调函数
    		seckillBox.countdown(killTime, function(event) {
    			// 格式化时间
    			var format = event.strftime('秒杀计时: %D天  %H小时  %M分钟  %S秒');
    			// 更新倒计时节点组件
    			seckillBox.html(format);
    		}).on('finish.countdown', function() { // 倒计时结束的回调函数
    			// 倒计时结束
    			seckill.seckillView(seckillId);
    		});
    	},
    
    	// 详情页秒杀逻辑
    	detail : {
    		// 详情页初始化
    		init : function(params) {
    			// ******1。手机验证和登录,2。计时交互
    			// *******规划我们的交互流程
    			// 利用jquery的cookie插件在cookie中查找手机号
    			var killPhone = $.cookie('killPhone');
    			// 访问参数中对应的数据(javascript的访问方式)
    			var seckillId = params['seckillId'];
    			var startTime = params['startTime'];
    			var endTime = params['endTime'];
    			// 验证手机号
    			if (!seckill.validatePhone(killPhone)) {// 未登录
    				// 获取弹出层对象
    				var killPhoneModal = $("#killPhoneModal");
    				// 显示弹出层
    				killPhoneModal.modal({
    					show : true,// 显示弹出层
    					backdrop : 'static',// 禁止位置关闭
    					keyboard : false
    				// 关闭键盘事件
    				});
    				// 为手机号的提交按钮绑定点击事件
    				$('#submitPhone')
    						.click(
    								function() {
    									// 获取用户输入的手机号
    									var inputPhone = $('#killPhone').val();
    									// 提交的电话号码有效
    									if (seckill.validatePhone(inputPhone)) {
    										// 电话写入cookie
    										// {expires:7,path:'/seckill'}表示这个cookie的有效期为7天,
    										// 只有访问本域名下/seckill路径才会在request中带上这个数据到cookie
    										$.cookie('killPhone', inputPhone, {
    											expires : 7,
    											path : '/seckill'
    										})
    										// 刷新页面
    										window.location.reload();
    									} else {// 提交的电话号码无效
    										// 显示手机号输入错误的提示信息(先隐藏节点,再写入数据,再显示出来,添加缓慢出现的显示效果)
    										$('#killPhoneMessage')
    												.hide()
    												.html(
    														'<label class="label label-danger">手机号错误!</label>')
    												.show(500);
    									}
    								});
    			}
    			// 已经登录
    			seckill.seckillView(seckillId);
    
    		}
    	}
    
    }

    这是我参考老师的代码,按照自己的理解写的逻辑代码,我感觉这样更好理解一些,经测试可以实现功能。

Java高并发秒杀API之web层

Java实现高并发秒杀API的第三门课,介绍Web层的设计和实现

66079 学习 · 395 问题

查看课程

相似问题