其实商品模块本身没什么功能,但这里牵扯到两个点:一个是将商品添加到购物车、另一个是商品在前台页面的展示,其中还有分页的一个写法。都需要注意一下。
一、商品正常的查询功能
其实商品本身的查询功能:不论是首页热门商品或是最新商品的查询,还是按商品分类查询,
都只是一条SQL语句的问题,
需要注意的是在每条SQL语句后都应判断商品是否是上架状态,
也算一个小坑吧,
不加的话会被测试提BUG的。
1、首页热门商品,按照商品表中“is_hot”字段查询即可,将查询后的结果按照上架的时
间逆序排列,首页这边只需
要展示
9个商品,那么我们也只需要查询9个商品,在SQL语句中使用limit关键
字来限制查询的条数。总结一下,SQL语句就应该是下面的
写法:
“select pid,pname,market_price,pimage from product where is_hot=1 and state=1 order by pdate desc limit 9";
这里也可以用*来查询,但是这样效率就会差点,所以一般是把前端需要展示的字段查出来就行了。
2、首页最新商品,与热门商品简直一毛一样,区别只是按照上架的时间逆序排列,更简单了。sql也是一样:
"select pid,pname,market_price,pimage from product where state=1 order by pdate desc limit 9";
3、按分页显示商品,这里是按照分页来查询该商品分类下的商品,并在页面加载,但是分类下的商品一般来
讲是有很多的,
所以,我们需要进行分页。好,那这里的SQL其实也很简单。
"select pid,pname,market_price,pimage from product where state=1 and cid=? order by pdate desc limit begin,9";
这里SQL中的cid是指商品分类的id,begin是指偏移量,或者说offset更准确,它的一个含义是说我当前SQL
的查询结果中取的值得
开始的项的下标(大概意思是这样的)。计算公式也很简单:begin=(currPage-1)*pageSize;
前面是sql的简单介绍,下面来简单分析下分页的逻辑。
当我们在页面显示的东西一页显示不下的时候就可以使用分页了。分页的时候,前端页面需要向后台传递的
参数只是当前页的页面,
我们使用currPage来表示,而后台需要向前台输出的变量有:currPage(当前页),
totalCount(总条数),totalPage(总页数),pageSize(每页条数)
以及每页显示商品信息的list集合(List).通常将这集合
变量放到一个JavaBean中这样也有利于数据的封装,我们叫做PageBean.
而数据传到前端后的一个显示也就很
简单了。只要使用jsp中el表达式的循环将PageBean中的数据显示到页面上即可。
以上就是分页的一个前端代码了,核心呢就是使用了el表达式中的<c:forEach>标签。这个格式都是固定的,
没有什么可说的。
以上这些呢就是正常查询商品列表的全部了,剩下边边角角的东西也不重要。
二、商品详情
其实商品详情这里也没什么东西,一手SQL就搞定了。只需要从前端将商品id以get请求的方式传到后台就可以了。
"select pid,pname,market_price,shop_price,pimage,pdesc from product where pid=? and pflag=?";
这里在查询时其实可以不使用pflag去标识商品的状态,因为从前端传过来的pid肯定都是上架了的。
三、将商品添加到购物车
添加商品到购物车其实有两个逻辑,以淘宝和京东为例
淘宝采用的是在登录的时候就校验用户是否登录,在用户登录之后再将商品加入购物车的模式;
而京东采用的是先将用户加入购物车,在付款的时候再提示用户登录。
其实这两种方式对应的是两种实现模式,前一种在加入购物车的时候就提示用户登录,在用户登录之后就
将购物车与用户绑定在一起,确切来讲应该是以用户名作为session域的id将购物车信息封装到一个JavaBean中。
而另一种方式是先将商品信息放到购物车,在付款时再提示用户登录,这样我在不登录的情况下将商品添加
到购物车之后,是先将商品id存到cookie中,然后用户登录后再存到session中。
将购物车与用户绑定在一起,确切来讲应该是以用户名作为session域的id将购物车信息封装到一个JavaBean中。
而另一种方式是先将商品信息放到购物车,在付款时再提示用户登录,这样我在不登录的情况下将商品添加
到购物车之后,是先将商品id存到cookie中,然后用户登录后再存到session中。
而这里我们采用的是第一种方式,在加购物车时提示用户登录,在加入购物车成功后将购物车信息存到session
中,这样其实
便于我们在前台数据的存取或者说在其他模块的一个数据的存取。这里的代码其实没有什么难度,
但是购物车的实现逻辑以及它的几个
问题还是需要明确的。
1、第一个问题,我们在实现购物车时时采用了第一种方式,但我们说session是默认一次会话有效,
这里并不是存数据的session
失效了,而是存储session ID的cookie失效了,那我们想让保存购物车信息的
session在
我们下次打开浏览器还能看的到的话,就可以
将存储session ID的cookie做持久化。
Cookie[] cookies = request.getCookies(); 获取浏览器中存储的所有cookie;
然后遍历这个数组,找到存储session ID的cookie,而存储session ID的cookie的key是:
JSESSIONID,使用这个key就可以找到存储session的cookie
然后使用cookie的一些api就可以修改cookie的一些属性:
cookie.getValue(); 获取cookie中的值
cookie.setPath("路径");设置cookie的有效路径
cookie.setMaxAge(30*60);设置cookie存储的有效时间
response.addCookie(Cookie cookie);添加cookie
这样就可以让session在多次会话间共享了
2、第二个问题是,在实际的时候我们服务器肯定是有很多人访问的,如果每个人都创建一个session来
存储购物车的话,
那么我们服务器的内存肯定是吃不消的。这样我们就会用到另一个称谓session的序列化。
而session
的序列化呢我们也不需要
写什么代码,只需要在项目的META-INF/目录下创建配置文件
context.xml即可。
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="it315"/>
</Manager>
</Context>
这里有两个参数需要说明一下:
maxIdleSwap 这个指session多长时间不操作会序列化
directory 而这个就是指session序列化后文件存储的路径。通常这个目录是在你tomcat文件夹下的
\work\Catalina\localhost\BlackHorseMarket\it315 这个目录。
3、而第三个问题呢是:在session过期的时候,因为存储购物车信息的session总会有销毁的时候,
那在session
销毁的时候我们
应当做购物车信息的持久化。这里呢我们是将购物车存到了数据库里。
而什么时候做这个操作就是个
问题了。由于人为无法确定
session什么时候销毁,我们也就没办法实现这个逻辑。
那这里我们可以使用一个新的技术来完成这个,那就是listener,监听器。
我们使用这个监听器来监听session的销毁,然后再session销毁的时候将session中存储的购物车信息存储到
数据库里。
HttpSession session = se.getSession();
User user = (User)session.getAttribute("existUser");
Cart cart = null;
if(user != null)
cart = (Cart)session.getAttribute(user.getUsername());
if(cart != null){
CartService cartService = (CartService)BeanFactory.getBean("cartService");
cartService.addCart(cart,user.getUid());
}
以上就是我们在做购物车业务时会遇到的问题。这里也需要体会理解一下。而另一个问题在我们删除购物车中
某一个购物项时所面临的问题,由于我们购物车的信息是存在session中的,也会存到数据库中,那么我们怎么保证
我们每次删除的项在同步到数据库时与数据库保持一致呢。要是每次做删除操作的时候都直接操作数据库,那这个在
效率上也太低了。这里也是有两种解决方式,一种是我的,另一种是老师给出的解决方式。。
1、同步数据库:使用监听器,在session过期时将session中的数据同步至数据库中
判断该用户的购物车是否在数据库中
若存在,则做更新操作
(1)、做更新操作时,首先查询数据库中的所有购物项对应的pid,存放到一个list集合(list1)中
(2)、遍历session中的所有购物项
判断该购物项是否存在于数据库的购物项(list1)中
若存在,则做更新操作
若不存在,则做插入操作
获取session中的所有购物项的商品id放到list集合(list2)中
(3)、遍历数据库中的订单项集合(list1),删除数据库中多余的数据
判断数据库的购物项的商品id是否在session中,若不存在则删除数据库中的购物项
若不存在,则做插入操作
这种方式可以实现删除购物项以及清空购物车的操作,但清空购物车要求实时清空,所以清空购物车时需要将 数据库的也清空
判断该用户的购物车是否在数据库中
若存在,则做更新操作
(1)、做更新操作时,首先查询数据库中的所有购物项对应的pid,存放到一个list集合(list1)中
(2)、遍历session中的所有购物项
判断该购物项是否存在于数据库的购物项(list1)中
若存在,则做更新操作
若不存在,则做插入操作
获取session中的所有购物项的商品id放到list集合(list2)中
(3)、遍历数据库中的订单项集合(list1),删除数据库中多余的数据
判断数据库的购物项的商品id是否在session中,若不存在则删除数据库中的购物项
若不存在,则做插入操作
这种方式可以实现删除购物项以及清空购物车的操作,但清空购物车要求实时清空,所以清空购物车时需要将 数据库的也清空
2、是在每个购物项上加一个标记,用来标识每次执行同步操作时具体应该做什么。
比如:1:代表插入操作
2:代表更新操作
3:代表删除操作
这样就极大的便利了我们同步数据库的操作,每次同步时只需要看这个标识来执行不同的SQL即可。
那以上这些就是我们商品模块的所有东西了,其实总的看来也是很简单的。。