(三)Java高併發秒殺系統API之Web層開發
既然是Web層的會肯定要先引入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
的配置檔案
接下來編寫Controller SeckillController
首先在com.suny
下建立包為Controller
的包,然後在裡面新建一個類SeckillController
:
package com.suny.controller;
/**
* Created by 孫
*/
@Controller
@RequestMapping("/seckill")
public class SeckillController {
private final SeckillService seckillService;
@Autowired
public SeckillController(SeckillService seckillService) {
this.seckillService = seckillService;
}
/**
* 進入秒殺列表.
*
* @param model 模型資料,裡面放置有秒殺商品的資訊
* @return 秒殺列表詳情頁面
*/
@RequestMapping(value = {"/list","","index"}, 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);
}
}
建立一個全域性ajax請求返回類,返回json型別
SeckillResult
:
package com.suny.dto;
/**
* 封裝所有的ajax請求返回型別,方便返回json
* Created by 孫
*/
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 + '\'' +
'}';
}
}
頁面的編寫
因為專案的前端頁面都是由Bootstrap
開發的,所以我們要先去下載Bootstrap
或者是使用線上的CDN.
-Bootstrap中文官網:http://www.bootcss.com/
-Bootstrap中文文件 :http://v3.bootcss.com/
使用線上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
如圖放置
首先編寫一個公共的頭部
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">
然後編寫一個公共的
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" %>
編寫列表頁面,位於
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>
編寫列表頁面,位於
WEB-INF
下common
中的detail.jsp
,秒殺詳情頁面
<%--
Created by IntelliJ IDEA.
User: jianrongsun
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>
然後把專案執行一下我們又會碰到一個錯誤就是jstl
中的fmt
標籤格式化時間只能格式化java.Util.Date
型別的日期跟時間,而在我們這裡我麼使用了java8
的LocalDateTIme
,所以解析時間會出異常,這時我們應該想到自己去實現jstl
標籤來自定義解析這個時間日期 自定義標籤步驟如下:
在
/WEB-INF
建立目錄tags
然後建立一個檔案
localDateTime.tag
在tags
目錄下localData.tag
用來格式化日期localDataTime.tag
用來格式化日期跟時間的組合,也就是資料庫中的Timestamp
型別 -然後在localDataTime.tag
中寫自己自定義的格式化流程
<%--格式化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"/>
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}"/>
然後我們去頁面匯入需要的標籤,然後去使用,修改
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>
然後我們的格式就應該可以正常被格式化出來了
建立一個模組化的
seckill.js
檔案,位於Webapp
下resources
下script
資料夾下,檔案內容如下:
/**
* 模組化javaScript
* Created by jianrongsun 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.log(nowTime + ">" + endTime);
// 秒殺結束
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;
}
};
自定義jstl標籤參考資料:
stackoverflow上的資料1:https://stackoverflow.com/questions/35606551/jstl-localdatetime-format
stackoverflow上的資料2:https://stackoverflow.com/questions/30230517/taglib-to-display-java-time-localdate-formatted
編寫完了就部署執行吧,不出意外的話就是這個樣子的:
相關文章
- SpringBoot實現Java高併發秒殺系統之Web層開發(三)Spring BootJavaWeb
- (二)Java高併發秒殺API之Service層JavaAPI
- (四)Java高併發秒殺API之高併發優化JavaAPI優化
- Java高併發秒殺系統【觀後總結】Java
- Java高併發秒殺系統API之SSM框架整合swagger與AdminLTEJavaAPISSM框架Swagger
- 高併發秒殺系統架構詳解,不是所有的秒殺都是秒殺!架構
- 【高併發】秒殺系統架構解密,不是所有的秒殺都是秒殺(升級版)!!架構解密
- 如何設計一個高可用、高併發秒殺系統
- 【高併發】Redis如何助力高併發秒殺系統,看完這篇我徹底懂了!!Redis
- 6步帶你用Spring Boot開發出商城高併發秒殺系統Spring Boot
- Web系統大規模併發——電商秒殺與搶購Web
- SSM框架實現高併發秒殺API學習筆記SSM框架API筆記
- 使用Redis構建高併發高可靠的秒殺拍賣系統 - LuisRedisUI
- 短影片直播系統,實現高併發秒殺的多種方式
- RocketMQ實戰--高併發秒殺場景MQ
- 高併發秒殺專案隨手筆記筆記
- Redis 實現高併發下的搶購 / 秒殺功能Redis
- PHP高併發商品秒殺問題的解決方案PHP
- 秒殺搶購思路以及高併發下資料安全
- PHP開發中多種方案實現高併發下的搶購、秒殺功能PHP
- Java高併發系統的限流策略Java
- 聊聊高併發系統之限流特技
- 01 整合IDEA+Maven+SSM框架的高併發的商品秒殺專案之業務分析與DAO層IdeaMavenSSM框架
- 高併發業務場景下的秒殺解決方案 (初探)
- JAVA開發之簡化Dao層、提高開發效率(三)Java
- 聊聊高併發系統之HTTP快取HTTP快取
- 聊聊高併發系統之降級特技
- 接招吧!最強 “高併發” 系統設計 46 連問,分分鐘秒殺一眾面試者!面試
- 構建高併發&高可用&安全的IT系統-高併發部分
- 商城秒殺系統總結(Java)Java
- Java之併發三問題Java
- 分享一門go最強實戰課程《全流程開發 GO實戰電商網站高併發秒殺系統》——推薦分享Go網站
- Java高併發之CyclicBarrier簡介Java
- Redis+Lua解決高併發場景搶購秒殺問題Redis
- 分享一個整合SSM框架的高併發和商品秒殺專案SSM框架
- 搭建高併發、高可用的系統
- 模擬web高併發Web
- 遊戲陪玩app開發,高併發系統如何設計?遊戲APP