在前面幾節中已經完成了service層和dao層,到目前爲止只是後端的設計與編寫,這節就要設計到前端的設計了。下面開始總結下這個秒殺業務前端有哪些要點:javascript
1. 前端頁面的流程css
首先是列表頁,點某個商品進入詳情頁,在這裏會有個判斷是否用戶已登陸的邏輯。若是已登陸則進入詳情頁展現邏輯,若是用戶未登陸則讓用戶登陸,將用戶的信息寫入cookie後再進入展現邏輯。對於詳情頁,它首先拿到系統的當前時間,將其與當前秒殺單的秒殺開始時間和秒殺結束時間做比較。若大於秒殺結束結束時間則顯示秒殺已結束,若小於秒殺開始時間則顯示秒殺未開始和倒計時。若在秒殺時間以內或者倒計時結束則顯示商品秒殺地址,用戶點擊,執行秒殺,返回執行結果。html
2. Restful接口設計前端
具體什麼是Restful呢?他是一種url設計規範,一種資源狀態和資源狀態的轉移,關於Restful知識的具體講解能夠看這篇博文:我所理解的RESTful Web APIjava
業務的秒殺API設計以下:node
Get/seckill/list 秒殺列表jquery
Get/seckill/{id}/detail 詳情頁web
Get/seckill/time/now 系統時間ajax
Post/seckill/{id}/exposer 暴露秒殺spring
Post/seckill/{id}/execution 執行秒殺
其中:Get表示查詢操做,Post表示添加/修改操做, Put表示修改操做,DELETE表示刪除操做。經過不一樣的提交方式來表示它的動做,然後面的url設計遵循的規範是:/模塊/資源/{標識}/集合1/...
3. SpringMVC框架
這個應該是這個案例的重點知識點了吧,前面介紹了Mybatis和Spring的整合,如今來介紹Spring如何整合SpringMVC。首先是在web.xml中註冊SpringMVC的核心控制器DispatcherServlet,並配置DispatcherServlet須要加載的配置文件。
web.xml
1 <web-app xmlns="http://java.sun.com/xml/ns/javaee" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 4 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 5 version="3.0" 6 metadata-complete="true"> 7 <!--修改servlet版本爲3.0--> 8 9 <!-- 配置DispatcherServlet--> 10 <servlet> 11 <servlet-name>seckill-servlet</servlet-name> 12 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 13 <!--配置springMVC須要加載的配置文件 14 spring-dao.xml, spring-service.xml, spring-web.xml 15 框架整合順序:mybatis->spring->springMVC 16 --> 17 <init-param> 18 <param-name>contextConfigLocation</param-name> 19 <param-value>classpath:spring/spring-*.xml</param-value> 20 </init-param> 21 </servlet> 22 23 <servlet-mapping> 24 <servlet-name>seckill-servlet</servlet-name> 25 <!--默認匹配全部的請求--> 26 <url-pattern>/</url-pattern> 27 </servlet-mapping> 28 29 </web-app>
能夠看到SpringMVC須要加載的文件分別是Spring的三個配置文件,spring-dao.xml,spring-service.xml,spring-web.xml。這三個配置文件分別配置了不一樣層上的東西,dao層,service層和web層。如今尚未spring-web.xml這個文件,在resource目錄下的spring目錄下新建這個文件用來配置web層的有關配置。
spring-web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-3.0.xsd 10 http://www.springframework.org/schema/mvc 11 http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 12 <!--配置springMVC --> 13 <!--1:開啓springMVC註解模式--> 14 <!--簡化配置: 15 (1)自動註冊DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter 16 (2)提供一系列:數據綁定,數字和日期format @NumberFormat,@DataTimeFormat, 17 xml,json默認讀寫支持--> 18 <mvc:annotation-driven/> 19 20 <!-- 2:servlet-mapping 映射路勁:"/" --> 21 <!-- 靜態資源默認servlet配置 22 (1).加入對靜態資源的處理:js,gif,png 23 (2).容許使用"/"作總體映射 24 --> 25 <mvc:default-servlet-handler/> 26 27 <!--3:配置jsp顯示ViewResolver--> 28 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 29 <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 30 <property name="prefix" value="/WEB-INF/jsp/"/> 31 <property name="suffix" value=".jsp"/> 32 </bean> 33 34 <!--4:掃描web相關的bean--> 35 <context:component-scan base-package="org.seckill.web"/> 36 </beans>
SpringMVC框架配置完成以後便開始編寫業務的Controller,分發調度請求並調用Service層中相應的service來處理這些請求並返回模型和視圖。在org.seckill目錄下新建文件目錄web用來存放Controller。新建SeckillController,負責對於Seckill這個資源模塊的請求調度,代碼以下:
SeckillController
1 package org.seckill.web; 2 3 import org.seckill.dao.SeckillResult; 4 import org.seckill.dto.Exposer; 5 import org.seckill.dto.SeckillExecution; 6 import org.seckill.entity.Seckill; 7 import org.seckill.enums.SeckillStatEnum; 8 import org.seckill.exception.RepeatKillException; 9 import org.seckill.exception.SeckillCloseException; 10 import org.seckill.exception.SeckillException; 11 import org.seckill.service.SeckillService; 12 import org.slf4j.Logger; 13 import org.slf4j.LoggerFactory; 14 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.stereotype.Controller; 16 import org.springframework.ui.Model; 17 import org.springframework.web.bind.annotation.*; 18 19 import java.util.Date; 20 import java.util.List; 21 22 /** 23 * Created by yuxue on 2016/10/17. 24 */ 25 @Controller 26 @RequestMapping("/seckill")// url:/模塊/資源/{id}/細分 / seckill/list 27 public class SeckillController { 28 private final Logger logger= LoggerFactory.getLogger(this.getClass()); 29 30 @Autowired 31 private SeckillService seckillService; 32 33 @RequestMapping(value="/list", method = RequestMethod.GET ) 34 public String list(Model model) { 35 //獲取列表頁 36 List<Seckill> list=seckillService.getSeckillList(); 37 model.addAttribute("list",list); 38 //list.jsp+model=ModelAndView 39 return "list"; 40 } 41 42 @RequestMapping(value = "/{seckillId}/detail",method=RequestMethod.GET) 43 public String detail(@PathVariable("seckillId") Long seckillId,Model model){ 44 if(seckillId==null){ 45 return "redirect:/seckill/list";//請求重定向 46 } 47 Seckill seckill=seckillService.getById(seckillId); 48 if(seckill==null){ 49 return "forward:/seckill/list"; //請求轉發 50 } 51 model.addAttribute("seckill",seckill); 52 return "detail"; 53 } 54 55 //ajax json 56 /* 57 @ResponseBody表示該方法的返回結果直接寫入HTTP response body中 58 通常在異步獲取數據時使用,在使用@RequestMapping後,返回值一般解析爲跳轉路徑, 59 加上@ResponseBody後返回結果不會被解析爲跳轉路徑,而是直接寫入HTTP response body中。 61 */ 62 @RequestMapping(value = "/{seckillId}/exposer",method=RequestMethod.GET, 63 produces={"application/json;charset=UTF-8"}) 64 @ResponseBody 65 public SeckillResult<Exposer> exposer(@PathVariable Long seckillId){ 66 SeckillResult<Exposer> result; 67 try{ 68 Exposer exposer=seckillService.exportSeckillUrl(seckillId); 69 result=new SeckillResult<Exposer>(true,exposer); 70 }catch(Exception e){ 71 logger.error(e.getMessage(),e); 72 result=new SeckillResult<Exposer>(false,e.getMessage()); 73 } 74 return result; 75 } 76 77 /* 78 從客戶端的Cookie中得到用戶手機號碼,將required屬性設置爲false,不然若瀏覽器的cookie中未保存 79 手機號碼的話Spring會報錯,這裏設置爲false,將對用戶手機號的驗證寫在咱們本身的判斷邏輯中 80 */ 81 @RequestMapping(value="/{seckillId}/{md5}/execution",method=RequestMethod.POST, 82 produces = "application/json;charset=UTF-8") 83 @ResponseBody 84 public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId") Long seckillId, 85 @PathVariable("md5") String md5, 86 @CookieValue(value="killphone",required=false)Long phone){ 87 if(phone==null){ 88 return new SeckillResult<SeckillExecution>(false,"未註冊"); 89 } 90 SeckillResult<SeckillExecution> result; 91 try {
94 SeckillExecution execution = seckillService.executeSeckill(seckillId, phone, md5); 95 return new SeckillResult<SeckillExecution>(true,execution); 96 }catch (RepeatKillException e){ 97 //logger.error(e.getMessage(),e);沒有必要打印日誌,由於是系統容許的異常 98 SeckillExecution seckillExecution=new SeckillExecution(seckillId, SeckillStatEnum.REPEAT_KILL); 99 return new SeckillResult<SeckillExecution>(false,seckillExecution); 100 }catch(SeckillCloseException e){ 101 SeckillExecution seckillExecution=new SeckillExecution(seckillId, SeckillStatEnum.END); 102 return new SeckillResult<SeckillExecution>(false,seckillExecution); 103 }catch (Exception e){ 104 logger.error(e.getMessage(),e); 105 SeckillExecution seckillExecution=new SeckillExecution(seckillId, SeckillStatEnum.INNER_ERROR); 106 return new SeckillResult<SeckillExecution>(false,seckillExecution); 107 } 108 } 109 110 @RequestMapping(value="/time/now", method = RequestMethod.GET)
public SeckillResult<Long> time(){ 113 Date now=new Date(); 114 return new SeckillResult<Long>(true,now.getTime()); 115 } 116 117 }
分析:
1.return "redirect:/seckill/list"和return "forward:/seckill/list" 分別實現了請求重定向和請求轉發。
2.關於註解@ResponseBody和@RequestMapping中的produces
1)@ResponseBody
該註解用於將Controller的方法返回的對象,經過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區。即咱們的Controller執行後不須要跳轉到別的什麼頁面,只須要返回某種格式(json,xml)的數據時候就能夠用使用這個註解啦!而@RequestMapping中的produces="application/json;charset=UTF-8"便指定了返回的內容類型爲json,編碼格式爲UTF-8。具體解釋見這篇博文:Spring MVC之@RequestMapping 詳解以及這篇@RequestBody, @ResponseBody 註解詳解。
3.@CookieValue註解: 從Http請求頭中的Cookie提取指定的某個Cookie,這裏required=false表示若是沒有這個cookie的話不讓SpringMVC報錯,而是在咱們本身寫的邏輯中處理。
4.public SeckillResult<SeckillExecution> execute() 這個方法中用到了個泛型SeckillResult<T>,這個類也是個數據傳輸對象,在dto包下新建類SeckillResult
SeckillResult
1 package org.seckill.dao; 2 3 /** 4 * Created by yuxue on 2016/10/18. 5 */ 6 //全部ajax請求返回類型,封裝json結果 7 public class SeckillResult<T> { 8 9 private boolean success; 10 11 private T data; 12 13 private String error; 14 15 public SeckillResult(boolean success, T data) { 16 this.success = success; 17 this.data = data; 18 } 19 20 21 public SeckillResult(boolean success, String error) { 22 this.success = success; 23 this.error = error; 24 } 25 26 public boolean isSuccess() { 27 return success; 28 } 29 30 public void setSuccess(boolean success) { 31 this.success = success; 32 } 33 34 public T getData() { 35 return data; 36 } 37 38 public void setData(T data) { 39 this.data = data; 40 } 41 42 public String getError() { 43 return error; 44 } 45 46 public void setError(String error) { 47 this.error = error; 48 } 49 }
分析:
一開始我不明白爲何要用這個類,打完代碼後豁然醒悟:這個類其實封裝了全部的請求返回類型!!!對於與Seckill有關的業務SeckillService,它裏面有多個方法,一些方法要返回給前端數據,這裏的問題即是數據類型可能會有不少種,好比暴露秒殺地址方法返回的是Exposer對象而execute方法返回的是SeckillExecution, 那麼便用SeckillResult這個泛型來統一封裝來自SeckillService的返回類型。前端要用到後端傳來的數據時直接就從這裏面去取相應的類型就好。這裏是個很重要的設計思路:對於上層只提供統一的一致的接口,而底層複雜的細節則由這個接口封裝起來,這些是我我的的理解,不知道對不對。
4. 基於Bootstrap開發頁面
終於到了開發前端頁面的時候了,老實說的話前端真的是否是很明白啊!感受前端要記的東西太多了,各類雜七雜八的東西。這個案例是基於Bootstrap這個框架來開發前端頁面的,Bootstrap其實幫你寫好了前端控件的樣式,拿過來直接用就能夠開發出顯示效果不錯的前端頁面了,本身不須要去寫css樣式。總共要寫的頁面有兩個:list.jsp秒殺商品列表頁和detail.jsp秒殺上屏詳情頁。
首先是編寫list.jsp頁面,爲了使用Bootstrap框架,這個業務採用的是在線引入的方式因此必需要聯網,總共要引入的文件有3個:Bootstrap的樣式css文件,依賴的jQuery文件和核心javascript文件。關於Bootstrap的安裝使用方式能夠去Bootstrap中文網去查看一下。在webapp/WEB-INF目錄下新建jsp目錄來存放咱們寫的jsp文件
list.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <%--引入jstl--%> 3 <%@include file="common/tag.jsp"%> 4 <!DOCTYPE html> 5 <head> 6 <title>秒殺列表頁</title> 7 <%--jsp頁面靜態包含--%> 8 <%@include file="common/head.jsp"%> 9 </head> 10 <body> 11 <%--頁面顯示部分--%> 12 <div class="container"> 13 <div class="panel panel-default"> 14 <div clas="panel-heading text-center"> 15 <h2>秒殺列表</h2> 16 </div> 17 <div class="panel-body"> 18 <table class="table table-hover"> 19 <thead> 20 <tr> 21 <th>名稱</th> 22 <th>庫存</th> 23 <th>開始時間</th> 24 <th>結束時間</th> 25 <th>建立時間</th> 26 <th>詳情頁</th> 27 </tr> 28 </thead> 29 <tbody> 30 <c:forEach var="sk" items="${list}"> 31 <tr> 32 <td>${sk.name}</td> 33 <td>${sk.number}</td> 34 <td> 35 <fmt:formatDate value="${sk.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/> 36 </td> 37 <td> 38 <fmt:formatDate value="${sk.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/> 39 </td> 40 <td> 41 <fmt:formatDate value="${sk.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/> 42 </td> 43 <td> 44 <%--target="_blank" 使得點擊超連接後彈出的是新的頁面--%> 45 <a class="btn btn-info" href="/seckill/${sk.seckillId}/detail" target="_blank">link</a> 46 </td> 47 </tr> 48 </c:forEach> 49 </tbody> 50 </table> 51 </div> 52 </div> 53 </div> 54 </body> 55 <!-- jQuery文件。務必在bootstrap.min.js 以前引入 --> 56 <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script> 57 <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> 58 <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> 59 </html>
這裏將頁面要用到的jstl標籤單獨放到tag.jsp中
1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 2 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
還有引入的head.jsp,做用是兼容平板,手機的頁面顯示,這也是bootstrap做爲響應式佈局的特色
1 <meta charset="utf-8"> 2 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 3 <meta name="viewport" content="width=device-width, initial-scale=1"> 4 <!-- Bootstrap --> 5 <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
在webapp/WEB-INF目錄下新建詳情頁面detail.jsp
detail.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <!DOCTYPE html> 3 <html lang="zh-cn"> 4 <head> 5 <title>秒殺詳情頁</title> 6 <%--jsp頁面靜態包含--%> 7 <%@include file="common/head.jsp"%> 8 </head> 9 <body> 10 <div class="container"> 11 <div class="panel panel-default text-center"> 12 <div class="pannel-heading"> 13 <h1>${seckill.name}</h1> 14 </div> 15 <div class="panel-body"> 16 <h2 class="text-danger"> 17 <%--顯示time圖標--%> 18 <span class="glyphicon glyphicon-time"></span> 19 <%--展現倒計時--%> 20 <span class="glyphicon" id="seckill-box"></span> 21 </h2> 22 </div> 23 </div> 24 </div> 25 <%--登陸彈出層,輸出電話號碼--%> 26 <div id="killPhoneModal" class="modal fade"> 27 <div class="modal-dialog"> 28 <div class="modal-content"> 29 <div class="modal-header"> 30 <h3 class="modal-title text-center"> 31 <span class="glyphicon glyphicon-phone"></span> 32 </h3> 33 </div> 34 <div class="modal-body"> 35 <div class="row"> 36 <div class="col-xs-8 col-xs-offset-2"> 37 <input type="text" name="killphone" id="killPhoneKey" 38 placeholder="填手機號^o^" class="form-control" > 39 </div> 40 </div> 41 </div> 42 43 <div class="modal-footer"> 44 <!--驗證信息--> 45 <span id="killPhoneMessage" class="glyphicon"></span> 46 <button type="button" id="killPhoneBtn" class="btn btn-success"> 47 <span class="glyphicon glyphicon-phone"></span> 48 </button> 49 </div> 50 </div> 51 </div> 52 </div> 53 </body> 54 <!-- jQuery文件。務必在bootstrap.min.js 以前引入 --> 55 <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script> 56 <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> 57 <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> 58 59 <%--使用CDN獲取公共js http://www.bootcdn.cn/ --%> 60 <%--jQuery cookie操做插件--%> 61 <script src="http://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> 62 <%--jQuery countdown倒計時插件--%> 63 <script src="http://cdn.bootcss.com/jquery.countdown/2.1.0/jquery.countdown.min.js"></script> 64 <%--開始編寫交互邏輯--%> 65 <script src="/resources/script/seckill.js" type="text/javascript"></script><%--老師說這裏有個小坑,結尾必須寫</script>這種形式,不能是/>,不然下面的js不會加載--%> 66 <script type="text/javascript"> 67 $(function () { 68 //使用El表達式傳入參數 69 seckill.detail.init({ 70 seckillId:${seckill.seckillId}, 71 startTime:${seckill.startTime.time}, 72 endTime:${seckill.endTime.time} 73 }); 74 }); 75 </script> 76 </html>
1.開啓tomacat服務器,測試網頁可否正常訪問,跳轉。這裏出現了個小問題:list.jsp中的跳轉的detail.jsp的超連接<a class="btn btn-info" href="/seckill/${sk.seckillId}/detail" target="_blank">link</a>我把其中的detail寫成了detail.jsp結果Controller不能攔截到路徑,查了下Controller中RequestMapping的配置路徑爲@RequestMapping(value = "/{seckillId}/detail",method=RequestMethod.GET),明白了,原來這個路徑要「如出一轍」,我以前認爲只要在SpringMVC的DispatcherServlet裏配置攔截路徑爲全部路徑的話,那麼就是攔截全部的html和jsp,因此後綴名什麼的應該不重要,只要名字相同就可......傻叉了一回....,這個細節之後要注意。
2.關於<div id="killPhoneModal" class="modal fade">,這是個Bootstrap中的模態框插件,模態框(Modal)是覆蓋在父窗體上的子窗體。一般,目的是顯示來自一個單獨的源的內容,能夠在不離開父窗體的狀況下有一些互動。子窗體可提供信息、交互等。在模態框中須要注意兩點:第一是 .modal,用來把 <div> 的內容識別爲模態框。第二是 .fade class。當模態框被切換時,它會引發內容淡入淡出。具體的使用見:http://www.runoob.com/bootstrap/bootstrap-modal-plugin.html
在webapp/resources目錄下新建script目錄,用來存放咱們寫的的頁面交互腳本。新建seckill.js
1 //存放主要交互邏輯js代碼 2 //javascript 模塊化 3 var seckill={ 4 //封裝秒殺相關ajax的url 5 URL:{ 6 now:function () { 7 return '/seckill/time/now'; 8 }, 9 exposer:function (seckillId) { 10 return '/seckill/'+seckillId+'/exposer'; 11 }, 12 execution:function(seckillId,md5){ 13 return 'seckill/'+seckillId+'/'+md5+'/execution'; 14 } 15 }, 16 handleSeckillkill:function (seckillId,node) { 17 //處理秒殺邏輯,控制現實邏輯,執行秒殺 18 node.hide().html('<button class="btn btn-primary btn-lg" id="killBtn">開始秒殺</button>'); 19 $.post(seckill.URL.exposer(seckillId),{},function (result) { 20 //在回調函數中,執行交互流程 21 if(result&&result['success']){ 22 var exposer=result['data']; 23 if(exposer['exposed']){ 24 //開啓秒殺 25 var md5=exposer['md5']; 26 var killUrl=seckill.URL.execution(seckillId,md5); 27 console.log("killUrl:"+killUrl); 28 //綁定一次點擊事件 29 $('#killBtn').one('click',function () { 30 //執行秒殺請求 31 //1.先禁用按鈕 32 $(this).addClass('disabled'); 33 //2.發送秒殺請求執行秒殺 34 $.post(killUrl,{},function (result) { 35 if(result&&result['success']){ 36 var killResult=result['data']; 37 var state=killResult['data']; 38 var stateInfo=killResult['stateInfo']; 39 //3.顯示秒殺結果 40 node.html('<span class="label label-success">'+stateInfo+'</span>'); 41 } 42 }); 43 }); 44 node.show(); 45 }else{ 46 //未開啓秒殺 47 var now=exposer['now']; 48 var start=exposer['start']; 49 var end=exposer['end']; 50 //從新計算計時邏輯 51 seckillId.countdown(seckillId,now,start,end); 52 } 53 }else{ 54 console.log('result:'+result); 55 } 56 }); 57 }, 58 //驗證手機號 59 validatePhone: function (phone) { 60 if (phone && phone.length == 11 && !isNaN(phone)) { 61 return true; 62 } else { 63 return false; 64 } 65 }, 66 countdown:function (seckillId,nowTime,startTime,endTime) { 67 var seckillBox=$('#seckill-box'); 68 //時間判斷 69 if(nowTime>endTime){ 70 //秒殺結束 71 seckillBox.html('秒殺結束!'); 72 }else if(nowTime<startTime){ 73 //秒殺未開始,計時事件綁定 74 var killTime=new Date(startTime+1000); 75 seckillBox.countdown(killTime,function(event){ 76 //時間格式 77 var format=event.strftime('秒殺倒計時:%D天 %H時 %M分 %S秒'); 78 seckillBox.html(format); 79 /*時間完成後回調事件*/ 80 }).on('finish.countdown',function () { 81 //獲取秒殺地址,控制現實邏輯,執行秒殺 82 seckill.handleSeckillkill(seckillId,seckillBox); 83 }); 84 }else{ 85 //秒殺開始 86 seckill.handleSeckillkill(seckillId,seckillBox); 87 } 88 }, 89 //詳情秒殺頁邏輯 90 detail: { 91 //詳情頁初始化 92 init: function (params) { 93 //手機驗證和登錄,計時交互 94 //規劃咱們的交互流程 95 //在cookie中查找手機號 96 var killPhone = $.cookie('killPhone'); 97 var startTime = params['startTime']; 98 var endTime = params['endTime']; 99 var seckillId = params['seckillId']; 100 //驗證手機號碼 101 if (!seckill.validatePhone(killPhone)){ 102 //綁定phone 103 //控制輸出 104 var killPhoneModal=$('#killPhoneModal'); 105 //顯示彈出層 106 killPhoneModal.modal({ 107 show:true,//顯示彈出層 108 backdrop:'static',//禁止位置關閉 109 keyboard:false//關閉鍵盤事件 110 }); 111 $('#killPhoneBtn').click(function(){ 112 var inputPhone=$('#killPhoneKey').val(); 113 console.log('inputPhone='+inputPhone);//TODO 114 if(seckill.validatePhone(inputPhone)){ 115 //電話寫入cookie 116 $.cookie('killPhone',inputPhone,{expires:7,path:'/seckill'}); 117 //刷新頁面 118 window.location.reload(); 119 }else{ 120 $('#killPhoneMessage').hide().html('<label class="label label-danger">手機號錯誤!</label>').show(300); 121 } 122 }); 123 } 124 //已經登陸 125 var startTime = params['startTime']; 126 var endTime = params['endTime']; 127 var seckillId = params['seckillId']; 128 $.get(seckill.URL.now(),{},function(result){ 129 if(result&&result['success']){ 130 var nowTime=result['data']; 131 //時間判斷,計時交互 132 seckill.countdown(seckillId,nowTime,startTime,endTime); 133 }else{ 134 console.log('result:'+result); 135 } 136 } 137 ); 138 } 139 } 140 }
仍是吐槽一句:前端真心不熟啊。。。。js,jQuery什麼的,要學的東西還有不少啊。
到如今前端的編寫算是完成了,下一節講的是怎麼優化這個業務讓其能承受更多的併發量,呼呼呼,寫到這裏不容易啊,哪裏搞錯了的望指正,謝謝。