《基于JavaEE的电子商务网站建设》课件第10章_第1页
《基于JavaEE的电子商务网站建设》课件第10章_第2页
《基于JavaEE的电子商务网站建设》课件第10章_第3页
《基于JavaEE的电子商务网站建设》课件第10章_第4页
《基于JavaEE的电子商务网站建设》课件第10章_第5页
已阅读5页,还剩167页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章图书显示、购物车及订单模块的实现10.1图书显示模块10.2购物车模块10.3订单模块

10.1图书显示模块

10.1.1所有图书列表显示、查询及排序功能的实现

1.图书列表相关Web页面的处理

图书列表页面booklist.jsp(使用s:include标签)包含代码①、②、③、④、⑥ 5个页面,而代码⑤是分页处理代码,代码①、②分别是头页面和尾页面,这些在第9章已经讲解。

booklist.jsp页面的主要代码如下(省略所有样式的定义):<body>

<s:includevalue="Head.jsp"></s:include> ①

<s:formaction=""theme="simple">

<table><tr><td>

<s:includevalue="order.jsp"></s:include> ②

</td><td>

<s:includevalue="search.jsp"></s:include> ③

</td></tr></table>

<hr>

<s:iteratorvalue="#request.records"status="st">

<s:includevalue="onebooklist.jsp"></s:include> ④

</s:iterator>

<table><tr><td>

<s:beanname="org.apache.struts2.util.Counter"id="counter">

<s:paramname="first"value="#request.pageview.pageindex.startindex"/>

<s:paramname="last"value="#request.pageview.pageindex.endindex"/>

<s:ahref="bookListAction.action?page=1">首页</s:a>

<s:iterator>

<s:iftest="#request.pageview.currentpage!=current-1">

<ahref='bookListAction.action?page=<s:property/>'><s:property/></a>

</s:if>

<s:else><fontcolor="black"><b><s:property/></b></font></s:else>

</s:iterator>

<ahref="bookListAction.action?page=${pageview.totalpage}">尾页</a>|当前第${pageview.currentpage}页

|共${pageview.totalpage}页

</s:bean></td></tr></table> ⑤

</s:form>

<s:includevalue="Foot.jsp"></s:include> ⑥

</body>

s:include标签起包含页面的作用,value属性是所包含页面的名字。

代码④在图书列表中使用s:iterator标签对每个图书列表项进行逐一显示,其value的属性值为"#request.records",说明在bookListAction中对应的逻辑函数会返回名为records的变量,范围为request,这个变量就是所有符合查询结果的图书信息集合,具体可以查看下文中Action的定义。

1)排序页面(order.jsp)

排序页面如图10-1所示,使用下拉列表来选择排序条件。

其中下拉列表名称为order,“默认”的选项值为null,“上架日期”的选项值为date,“价格从低到高”的选项值为lowprice,“价格从高到低”的选项值为highprice。因此,排序页面order.jsp的主要代码为:图10-1排序页面<s:formaction="bookListAction"method="post">

排序方式:

<s:selectname="order"list="#{null:'默认','date':'上架日期','lowprice':'价格从低到高','highprice':'价格从高到低'}"></s:select>

<inputtype="image"name="imageField"src="images/a/img_32.jpg"/>

</s:form>在客户端浏览器中的输出如下:

<selectname="order">

<OPTIONvalue=""selected>默认</OPTION>

<OPTIONvalue="date">上架日期</OPTION>

<OPTIONvalue="lowprice">价格从低到高</OPTION>

<OPTIONvalue="highprice">价格从高到低</OPTION>

</select>

Struts2标签的s:select表单标签除了我们常用的name、label等属性外,还有表10-1中的一些属性。

2)查询页面(search.jsp)

查询页面如图10-2所示,使用下拉列表来选择查询字段,使用单行文本输入控件来输入查询字段的匹配关键字。图10-2查询页面其中下拉列表的名称为type,“--查看所有图书--”的选项值为null,“书名”的选项值为bookName,“书籍类型”的选项为bookType,“作者”的选项值为author,“出版社”的选项值为publisher,匹配关键字的文本输入控件名称为keyword。因此,查询页面search.jsp的主要代码为:<s:formaction="bookListAction"method="post">

图书查询:

<s:selectname="type"list="#{null:'--查看所有图书--','bookName':'书名','bookType':'书籍类型','author':'作者','publisher':'出版社'}"></s:select>

<s:textfieldname="keyword"size="40"></s:textfield>

<inputtype="image"name="imageField"src="images/a/img_08.jpg"/>

</s:form>以上表单提交触发的Action为bookListAction,其中通过判断type下拉列表的值来设置图书搜索字段,并通过keyword输入框来获取对应字段的匹配关键字,实现匹配关键字的模糊查询。

type下拉列表的list属性值直接使用OGNL表达式来创建列表,列表中的每一项都将作为HTML列表框的一个选项。在客户端浏览器中的输出如下:<selectname="type">

<OPTIONvalue="">--请选择--</OPTION>

<OPTIONvalue="bookName">书名</OPTION>

<OPTIONvalue="bookType">书籍类型</OPTION>

<OPTIONvalue="author">作者</OPTION>

<OPTIONvalue="publisher">出版社</OPTION>

</select>

3)图书列表项页面(onebooklist.jsp)

图书列表项页面如图10-3所示,显示图书名称、图片、作者、出版社、出版时间、图书描述和图书价格等信息,并提供了购买超链接。图10-3图书列表项页面

图书列表项页面onebooklist.jsp的主要代码如下(省略部分样式):

<table><tr><td>

<ahref="singleBookAction.action?id=${id}"target="_blank">

<imgsrc="${bookPic}"/></a>

</td><td>

<table><tralign="center"><td>

<h5><ahref="singleBookAction.action?id=${id}"target="_blank"><fontcolor="#006ff0">${bookName}</font></a></h5>

<hrwidth="700"></td></tr><tr><td><fontcolor="red">人气指数:${clickCount}</font>

</td></tr><tr><td>

<fontcolor="grey">作者:</font><fontcolor="#006ff0">${author}</font>

<fontcolor="grey">出版社:</font><fontcolor="#006ff0">${publisher}</font>

<fontcolor="grey">出版时间:${publishDate}</font>

</td></tr><tr><td>

内容简介:${description}<br><br>

</td></tr><tralign="right"><td>

<fontcolor="grey"><s>¥${marketPrice}</s></font><fontcolor="red">¥${sellPrice}</font>

<fontcolor="grey">节省:¥${savedPrice}</font>

<s:iftest="visible">①

<ahref="<s:urlaction="cartAction"/>?id=${id}&&visible=${visible}"><imgsrc=/images/a/cart.gif'></a>

</s:if>

<s:else><ahref="#"><imgsrc="/images/a/quehuo.gif"></a></s:else>

</td></tr></table></td></tr></table>代码①做了个条件选项,当图书的visible属性为真时,表示此图书在货架上可卖,因此显示如图10-3所示的购买图标,并触发cartAction业务(将在10.2节具体实现);当图书的visible属性为假时,表示此图书不在货架上,显示缺货的图样。本实例对缺货的处理仅保持接口,并未实现。

以上所有页面组合成图书列表booklist.jsp页面,也就是本项目的主页,如图10-4所示,图中截取了每页6条记录的两条,读者能清楚地看到本项目的主页内容。图10-4项目主页面

2.实现图书列表处理的Action

由于图书实体BookInfo的属性较多,其输入信息就会比较复杂,因此我们介绍另一种直接使用领域对象的方式,就是让action实现com.opensymphony.xwork2.ModelDriven接口。ModelDriven让用户可以直接操作应用程序中的领域对象,允许你在Web层和业务逻辑层使用相同的对象。

ModelDriven接口中只有一个方法:

publicTgetModel()

该方法返回一个用于接收用户输入数据的模型对象。在Web页面中,这个模型对象的属性可以直接通过属性名来访问,在action中也不需要为这个模型对象提供JavaBean风格的get/set方法。

1)建立模型对象

下面建立的模型对象在图书列表、图书添加、图书更

新和单本图书显示中都要用到,com.bean.book.BookInfoFormBean的代码如下,除实体BookInfo的所有属性外还包括了分页页码、排序、查询类别和查询关键字的定义,这些都是在对应action中要获取的表

单值。packagecom.bean.book;

importjava.util.Date;

publicclassBookInfoFormBean{

//当前选择分页页面

privateintpage=1;

//选定排序顺序

privateStringorder;

//查询类别

privateStringtype;

//查询关键字privateStringkeyword;

privateIntegerid;

privateStringISBN;

privateStringbookName;

privateStringauthor;

privateStringbookType;

privateStringpublisher;

publicStringbookPic;

privateDatepublishDate;;

privateStringdescription;

privateFloatmarketPrice;

privateFloatsellPrice;

privateBooleanvisible=true;

privateDatecreateDate;

privateIntegerclickCount=1;

privateIntegersellCount=0;

privateBooleancommend=false;

……//省略get/set方法

}

2)完成BookAction.java编码

代码如下:

packagecom.action.book;

……//省略导入包

@Controller//用于说明BookAction是spring容器管理的bean类

publicclassBookActionextendsActionSupportimplementsModelDriven<BookInfoFormBean>{

@Resource//在BookAction中注入BookInfoService

privateBookInfoServicebookInfoService;

privateBookInfoFormBeanbookInfoFormBean=newBookInfoFormBean();

publicvoidsetBookInfoService(BookInfoServicebookInfoService){

this.bookInfoService=bookInfoService;

}

publicStringbookList(){

try{

ActionContextct=ActionContext.getContext();

HttpServletRequestrequest=(HttpServletRequest)ct

.get(ServletActionContext.HTTP_REQUEST);PageView<BookInfo>pageview=newPageView<BookInfo>(6,

bookInfoFormBean.getPage());

QueryResult<BookInfo>qr=newQueryResult<BookInfo>();

LinkedHashMap<String,String>aa=newLinkedHashMap<String,String>();

if(bookInfoFormBean.getOrder()!=null

&&!"".equals(bookInfoFormBean.getOrder())){

if(bookInfoFormBean.getOrder().equals("date")){

aa.put("createDate","desc");}elseif(bookInfoFormBean.getOrder().equals("lowprice")){

aa.put("sellPrice","asc");

}else{

aa.put("sellPrice","desc");

}

}

Stringtype=bookInfoFormBean.getType();

if(type!=null&&!"".equals(type)){if(bookInfoFormBean.getKeyword()!=null

&&!"".equals(bookInfoFormBean.getKeyword())){

StringBuffersql=newStringBuffer("o."+type+"like?");

List<Object>pram=newArrayList<Object>();

pram.add("%"+bookInfoFormBean.getKeyword()+"%");

qr=bookInfoService.getScrollData(BookInfo.class,pageview

.getFirstindex(),pageview.getMaxresult(),sql

.toString(),pram.toArray(),aa);

}

}else{①

qr=bookInfoService.getScrollData(BookInfo.class,pageview

.getFirstindex(),pageview.getMaxresult(),aa);

}

pageview.setQueryResult(qr);

//设置pageview和records两个request范围的变量

request.setAttribute("pageview",pageview);

request.setAttribute("records",pageview.getRecords());

returnSUCCESS;

}catch(Exceptione){

e.printStackTrace();

returnERROR;

}

}

//重写ModelDriven接口方法

publicBookInfoFormBeangetModel(){

returnbookInfoFormBean;

}

}从以上代码可以看到实现了ModelDriven<BookInfoFormBean>接口,并重写了接口中的getModel()方法,实现了模型对象与action的结合。

代码中最重要的就是bookList()逻辑方法的实现,也就是商品列表显示方法。bookList()方法的实现过程可分为三个阶段来理解:●使用bookInfoFormBean.getOrder()获取order.jsp中对排序条件的选择。条件为空,即在列表中选择“默认”,没有排序语句;条件不为空,如果为date,即在列表中选择“上架日期”,那么在查询条件中设置按createDate属性降序排列;如果为lowprice,即在列表中选择“价格从低到高”,那么设置按sellPrice属性升序排列;其它设置按sellPrice属性降序排列。●使用bookInfoFormBean.getOrder()获取order.jsp中对排序条件的选择。条件为空,即在列表中选择“默认”,没有排序语句;条件不为空,如果为date,即在列表中选择“上架日期”,那么在查询条件中设置按createDate属性降序排列;如果为lowprice,即在列表中选择“价格从低到高”,那么设置按sellPrice属性升序排列;其它设置按sellPrice属性降序排列。●使用bookInfoFormBean.getType()获取search.jsp中对查询条件的选择。条件为空,即在列表中选择“--查看所有图书--”,则直接运行代码①,调用没有where条件语句的getScrollData()方法。● bookInfoFormBean.getType()不为空时,使用bookInfoFormBean.getKeyword()方法获取对应查询字段的关键字。如果关键字不为空,那么使用StringBuffer(“o.”+type+“like?”)来定义where中的查询条件,实现模糊查询,然后调用getScrollData()方法完成整个JPQL语句的执行。

bookList()方法最后返回pageview和records两个变量,读者可以在booklist.jsp页面中看到,它们分别用于分页数据和图书列表项循环变量。

3. Action配置及运行

完成了Web页面和Action的定义后,就必须对二者进行关联,也就是对struts.xml进行配置。

@Controller注释把BookAction定义为spring容器管理的bean类,其默认bean名称为bookAction,因此在struts.xml的配置代码如下:

<actionname="bookListAction"class="bookAction"method="bookList">

<resultname="success">/booklist.jsp</result>

</action>10.1.2单本图书信息显示的实现

1. singlebook.jsp页面

电子商城应通过页面来具体显示所有商品的相关信息,让用户充分了解商城中物品的信息。由于商品信息一般都比较多,而在商品列表中只能列出用户最关心的信息,因此单本图书信息页面的制作是十分必要的。

singlebook.jsp页面利用action中返回的book变量来获取图书的所有信息并显示,具体代码如下(运行显示界面见图10-5):

<h5><s:propertyvalue="#request.book.bookName"/></h5><br>

<hrwidth="600"color="red">

<tablewidth="600"><tr><td>

<imgsrc="<s:propertyvalue="#request.book.bookPic"/>"/></td>

<td><table><tr><td>作者:</td><td><s:propertyvalue="#request.book.author"/></td></tr>

<tr><td>出版社:</td><td><s:propertyvalue="#request.book.publisher"/></td>

<tr><td>上架时间:</td><td><s:propertyvalue="#request.book.createDate"/>

<tr><tdcolspan="2">

<s:iftest="#request.book.visible">在售</s:if><s:else>停售</s:else></td></tr>

</table></td>

<td><table><tr>

<td>ISBN:</td><td><s:propertyvalue="#request.book.ISBN"/></td></tr><tr><td>出版时间:</td><td><s:propertyvalue="#request.book.publishDate"/>

<tr><td>所属分类:</td><td><s:propertyvalue="#request.book.bookType"/></td>

<tr><td>是否推荐:</td>

<td><s:iftest="#mend">是</s:if><s:else>否</s:else>

</td></tr>

</table>

</td></tr></table>

<br>

<table><tr><td>定价:¥<s:propertyvalue="#request.book.marketPrice"/></td>

<td>书城价:¥<s:propertyvalue="#request.book.sellPrice"/></td>

<td>节省:¥<s:propertyvalue="#request.book.savedPrice"/></td></tr>

<tr><td>人气指数:<s:propertyvalue="#request.book.clickCount"/></td>

<td>销售量:<s:propertyvalue="#request.book.sellCount"/></td></tr>

<tr><td>

<s:iftest="#request.book.visible">

<ahref="<s:urlaction="cartAction"/>?id=${id}&&visible=${visible}">

<imgsrc="/images/a/cart.gif"></a>

</s:if>

<s:else><ahref="#"><imgsrc="/images/a/quehuo.gif"></a></s:else></td>

<td><ahref="bookListAction.action">

<imgsrc="/images/buy/as-s-continus.gif"border="0"/></a></td></tr>

</table>

<hrwidth="600"color="blue">

<tablewidth="600">

<tr><td><h3>内容简介:</h3></td></tr>

<tr><td><s:propertyvalue="#request.book.description"/></td></tr>

</table>

2. Action的实现

细心的读者会发现连接到singleBookAction的地址中有id变量的传入,这个id就是每本书的关键字id,能唯一确定单本图书表的记录,使用这个变量通过通用业务逻辑的find()函数就能获取到该id的图书记录值。

在9.1.1节的com.action.bookBookAction.java中添加singleBook()方法,可实现单本图书信息获取的业务逻辑,代码如下:publicStringsingleBook(){

ActionContextct=ActionContext.getContext();

HttpServletRequestrequest=(HttpServletRequest)ct

.get(ServletActionContext.HTTP_REQUEST);

BookInfobookInfo=bookInfoService.find(BookInfo.class,

bookInfoFormBean.getId());

request.setAttribute("book",bookInfo);

returnSUCCESS;

}

3. Struts.xml配置及运行

完成了Web页面和Action的定义后,同样必须对二者进行关联,配置struts.xml文件,代码如下:

<actionname="singleBookAction"class="bookAction"method="singleBook">

<resultname="success">/singlebook.jsp</result>

</action>

重启Tomcat,运行http://localhost/bookSite/singleBookAction.action?id=6的结果如图10-5所示。图10-5单本图书显示页面10.2购 物 车 模 块

10.2.1购物车的配置文件

1. beans.xml配置

为了让读者更加详细地了解Spring容器对bean的管理,在购物车模块中我们不采用Spring注解进行依赖注入,而使用在beans.xml中配置的方式来完成bean的定义和依赖注入。

在beans.xml中添加如下代码:<beanid="bookInfoServiceBean"class="com.service.bean.impl.BookInfoServiceBean"/>

<beanid="cartAction"class="com.action.shopping.CartAction"scope="prototype">

<propertyname="bookInfoService">

<reflocal="bookInfoServiceBean"/>

</property>

</bean>

<beanid="cartManageAction"class="com.action.shopping.CartManageAction"scope="prototype"/>

2. struts.xml配置

对于购物车模块,一共涉及两大部分的action配置,包括购物车action和购物车管理action。

(1)购物车配置的代码如下:

<actionname="cartAction"class="cartAction">

<resultname="success">/cart.jsp</result>

</action>(2)购物车管理配置的代码如下:

<!--清空购物车-->

<actionname="delete"class="cartManageAction"method="delete">

<resulttype="redirect">cartAction.action</result>

</action>

<!--购物车物品单项删除-->

<actionname="deleteall"class="cartManageAction"method="deleteAll">

<resulttype="redirect">cartAction.action</result></action>

<!--购物车更新-->

<actionname="updateAmount"class="cartManageAction"method="updateAmount">

<resulttype="redirect">cartAction.action</result>

</action>

购物车的更新主要是图书数量的更新,在10.2.3节将完成购物车管理的一系列功能。10.2.2购物车的实现

Session的好处是开发简单、效率较高,但相对内存占用会较多,尤其是访问量比较大的网站;而数据库的效率显然也是个问题。很多时候一些大型电子商务网站会从业务角度来综合使用这两种方式。具体为:

(1)只有在用户选择“添加商品到购物车”时才创建购物车对象。要知道大多数的用户都处于浏览状态,为每个光临的用户都自动创建一个购物车显然是不明智的。

(2)将购物车临时存储到Session中有个好处,就是我们可以为没有登录的用户提供购物车服务,只有在用户进行结算的时候才需要登录。当然,我们也可以使用SessionID作为唯一识别符将购物车存储到数据库中。

(3)对于已经登录的用户,如果他的购物车不为空,我们会在Session过期时将他的购物车数据存储到数据库中,这样用户下次进入网站的时候就可以持有上次挑选的商品进行一次结算,这种人性化的方式更加吸引用户。不过这里面有个陷阱就是折扣的问题,因为很多促销活动中,商品的价格和日期有关,因此这种方式可能带来商品价格上的混乱。

对于中小型购物网站显然不用考虑得这么周全。本项目使用Session来实现购物车。

1.实现Session监听

利用Session实现购物车存在的一个关键解决问题就是Session的监听。

大部分读者应该清楚,Session变量的作用范围仅限于同一个IE浏览器页面,如果打开另一个IE浏览器页面,则Session变量将会重新赋值。而用户可能会打开多个窗口来查看图书信息并进行购买,要保证用户的商品都在同一个购物车中,就要实现Session创建和摧毁的监听。

1) Session监听器类

Session监听器类为com.action.shopping.SiteSessionListener.java,具体代码如下:

packagecom.action.shopping;

importjava.util.HashMap;

importjava.util.Map;

importjavax.servlet.http.HttpSession;

importjavax.servlet.http.HttpSessionEvent;

importjavax.servlet.http.HttpSessionListener;

publicclassSiteSessionListenerimplements

HttpSessionListener{

privatestaticMap<String,HttpSession>sessions=newHashMap<String,HttpSession>();

publicvoidsessionCreated(HttpSessionEventsessionEvent)

{

sessions.put(sessionEvent.getSession().getId(),sessionEvent.getSession());}

publicvoidsessionDestroyed(HttpSessionEventsessionEvent)

{

sessions.remove(sessionEvent.getSession().getId());}

publicstaticHttpSessiongetSession(StringsessionID)

{

returnsessions.get(sessionID);}

publicstaticvoidremoveSession(StringsessionID)

{

if(sessions.containsKey(sessionID))

sessions.remove(sessionID);}

}

2) Session监听器配置

Session监听器配置在web.xml中,也就是在工程启动时,具体代码如下:

<listener>

<listener-class>com.action.shopping.SiteSessionListener</listener-

class>

</listener>

3)测试监听器

(1)不使用监听器。根据10.2.1节的配置,新建购物车的action业务逻辑,代码在com.action.shopping.CartAction.java中。

packagecom.action.shopping;

……//省略导入包

publicclassCartActionextendsActionSupport{

privateBookInfoServicebookInfoService;publicvoidsetBookInfoService(BookInfoServicebookInfoService){

this.bookInfoService=bookInfoService;}

publicStringexecute()throwsException

{

ActionContextct=ActionContext.getContext();

HttpServletRequestrequest=(HttpServletRequest)ct.get(ServletActionContext.HTTP_REQUEST);

if(request.getSession().getAttribute("out")==null){

request.getSession().setAttribute("out",newDate());

}

returnSUCCESS;

}

}

新建cart.jsp文件,输出out变量,即${out},测试运行http://localhost/bookSite/cartAction.action,打开两个浏览器,发现显示的时间不相同,说明在不同的页面同一个Session值不会被保存。

(2)使用监听器。修改以上的execute方法,代码如下:

publicStringexecute()throwsException

{

ActionContextct=ActionContext.getContext();

HttpServletRequestrequest=(HttpServletRequest)ct.get(ServletActionContext.HTTP_REQUEST);

Stringsid=request.getParameter("sid");

HttpSessionsession=SiteSessionListener.getSession(sid);

System.out.println(session);

if(session==null){

request.getSession().setAttribute("buycart",newDate());

}

else{

request.setAttribute("message",session.getAttribute("buycart"));

}

returnSUCCESS;

}修改cart.jsp文件,输出message变量,即${message},测试运行http://localhost/bookSite/cartAction.action,在【console】控制台输出字符串A(A代表访问的session的sid值,一般如“D6DEC55CEBC4EFB51B8FC52EEAA67181”字样),另外打开一个IE窗口,在【console】控制台输出字符串B,而且页面显示的时间不一致。但是当把第二个页面的访问地址改成http://localhost/bookSite/cartAction.action?sid=字符串A,则第二个页面的时间就会与第一个页面的时间一致,这说明Session监听器设置成功。

在购物模块中可以把第一个页面的时间看成是购物车的物品,当打开新的浏览器时就可以通过Session监听器获得此购物车的物品。下面进入购物车模块制作的讲解。

2.初步实现购物车功能

实现购物车功能时,首先要实现每项购买产品的添加。那么,添加到购物车的购物项应该存放哪些相关数据呢?这就是我们这节首先要解决的问题。

1)购物项辅助类的实现

编写购物项类com.bean.BuyItem.java,其中属性book代表每个购物项中的书目,属性amount代表对应购物项中书的数量,具体代码如下:

packagecom.bean;

importcom.bean.book.BookInfo;

publicclassBuyItem

{

privateBookInfobook;

privateintamount;

publicBuyItem(){}

publicBuyItem(BookInfobook){

this.book=book;}

publicBuyItem(BookInfobook,intamount){

this.book=book;

this.amount=amount;}

……//省略get/set方法

ublicinthashCode(){

finalintprime=31;

intresult=1;

result=prime*result+((book==null)?0:

book.hashCode());

returnresult;}

publicbooleanequals(Objectobj){

f(this==obj)returntrue;

if(obj==null)returnfalse;

if(getClass()!=obj.getClass())returnfalse;

BuyItemother=(BuyItem)obj;

if(book==null){

if(other.book!=null)returnfalse;

}elseif(!book.equals(other.book))returnfalse;

returntrue;}

}以上hashCode()和equals()两个方法的定义表示BuyItem类之间的比较依赖book属性,也就是book属性相同的两个BuyItem实例相等,也就是同一本书被看成同一个购物项,如果被多次点击购买,那么只是在同一个购物项中增加amount的数量。

我们可以对购物项的比较做一个测试,建立测试类junit.test.BuyCartTest.java,测试购买同一种图书是否能通过购物项判断出来,具体代码如下:packagejunit.test;

……//省略导入包

publicclassBuyCartTest

{@Test

publicvoidtest()

{

BookInfobook1=newBookInfo(1);

BuyItembuyItem1=newBuyItem(book1,5);

BookInfobook2=newBookInfo(1);

BuyItembuyItem2=newBuyItem(book2,9);

System.out.println(buyItem1.equals(buyItem2));

}

}

2)购物车类的实现

有了购物项的定义,那么只有建立购物车类,再把购物项添加到购物车就可以完成购物车的业务逻辑。

建立购物车com.bean.BuyCart.java,其中包含购物项列表items和添加购物项功能addItem()方法,具体代码如下:packagecom.bean;

……//省略导入包

publicclassBuyCart

{privateList<BuyItem>items=newArrayList<BuyItem>();

……//省略get/set方法

publicvoidaddItem(BuyItemitem)

{if(!items.contains(item))

items.add(item);

else

{for(BuyItembi:items)

{if(bi.equals(item))

{bi.setAmount(bi.getAmount()+1);

break;

}}}}

在addItem()方法中先判断购物项列表中是否存在要购买的书,如果不存在,则添加购物项;如果存在该购物项,则累加其购买数量。

3)购物车Action的实现

实现了购物车类,就完成了购物车Action的逻辑处理辅助类的编写。因此,根据前面的session测试方法,修改com.action.shopping.CartAction.java文件,即可实现Web页面的输出和购物车物品的获取。具体代码如下:packagecom.action.shopping;

……//省略导入包

publicclassCartActionextendsActionSupport{

privateIntegerid;

privateBooleanvisible;

privateBookInfoServicebookInfoService;

……//省略get/set方法

publicStringexecute()throwsException{ActionContextct=ActionContext.getContext();

HttpServletRequestrequest=(HttpServletRequest)ct.get(ServletActionContext.HTTP_REQUEST);

HttpServletResponseresponse=(HttpServletResponse)ct.get(ServletActionContext.HTTP_RESPONSE);

BuyCartbuyCart=(BuyCart)request.getSession().getAttribute("buycart");

//判断其它页面有无buyCart存在

if(buyCart==null){Stringsid=WebUtil.getCookieByName(request,"buyCartID");

if(sid!=null)

{HttpSessionsession=SiteSessionListener.getSession(sid);

if(session!=null)

buyCart=(BuyCart)session.getAttribute("buycart");

if(buyCart!=null)

{SiteSessionListener.removeSession(sid);

request.getSession().setAttribute("buycart",buyCart);

WebUtil.addCookie(response,"buyCartID",request.getSession().getId(),request.getSession().getMaxInactiveInterval());

}

}

}

//若其它页面无buyCart存在,则新建session

if(buyCart==null)

{buyCart=newBuyCart();

request.getSession().setAttribute("buycart",buyCart);//session的最大存放时间为30分钟

WebUtil.addCookie(response,"buyCartID",request.getSession().getId(),request.getSession().getMaxInactiveInterval());

}

if(getId()!=null&&getId()>0)

{BookInfobook=bookInfoService.find(BookInfo.class,getId());

if(book!=null&&getVisible()){buyCart.addItem(newBuyItem(book,1));

//把商品放入购物车

}else{System.out.println("停售");}

}

request.getSession().setAttribute("buyCart",buyCart);

returnSUCCESS;

}

}以上代码中使用了工具类com.utils.WebUtil.java中的addCookie()方法,对cookies进行处理,该类的代码为:

packagecom.utils;

……//省略导入包

publicclassWebUtil{

publicstaticStringgetCookieByName(HttpServletRequestrequest,Stringname){

Map<String,Cookie>cookieMap=

WebUtil.readCookieMap(request);

if(cookieMap.containsKey(name)){

Cookiecookie=(Cookie)cookieMap.get(name);

returncookie.getValue();

}else{returnnull;}}

protectedstaticMap<String,Cookie>readCookieMap(HttpServletRequestrequest){

Map<String,Cookie>cookieMap=newHashMap<String,Cookie>();

Cookie[]cookies=request.getCookies();

if(null!=cookies){

for(inti=0;i<cookies.length;i++){

cookieMap.put(cookies[i].getName(),cookies[i]);

}}

returncookieMap;

}}

4)测试简单的购物车数据

下面我们把cart.jsp页面改为如下代码,显示购买的书名和数量:

<s:iteratorvalue="#session.buyCart.items"status="st">

${bookInfo.bookName},${amount}<br/>

</s:iterator>重启服务器,http://localhost/bookSite/bookListAction.action点击购买超链接,出现购买图书的名字和数量列表,打开两个窗体,购买的图书会自动累加说明购物车初步功能完成,如图10-6所示。图10-6简单购物车页面

3.完善购物车

现在我们该做的事就是完善购物车的显示页面,让页面中显示一般购物车通常具备的功能,如提供更新数量的表单、提供删除商品的链接和提供生成订单的链接等。

1)美化cart.jsp文件

读者可以自己制作或使用课件中的cart2.jsp(根据struts.xml配置把文件名改为cart.jsp)来实现静态购物车页面的美化,参考图样见图10-7。图10-7静态购物车页面●各项超链接:包括单本图书详细信息查看、继续挑选商品和进入结算中心。

●图书购物项列表:包括每项的书名、图书定价、商城价、每本节省价和数量。

●购物车统计项:包括购物车商品总价和总共节省费用。

●购物车管理操作:包括更新购物项数量、删除购物项和删除购物车,这部分内容将在10.2.3节中讲解。

2)各项超链接

(1)单本图书详细信息。在每本书的书名上含有单本图书的详细信息链接,地址为

<ahref="singleBookAction.action?id=${book.id}"

target="_blank">…</a>,大部分购物车都具有这个功能,让买家在确定购买前能再次查看物品的详细信息。

(2)继续挑选商品。“继续挑选商品”图标链接的地址为<ahref="bookListAction.action">

……</a>,也就是重新进入图书列表页面挑选图书。

(3)进入结算中心。图中两个“进入结算中心”图标链接的地址设置为<ahref="orderAction.action">……</a>,就是进入订单功能模块,这部分内容将在10.3节中讲解。

3)图书购物项列表

中间的图书购物项列表使用循环来实现各购物项的显示,代码参考如下(省略各样式):

<formname="buycart"action="<s:urlaction="updateAmount"/>"method="post">

<inputtype="hidden"name="method"value=""/>

<table><tr><td><strong>我的购物车里的商品--马上购买</strong></td>

<td><divalign=center><strong>市场价</strong></div></td><tdwidth=181><divalign=center><strong>图书价格</strong></div></td>

<tdwidth=73><divalign=center><strong>数量</strong></div></td>

<tdwidth=66> </td></tr>

<s:iteratorvalue="#session.buyCart.items"status="">

<tr><td><strong><ahref="singleBookAction.action?id=${book.id}"target="_blank">${book.bookName}</a></strong><br/></td><td><s><b>¥${book.marketPrice}元</b></s></td>

<td><palign="center"><b>¥${book.sellPrice}

元</b><br/>

为您节省:¥${book.savedPrice}元<br/></p></td>

<td><inputtype="text"value="${amount}"name="amount_${book.id}"onkeypress="javascript:InputIntNumberCheck()"maxlength="3"/></td><td><ahref="delete.action?buyitemid=${book.id}">

<imgsrc="/images/buy/delete.gif"/></a></td></tr>

</s:iterator>

</table>

</form>以上通过<s:iteratorvalue=“#session.buyCart.items”>…</s:iterator>循环,对购物车列表项的数据库信息遍历,并把图10-7中的静态文字内容编写成动态数据,分别对应的代码为:

●图书名称:${};

●图书定价:${book.marketp

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论