引言
现在,开发和管理一个电子商务系统需要高效率的开发和利用网络资源,特别是如果你想让你的顾客在网上购买你的产品或是取得你提供的服务的话,更要注意这一点。构建一个这样的商务网站来实现你商业上的目的并不是一件非常简单的工作,在开发电子商务网站的时候,我们就要充分的利用搞技术含量的技术,我们可以利用到最先进的Java 技术:Java Server Pages(JSP),Java Servlets 和JavaBeans(甚至是EJB),它们各自都有自己的不同的优点,因此了解在构建一个电子商务网站时如何合理的利用它们各自的优势,并且把它们联合起来以完成你想达到的效果是非常重要的。
当然,我们可以只使用 JSP来构建电子商务系统,比如一个简单的购物车系统,但是如果你要想完成一个有效的的应用程序,并使它用于商业上,则需要综合以上我所说的三种技术相互补充的力量。让我们来看怎么把它们联合起来以完成最好的效果吧!我们都知道,JSP是Sun公司倡导的用来替代微软ASP的纯Java替代品,JSP技术发展壮大了Java Servlet技术,事实上, JSP引擎在运行JSP时也把JSP页面翻译成 Servlets;而不用我多说,大家一定都知道Servlets在网络编程世界是非常流行的,因为它在理论上和实践上都是可以完全取代 CGI脚本的,Servlets能产生动态的网页,这是通过把静态的HTML与数据库查询或事务性服务提供的内容混合起来实现的。JSP则是通过在HTML页面中内嵌Java代码这条途径来实现生成动态的网页的目的的,把Java代码插入到HTML页的这种能力极大的增加了基于Java Servlet网络体系结构的灵活性。
为了产生 HTML , servlet 必须用println()输出格式化的HTML字符串,如:
out.println("<html>");
out.println("<br><br>购物车系统");
out.println("</html>");
从上面的代码段中可以看出,servlet用println()输出HTML页面,也就是说,当编写一个 Java Servlet时,开发者必须充当程序员和网页设计师两个身份。而JSP则是在HTML中嵌入简单的Java代码,使普通的HTML网页设计师也能写出优秀的动态网页,这样就使网站的设计沿着两条平行的轨道,即Java程序设计和HTML页面设计共同进行下去,从而加快网站开发的速度和开发的质量。JSP也支持业务逻辑组件和现有的组件之间的宽松连接,从而做到可重用性。
下面,我想通过一个简单的购物车程序来说明一下 JSP,Servlet和Bean在网络体系结构中是怎样相互作用的,并且借这个例子解释编写一个实际可用的电子商务应用程序应该注意的一些问题。
简单购物车的实现方案
我们的购物车方案实际上是一种简化了的在线商店的模型:顾客选择商品,添加到他们的购物车中,然后通过一系列形式最终购买这些商品。上图中就显示了我们的应用程序体系结构是如何把 JSP、servlets 和 JavaBeans有机的结合起来的,从图上更可以看出,只使用 JSP来构建一个简单网络应用程序是可行,但是一个有效的应用程序是这三种技术共同作用的结果。
解释了model-view-controller( MVC )模式,它把应用程序划分成独立的数据管理(Model),表现形式(View)和控制组件(Controller),成为最先进的图形用户接口的基础,这些划分模块支持独立开发并且可以重复使用组件。我们也能把 MVC 模式应用于我们的网络应用程序中:JSP最适合充当实现网络应用程序的对外表现的部分;而JavaBeans封装了提供给Web网站的服务信息内容并且简化了数据在体系结构组件之间的传输;Servlet则正好充当控制者和协调用户请求和应用程序信息、更新程序数据等功能。
好,前面我们已经有了“CustomerServlet”大致的设计方案,现在让我们来看看编写我们应用程序上的一些细节问题。
代码1 CustomerServlet.java
package shoppingcart;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class CustomerServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
// 处理顾客请求
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
// 取得请求的Session对象
HttpSession session = request.getSession(true);
BasketBean basket = null;
file://如果没有购物车则创建一个新的如果已存在,则更新它
basket = (BasketBean)session.getAttribute(BasketBean.BASKET);
if(basket == null) {
// 新的顾客,创建一个购物车。
basket = new BasketBean();
session.setAttribute(BasketBean.BASKET, basket);
}
else {
// 已存在的顾客,保存篮中的内容。
basket.savePurchases(request);
}
// 取得当前的工作流程。
RequestDispatcher rd = null;
String nextPage = request.getParameter(BasketBean.PAGE);
if (nextPage == null ||
nextPage.equals(BasketBean.UPDATE)) {
// 从目录中查找选择
rd = getServletConfig().getServletContext().getRequestDispatcher("Inventory.jsp");
}
else if (nextPage.equals(BasketBean.PURCHASE)) {
// 提供购买信息
rd = getServletConfig().getServletContext()
.getRequestDispatcher("Purchase.jsp");
}
else if (nextPage.equals(BasketBean.RECEIPT)) {
file:// 提供购买信息
rd = getServletConfig().getServletContext().getRequestDispatcher("Receipt.jsp");
}
if (rd != null) {
rd.forward(request, response);
}
}
}
上面的程序段显示了CustomerServlet类中的doGet()和doPost()方法。CustomerServlet类做了两件事情来控制我们应用程序的工作流程:
一、通过 BasketBean 类实现,保持购物车组件的状态,;
二、它通过一系列的JSP页面向顾客发送请求。
一旦我们的购物车与某一个特定的顾客session相联系,顾客的BasketBean对象的实例就会存储在 HttpSession对象中。一个以普通ID进入CustomerServlet工作流程的客户,他会产生很多动作,servlet引擎提供了HttpSession对象来组织并存储这一系列的相互作用(Session对象为存储和取回任何使用唯一的键/值对的Java对象提供了方便的方法)。在CustomerServlet类中 ,我们首先通过HttpSession session = request.getSession(true)从 servlet 引擎中取得Session对象,大家都可以看到,我们传递了true值,意思是我们告诉Servlet引擎,如果一个session对象已经不存在了,就新建一个;然后我们查看Session中是否有我们的购物车,如果我们找不到购物车,我们就知道这个购物Session刚刚开始,我们必须新建一辆购物车,并且把它保存在Session对象中,如果我们能够在Session中找到购物车,那我们就知道顾客正处在一个购物期间,那时就必须存储购物车当前的状态。在查看了购物车的状态之后,我们把顾客的请求发送到相应的JSP页中去,请求本身包含一个状态参数(BasketBean.PAGE)告诉CustomerServlet把请求发送到哪里,我们的控制器取回这个参数,然后使用一个RequestDispatcher对象把请求提交给下一个JSP页。
代码段2:BasketBean类
package shoppingcart;
import javax.servlet.http.HttpServletRequest;
import java.util.Hashtable;
import java.util.Enumeration;
public class BasketBean {
final static public String BASKET = "Basket" ;
final static public String PAGE = "Page" ;
/*
工作流程的状态
*/
final static public String UPDATE = "Update" ;
final static public String PURCHASE = "Purchase" ;
final static public String RECEIPT = "Receipt" ;
/*
当前购物篮中有那些商品。
主键是商品号 ,值为 Product对象
*/
private Hashtable products_ = new Hashtable();
public BasketBean() {
}
/*
计算篮中的商品的总价值。
*/
public double getTotal() {
double totalPrice = 0.0 ;
Enumeration e = products_.elements();
while(e.hasMoreElements()) {
Product product = (Product)e.nextElement();
totalPrice += product.getPieces() *
product.getPrice();
}
return totalPrice;
}
/*
取得篮中某个商品的个数。
*/
public double getPieces(Product p_in_inv) {
int SKU = p_in_inv.getSKU();
Product p = (Product)products_.get(
Integer.toString(SKU));
if(p == null)
return 0.0 ;
else
return p.getPieces();
}
/*
用当前的选择更换篮中的内容。
*/
public void savePurchases(HttpServletRequest request) {
Product[] products = InventoryBean.getCatalogue();
String[] lbValues = request.getParameterValues("pieces" );
if (lbValues != null) {
products_.clear();
for (int i = 0 ; i < lbValues.length; i++) {
double lbs = Double.parseDouble(lbValues[i]);
if(lbs > 0 ) {
Product p = null;
p = (Product)products[i].clone();
p.setPieces(lbs);
products_.put(Integer.toString(p.getSKU()), p);
}
}
}
}
file://利用一个函数实现统一的显示商品价格的方式
public static String getStringifiedValue(double value) {
String subval = "0.00" ;
if (value > 0.0 ) {
subval = Double.toString(value);
int decimal_len = subval.length() -(subval.lastIndexOf(´.´) + 1 );
if(decimal_len > 1 )
subval = subval.substring(0 , subval.lastIndexOf(´.´) + 3 );
else
subval += "0" ;
}
return subval;
}
/*
清空篮内的东西
*/
public void clear() {
products_.clear();
}
}
代码段2中 BasketBean类实现购物车应用程序中一个简单的数据管理模型,它提供了一个方法,用于取得一个顾客正在购买的货物的信息,还提供了一个方法用来更新购物车的内容,我们使用一张哈希表来维护顾客请求的商品列表。InventoryBean对象管理商品的目录,我们是使用一个数组来实现商品的目录的。每个Product类的实例存储四个属性:商品名字,商品标识号,单价和购买的数量,只要顾客购买了东西,Product类的实例就会改变。
JSP显示页面
我们的购物车方案中设定了3个JSP 页面: Inventory.jsp , Purchase.jsp和Receipt.jsp (代码见下)。应用程序发送Inventory.jsp页面给新来的顾客,顾客通过不断的更新Inventory.jsp,来挑选商品;顾客选择好想要购买的商品以后,应用程序就会把顾客的购买请求发送到Purchase.jsp页,进行处理;最后,顾客证实确实购买这些商品,应用程序把顾客请求发送到Receipt.jsp.
我和说明的方便,我想把JSP的基本内容再简要的向大家介绍一下。JSP页面是使用特定的JSP标记与标准的 HTML混合,除了固定的模板数据以外,JSP页还能包括指令,脚本单元和动作,我们购物车系统也说明了以上三点,现在我想就这三个问题简单的谈一谈。
在JSP页面中,我们可以使用JSP指令将一些与页面有关的信息传递到JSP引擎,指令的主要作用就是用来与JSP引擎之间进行沟通的,JSP中的指令是有语法规范的:<%@ directive %>
page指令
page指令定义了一系列与JSP页面相关的属性,并用它们与JSP引擎进行通信。例如, 在Inventory.jsp中使用的一条page指令:<%@ page buffer="5kb" language="java" import="shoppingcart.*" errorPage="Error.jsp" %> 这条指令告诉JSP引擎,输出缓冲区大小是5k,在溢出之前输出缓冲区的输出流,它也向JSP引擎说明,当前页使用的脚本语言是Java语言,并请求引擎导入shoppingcart包中的所有Java类,最后,它还指示如果有任何无法处理的错误,就重定向到Error.jsp页面中去。因为在JSP1.1中,只能使用 Java作为脚本语言,所以我们可以省略page指令中关于脚本语言的那部分说明。
include指令用来指定JSP文件被编译的时候,需要插入的文本或者代码,被包含的文件要能够被JSP引擎控制和访问。Inventory.jsp文件也使用了include指令:
<%@ include file="header.html" %>
<%@ include file="footer.html" %>
第一个指令为我们的页面插入了一个标准的页眉;第二个指令则插入一个标准的注脚。我们可以使用这些指令为我们的JSP页面创造一致的外观。
JSP脚本元素为你提供了把Java代码插入由当前的JSP页面产生的Servlet功能。在JSP中,有三种脚本语言元素---声明、小脚本和表达式。这些元素的语法形式是:
<%! declaration; %>
<% scriptlet %>
<%= expression %>
Inventory.jsp中三种元素都使用了。
下面的JSP片段用来声明局部变量保存当前购物篮(BasketBean的实例)和产品目录。
<%! BasketBean basket;
Product[] catalogue;
%>
从上面我们可以看出,JSP 声明必须以一个分号结束,并且这个声明的范围是整个JSP页。
声明这些局部变量以后,Inventory.jsp 使用一段小脚本从session对象中取回购物车对象(BasketBean)和商名目录,如下。
<% basket =(BasketBean) session.getAttribute( BasketBean.BASKET);
catalogue = InventoryBean.getCatalogue();
%>
所以我们可以看出,JSP 声明和 JSP小脚本只是放在特定的JSP标记之间的Java代码,当JSP引擎把一个JSP程序翻译成一个servlet时,它就把这些Java代码内嵌到新的Servlet代码中去。
前面我们说过,我们从一个session对象中取得购物车对象,这个session对象是一个内部物体。JSP引擎提供一些内部隐含对象,这些对象可以直接被引用,我们可以不事先声明,也不需要专门的代码来创建他们的实例。它们在小脚本和表达式中总是可以使用的,而不需要预先声明。JSP 1.1 规范中列出内部隐含对象完整的集合。在程序中,另一个象这样的对象就是 HttpServletRequest对象(request),它在CustomerServlet类中作为一个参数被传递到 doPost()方法中,这就意味着Inventory.jsp 能够通过调用request.getSession(true).getAttribute(BasketBean.BASKET)来取回购物车的信息了。
在JSP中表达式和小脚本为JSP动态生成网页提供一个强有力的工具。从下面的Inventory.jsp程序中我们可以看出,JSP代码段循环访问商品目录并且动态地为每个产品产生HTML表格,我们使用小脚本编写循环,然后在每一行中都混合使用HTML和JSP表达式。
(注:JSP引擎把小脚本标记之间的Java 代码直接插入引擎内部产生的 servlet 代码。JSP引擎对待JSP表达式也是不同的。它先把JSP表达式变换成字符串,然后在内部产生的servlet中把它们包入一个out.println()调用中。)
代码段3 Inventory.jsp
<!--
Inventory.jsp -
显示商品目录并且获取用户购买的物品及其数量单价等信息
-->
<html>
<%--
页面的头部,使用另一个HTML页面,通过include指令来实现
--%>
<%@ include file="header.html" %>
<!--
显示标题
-->
<BR>
<CENTER>
<TITLE> 中国科学技术大学百货商店</TITLE>
<FONT SIZE="+1">
<B> 欢迎选购我们的商品</B>
</FONT>
<BODY BGCOLOR="#FFFFF">
<!--
Page指令