基于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 ...
随机推荐
- Session使用(14)
用session统计某个网页的访问人数(因为我还不会js,所以就做了个简易版本的) 1.创建Session监听器,每创建了一个Session对象就执行监听类中·的sessionCreated方法. p ...
- Runnable与Callable区别
相同点: 两者都是接口:(废话) 两者都可用来编写多线程程序: 两者都需要调用Thread.start()启动线程: 不同点: 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果:而 ...
- python学习第四天笔记整理
一.迭代器及生成器 #迭代器:迭代的工具 #1 什么是迭代:指的是一个重复的过程,每一次重复称为一次迭代,并且每一次重复的结果是下一次重复的初始值# while True:# print('===== ...
- HDU - 1241 Oil Deposits 经典dfs 格子
最水的一道石油竟然改了一个小时,好菜好菜. x<=r y<=c x<=r y<=c x<=r y<=c x<=r y<=c #include ...
- formated time string for file naming
#include <stdio.h> #include <time.h> int main() { time_t rawtime; struct tm *timeinfo; ] ...
- 利用 awk 统计nginx 中某一个用户的访问次数
线上总是会遇到攻击,所以就需要分析 access.log 看看那些用户的访问次数不正常,针对这些不正常的用户,要做处理,以 access.log为例说明下怎么统计. 通过 access.log 日志来 ...
- 【ZCTF】easy reverse 详解
0x01 前言 团队逆向牛的解题思路,分享出来~ 0x02 内容 0. 样本 bbcdd1f7-9983-4bf4-9fde-7f77a6b947b4.dll 1. 静态分析 使用IDAP ...
- 吴恩达机器学习笔记35-诊断偏差和方差(Diagnosing Bias vs. Variance)
当你运行一个学习算法时,如果这个算法的表现不理想,那么多半是出现两种情况:要么是偏差比较大,要么是方差比较大.换句话说,出现的情况要么是欠拟合,要么是过拟合问题.那么这两种情况,哪个和偏差有关,哪个和 ...
- KNN算法基本实例
KNN算法是机器学习领域中一个最基本的经典算法.它属于无监督学习领域的算法并且在模式识别,数据挖掘和特征提取领域有着广泛的应用. 给定一些预处理数据,通过一个属性把这些分类坐标分成不同的组.这就是KN ...
- 机器学习基石笔记:03 Types of Learning
原文地址:https://www.jianshu.com/p/86b2a9cef742 一.学习的分类 根据输出空间\(Y\):分类(二分类.多分类).回归.结构化(监督学习+输出空间有结构): 根据 ...