基于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来实现倒计时效果。倒计时插件会维护一个倒计时事件,时间结束时直接会调用秒杀接口来实现秒杀业务。

原文地址:https://www.cnblogs.com/sword-successful/p/9230446.html

时间: 2024-07-29 12:23:10

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

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

前言 该篇主要实现秒杀业务层,秒杀业务逻辑里主要包括暴露秒杀接口地址.实现秒杀业务逻辑.同时声明了三个业务类:Exposer.SeckillExecution.SeckillResult. Exposer主要用来实现暴露接口时一个md5的加密,防止用户在客户端篡改数据.根据seckillid生成md5,提交秒杀请求时会根据这个md5和seckillid比对是否是合法的请求.SeckillExecution主要封装秒杀时的返回值. SeckillExecution有2个属性,state.state

基于Springmvc+Spring+Mybatis+Jqueryeasyui个人信息管理平台(日程管理、天气类型、资产管理、理财规划)

基于Springmvc+Spring+Mybatis+Jqueryeasyui个人信息管理平台(日程管理.天气类型.资产管理.理财规划) 课程讲师老牛 课程分类Java 适合人群中级 课时数量78课时 更新程度完毕 服务类型C类普通服务类课程 用到技术Springmvcspringmybatisjquery easyui 涉及项目个人信息管理好友管理报表实现 咨询QQ2050339477 课程链接http://www.dwz.cn/LO1X3 课程背景 本系统主要用于个人信息的管理通过软件工具对

课程分享】基于Springmvc+Spring+Mybatis+Bootstrap+jQuery Mobile +MySql教务管理系统

课程讲师:老牛 课程分类:Java框架 适合人群:初级 课时数量:85课时 更新程度:完成 用到技术:Springmvc+Spring+Mybatis+Bootstrap+jQueryMobile 涉及项目:PC端和手机端教务管理系统 需要更多相关资料可以联系 Q2748165793 课程大纲 技能储备 第1课springMVC概述和基础配置 第2课springMVC注解和参数传递 第3课springMVC和JSON数据 第4课springMVC上传下载 第5课springMVC 与 sprin

基于Springmvc+Spring+Mybatis+Bootstrap+jQuery Mobile +MySql教务管理系统(分为PC端和手机端)

刚开始我也不信,可自己根据http://url.cn/TgrIZT注册一下,然后通过这个网站获取了学习卡的用户名和密码之后,真的有200元抵用券到了自己的账户中,所以,我就买了一些课程,自从在北风网学习了一些课程之后,我感觉自己对于提成技能特别高,可能和自己刚刚毕业有关系,在学校每天都是理论知识,没有过多的时间,但是自从在北风网上学习了一些项目的知识之后,尤其和老师们一起做项目,我起初以为只是简单的视频教程,谁知道和培训机构一样,老师还可以给你解答问题,费用只相当于培训机构的10%,后来自己又学

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

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结[第六天] 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)[第七天](redis缓存) 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)[第八天](solr服务器搭建.搜

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

Idea SpringMVC+Spring+MyBatis+Maven整合 创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetype,然后选中下方列表中的webapp,然后点击Next 在GroupId和ArtifactId中填入指定内容,点击Next 直接点Next 输入项目名称,Finish Idea会自动开始下载所依赖的包,等待其完成. 项目结构 项目刚建好的时候是没有这些文件的,所以自己手动创建缺少的文件夹(包) 创建完后

SpringMVC+Spring+Mybatis(SSM~Demo) 【转】

SpringMVC+Spring+Mybatis 框架搭建 整个Demo的视图结构: JAR: 下载地址:http://download.csdn.net/detail/li1669852599/8546059 首先,我是使用MyEclipse工具做的这个例子,整合了Sping 3 .Spring MVC 3 .MyBatis框架,演示数据库采用MySQL数据库.例子中主要操作包括对数据的添加(C).查找(R).更新(U).删除(D).我在这里采用的数据库连接池是来自阿里巴巴的Druid,至于D

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

单工程搭建springmvc+spring+mybatis(maven,idea) 1.pom.xml <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven

第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis缓存)

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结[第五天] 第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结[第六天] 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)[第七天](redis缓存) 第04