【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价

昨天把项目部署了一下,玩了玩,今天完善了一下购物车中修改商品数量就能局部更新相应的总价的功能,大家都知道这得用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中了,跟前面的就接上了。

时间: 2024-10-10 20:39:05

【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价的相关文章

【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布

前面陆陆续续的完成了网上商城的一些基本功能,虽然还有很多地方有待完善,但是不影响项目的部署和发布,我们可以先来玩一把,这一节主要介绍下域名空间的申请以及项目的部署和发布流程. 1. 域名空间的申请 作为一个伟大的屌丝,肯定没钱买域名空间,很自然的想到去申请个免费的,现在免费的域名空间也很多,我在福佳jsp技术网上申请了一个试用期是15天的,大家也可以去申请个玩玩,反正作为学习,这已经足够了,当然,如果要长期的肯定要付费的.注册过程我截几个图,如下: 然后下一步,最后开通如下: 建议把上面这些信息

【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示

网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要进入商品的详细信息页面,就像淘宝里面那样.那么每次点击都要去后台查询一下该商品的详细信息,就会发送相应的sql语句,每次刷新一下详细页面也会发sql语句,这样的话,性能肯定会受到很大的影响.那么使用Hibernate的二级缓存就可以解决这个问题. 有些人可能会想,我们可以使用重定向,这样的话,在用户第一次访问的时候把信息查出来放到session中,以后每次用户刷新就可以去session中拿了,这样就不用去数据库中

【SSH网上商城项目实战21】从Demo中看易宝支付的流程

这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后,再做实际的开发,因为是一个Demo,所以我没有考虑一些设计模式的东西,就是直接实现支付功能.实现支付功能需要易宝给我们提供的API.那么问题来了,使用第三方支付平台最主要的一件事就是获取该平台的API,我们首先得获取他们的API以及开发文档,然后才可以做进一步的开发. 1. 获取易宝的API 获取API的第一步,要在易宝上注册一个账号,这个账号是商家的账号,后面买家付款后,会将钱款存入该账号中,然后商家自己提取到银行卡,易宝

【SSH网上商城项目实战25】使用java email给用户发送邮件

当用户购买完商品后,我们应该向用户发送一封邮件,告诉他订单已生成之类的信息,邮箱地址是从用户的基本信息中获取,好了,首先我们来看一下Java中发送邮件的方法. 1. java中发送email的方法     在完善这个项目之前,先来回顾一下java中是如何发送邮件的,首先肯定需要发送邮件的jar包:mail.jar,导入到lib目录下,好了,下面我们先写一个普通的java程序来回顾一下java email的知识点: public class SendEmailDemo { public stati

【SSH网上商城项目实战10】商品类基本模块的搭建

前面我们完成了与商品类别相关的业务逻辑,接下来我们开始做具体商品部分. 1. 数据库建表并映射Model 首先我们在数据库中新建一张表,然后使用逆向工程将表映射成Model类,表如下: /*=============================*/ /* Table: 商品表结构 */ /*=============================*/ create table product ( /* 商品编号,自动增长 */ id int primary key not null aut

【SSH网上商城项目实战20】在线支付平台的介绍

之前已经完成了首页的显示,用户添加购物车,确认订单等功能,下面就是支付功能的开发了.用户确认了订单后会直接跳转到支付页面进行在线支付,在线支付需要第三方的接口,这一节主要介绍一些关于第三方支付的内容,从下一节开始,我们真正开发在线支付模块. 1. 在线支付介绍 在线支付是指卖方与买方通过因特网上的电子商务网站进行交易时,银行为其提供网上资金结算服务的一种业务.它为企业和个人提供了一个安全.快捷.方便的电子商务应用环境和网上资金结算工具.在线支付不仅帮助企业实现了销售款项的快速归集,缩短收款周期,

【SSH网上商城项目实战13】Struts2实现文件上传功能

上一节我们做完了添加和更新商品的功能,这两个部分里有涉及到商品图片的上传,并没有详细解说.为此,这篇文章详细介绍一下Struts2实现文件上传的功能. 1. 封装文件信息 我们首先得有一个Model来封装文件的信息,这个Model里需要有三个属性:文件.文件类型和文件名.针对我们要传的图片,我们新建一个Model如下: public class FileImage { private File file; private String contentType; private String fi

【SSH网上商城项目实战09】添加和更新商品类别功能的实现

上一节我们做完了查询和删除商品的功能,这一节我们做一下添加和更新商品的功能. 1. 添加商品类别 1.1 添加类别的UI设计 我们先说一下思路:首先当用户点击"添加商品"时,我们应该弹出一个"添加商品"的UI窗口(注意这里不是跳转到新的jsp,EasyUI只有一个页面),弹出这个"添加商品"的窗口后,应该锁住它父类的所有窗口(即点击其他地方无效,只能操作添加商品的窗口),等用户填好了信息后,在新弹出来的窗口上点击"添加"后,将

【SSH网上商城项目实战29】使用JsChart技术在后台显示商品销售报表

这个项目终于接近尾声了,注册功能我就不做了,关于注册功能我的另一篇博客详细的介绍了一下注册的表单验证,可以直接把功能加到本项目中,修改一下相关的跳转即可,就不再做了.另外,目前这个项目只有action层和service层,dao层我还没抽取,做完这个报表,我把dao层抽取一下,再对整个项目做个总结,差不多就可以上传源码了,到时候欢迎大家下载~ 这一节主要做一下最后一个功能:使用JsChart这个工具来显示商品的销售报表,JsChart是很好用的一款制作报表的工具,之所以好用,是因为它的官方实例做