为了账号安全,请及时绑定邮箱和手机立即绑定

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

关于课程:

《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 回答

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

其余不知道

1 回复 有任何疑惑可以回复我~
//存放主要的交互逻辑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);

		}
	}

}

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

0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消

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

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信