前言

该篇主要实现客户端和服务的交互。在第一篇概况里我已经贴出了业务场景的交互图片。 客户端交互主要放在seckill.js里来实现。页面展现基于jsp+jstl来实现。

准备工作

1、配置web.xml。web.xml里配置springmvc前端控制器时需要把spring托管的3个xml全部加载。分别是spring-dao.xml、spring-service.xml、spring-web.xml。

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</init-param>
</servlet> <servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> </web-app>

2、配置spring-web.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--1、配置spring mvc -->
<mvc:annotation-driven/> <!--2、静态资源默认配置-->
<mvc:default-servlet-handler/> <!--3、配置视图-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--4、扫描web相关controller-->
<context:component-scan base-package="com.seckill.web"/>
</beans>

秒杀接口

@Controller
@RequestMapping("/seckill")
public class SeckillController { @Autowired
SeckillService seckillService; @RequestMapping("/list")
public ModelAndView list(){ ModelAndView mav=new ModelAndView("list");
List<Seckill> list = seckillService.getSeckillList();
mav.addObject("list",list); return mav;
} /**
* 返回值如果是ModelAndView时怎么控制重定向和转发呢
* **/
@RequestMapping(value="/{seckillId}/detail/",method = RequestMethod.GET)
public ModelAndView detail(@PathVariable("seckillId")Long seckillId){ ModelAndView mav=new ModelAndView("detail");
Seckill seckill=seckillService.getById(seckillId);
mav.addObject("seckill",seckill);
return mav; } //处理ajax请求返回json
@RequestMapping(value="/{seckillId}/exposer",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
@ResponseBody
public SeckillResult<Exposer> exposer(@PathVariable("seckillId")Long seckillId){ SeckillResult<Exposer> result=null;
try{
Exposer exposer=seckillService.exposeSeckillUrl(seckillId);
result=new SeckillResult<Exposer>(true,exposer); }catch (Exception e){
result=new SeckillResult<Exposer>(false,e.getMessage());
} return result; } @RequestMapping(value="/{seckillId}/{md5}/execute",method = RequestMethod.POST,produces = {"application/json;charset=UTF-8"})
@ResponseBody
public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId")Long seckillId,
@PathVariable("md5")String md5,
@CookieValue(value="phone",required=false)Long phone){ if(phone==null){
return new SeckillResult<SeckillExecution>(false,"手机号未注册");
} SeckillResult<SeckillExecution> result=null; try{ SeckillExecution execution=seckillService.executeSeckill(seckillId,phone,md5);
result=new SeckillResult<SeckillExecution>(true,execution); }catch(RepeatKillException e){ SeckillExecution execution=new SeckillExecution(seckillId,-1,"重复秒杀");
result=new SeckillResult<SeckillExecution>(true,execution); }catch(SeckillCloseException e){ SeckillExecution execution=new SeckillExecution(seckillId,0,"秒杀结束");
result=new SeckillResult<SeckillExecution>(true,execution); }catch (Exception e){ SeckillExecution execution=new SeckillExecution(seckillId,-2,"系统异常");
result=new SeckillResult<SeckillExecution>(true,execution); } return result; } //返回系统时间
@RequestMapping(value="/time/now/",method = RequestMethod.GET)
@ResponseBody
public SeckillResult<Long> time(){
Date d=new Date(); return new SeckillResult<Long>(true,d.getTime());
}
}

  

客户端实现

1、秒杀商品列表页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@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" %> <html>
<head>
<title>秒杀列表页</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
<!-- 可选的Bootstrap主题文件(一般不使用) -->
<link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap-theme.min.css" rel="stylesheet"> <!-- HTML5 Shim 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]--> </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>
<th>名称</th>
<th>库存</th>
<th>开始时间</th>
<th>结束时间</th>
<th>创建时间</th>
<th>秒杀</th>
</tr>
</thead>
<tbody>
<c:forEach var="item" items="${list}">
<tr>
<td>${item.name}</td>
<td>${item.number}</td>
<td>
<fmt:formatDate value="${item.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
</td>
<td>
<fmt:formatDate value="${item.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
</td>
<td>
<fmt:formatDate value="${item.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
</td>
<td>
<a class="btn btn-info" href="/seckill/${item.seckillId}/detail/">秒杀</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div> </body>
</html>

2、秒杀商品详情页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@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" %> <html>
<head>
<title>秒杀详情</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
<!-- 可选的Bootstrap主题文件(一般不使用) -->
<link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap-theme.min.css" rel="stylesheet">
<!-- HTML5 Shim 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="panel panel-default text-center">
<div class="pannel-heading">
<h1>${seckill.name}</h1>
</div> <div class="panel-body">
<h2 class="text-danger">
<%--显示time图标--%>
<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 class="modal-body">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" name="killPhone" id="killPhoneKey"
placeholder="填写手机号^o^" 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>
Submit
</button>
</div> </div>
</div> </div> <script src="http://apps.bdimg.com/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="http://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="http://cdn.bootcss.com/jquery.countdown/2.1.0/jquery.countdown.min.js"></script>
<script src="/resources/scripts/seckill.js?201806242323235"></script>
<script type="text/javascript"> $(function(){ seckill.detail.init({
seckillId:${seckill.seckillId},
startTime:${seckill.startTime.time}, //取毫秒数
endTime:${seckill.endTime.time} }) }) </script>
</body>
</html>

  

3、秒杀业务逻辑seckill.js

var seckill={

    /**秒杀相关url**/
URL:{
now:'/seckill/time/now/'
}, /**验证手机号**/
validatePhone:function(phone){
if(phone && phone.length==11 && !isNaN(phone)){
return true;
} return false; }, /**倒计时**/
countdown:function(seckillId,nowTime,startTime,endTime){
console.log(seckillId+","+nowTime+","+startTime+","+endTime); var seckillBox=$("#seckill-box");
if(nowTime>endTime){
seckillBox.html("秒杀已经结束");
}else if(nowTime<startTime){
//秒杀还没开始,显示倒计时
var killTime = new Date(startTime + 1000);
seckillBox.countdown(killTime,function(e){
var format = e.strftime('秒杀倒计时: %D天 %H时 %M分 %S秒 ');
seckillBox.html(format);
}).on("finish.countdown",function(){
console.log("倒计时结束,开始秒杀");
seckill.seckill(seckillId,seckillBox);
});
}else{
//秒杀开始
seckill.seckill(seckillId,seckillBox);
}
}, detail:{
/**初始化参数**/
init:function(params){
var phone=$.cookie('phone'); //验证手机号
if(!seckill.validatePhone(phone)){
var killphoneModal=$("#killPhoneModal");
//如果有取到cookie里的手机,则弹出模拟登陆
killphoneModal.modal({
show: true,//显示弹出层
backdrop: 'static',//禁止位置关闭
keyboard: false//关闭键盘事件
}); $("#killPhoneBtn").click(function(){ var inputphone=$("#killPhoneKey").val();
console.log('inputphone:'+inputphone);
if(seckill.validatePhone(inputphone)){
$.cookie("phone",inputphone,{expires:7,path:'/seckill'});
//验证通过,刷新页面
window.location.reload();
}else{
$('#killPhoneMessage').hide().html('<label class="label label-danger">手机号错误!</label>').show(300);
}
}) } var seckillId=params["seckillId"];
var startTime=params["startTime"];
var endTime=params["endTime"];
$.get(seckill.URL.now,{},function(result){
if(result && result["success"]){
var nowTime=result["data"];
seckill.countdown(seckillId,nowTime,startTime,endTime);
}else{
console.log(result);
}
}) }
}, /**执行秒杀**/
seckill:function(seckillId,node){ //获取秒杀地址、控制node节点显示,执行秒杀
node.hide().html("<button id='killBtn' class='btn btn-primary btn-lg'>开始秒杀</button>") $.get('/seckill/'+seckillId+'/exposer',{},function(result){ if(result && result["success"]){
//在回调函数中执行秒杀操作
var exposer=result["data"];
if(exposer["exposed"]){
//秒杀已开始
var md5=exposer["md5"];
var killUrl='/seckill/'+seckillId+'/'+md5+'/execute';
console.log(killUrl); $("#killBtn").one('click',function(){
//1、禁用秒杀按钮
$(this).addClass('disabled');
//2、执行秒杀操作
$.post(killUrl,{},function(result){
if(result && result["success"]){
var killResult=result["data"];
var state=killResult["state"];
var stateInfo=killResult["stateInfo"]; node.html("<span class='label label-success'>"+stateInfo+"</span>"); }
}) }); node.show();
}else{
//秒杀未开始, 防止浏览器和服务器出现时间差,再次执行倒数计时
var now = exposer['now'];
var start = exposer['start'];
var end = exposer['end'];
seckill.countdown(seckillId, now, start, end);
} }else{
console.log('result:'+result); //没有拿到秒杀地址
} }) } }

  

总结

秒杀相关业务逻辑主要是根据秒杀商品的开始时间、结束时间以及客户端的当前时间来判断秒杀是否开始、是否结束。未开始时调用jquery.countdown来实现倒计时效果。倒计时插件会维护一个倒计时事件,时间结束时直接会调用秒杀接口来实现秒杀业务。

基于SpringMVC+Spring+MyBatis实现秒杀系统【客户端交互】的更多相关文章

  1. 基于SpringMVC+Spring+MyBatis实现秒杀系统【概况】

    前言 本教程使用SpringMVC+Spring+MyBatis+MySQL实现一个秒杀系统.教程素材来自慕课网视频教程[https://www.imooc.com/learn/631].有感兴趣的可 ...

  2. 基于SpringMVC+Spring+MyBatis实现秒杀系统【业务逻辑】

    前言 该篇主要实现秒杀业务层,秒杀业务逻辑里主要包括暴露秒杀接口地址.实现秒杀业务逻辑.同时声明了三个业务类:Exposer.SeckillExecution.SeckillResult. Expos ...

  3. 基于SpringMVC+Spring+MyBatis实现秒杀系统【数据库接口】

    前言 该篇教程主要关注MyBatis实现底层的接口,把MyBatis交给Spring来托管.数据库连接池用的c3p0.数据库用的MySQL.主要有2个大类:秒杀商品的查询.秒杀明细的插入. 准备工作 ...

  4. 手把手教你使用VUE+SpringMVC+Spring+Mybatis+Maven构建属于你自己的电商系统之vue后台前端框架搭建——猿实战01

            猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...

  5. 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十二天】(系统架构讲解、nginx)

    https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...

  6. 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十天】(单点登录系统实现)

    https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...

  7. Idea SpringMVC+Spring+MyBatis+Maven调整【转】

    Idea SpringMVC+Spring+MyBatis+Maven整合   创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...

  8. SpringMVC+Spring+MyBatis+Maven调整【转】

    Idea SpringMVC+Spring+MyBatis+Maven整合   创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...

  9. 单工程搭建springmvc+spring+mybatis(maven,idea)

    单工程搭建springmvc+spring+mybatis(maven,idea) 1.pom.xml <properties> <project.build.sourceEncod ...

随机推荐

  1. 用chrome模拟微信浏览器访问页面

    有的网页通过限制 user agent  来达到禁止在微信浏览器以外的地方访问,我们通过chrome修改user agent即可破解. CHROME浏览器,进入开发者模式 切换到手机浏览模板 打开 N ...

  2. python_flask 基础巩固(自定义URL转换器)

    自定义URL转换器(在BaseConverter类外定义)from werkzeug.routing import BaseConverter定义类继承BaseConverter 实现类app.url ...

  3. 计算机网络六:无线局域网、IEEE 802.11、WIFI和蓝牙

    无线局域网.IEEE 802.11.WIFI和蓝牙 ㈠无线局域网 1.定义       无线局域网络(Wireless Local Area Networks),简称WLAN.它是相当便利的数据传输系 ...

  4. 个人对于angularjs依赖注入的理解

    依赖注入(Dependency Injection,DI),作者认为本文中所有名词性的"依赖" 都可以理解为 "需要使用的资源". 对象或者函数只有以下3种获取 ...

  5. CentOS7 安装配置rsync

    centos7自带rsync,今天简单记录下. rsync安装配置步骤 服务器端: 1.修改默认配置文件/etc/rsyncd.conf,该成如下: # /etc/rsyncd: configurat ...

  6. OC基础成员变量、属性变量、实例方法与类方法

    首先,为什么我们要定义一个新类呢?按照我的理解,就是为了抽象出来一个新的东西(也就是类),用来存储更多的数据变量和方法,一切类都直接或间接继承与NSObject. 在类的头文件里我们可以定义成员变量. ...

  7. Exp4 恶意代码分析 ——20164325王晓蕊

    1.实践目标 监控你自己系统的运行状态,看有没有可疑的程序在运行. 分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用原生指令或sysinternals,systracer套件 ...

  8. PSR-PHP开发规范(本文版权归作者:luluyrt@163.com)

    遵循PSR-4的自动加载 一.简介 首先这里要了解PSR,Proposing a Standards Recommendation(提出标准建议)的缩写,就是一种PHP开发规范,让我们研发出来的代码更 ...

  9. HBase体系架构和集群安装

    大家好,今天分享的是HBase体系架构和HBase集群安装.承接上两篇文章<HBase简介>和<HBase数据模型>,点击回顾这2篇文章,有助于更好地理解本文. 一.HBase ...

  10. JavaScript中常见的10个BUG及其修复方法

    如今网站几乎100%使用JavaScript.JavaScript看上去是一门十分简单的语言,然而事实并不如此.它有很多容易被弄错的细节,一不注意就导致BUG. 1. 错误的对this进行引用 在闭包 ...