SSM 框架搭建 sckill 秒杀系统 —— step.5 web展示层建设

索引:

  1. SSM 框架搭建 sckill (秒杀系统) —— step.1 前期准备 + 框架配置
  2. SSM 框架搭建 sckill (秒杀系统) —— step.2 持久层建设
  3. SSM 框架搭建 sckill 秒杀系统 —— step.3 业务逻辑层建设
  4. SSM 框架搭建 sckill 秒杀系统 —— step.4 web控制层建设
  5. SSM 框架搭建 sckill 秒杀系统 —— step.5 web展示层建设

一、web 展示层(view)简介

        展示层是一个系统与实际用户之间的交互层级,用图形化界面的方式,将后端的业务逻辑进行包装。最终呈现给用户一个简单易懂的可交互页面。因此,通常而言,这个层级是在系统设计中占有的设计时间比编码时间要更长。(不过就本系统而言,因为更注重的是逻辑和业务的实现,所以并没有在展示层的设计上下多大功夫,只是简单的展示而已。)

二、MVC – web 展示层设计框架

        但凡设计系统前端,那么对 MVC 这个缩写一定都不陌生。MVC (model - view - controller)作为交互系统的设计框架,将交互方式分成了: 数据装载与搬运部分( model );展示与交互界面( view );和逻辑流程控制部分( controller )。在本系统的设计中,model 部分由 DTO(Data - Transfer - Object ) 承担,而 controller 部分则由 Spring 进行统一调度,至于 view 部分,则是由 jsp 进行承担。

三、web 交互界面标准化框架

        在 web - UI 界面的构建中,市面上有许多成熟、优美的开源框架,比如:Bootstrap、Vue、React 等。这些开源框架通过编写原生 HTML 、CSS、JavaScript、jQuery ,将一些通用的功能和页面设计封装成库类插件。通过调用这些开源的库类,可以省去我们很多写页面 UI 设计的时间。同样的,在该系统中,由于更注重系统逻辑编写,在交互界面的设计上,采用了简单的 bootstrap 的标准化设计。

(1)web 目录结构

        web 界面的搭建,首先是进行目录结构的规划,web 前端相关代码,均放置于与 java 同级的 webapp 文件夹下。目录内容如下:
在这里插入图片描述
        目录结构简述如下:


webapp 
│  
├─resources :用于存放 js、css 等配置文件
│  └─script
│          *.js
│          
└─WEB-INF
    │  web.xml : web 配置文件
    │  
    ├─jsp :用于放置 web 端的界面代码,将页面代码放在 WEB-INF 文件夹下的好处是,可以将 web 端页面代码保护起来,用户在访问系统时,无法通过输入 URL 绝对路径的方式对页面进行访问。
    │  │  *.jsp
    │  │  
    │  └─common :放置 web 端公有页面配置,如界面设计中的基本导入插件等。
    │          *.jsp
    │          
    └─lib :放置一些需要导入项目的 jar 包(不过在有 maven 工具和 Spring 的统一管理下,基本没什么作用。
    

(2)项目编写

        由于 web 界面较为简单,此处不再将 jsp 代码附上。在 web 前端,最核心的逻辑部分是实现交互的 JavaScript 代码,视频中给出了一种逻辑编码的新思路,即不再将编码封装成函数进行调用,而是将整个逻辑写成 json 的形式,这样做的好处是整个逻辑被封装到了一块,形成所谓的模块化,代码所有的函数形成内部调用。但个人还是不太习惯用这种方式,因为这样的写法,一个模块信息量太大,不利于后续的维护。
       以下是 JavaScript 的核心代码块。需要注意的是,在导入该 JavaScript 片段前,必须确保已经在 jsp 页面中加载了 bootstrap 框架,否则代码中引用 bootstrap 的代码块片段将会失效。

// 存放只要交互逻辑 js 代码
// javascript 模块化
var seckill = {
    // 封装秒杀相关 ajax 的url
    URL : {
        now : '/seckill/time/now',
        exposer : function (seckillId){
            return '/seckill/' + seckillId + '/exposer';
        },
        execution : function (seckillId, md5) {
            return '/seckill/' + seckillId + md5 + '/execution';
        }
    },
    validatePhone : function (phone){
        if(phone && phone.length == 11 && !isNaN(phone)){
            console.log("return true : ", phone, phone.length, isNaN(phone) );
            return true;
        }else {
            console.log("return false : ", phone, isNaN(phone) );
            return false;
        }
    },
    handleSeckill : function (seckillId, node) {
        // 处理秒杀逻辑
        node.hide()
            .html('<botton class="btn btn-primary brn-lg" id="killBtn">开始秒杀</botton>');
        $.post(seckill.URL.exposer(seckillId), {}, function (result) {
            // 在回调函数中执行交互流程
            if(result && result['success']){
                var exposer = result['data'];
                if(exposer['exposed']){
                    // 开启秒杀, 获取秒杀地址
                    var md5 =exposer['md5'];
                    var killUrl = seckill.URL.execution(seckillId, md5);
                    console.log('killURL : ' + kilUrl);
                    // 绑定一次点击事件
                    $('#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'];
                                // 3.显示秒杀结果
                                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);
            }
        })
    },
    countdown : function (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 (event){
                var format = event.strftime('秒杀倒计时: %D天 %H时 %M分 %S秒');
                seckillBox.html(format);
            }).on('finish.countdown', function () {
                // 时间完成后回调事件 -- 获取秒杀地址,实现逻辑,执行秒杀
                seckill.handleSeckill(seckillId, seckillBox);
            });
        }else {
            // 秒杀开始
            seckill.handleSeckill(seckillId, seckillBox);
        }
    },
    // 详情页秒杀逻辑
    detail : {
        // 详情页初始化
        init : function (params) {
            // 手机验证和登录,计时交互
            // 规划交互流程
            // 在cookie中查找手机号
            var killPhone = $.cookie('killPhone');
            var seckillId = params['seckillId'];
            var startTime = params['startTime'];
            var endTime = params['endTime'];
            // 验证手机号
            if(!seckill.validatePhone(killPhone)){
                // 绑定phone
                var killPhoneModel = $("#killPhoneModel");
                // 控制输出,显示弹出层
                killPhoneModel.modal({
                    show : true,  // 显示弹出层
                    backdrop : 'static',  //禁止位置关闭
                    keyboard : false  // 关闭键盘事件
                });
                $('#killPhoneBtn').click(function(){
                   var inputPhone = $('#killPhoneKey').val();
                   if(seckill.validatePhone(inputPhone)){
                       // 将 phone 写入 cookie
                       $.cookie('killPhone', inputPhone, {
                           expires : 7,
                           path : '/seckill'
                       });
                       // 刷新页面
                       window.location.reload();
                   }else {
                       $('#killPhoneMessage').hide().html('<label class="label label-danger">手机号错误</label>').show(300);
                   }
                });
            }
            // 登录之后: 计时交互
            $.get(seckill.URL.now, {}, function (result) {
                if(result && result['success']){
                    var nowTime = result['data'];
                    // 时间判断,计时交互
                    seckill.countdown(seckillId, nowTime, startTime, endTime);
                }
            });
        }
    }
}

(3)启动项目

       当代码全部编写完毕,就是项目的启动,不知道有没有人跟我踩到了同样的坑。那就是明明代码编写无误,启动时却来了个 404 !!(找不到页面,说明 URL 定向错误,这就很过分,明明页面在的说。)
在这里插入图片描述
       由于确定页面在物理上是存在的,那么可能的原因只能是 URL 在定向时发生了错误,导致页面未被索引成功。这个是视频中没被提到的,因为 IDEA 在创建 java - web 项目时,默认在服务器根目录下创建一个与项目名相同的文件夹,以此存放 web 项目,但本项目的存放位置是 root 因此无法被索引到。解决方法如下:
在菜单栏找到 Edit Configurations… 单击,在弹出的窗口中,找到对应的 Tomcat Server 启动项,选中 Deployment ,将 ‘Application context’ 改为 ‘/’ 点击 ‘OK’, 此时,修改完毕。重新启动服务器,可以看到问题解决了!
在这里插入图片描述
在这里插入图片描述
       如果成功,可以看到类似的界面,此时,功能符合预期,项目建立完毕。
在这里插入图片描述

小贴士:HTTP状态码分类

分类分类描述
1XX表服务器接收到信息请求,客户端应继续请求
2XX表成功(最佳状态),客户端的操作被成功接收并处理后返回给客户端
3XX表重定向,需要客户端进一步操作
4XX表客户端错误(最头疼的错误),说明访问资源不存在或请求无法完成
5XX表服务器错误(通常来讲就是服务器挂掉或者出现代码bug了)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

揽月泛夜舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值