SSM實戰——秒殺系統之Web層Restful url設計、SpringMVC整合、頁面設計

一:Spring整合SpringMVCjavascript

1:編寫web.xml,配置DispatcherServletcss

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">
  
  <servlet>
      <servlet-name>seckill-dispatcher</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>seckill-dispatcher</servlet-name>
      <!-- 默認匹配全部請求 -->
      <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

2:在resource/spring下,新建spring-web.xml,整合SpringMVChtml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        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-4.1.xsd">
   <!-- 1:開啓註解模式 -->
   <mvc:annotation-driven/>
   <!-- 2:配置靜態資源默認處理器-->
   <mvc:default-servlet-handler/>
   <!-- 3:配置JSP視圖解析器 -->
   <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- 4:配置掃描controller所在包 -->
    <context:component-scan base-package="org.myseckill.web"/>
</beans>

 

 

二:SpringMVC controller開發並實現restful url設計html5

RestFul架構見博客:http://kb.cnblogs.com/page/512047/java

Restful url 格式:/模塊/資源/{id}/細分node

 

1:在org.myseckill包下新建web包,用於存放全部controller。jquery

2:web包下新建一個controller:SeckillControllerweb

package org.myseckill.web;

import java.util.Date;
import java.util.List;

import org.junit.runners.Parameterized.Parameter;
import org.myseckill.entity.Seckill;
import org.myseckill.exception.RepeatKillException;
import org.myseckill.service.SeckillService;
import org.myseckill.dto.Exposer;
import org.myseckill.dto.SeckillExecution;
import org.myseckill.dto.SeckillResult;
import org.myseckill.enums.SeckillStateEnum;
import org.myseckill.exception.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller//註冊該bean
@RequestMapping("/seckill")//映射項目模塊
public class SeckillController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SeckillService seckillService;
    //列表頁請求
    @RequestMapping(value="/list",method=RequestMethod.GET)
    public String list(Model model){//model用於存放數據,字符串用於控制跳轉
        List<Seckill> list=seckillService.getSeckillList();
        model.addAttribute("list",list);
        return "list";
    }
    
    //詳情頁請求
    @RequestMapping(value="/{seckillId}/detail",method=RequestMethod.GET)
    public String detail(@PathVariable("seckillId")Long seckillId,Model model){
                
        if (seckillId == null) {
            return "redirect:/seckill/list";
        }
        Seckill seckill = seckillService.getById(seckillId);
        if (seckill == null) {
            return "forward:/seckill/list";
        }
        model.addAttribute("seckill", seckill);
        return "detail";
    }
    
    @RequestMapping(value="/{seckillId}/exposer",method=RequestMethod.POST,produces={"application/json;charset=UTF-8"})
    @ResponseBody//把返回數據轉換成JSON格式,綁定到響應中
    //Ajax方法,返回JSON數據
    public SeckillResult<Exposer> exposer(@PathVariable Long seckillId){
        SeckillResult<Exposer> result;
        try {//成功
            Exposer exposer = seckillService.exportSeckillUrl(seckillId);
            result = new SeckillResult<Exposer>(true,exposer);
        } catch (Exception e) {//失敗
            logger.error(e.getMessage(),e);
            result = new SeckillResult<Exposer>(false,e.getMessage());
        }
        return result;
    }
    
    @RequestMapping(value="/{seckillId}/{md5}/execution",method=RequestMethod.POST,produces={"application/json;charset=UTF-8"})
    @ResponseBody
    public SeckillResult<SeckillExecution> execute(@PathVariable Long seckillId, @PathVariable String md5,@CookieValue(value = "killPhone", required = false) Long userPhone) {
        if(userPhone==null){
            return new SeckillResult<SeckillExecution>(false, "未註冊");
        }
        try {
            SeckillExecution execution=seckillService.executeSeckill(seckillId, userPhone, md5);
            return new SeckillResult<SeckillExecution>(true, execution);
        } catch (RepeatKillException e) {
            SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.REPEAT_KILL);
            return new SeckillResult<SeckillExecution>(true,execution);
        } catch (SeckillException e) {
            SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.END);
            return new SeckillResult<SeckillExecution>(true,execution);
        } catch (Exception e){
            SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);
            return new SeckillResult<SeckillExecution>(false,execution);
        }
    }    
    
    @RequestMapping(value="/time/now",method=RequestMethod.GET)
    @ResponseBody
    public SeckillResult<Long> time(){
        Date now = new Date();
        return new SeckillResult<Long>(true,now.getTime());
    }    
}

3:新建一個dto:SeckillResult,封裝controller的處理結果ajax

package org.seckill.dto;

//全部ajax請求返回類型,封裝json結果
public class SeckillResult<T> {
    private boolean success;//請求是否成功
    
    private T data;
    
    private String error;

    public SeckillResult(boolean success, T data) {
        super();
        this.success = success;
        this.data = data;
    }

    public SeckillResult(boolean success, String error) {
        super();
        this.success = success;
        this.error = error;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }        
}

 

三:頁面開發spring

在WEB-INF下新建文件夾jsp,用於存放全部頁面。

1:jsp文件夾下新建common文件夾,用於存放一些共用的jsp頁面頭/尾。

head.jsp:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link
    href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.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]-->
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath %>">   

tag.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

 

2:建立頁面jsp

列表頁list.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@include file="common/tag.jsp"%>
<!DOCTYPE html>
<html>
   <head>
      <title>秒殺列表頁</title>
      <%@include file="common/head.jsp"%>
   </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="sk" items="${list}">
                               <tr>
                                   <td>${sk.name}</td>
                                   <td>${sk.number}</td>
                                   <td>
                                       <fmt:formatDate value="${sk.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
                                   </td>
                                   <td>
                                       <fmt:formatDate value="${sk.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
                                   </td>
                                   <td>
                                       <fmt:formatDate value="${sk.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
                                   </td>
                                   <td>
                                       <a class="btn btn-info" href="seckill/${sk.seckillId}/detail" target="_blank">link</a>
                                   </td>
                               </tr>
                           </c:forEach>
                       </tbody>
                   </table>
               </div>
           </div>
       </div>
 
     
   </body>
   <!-- jQuery文件。務必在bootstrap.min.js 以前引入 -->
   <script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js"></script>
 
   <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
   <script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js"></script>
   
</html></th>

 

2:詳情頁detail.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
   <head>
      <title>秒殺詳情頁</title>
      <%@include file="common/head.jsp"%>
   </head>
   <body>
       <div class="container">
           <div class="panel panel-default text-center">
               <div class="panel-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>
   </body>
   <!-- jQuery文件。務必在bootstrap.min.js 以前引入 -->
   <script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js"></script>
 
   <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
   <script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js"></script>
   <!-- 使用cdn獲取公共js http://www.bootcdn.cn -->
   <!-- jQuery cookie操做插件 -->
   <script src="http://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
   <!-- jQuery countDown倒計時插件 -->
   <script src="http://cdn.bootcss.com/jquery.countdown/2.2.0/jquery.countdown.min.js"></script>
   <!-- 開始編寫交互邏輯 -->
   <script src="/MySeckill/resources/script/seckill.js" type="text/javascript"></script>
   <script type="text/javascript">
           $(function(){
               //使用EL表達式傳入參數
               seckill.detail.init({
                   'seckillId' : '${seckill.seckillId}',
                   'startTime' : '${seckill.startTime.time}',//毫秒
                   'endTime' : '${seckill.endTime.time}'

               });
           });
   </script>
</html>

3:在WebRoot下新建一個文件夾resources,用於存放一些共用的資源,如js、images等。

resource下新建一個文件夾script,新建一個js文件 seckill.js,用於書寫交互函數:

//存放主要交互邏輯js代碼
//javascript模塊化.json類型
var seckill={
        //封裝秒殺相關ajax的url
        URL:{
            now : function(){
                return "seckill/time/now";
            },
            exposer : function(seckillId){
                return 'seckill/'+seckillId+'/exposer';
            },
            execution : function(seckillId,md5){
                return 'seckill/'+seckillId+'/'+md5+'/execution';
            }
        },
        handlerSeckill:function(seckillId, node){
            //獲取秒殺地址,控制顯示邏輯 執行秒殺
            node.hide().html('<button class="btn btn-primary btn-lg" id="killBtn">開始秒殺</button>');
            $.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:"+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'];
                                    //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);
                }
            });
        },
        //驗證手機號
        validatePhone:function(phone){
            if(phone && phone.length==11 && !isNaN(phone)){//isNaN不是數字
                return true;
            } else {
                return false;
            }
        },
        countdown:function(seckillId, nowTime, startTime, endTime){
            var seckillBox = $('#seckill-box');
            if(nowTime > endTime){
                seckillBox.html('秒殺結束!');
            } else if(nowTime < startTime){
                //秒殺未開始,倒計時
                var killTime = new Date(startTime-0 + 1000);
                seckillBox.countdown(killTime,function(event){
                    //時間格式
                    var format = event.strftime('秒殺倒計時: %D天 %H時 %M分 %S秒');
                    seckillBox.html(format);
                    /*時間完成後回調函數*/
                }).on('finish.countdown',function(){
                    //獲取秒殺地址,控制顯示邏輯 執行秒殺
                    seckill.handlerSeckill(seckillId, seckillBox);
                });
            }else{
                //秒殺開始
                seckill.handlerSeckill(seckillId, seckillBox);
            }
        },
        //詳情頁秒殺邏輯
        detail:{
            //詳情頁初始化
            init : function(params){
                //用戶手機驗證和登錄,計時交互
                //在cookie中查找手機號
                var killPhone = $.cookie('killPhone');
                var startTime = params['startTime'];
                var endTime = params['endTime'];
                var seckillId = params['seckillId'];
                //驗證手機號
                if(!seckill.validatePhone(killPhone)){
                    //綁定phone
                    var killPhoneModal = $('#killPhoneModal');
                    killPhoneModal.modal({
                        show:true,//顯示彈出層
                        backdrop:'static',//禁止位置關閉
                        keyboard:false//關閉鍵盤事件
                    });
                    $('#killPhoneBtn').click(function(){
                        var inputPhone = $('#killPhoneKey').val();
                        if(seckill.validatePhone(inputPhone)){
                            //電話寫入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);
                    } else {
                        console.log('result:'+result);
                    }
                });
            }
        }
}

 

 

4:部署測試記錄

提示DispatcherServlet找不到,或者配置文件找不到,首先檢查部署到tomcat的目錄下有無對應文件。

若是沒有,則檢查是否Myeclipse中的關於項目編譯文件輸出目錄與部署文件拉取目錄不一致致使出錯。

通常,Maven項目都會把項目編譯文件輸出到target目錄下,而咱們須要的是WebRoot/WEB-INF/classes目錄,因此須要修改。

1)右鍵項目,Buildpath——configer buildPath

2)選擇 source 選項卡

3)修改output folder:

4)左側,打開部署選項配置

5)修改拉取路徑

相關文章
相關標籤/搜索