基于SpringMVC+Spring+MyBatis实现秒杀系统【客户端交互】
前言
该篇主要实现客户端和服务的交互。在第一篇概况里我已经贴出了业务场景的交互图片。 客户端交互主要放在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实现秒杀系统【客户端交互】的更多相关文章
- 基于SpringMVC+Spring+MyBatis实现秒杀系统【概况】
前言 本教程使用SpringMVC+Spring+MyBatis+MySQL实现一个秒杀系统.教程素材来自慕课网视频教程[https://www.imooc.com/learn/631].有感兴趣的可 ...
- 基于SpringMVC+Spring+MyBatis实现秒杀系统【业务逻辑】
前言 该篇主要实现秒杀业务层,秒杀业务逻辑里主要包括暴露秒杀接口地址.实现秒杀业务逻辑.同时声明了三个业务类:Exposer.SeckillExecution.SeckillResult. Expos ...
- 基于SpringMVC+Spring+MyBatis实现秒杀系统【数据库接口】
前言 该篇教程主要关注MyBatis实现底层的接口,把MyBatis交给Spring来托管.数据库连接池用的c3p0.数据库用的MySQL.主要有2个大类:秒杀商品的查询.秒杀明细的插入. 准备工作 ...
- 手把手教你使用VUE+SpringMVC+Spring+Mybatis+Maven构建属于你自己的电商系统之vue后台前端框架搭建——猿实战01
猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...
- 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十二天】(系统架构讲解、nginx)
https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...
- 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十天】(单点登录系统实现)
https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...
- Idea SpringMVC+Spring+MyBatis+Maven调整【转】
Idea SpringMVC+Spring+MyBatis+Maven整合 创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...
- SpringMVC+Spring+MyBatis+Maven调整【转】
Idea SpringMVC+Spring+MyBatis+Maven整合 创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...
- 单工程搭建springmvc+spring+mybatis(maven,idea)
单工程搭建springmvc+spring+mybatis(maven,idea) 1.pom.xml <properties> <project.build.sourceEncod ...
随机推荐
- JMS Cluster modules
是GeoServer实现集群还是在数据库实现集群? Hadoop.Spark.HBase与Redis的适用性见解:https://blog.csdn.net/cuiyaonan2000/article ...
- 利用Python+163邮箱授权码发送带附件的邮件
背景 前段时间写了个自动爬虫的脚本,定时在阿里云服务器上执行,会从某个网站上爬取链接保存到txt文本中,但是脚本不够完善,我需要爬虫完毕之后通过邮件把附件给我发送过来,之前写过一个<利用Pyth ...
- socket的阻塞与非阻塞,同步与非同步
网络编程中通常提到四种方式,同步/异步,阻塞/非阻塞.以下对它们的概念进行总结 1.同步/异步:主要针对C端 同步:所谓同步,就是在C端发出一个功能调用时,在没有得到结果之前,调用不返回,也就是必须一 ...
- easyUI分页实现加搜索功能
前台页面: js代码: ps:pagination为true时会在table下面加上easyUI的分页. load函数会将查询值传给datagrid并传给后台重新加载. DAO.xml为: 后台代码实 ...
- 【笔记】css基于box的一行时垂直方向居中,多行平均居中,多出部分还省略号代替
题目很长,其实他就是这样的: 看标题,一行的时候是这样的,在行中间 标题文字多的时候是这样的,变成2行,超出部分用省略号: 但是为了更好的兼容性,没有使用flex,使用的是box布局. 核心代码就是这 ...
- JavaScript实现页面刷新滚动条位置不变(利用cookie)
实验环境:vs2015 asp.net(C#) 主要原理: 1.在页面滚动时或点击按钮时将当前滚动条位置记录到cookie[pos], 2.页面刷新或重载时查询cookie[pos]中的值是否存在,若 ...
- pycharm自动创建python头文件
步骤如下例各图:
- Qt Creator快捷键设置
QT Creator 下载地址 http://download.qt.io/ 一.快捷键配置方法: 进入“工具->选项->环境->键盘”即可配置快捷键. 二.常用默认快捷键: 编 ...
- Hadoop Partition函数应用(归档)
一.实例描述 在这个实例里我们使用简单的数据集,里面包含多条数据,每条数据由姓名.年龄.性别和成绩组成.实例要求是按照如下规则归档用户. 1.找出年龄小于20岁中男生和女生的最大分数 2.找出20岁到 ...
- CSRF 攻击(跨域攻击)
一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...