文章出處

昨天把項目部署了一下,玩了玩,今天完善了一下購物車中修改商品數量就能局部更新相應的總價的功能,大家都知道這得用Ajax實現,我之前也沒學Ajax,剛好借助這個小功能,去簡單學習一下Ajax的知識。 

 

1.問題的分析

先看一下頁面中的情況: 
頁面情況
  功能如上,在沒有Ajax之前,一般都是根據用戶修改的值去找Action,然后返回新的jsp頁面重新加載整個頁面,完成數字的更新。但是有了Ajax技術后,我們可以利用Ajax技術局部刷新要改變的地方,而不是重新加載整個頁面。首先看一下上圖對應的jsp部分的代碼:

 

<div class="section_container">
    <!-- 購物車 -->
    <div id="shopping_cart">
        <div class="message success">我的購物車</div>
            <table class="data-table cart-table" cellpadding="0" cellspacing="0">
                <tr>
                    <th class="align_center" width="10%">商品編號</th>
                    <th class="align_left" width="35%" colspan="2">商品名稱</th>
                    <th class="align_center" width="10%">銷售價格</th>
                    <th class="align_center" width="20%">數量</th>
                    <th class="align_center" width="15%">小計</th>
                    <th class="align_center" width="10%">刪除</th>
                </tr>
                <c:forEach items="${sessionScope.forder.sorders }" var="sorder" varStatus="num">
                <tr lang="${sorder.product.id}">
                    <td class="align_center"><a href="#" class="edit">${num.count }</a></td>
                    <td width="80px"><img src="${shop}/files/${sorder.product.pic}" width="80" height="80" /></td>
                    <td class="align_left"><a class="pr_name" href="#">${sorder.name }</a></td>
                    <td class="align_center vline">${sorder.price }</td>
                    <td class="align_center vline">
                        <!-- 文本框 -->
                        <input class="text" style="height: 20px;" value="${sorder.number }" lang="${sorder.number }">        
                    </td>
                    <td class="align_center vline">${sorder.price*sorder.number }</td>
                    <td class="align_center vline"><a href="#" class="remove"></a></td>
                </tr>
                </c:forEach>

            </table>
            <!-- 結算 -->
            <div class="totals">
                <table id="totals-table">
                    <tbody>
                        <tr>
                            <td width="60%" colspan="1" class="align_left"><strong>小計</strong></td>
                            <td class="align_right" style=""><strong><span
                                        class="price" id="total">${sessionScope.forder.total}</span>
                            </strong></td>
                        </tr>
                        <tr>
                            <td width="60%" colspan="1" class="align_left">運費</td>
                            <td class="align_right" style=""><span class="price" id="yunfei">0.00</span></td>
                        </tr>
                        <tr>
                            <td width="60%" colspan="1" class="align_left total"><strong>總計</strong></td>
                            <td class="align_right" style=""><span class="total" id="totalAll"><strong>${sessionScope.forder.total}</strong></span>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <div class="action_buttonbar">
                    <font><a href="${shop}/user/confirm.jsp">
                        <button type="button" title="" class="checkout fr" style="background-color: #f38256;">訂單確認</button></a>
                    </font>
                    <font><a href="#">
                        <button type="button" title="" class=" fr">
                            <font>清空購物車</font>
                        </button>
                    </font>
                    <a href="${shop}/index.jsp">
                        <button type="button" title="" class="continue fr">
                            <font>繼續購物</font>
                        </button></a>
                    <div style="clear:both"></div>
                </div>
            </div>
        </div>

看著貌似很多的樣子,其實功能很簡單,就是從域中拿出相應的數據顯示出來而已,我們現在要實現上面描述的功能的話,先來分析一下思路:

 

  1. 首先得注冊一個事件:即修改了數量那里的文本框觸發的事件;
  2. 在該事件中,我們拿到用戶輸入的數,判斷輸入的合法性,因為要防止用戶亂輸入;
  3. 如果合法,通過Ajax請求將數據發送到后臺;
  4. 后臺針對新的數量,調用相應的業務邏輯方法得到新的結果,并將其通過流返回到前臺;
  5. Ajax收到結果后,再對相應位置的數據進行更新。整個流程就走完了。
  6. 如果非法,則顯示修改前的數字。不做任何處理

2. Ajax請求的實現

分析完了流程,接下來我們就著手去實現了,首先把js部分的代碼貼在這,然后我們根據上面的流程詳細分析:

<script type="text/javascript">
    $(function(){
        //1. 注冊事件
        $(".text").change(function(){
        //2. 驗證數據的有效性
            var number = this.value; //也可以使用$(this).val();
            //isNaN(number)表示若number不是數字就返回真
            if(!isNaN(number) && parseInt(number)==number && number>0){ 
                //如果合法,同步更新的數
                $(this).attr("lang", number);
                //找到當前標簽中第一個是tr的父節點,然后拿到屬性為lang的值,也就是商品的id
                var pid = $(this).parents("tr:first").attr("lang");
                //發送Ajax請求,傳輸當前的數量與商品的id,返回修改數量后的總價格
                $.post("sorder_updateSorder.action", 
                    {number:number, 'product.id':pid},
                    function(total){        
                        $("#total").html(total); //所有商品小計
                        var yunfei = $("#yunfei").html();
                        $("#totalAll").html((total*1 + yunfei*1).toFixed(2));//所有商品小計和運費的和
                }, "text");
                //計算單個商品的小計,保留兩位小數
                var price = ($(this).parent().prev().html()*number).toFixed(2);
                $(this).parent().next().html(price);
            } else {
                //如果非法,還原為剛剛合法的數
                this.value = $(this).attr("lang");
            }
        })
    })
</script>

2.1 注冊事件

  我們看上面的代碼可知,注冊事件首先要定位到這個文本框,這里是通過類選擇器來定位的,因為是文本框,所以用change()來注冊該事件,然后在里面定義一個function()函數來處理該事件。

2.2 判斷數據合法性

  好了,注冊好了事件后,我們首先要對用戶輸入的數進行合法性判斷,因為用戶可能輸入了0或者負數,可能輸入了小數,甚至輸入了字母或其他字符等等。所以要進行驗證。isNaN(number)表示若number不是數字就返回真,我們可以用這個函數來判斷是否為數字;parseInt(number)表示對數組進行取整,然后跟它自身進行比較,我們巧妙的運用了這個來判斷number是否為整數。

2.3 發送Ajax請求

  如果數據是合法的,我們獲取該數據后,就可以向后臺發送Ajax請求了,我們需要考慮一個問題:需要傳哪些參數呢?首先用戶想要更新數量,毫無疑問,用戶輸入的數字肯定要傳過去,其次到底傳哪個商品呢?也就是說我們需要獲取用戶想要修改的商品的id號,知道了要傳的參數后,我們想辦法獲取id號即可。 
  這里有一個問題,用戶的購物車里可能不止一件商品,很自然的會想到,如果能用一條語句可以拿到不同商品的id,就非常好了,因此,想到了可以使用該文本框的父標簽,因為不同的商品它的父標簽都一樣,都是第一個<tr>標簽,所以我們把商品的id放在那個<tr>標簽中的lang屬性里,為什么要放在lang屬性里呢?因為lang屬性基本不會用到,它是用來定義語言的,而且用lang屬性還不容易和其他屬性沖突~這樣我們就可以通過$(this).parents("tr:first").attr("lang");來獲取商品的id了。 
  接下來開始發送Ajax請求,使用post方式發送,post方法中有四個參數:

 

  • 第一個參數是要發送到的Action
  • 第二個參數是要傳過去的參數,使用的是json格式
  • 第三個參數是一個function(result),result是用來接收后臺穿過來的數據
  • 第四個方式是規定接收什么類型的數據,json表示接收json數據,text表示接收流

     從后臺返回的total是所有商品的總價格,所以在function中,首先我們根據id拿到所有商品小計的元素然后賦值為total即可,totalAll是加了運費的總價,后面那個toFixes(2)表示保留兩位小數。然后再拿到單個商品小計的元素,計算一下單個商品的小計,這樣前臺頁面在沒有重新載入的情況下,更新了我們想要更新的部分,這就是Ajax強大的地方,這個和前面EasyUI一樣的,EasyUI也是Ajax請求。 
   好了,關于Ajax部分到這里就介紹完了,下面是后臺的處理剛剛的請求,是針對自己這個項目的,用來記錄項目進度用的。

 

3. 后臺的更新

      剛剛Ajax請求的action是SortedAction中的updateSorder()方法,所以我們去SorderAction中完成updateSorder()方法:

@Controller
@Scope("prototype")
public class SorderAction extends BaseAction<Sorder> {
    public String addSorder() {

    //省略無關的代碼……

    //根據商品編號更新商品數量
    public String updateSorder() {
        Forder forder = (Forder) session.get("forder");
        //更新購物項,傳進來的product.id被封裝到了model中
        forder = sorderService.updateSorder(model, forder);
        //計算新的總價格
        forder.setTotal(forderService.cluTotal(forder));
        session.put("forder", forder);
        //以流的形式返回新的總價格
        inputStream = new ByteArrayInputStream(forder.getTotal().toString().getBytes());
        return "stream";
    }
}

相應的Service中的方法完善如下:

//SorderService接口
public interface SorderService extends BaseService<Sorder> {
    //省去無關的代碼……
    //根據商品id和數量更新商品數量
    public Forder updateSorder(Sorder sorder, Forder forder);
}

//SorderServiceImpl實現類
@Service("sorderService")
public class SorderServiceImpl extends BaseServiceImpl<Sorder> implements
        SorderService {

    //省略無關的代碼……

    @Override
    public Forder updateSorder(Sorder sorder, Forder forder) {
        for(Sorder temp : forder.getSorders()) {
            if(temp.getProduct().getId().equals(sorder.getProduct().getId())) {
                temp.setNumber(sorder.getNumber());
            }
        }
        return forder;
    }
}

最后struts.xml文件中的配置,是把”stream”配在了<global-result>里面,如下

<global-results>
        <!-- 省去其他公共配置 -->
        <result name="stream" type="stream">
            <param name="inputName">inputStream</param>
        </result>
</global-results>

 好了,現在Action中計算出的總價格就可以通過流的形式傳到前臺了,Ajax就可以在它的function中接收到,放到total中了,跟前面的就接上了。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()