【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="">订单确认</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>
看着貌似很多的样子,其实功能很简单,就是从域中拿出相应的数据显示出来而已,我们现在要实现上面描述的功能的话,先来分析一下思路:
- 首先得注册一个事件:即修改了数量那里的文本框触发的事件;
- 在该事件中,我们拿到用户输入的数,判断输入的合法性,因为要防止用户乱输入;
- 如果合法,通过Ajax请求将数据发送到后台;
- 后台针对新的数量,调用相应的业务逻辑方法得到新的结果,并将其通过流返回到前台;
- Ajax收到结果后,再对相应位置的数据进行更新。整个流程就走完了。
- 如果非法,则显示修改前的数字。不做任何处理
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中了,跟前面的就接上了。
【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价的更多相关文章
- 【SSH网上商城项目实战30】项目总结(附源码下载地址)
项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了,积少成多,写博客的过程是固化思路的一个过程,对自己很有用,同时也能帮助别人.顺便说个题外话,在学习的过程中肯定会遇到很多异常出现,我们 ...
- 【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布
转自:https://blog.csdn.net/wwww_com/article/details/54405355 前面陆陆续续的完成了网上商城的一些基本功能,虽然还有很多地方有待完善,但是不影响 ...
- 【SSH网上商城项目实战21】从Demo中看易宝支付的流程
转自: https://blog.csdn.net/eson_15/article/details/51447492 这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后, ...
- 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示
转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...
- 【SSH网上商城项目实战30】项目总结
转自:https://blog.csdn.net/eson_15/article/details/51479994 0. 写在前面 项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了 ...
- 【SSH网上商城项目实战01】整合Struts2、Hibernate4.3和Spring4.2
转自:https://blog.csdn.net/eson_15/article/details/51277324 今天开始做一个网上商城的项目,首先从搭建环境开始,一步步整合S2SH.这篇博文主要总 ...
- 【SSH网上商城项目实战15】线程、定时器同步首页数据(类似于博客定期更新排名)
转自:https://blog.csdn.net/eson_15/article/details/51387378 上一节我们做完了首页UI界面,但是有个问题:如果我在后台添加了一个商品,那么我必须重 ...
- 【SSH网上商城项目实战25】使用java email给用户发送邮件
转自: https://blog.csdn.net/eson_15/article/details/51475046 当用户购买完商品后,我们应该向用户发送一封邮件,告诉他订单已生成之类的信息, ...
- 【SSH网上商城项目实战20】在线支付平台的介绍
转自:https://blog.csdn.net/eson_15/article/details/51441431 之前已经完成了首页的显示,用户添加购物车,确认订单等功能,下面就是支付功能的开发了. ...
随机推荐
- IT项目中使用 json格式数据 保存项目配置信息, 在配置文件再读取json文件的内容进行赋值
json格式小巧玲珑,适合做配置文件,特别是大型项目中, 可以将配置信息分类保存到不同的json文件中, 然后再在配置文件中读取配置文件的数据进行赋值, 这里以python为例进行说明: 假设在you ...
- Docker的安装与启动教程
一.安装Docker Docker官方建议在Ubuntu中安装,因为Docker是基于Ubuntu发布的,而且一般Docker出现的问题Ubuntu是最先更新或者打补丁的.在很多版本的CentOS中是 ...
- wamp集成多个版本php (php7.0)
https://www.cnblogs.com/ypf5208/p/5510274.html
- php对ip地址的处理
public function actions() { $url = "http://ip.taobao.com/service/getIpInfo.php?ip=".self:: ...
- 40.oracle事务
一.事务特性 事务必须具备以下四个特性,简称ACID属性 原子性(Atomicity):事务是一个完整的操作.事务的各步操作是不可分割的(原子的):要么都执行,要么都不执行场景:银行转账 A-100 ...
- 开源系统-edusoho在线教育
#部署 ```bash [root@localhost ~]# docker run --name edusoho -tid -p 9900:80 -e DOMAIN= ...
- c常用函数
一.strtol long int strtol(const char *nptr, char **endptr, int base) strtol()会将nptr指向的字符串,根据参数base,按权 ...
- Github使用笔记
========================Github使用===================概念解释:远程仓库Remote:就是指保存在github网站里的代码;本地仓库Repository ...
- ThinkPHP 5.0.x SQL注入分析
前言 前段时间,晴天师傅在朋友圈发了一张ThinkPHP 注入的截图.最近几天忙于找工作的事情,没来得及看.趁着中午赶紧搭起环境分析一波.Think PHP就不介绍了,搞PHP的都应该知道. 环境搭建 ...
- Docker 入门相关
什么是Docker和容器 可能是把Docker的概念讲的最清楚的一篇文章 为什么要用Docker 相关网址 Window平台Docker下载 一些基本知识 Volume docker volume l ...