整合SSM框架的高并发和商品秒杀项目(三)-Java高并发秒杀系统API之Web层开发
(三)Java高并发秒杀系统API之Web层开发
1. 引入SpringMvc
修改web.xml
,引入SpringMvc
的DispatcherServlet
:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<!--用maven创建的web-app需要修改servlet的版本为3.0-->
<servlet>
<servlet-name>seckill-dispatchServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</init-param>
<load-on-startup>
1
</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>seckill-dispatchServlet</servlet-name>
<!--直接拦截所有请求,不再采用spring2.0的/*或者*.do方式-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在这里的话如果你不配置这一段代码的:
<!--配置springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</init-param>
SpringMvc默认就会默认去WEB-INF
下查找默认规范的配置文件,像我这里配置的servlet-name
是seckill-dispatchServlet
的话,则默认会寻找WEB-INF
一个名为seckill-dispatchServlet-Servlet.xml
的配置文件
2. 编写Controller
首先在com.suny
下建立包为Controller
的包,然后在里面新建一个类SeckillController
:
package com.suny.controller;
/**
* Created by on 17-5-24.下午10:11
*/
@Controller
@RequestMapping("/seckill")
public class SeckillController {
private final SeckillService seckillService;
@Autowired
public SeckillController(SeckillService seckillService) {
this.seckillService = seckillService;
}
/**
* 进入秒杀列表.
*
* @param model 模型数据,里面放置有秒杀商品的信息
* @return 秒杀列表详情页面
*/
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String list(Model model) {
List<Seckill> seckillList = seckillService.getSeckillList();
model.addAttribute("list", seckillList);
return "list";
}
@RequestMapping(value = "/{seckillId}/detail", method = RequestMethod.GET)
public String detail(@PathVariable("seckillId") Long seckillId, Model model) {
if (seckillId == null) {
return "redirect:/seckill/list";
}
Seckill seckill = seckillService.getById(seckillId);
if (seckill == null) {
return "forward:/seckill/list";
}
model.addAttribute("seckill", seckill);
return "detail";
}
/**
* 暴露秒杀接口的方法.
*
* @param seckillId 秒杀商品的id
* @return 根据用户秒杀的商品id进行业务逻辑判断,返回不同的json实体结果
*/
@RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.GET)
@ResponseBody
public SeckillResult<Exposer> exposer(@PathVariable("seckillId") Long seckillId) {
// 查询秒杀商品的结果
SeckillResult<Exposer> result;
try {
Exposer exposer = seckillService.exportSeckillUrl(seckillId);
result = new SeckillResult<>(true, exposer);
} catch (Exception e) {
e.printStackTrace();
result = new SeckillResult<>(false, e.getMessage());
}
return result;
}
/**
* 用户执行秒杀,在页面点击相应的秒杀连接,进入后获取对应的参数进行判断,返回相对应的json实体结果,前端再进行处理.
*
* @param seckillId 秒杀的商品,对应的时秒杀的id
* @param md5 一个被混淆的md5加密值
* @param userPhone 参与秒杀用户的额手机号码,当做账号密码使用
* @return 参与秒杀的结果,为json数据
*/
@RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST)
@ResponseBody
public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId") long seckillId,
@PathVariable("md5") String md5,
@CookieValue(value = "userPhone", required = false) Long userPhone) {
// 如果用户的手机号码为空的说明没有填写手机号码进行秒杀
if (userPhone == null) {
return new SeckillResult<>(false, "没有注册");
}
// 根据用户的手机号码,秒杀商品的id跟md5进行秒杀商品,没异常就是秒杀成功
try {
// 这里换成储存过程
SeckillExecution execution = seckillService.executeSeckill(seckillId, userPhone, md5);
return new SeckillResult<>(true, execution);
} catch (RepeatKillException e1) {
// 重复秒杀
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.REPEAT_KILL);
return new SeckillResult<>(false, execution);
} catch (SeckillCloseException e2) {
// 秒杀关闭
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.END);
return new SeckillResult<>(false, execution);
} catch (SeckillException e) {
// 不能判断的异常
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.INNER_ERROR);
return new SeckillResult<>(false, execution);
}
// 如果有异常就是秒杀失败
}
/**
* 获取服务器端时间,防止用户篡改客户端时间提前参与秒杀
*
* @return 时间的json数据
*/
@RequestMapping(value = "/time/now", method = RequestMethod.GET)
@ResponseBody
public SeckillResult<LocalDateTime> time() {
LocalDateTime localDateTime = LocalDateTime.now();
return new SeckillResult<>(true, localDateTime);
}
}
3. 全局返回 JSON 类型
新建一个 SeckillResult
:
package com.suny.dto;
/**
* 封装所有的ajax请求返回类型,方便返回json
* Created by on 17-5-24.下午10:18
*/
public class SeckillResult<T> {
private boolean success;
private T data;
private String error;
public SeckillResult() {
}
public SeckillResult(boolean success, T data) {
this.success = success;
this.data = data;
}
public SeckillResult(boolean success, String error) {
this.success = success;
this.error = error;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
@Override
public String toString() {
return "SeckillResult{" +
"状态=" + success +
", 数据=" + data +
", 错误消息='" + error + '\'' +
'}';
}
}
4.页面的编写
因为项目的前端页面都是由Bootstrap
开发的,所以我们要先去下载Bootstrap
或者是使用在线的CDN.
使用在线CDN引入的方法:
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
文档里面写的很详细,然后我这里是使用离线版本的,方便我们本地调试,避免出现什么别的因素干扰我们:
- 首先下载JQuery
,因为Bootstrap
就是依赖JQuery
的
- 然后下载Bootstrap
- 然后下载一个倒计时插件jquery.countdown.min.js
- 再下载一个操作Cookie
插件jquery.cookie.min.js
如图放置:
4.1 编写公共头部文件
首先编写一个公共的头部jsp
文件,位于WEB-INF
下common
中的head.jsp
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/css/bootstrap-theme.min.css" type="text/css">
4.2 编写公共标签库文件
编写一个公共的jstl
标签库文件,位于WEB-INF
下common
中的tag.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
4.3 编写列表页面文件
编写列表页面,位于WEB-INF
下common
中的list.jsp
<%@page contentType="text/html; charset=UTF-8" language="java" %>
<%@include file="common/tag.jsp" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>秒杀列表</title>
<%@include file="common/head.jsp" %>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading text-center">
<h2>秒杀列表</h2>
</div>
<div class="panel-body">
<table class="table table-hover">
<thead>
<tr>
<td>名称</td>
<td>库存</td>
<td>开始时间</td>
<td>结束时间</td>
<td>创建时间</td>
<td>详情页</td>
</tr>
</thead>
<tbody>
<c:forEach items="${list}" var="sk">
<tr>
<td>${sk.name}</td>
<td>${sk.number}</td>
<td><fmt:formatDate value="${sk.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td><fmt:formatDate value="${sk.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td><fmt:formatDate value="${sk.createTIme}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td><a class="btn btn-info" href="/seckill/${sk.seckillId}/detail" target="_blank">详情</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
</html>
4.3 编写秒杀详情页面
位于WEB-INF
下common
中的detail.jsp
,秒杀详情页面:
<%--
Created by IntelliJ IDEA.
User:
Date: 17-5-25
Time: 下午5:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="common/tag.jsp" %>
<html>
<head>
<title>秒杀商品详情页面</title>
<%@include file="common/head.jsp" %>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h1>${seckill.name}</h1>
</div>
<div class="panel-body">
<h2 class="text-danger">
<span class="glyphicon glyphicon-time"></span>
<span class="glyphicon" id="seckill-box"></span>
</h2>
</div>
</div>
</div>
<div id="killPhoneModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title text-center">
<span class="glyphicon glyphicon-phone"></span>秒杀电话:
</h3>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" name="killPhone" id="killPhoneKey" placeholder="填写手机号码" class="form-control">
</div>
</div>
</div>
<div class="modal-footer">
<span id="killPhoneMessage" class="glyphicon"></span>
<button type="button" id="killPhoneBtn" class="btn btn-success">
<span class="glyphicon glyphicon-phone"></span>
提交
</button>
</div>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.cookie.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.countdown.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/script/seckill.js"></script>
<script type="text/javascript">
$(function () {
var startTimeVal = "${seckill.startTime.toLocalDate()} " + seckill.cloneZero("${seckill.startTime.toLocalTime()}");
var endTimeVal = "${seckill.endTime.toLocalDate()} " + seckill.cloneZero("${seckill.endTime.toLocalTime()}");
console.log("startTimeVal========" + startTimeVal);
console.log("endTimeVal========" + endTimeVal);
// 传入参数
seckill.detail.init({
seckillId:${seckill.seckillId},
startTime: startTimeVal,
endTime: endTimeVal
})
})
</script>
</html>
4.3.1 运行报错问题
然后把项目运行一下我们又会碰到一个错误就是jstl
中的fmt
标签格式化时间只能格式化java.Util.Date
类型的日期跟时间,而在我们这里我么使用了java8
的LocalDateTIme
,所以解析时间会出异常,这时我们应该想到自己去实现jstl
标签来自定义解析这个时间日期。
自定义标签步骤如下:
- 在
/WEB-INF
创建目录tags
- 然后创建一个文件
localDateTime.tag
在tags
目录下 localData.tag
用来格式化日期localDataTime.tag
用来格式化日期跟时间的组合,也就是数据库中的Timestamp
类型- 然后在
localDataTime.tag
中写自己自定义的格式化流程
4.3.2 自定义标签处理 Java8 LocalDateTime
<%--格式化java8的LocalDatime,解决jstl不支持java8时间的问题--%>
<%@ tag body-content="empty" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%-- 这里是定义页面使用标签中的属性设置,<tags:localDataTime dateTime="${sk.createTIme}"/> --%>
<%@ attribute name="dateTime" required="true" type="java.time.LocalDateTime" %>
<%@ attribute name="pattern" required="false" type="java.lang.String" %>
<%--首选判断日期时间转换规则是否存在,不存在给出默认的规则--%>
<c:if test="${empty pattern}">
<c:set var="pattern" value="yyyy-MM-dd HH:mm:ss"/>
</c:if>
<c:set var="datetime" value="${dateTime}"/> <%-- 获取jsp页面传入的【 日期时间 】,格式为【 2017-5-26T13:59:12 】 --%>
<c:set var="time" value="${fn:substringAfter(datetime, 'T')}"/> <%-- 获取页面传过来的【时间T】后面的 【 时:分:秒 】的值 --%>
<c:set var="timeLength" value="${fn:length(time)}"/> <%-- 获取页面传来的 【 时:分:秒 的长度 】 --%>
<c:set var="generalLength" value="${fn:length('123456')}"/> <%-- 这里定义了一个【Integer】类型的值,值为字符串 【123456 】的长度 --%>
<c:set var="cloneZero" value=":00"/> <%-- 这里设置一个值为【String】的字符串, --%>
<%-- 当 时:分:秒 不足6位的时候就说明缺少秒,我们给它自动补充 :00 --%>
<c:if test="${timeLength lt generalLength}">
<c:set var="datetimeCloneZero"
value="${datetime}${cloneZero}"/> <%-- 拼接页面传过来的 【 时:分 】 ,补充一个【秒数】,EL中 + 为相加,非拼接字符串 --%>
<c:set var="cleandDateTime"
value="${fn:replace(datetimeCloneZero,'T',' ')}"/> <%-- 把java8日期时间中的【 T 】给去掉,换成一个空的字符串 --%>
</c:if>
<%-- 当页面传过来的时间大于6位时说明时间时完整的,不进行自动填充【 :00 】,直接把日期时间中的 【 T 】 替换为空字符串 --%>
<c:if test="${timeLength gt generalLength}">
<c:set var="cleandDateTime" value="${fn:replace(datetime,'T',' ')}"/>
</c:if>
<%-- 解析时间, type="BOTH"为同时解析日期跟时间 --%>
<fmt:parseDate value="${cleandDateTime}" var="parsedDateTime" pattern="${pattern}" type="BOTH"/>
<fmt:formatDate value="${parsedDateTime}" pattern="${pattern}" type="BOTH"/>
4.3.3 自定义标签处理 Java8 LocalDate
localData.tag
的内容就比较简单了
<%@ tag body-content="empty" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ attribute name="date" required="true" type="java.time.LocalDate" %>
<%@ attribute name="pattern" required="false" type="java.lang.String" %>
<c:if test="${empty pattern}">
<c:set var="pattern" value="MM/dd/yyyy"/>
</c:if>
<fmt:parseDate value="${date}" var="parsedDate" type="date"/>
<fmt:formatDate value="${parsedDate}" type="date" pattern="${pattern}"/>
4.3.4 导入自定义标签处理
然后我们去页面导入需要的标签,然后去使用,修改list.jsp
文件
<%@page contentType="text/html; charset=UTF-8" language="java" %>
<%@include file="common/tag.jsp" %>
<%@taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>秒杀列表</title>
<%@include file="common/head.jsp" %>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading text-center">
<h2>秒杀列表</h2>
</div>
<div class="panel-body">
<table class="table table-hover">
<thead>
<tr>
<td>名称</td>
<td>库存</td>
<td>开始时间</td>
<td>结束时间</td>
<td>创建时间</td>
<td>详情页</td>
</tr>
</thead>
<tbody>
<c:forEach items="${list}" var="sk">
<tr>
<td>${sk.name}</td>
<td>${sk.number}</td>
<td><tags:localDataTime dateTime="${sk.startTime}"/></td>
<td><tags:localDataTime dateTime="${sk.endTime}"/></td>
<td><tags:localDataTime dateTime="${sk.createTIme}"/></td>
<td><a class="btn btn-info" href="/seckill/${sk.seckillId}/detail" target="_blank">详情</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
</html>
在这里我们修改了几个地方:
<%@taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<td><tags:localDataTime dateTime="${sk.startTime}"/></td>
<td><tags:localDataTime dateTime="${sk.endTime}"/></td>
<td><tags:localDataTime dateTime="${sk.createTIme}"/></td>
然后我们的格式就应该可以正常被格式化出来了
4.4 编写秒杀逻辑 JS 文件
- 建立一个模块化的
seckill.js
文件,位于Webapp
下resources
下script
文件夹下,文件内容如下:
/**
* 模块化javaScript
* Created by on 17-5-25.
*/
var seckill = {
// 封装秒杀相关的ajax的url
URL: {
now: function () {
return "/seckill/time/now";
},
exposer: function (seckillId) {
return "/seckill/" + seckillId + "/exposer";
},
execution: function (seckillId, md5) {
return "/seckill/" + seckillId + "/" + md5 + "/execution";
}
},
// 验证手机号码
validatePhone: function (phone) {
return !!(phone && phone.length === 11 && !isNaN(phone));
},
// 详情页秒杀业务逻辑
detail: {
// 详情页开始初始化
init: function (params) {
console.log("获取手机号码");
// 手机号验证登录,计时交互
var userPhone = $.cookie('userPhone');
// 验证手机号
if (!seckill.validatePhone(userPhone)) {
console.log("未填写手机号码");
// 验证手机控制输出
var killPhoneModal = $("#killPhoneModal");
killPhoneModal.modal({
show: true, // 显示弹出层
backdrop: 'static', // 静止位置关闭
keyboard: false // 关闭键盘事件
});
$("#killPhoneBtn").click(function () {
console.log("提交手机号码按钮被点击");
var inputPhone = $("#killPhoneKey").val();
console.log("inputPhone" + inputPhone);
if (seckill.validatePhone(inputPhone)) {
// 把电话写入cookie
$.cookie('userPhone', inputPhone, {expires: 7, path: '/seckill'});
// 验证通过 刷新页面
window.location.reload();
} else {
// todo 错误文案信息写到前端
$("#killPhoneMessage").hide().html("<label class='label label-danger'>手机号码错误</label>").show(300);
}
});
} else {
console.log("在cookie中找到了电话号码,开启计时");
// 已经登录了就开始计时交互
var startTime = params['startTime'];
var endTime = params['endTime'];
var seckillId = params['seckillId'];
console.log("开始秒杀时间=======" + startTime);
console.log("结束秒杀时间========" + endTime);
$.get(seckill.URL.now(), {}, function (result) {
if (result && result['success']) {
var nowTime = seckill.convertTime(result['data']);
console.log("服务器当前的时间==========" + nowTime);
// 进行秒杀商品的时间判断,然后计时交互
seckill.countDown(seckillId, nowTime, startTime, endTime);
} else {
console.log('结果:' + result);
console.log('result' + result);
}
});
}
}
},
handlerSeckill: function (seckillId, mode) {
// 获取秒杀地址
mode.hide().html('<button class="btn btn-primary btn-lg" id="killBtn">开始秒杀</button>');
console.debug("开始进行秒杀地址获取");
$.get(seckill.URL.exposer(seckillId), {}, function (result) {
if (result && result['success']) {
var exposer = result['data'];
if (exposer['exposed']) {
console.log("有秒杀地址接口");
// 开启秒杀,获取秒杀地址
var md5 = exposer['md5'];
var killUrl = seckill.URL.execution(seckillId, md5);
console.log("秒杀的地址为:" + killUrl);
// 绑定一次点击事件
$("#killBtn").one('click', function () {
console.log("开始进行秒杀,按钮被禁用");
// 执行秒杀请求,先禁用按钮
$(this).addClass("disabled");
// 发送秒杀请求
$.post(killUrl, {}, function (result) {
var killResult = result['data'];
var state = killResult['state'];
var stateInfo = killResult['stateInfo'];
console.log("秒杀状态" + stateInfo);
// 显示秒杀结果
mode.html('<span class="label label-success">' + stateInfo + '</span>');
});
});
mode.show();
} else {
console.warn("还没有暴露秒杀地址接口,无法进行秒杀");
// 未开启秒杀
var now = seckill.convertTime(exposer['now']);
var start = seckill.convertTime(exposer['start']);
var end = seckill.convertTime(exposer['end']);
console.log("当前时间" + now);
console.log("开始时间" + start);
console.log("结束时间" + end);
console.log("开始倒计时");
console.debug("开始进行倒计时");
seckill.countDown(seckillId, now, start, end);
}
} else {
console.error("服务器端查询秒杀商品详情失败");
console.log('result' + result.valueOf());
}
});
},
countDown: function (seckillId, nowTime, startTime, endTime) {
console.log("秒杀的商品ID:" + seckillId + ",服务器当前时间:" + nowTime + ",开始秒杀的时间:" + startTime + ",结束秒杀的时间" + endTime);
// 获取显示倒计时的文本域
var seckillBox = $("#seckill-box");
// 获取时间戳进行时间的比较
nowTime = new Date(nowTime).valueOf();
startTime = new Date(startTime).valueOf();
endTime = new Date(endTime).valueOf();
console.log("转换后的Date类型当前时间戳" + nowTime);
console.log("转换后的Date类型开始时间戳" + startTime);
console.log("转换后的Date类型结束时间戳" + endTime);
if (nowTime < endTime && nowTime > startTime) {
// 秒杀开始
console.log("秒杀可以开始,两个条件符合");
seckill.handlerSeckill(seckillId, seckillBox);
}
else if (nowTime > endTime) {
alert(nowTime > endTime);
console.log(nowTime + ">" + startTime);
// 秒杀结束
console.warn("秒杀已经结束了,当前时间为:" + nowTime + ",秒杀结束时间为" + endTime);
seckillBox.html("秒杀结束");
} else {
console.log("秒杀还没开始");
alert(nowTime < startTime);
// 秒杀未开启
var killTime = new Date(startTime + 1000);
console.log(killTime);
console.log("开始计时效果");
seckillBox.countdown(killTime, function (event) {
// 事件格式
var format = event.strftime("秒杀倒计时: %D天 %H时 %M分 %S秒");
console.log(format);
seckillBox.html(format);
}).on('finish.countdown', function () {
// 事件完成后回调事件,获取秒杀地址,控制业务逻辑
console.log("准备执行回调,获取秒杀地址,执行秒杀");
console.log("倒计时结束");
seckill.handlerSeckill(seckillId, seckillBox);
});
}
},
cloneZero: function (time) {
var cloneZero = ":00";
if (time.length < 6) {
console.warn("需要拼接时间");
time = time + cloneZero;
return time;
} else {
console.log("时间是完整的");
return time;
}
},
convertTime: function (localDateTime) {
var year = localDateTime.year;
var monthValue = localDateTime.monthValue;
var dayOfMonth = localDateTime.dayOfMonth;
var hour = localDateTime.hour;
var minute = localDateTime.minute;
var second = localDateTime.second;
return year + "-" + monthValue + "-" + dayOfMonth + " " + hour + ":" + minute + ":" + second;
}
};
5. 测试
编写完了就部署运行吧,不出意外的话就是这个样子的: