|
out.println(“<TD>”+aToy.getShortDescription());
out.println(“<TD>”+aToy.getFullDescription());
out.println(“<TD>”+aToy.getPriceAsString());
String boxId=String.valueOf(checkboxNumber++);
out.println(“<TD><INPUT id=”+boxId+”\”TYPE=\”checkbox\” NAME=\””+boxId+”\”>” );
}
out.println(“</TABLE>”);
out.println(“<br><br>”);
out.println(“<INPUT TYPE=\”submit\” NAME=\”PurchaseButton\” VALUE=\”Purchase selected toys\” id=\”PurchaseButton\”>”);
out.println(“</FORM>”);
out.println(“<p><h2>Thank you for your inteest in JKToys!!!</h2>”);
out.println(“</body></html>”);
out.flush();
out.close();
return;
}
注意,显示玩具的table是在一个form里建立的。table的最后一列包含一个checkbox,用来让客户选择哪些玩具他希望购买。checkbox的名字是从0开始的顺序的数字。它们将被用作索引,从包含所有玩具的向量里提取选择的玩具。这将在TotalPurchaseServlet里作。
每一个玩具的价格存在玩具对象里,这个值作为float保存。floats的格式不能被正确地打印,所以toy类有一个方法getPriceAsString(),它执行格式化。
保存这个方法。
6. 最后,创建一个showError()方法。它将在会话信息不管因何种原因无效时被调用。输入以下行实现这个方法。
private void showError(PrintWriter out){
//Outpur failure message
out.println(“<head><title>JK Toys error page</title></head>”);
out.println(“<body>”);
out.println(“<p><h2>Sorry,we don’t have a record of your customer name make a valid selection</h2>”);
out.println(“<p>Please press the <strong>Back</strong>button,and resubmit.</p>”);
out.println(“<p>Thank you for your interest in JKToys!!!”);
out.println(“</body></html>”);
out.flush();
return;
}
保存这个方法。
这个完成了DisplayToysServlet。你应该登录进JKToys Kids Zone,在确认你成功登录进站点的页面上选择Display toysfor my age group链接,以测试这个servlet。
第三部分:完成servlet,显示在DisplayToysServlet里选中的玩具
这个servlet,TotalPurchaseServlet,也总计选中的玩具的价格,显示总数。客户有个机会确认购买,完成定单,或取消定单。
1. 从com.ibmwaslab.servlet2包里选择TotalPurchaseServlet。打开doPost()方法。最初的几行已经为你输入好了:
//Obtain output stream from response object
PrintWriter out=res.getWriter();
//Set content type on the response header
res.setContentType(“text/html”);
//Get the session and retrieve the customer information
HttpSession session=req.getSession(false);
Vector toys=(Vector)session.getValue(“TOYS”);
这些行执行一些你在前面建立的servlets里作的典型的任务。PrintWriter从resposne 对象里取得,你设置MIME内容,从会话里取得玩具向量。这个向量包含所有这个客户的年龄组的玩具。
2. 在下面的步骤里,你将向doPost()方法里增加代码来完成功能。在doPost()输入:
//declare an object to hold the toy order
JKToysOrder toysToBuy=null;
//Get the input form contents
toysToBuy = getFromInput(req,toys);
实现你声明一个null JKToyOrder对象。这个对象将包含客户选择的玩具的集合。JKToyOrder类还包含定单的价格总和。
下一行调用了getFormInput()方法,你将在下一个步骤里建立它。保存doPost()方法,你将得到错误,因为你还没有些getFormInput()方法。继续,带着错误保存。
3. 创建getFormInput()方法。这个方法循环通过前面表格里的checkboxs,用checkbox的名字作为玩具向量的索引。被选中的玩具被加进定单。
注意:只有被选中的(checked)checkbox被从表格发送回servlet。submit按钮也被传送。按钮的值被忽略,看下面的代码。
输入下面的代码来完成getFormInput()方法。
private JKToyOrder getFormInput(HttpServletRequest req,Vector allToys){
JKToyOrder selectedToys =new JKToyOrder();
Enumeration fieldName=req.getParameterName();
int i=0;
while (fieldNames.hasMoreElements())
{
String paramName=(String)fieldName.nextElement();
String paramValue=(String)req.getParameterValue(paramName)[0];
try
{
int toyIndex=Integer.parseInt(paramName);
selectedToys.addToy(allToys.elementAt(toyIndex));
}
catch (NumberFormatException e)
{
//Skipping the button widget,only interested in checkboxes
//with numeric names
}
}
return slectedToys;
}
你也许要看看JkToyOrder类,看它是怎么工作的,它可以在com.ibm.waslab.common包里找到。
保存方法,打开doPost()。
4. 在你输入的最后一行后面,继续建立doPost()方法,输入以下的代码:
//toysToBuy order will be empty if nothing was selected
if(toysToBuy.isEmpty())
{
//Output failure message
out.println(“<html>”);
out.println(“<head><title>No toys selected</title></head>”);
out.println(“<body>”);
out.print(“<p><h2>Nothing selected</h2>”);
out.println(“<p><font color=\”red\”> You did not select any toys!</font></p>”);
out.println(“<p>Please press the <strong>Back</strong> button,and resubmit.</p>”);
out.println(“<p>Thank you for your interest in JKToys!!!”);
out.println(“</body></html>”);
out.flush();
return;
}
else
(
displaySelections(res,req,toysToBuy);
}
这段代码检查是否至少有一个玩具被选择,如果toysToBuy定单是空的,一个错误消息被显示。如果定单不空,displaySelections()方法被调用来显示一个包含被选中的玩具的表。
保存doPost()方法,应该没有错误。
5. 完成displaySelections()方法。这个方法同DisplayToysServlet里的displayToys方法很相似,有一些差别。输入以下的代码来完成TotalPurchase Servlet类里的一个新的方法:
//Enumeration selectedToys=toys.elements();
Toy aToy=null;
while(!toys.isEmpty())
{
aToy=(Toy) toys.getNextToy();
out.println(“<TR>”);
out.println(“<TD><IMG SRC=\”..”+aToy.getThumbnailFile()+”\”>”);
out.println(“<TD>”+aToy.getShortDescription());
out.println(“<TD>”+aToy.getFullDescriptin());
out.println(“<TD>”+aToy.getPriceAsString());
}
out.println(“<TR>”);
out.println(“<TD><INPUT TYPE=\”submit\=”
NAME=\”ConfirmationPurchaseButton\”
VALUE=\”Confirmation Purchase\”
id=\”ConfirmPurchaseButton\”>”);
out.println(“<TD><strong>Your total purchase amount is:</strong>”);
out.pritnln(“<TD><strong>”+toys.getTotalPriceAsString()+”</strong>”);
out.println(“</TABLE>”);
}
6. 这个方法负责显示选中的玩具,和显示定单的总价格。这里有两个按钮在表格上,一个处理购买,另一个取消定单;在这个课程里这两个按钮调用的servlets没有被实现,学生在业余时间实现它们。
在这个练习里你处理客户登录,基于客户的年龄显示一个选中的玩具的表,让客户从列表里选择玩具,显示最后的选中的玩具的总和和这次定购的总额。你学习了怎样用会话保持servlets和HTML页面之间的状态。你还学会了几种从一个表格里显示和选择项目的方法。
JSP3:JSP页面
在这个练习里你将创建一个JavaServer Page。servlet的目的是允许Customer Profile更新信息。
客户登录进JKToys的Kids Zone部分以后,客户可以作的一个选择是:更新他们的客户信息。为了处理这个,我们需要一个网页显示这个JKToysCustomer对象相联系的每一个信息(客户ID除外),作为编辑区域。这些字段需要用当前的客户记录的数据初始化。这些字段将是一个客户记录更新表格的一部分,将被提交给ProfileUpdateServlet来处理。
第一部分:JSP文件
1. 你将从一个HTML文件开始,[x]:\www\html\JKToys\html\body_jktoys-kids_zone_change_start.aspl(x是Lotus Domino Go Webserver安装的驱动器字母,文件是用NetObjects Fusion编辑的。第一步是在你的浏览器里打开这个文件(作为本地文件)。你看到的是一个Table,字段对应JKToysCustomer properties。每一个字段(加上一个隐藏字段)都需要在运行时用live Customer data生成。我们将用JSP语法作这个。
2. 用NetObjects ScriptBuilder打开HTML文件(Start->Programs->NetObjects ScriptBuilder->NetObjects ScriptBuilder 3.0)。ScriptBuilder是一个简单的(基于文字的)编辑器,重要用来编辑基于HTML的文件(.aspl,.asp,.jsp,.shtml,....)在这个文件里你将注意到几个HTML注释表明需要使用JSP代码的地方。定位第一个这样的注释,看上去应该象:
<!—The value field should be the Customer Number retrieved from the Customer object saved in the Session -->
你将需要先写一个scriptlet来从HttpSession里取得JKToysCustomer。下面的代码使用了JSP声明和JSP Scriptlet来完成这个:
<%@ import=com.ibm.waslab.common.* %>
<%KToysCustomer CUSTOMER=(JKToysCustomer)request.getSession(false).getValue(“CUSTOMER”);%>
Declaration provides a global import for the Servlet which will be generated during page compilation.这样com.ibm.waslab.common包里的类在我们的JSP scriptlet和expression里就不要用全名了。把以上的行加进HTML文件。
3. 然后,我们将提供JKToysCustomer对象的customerNumber属性作为HIDDEN输入域的值。在同INPUT 标签的VALUE=element相联系的引号里加入以下的JSP表达式:
<%=CUSTOMER.getCustomerNumber() %>
4. 我们现在需要把每一个字段放进表,用从CUSTOMER对象里来的它们当前的值。当你往下扫过文件,你会发现几个HTML标记看上去象:
<INPUT id=”FormsEditFieldx” TYPE=”text” NAME=”xxx” VALUE=”” SIZE=....>
对这些中的每一个,你要在值域的引号之间增加一个JSP表达式。(看注释一确定你应该输入什么。有6个这样的字段。)
5. 我们要显示的最后一个输入域是一个下拉列表,让客户选择年龄组。This needs to be populated and have the “currently” specified age group,”selected”.这需要更多的scriptlet来有效地作这个。你所要的是产生5个<OPTION>标签标记(在<SELECT>块的里面)。每一个标签应该是“Under 5”,”5-7”,”7-9”,”9-13”和”Over 13”。接着,这些”subtags”中有一个应该看上去这样:
<OPTION SELECTED> age_group
这个规定了初始选中的项目。
第二部分:发表、运行和调试JSP
1. 把改过的文件保存在[x]:\www\html|JKToys\html\body_jktoys_kids_zone_change.jsp。注意,这个文件名和文件类型同提供的不一样。
2. 接着输出你的WASDev项目(VA Java)到两个分开的目录树里(x;\WebSphere\AppServer\servlets和x:\IBMVJava\ide\project_resources\IBM WebSphere Test Enviroment\servlets).(第一个目录允许在VA Java外面运行,而第二个在SERunner的类路径里。)
3. 下面通过网站,登录进Kids Zones。(你应该从VAJava里面运行SERunner。)在登录确认页面,你选择Update registratio information。一旦你选择了这个,IBM WebSphere Application Server将调用页面编译。一个servlet将从.jsp文件产生,这个servlet将被编译。如果编译有错误(因为你的.jsp文件里的不合法的JSP语法),编译错误消息将在一个HTML错误页里返回(回到浏览器)。(注意,”Retrieve syntax error infromation”必须在JSP Execution Monitor Options dialog里被启用。选择Workspace->Tools->JSP Execution Monitor;等对话框窗口出现;确认”Retrieve syntax error infromation” checkbox 被checked。)
你将需要查看任何一个编译错误消息,修改你的.jsp文件,重复处理。如果你被错误消息弄糊涂了,你可以查看生成的servlet代码。这个代码被写进VA Java里的”JSP Page Compiler Generator Code”项目。
4. 在某些时候,如果你要调试你的JSP文件,你需要停止SERunner。确信”JSP Page Compiler Generator Code”项目被加进SERunner的类路径。重启SERunner,重新访问站点。就象你在你的servlet里加断点一样,你可以把它们加进JSP Servlet。
5. 你也许还希望看看页面编译的翻译过程。打开JSP Execution Monitor(JSP Execution Monitor Options dialog),在监视器里一步一步地访问.jsp文件。
你在这个练习里作了什么
这个练习说明了用JavaServer Pages来建立“HTML模板”文件,这个文件会被JSP页面编译过程转化为可执行的Servlets。得到的模板文件(.jsp)可以被WYSIWYG HTML编辑工具处理,可以用这个格式来维护而不是代码的格式(也就是servlet).
不同的JSP语法被试探,JSP Declaration,JSP Scriplets和JSP Expressions在被建立的.jsp文件里用到了。
答案
这里是建立下拉列表的scriptlet
<%
String[] ages=
{“Under 5”,”5-7”,”9-13”,”Over 13”};
for (int i=0;i<ages.length;i++){
out.print(“<OPTION”);
if ((CUSTOMER.gerAge().trim()).equals(ages))
out.print(“SELECTED”);
out.println(“>”+ages);
}
>
JSPBeans4:JavaServer Pages with Beans
在这个练习里,你将更新一个JavaBean,用它来在两个servlets之间通信,其中第二个servlet是从一个JavaServer Page生成的。JSP的目的是显示客户选择的可能要购买的玩具。
许多网页有复杂的布置。这很难在一个servlet里用编程的方法表达。这是服务器端脚本技术的主要理由。JSP编程模型的力量在于隔离可重用的组件(JavaBeans)里的应用代码,而不污染演示 HTML模板。
你将把一个JavaBean的一些状态扩展为属性,以便使用HTML模板语法的JSP容易地使用这个JavaBean。你还将用JSP标记和JSP HTML模板标记(insert、repeat)来扩充HTML文件。
第一部分:更新JKToys JavaBean
1. 在这个练习里我们将在com.ibm.waslab.common包里工作。我们从在类JKToyOrder上打开一个类浏览器开始。选择这个类的BeanInfo view。这个类是用来维护当前选择的要定购的玩具的。It is populated by the TotalPurchaseServlet。我们会让一个JSP表示“order review”信息,而不是用现在输出HTML和动态内容的displaySelections方法。
为了做到这个,我们需要一个新的方法来以”JavaBean”风格的方式循环过一个选择的玩具。这需要把列表作为一个Indexed Property。
创建一个新的IndexedProperty,orderedToy,在类JKToyOrder里。为了做到这个,单击Property Wizard 按钮。在结果对话框check readable,writeable,indexed。提供Property的名字为orderedToy,选择Property的类型为com.ibm.waslab.common.Toy(这个将被向导转化为Toy[])。对我们的目的而言,uncheck规定property为bound的box。按Finish.
2. 返回到类的Methods或Hierarchy视图,来实现刚才生成的4个方法。如果你看类定义,你会发现一个新的实例变量名字叫fieldOrderedToy,类型为Toy[]。这个是Bean Property wizard产生的。这个实例变量并不需要,因为玩具已经存在一个实例变量叫orderedToys,类型为java.util.Stack。这个实例变量已经在类的其它地方被使用了。
删除变量fieldOrderedToy,保存类。你将会在步骤1里Property wizard产生的三或四个附属方法里得到错误标记。
3. 编辑四个附属方法的每一个。使用java.util.Stack和java.util.Vector的正确的方法(例如CopyInto,elementAt,setElementAt,....)来实现这个四个方法的每一个。(需要帮助的话,看这个练习的末尾的答案。)
应该注意到,setOrderedToy(int Toy)和getOrderedToy(int)方法也许会抛一个ArrayOutOfBoundsException异常。这个异常会触发JSP里<REPEAT>标记里循环的结束。
4. 验证类JKToyOrder实现java.io.Serializable。
5. 最后,输出com.ibm.waslab.common包到以下路径:
[x:]\IBMVJava\ide\project_resources\IBM WebSphere Test Environment\servlets
[x:]\WebSphere\AppServer\servlets(只有在要在VAJava外面运行时才需要)
第二部分:调用JSP
1. 打开com.ibm.waslab.servlet2.TotalPurchaseServlet。编辑doPost()方法。在方法的底部(在另一个块里),displaySelections被调用。这个需要被对JSP的调用掉换。第一步是把JKToyOrder对象放进HttpSession对象或HttpServletRequest对象。
为了把定单对象加进会话,增加以下的代码:
session.putValue(“OrderedToys”,toysToBuy);
注意,定单从会话里取得的键是”OrderedToys”。
可选的,JavaBean可以被放在请求范围(而不是会话),把setAttribute方法用在com.sum.serve.http.HttpServiceRequest对象。
2. 下一步是调用callPage()方法来调用JSP。CallPage在回应对象里被调用。callPage是一个com.sun.server.http.HttpServiceResponse类上的方法。你必须先把res造型为类型com.sun.server.http.HttpServiceResponse。以下的代码将足够了(如果你加了一个import语句到类定义里面)。
HttpServiceResponse response=(HttpServiceResponse) res;
response.callPage(“/JKToys/html/jktoys_display_order.jsp”,req);
第三部分:Populating the JSP
1. 最后一步是创建JSP文件。文件jktoys_display_order_start.jsp(在x:\www\html\JKToys\html目录里找到)包含从displaySelection方法里提取的HTML(从com.ibm.waslab.servlet2.TotalPurchaseServlet)。你将需要为”OrderedToys”Bean增加一个BEAN标记。这个可以被放在文件的任何地方(在Bean被引用以前)。
2. 你还将要把TABLE的<tr>块包进一个<REPEAT>块。用insert标记和JSP表达式把动态内容插入HTML表格。
注意:你还将要增加一个scriptlet来在REPEAT块的开头测试一个ArrayOutOfBoundsException(在任何静态内容被推到回应流里去以前)。也要注意,getPriceAsString()方法没有同一个Property(在JkToyOrder类或Toy类)联系起来。<INSERT>标记不能用来显示这个信息,除非方法在每一个各自的类里被prompted为一个Property。如果你不想”prompt“这个属性的话,这个方法可以用scriptlet来调用。
或者,你可以只用scriptlet和JSP表达式而不是<REPEAT>和<REPEAT>标记。
3. 保存更新过的JSP文件为jktoys_display_order.jsp。(注意新的文件名!!!)测试正确的操作。
你在这个练习里作了什么
在这个练习里,你作了一个典型的Servlet->Bean->JSP“控制”流。注意,JSP文件可以被HTML WYSIWYG编辑器维护和编辑(同在Java方法里管理它不一样)。
答案:
public Toy getOrderedToy(int index) throws
ArrayIndexOutOfBoundsException{
return (Toy)orderedToys.elementAt(index);
}
public com.ibm.waslab.common.Toy[] getOrderedToy(){
com.ibm.waslab.commom.Toy[] toys=new
com.ibm.waslab.common.Toy{orderedToys.size()};
orderedToys.copyInto(toys);
return toys;
}
public void setOrderedToy(int index,Toy orderedToy)throws
ArrayIndexOutOfBoundsException{
orderedToys.setElementAt(orderedToy,index);
}
public void setOrderedToy(com.ibm.waslab.common.Toy[] orderedToy)
{
orderedToys=new java.util.Stack();
int max=orderrdToy.length;
for (int i=0;i<max;i++)
orderedToys.addElement(orderedToy);
}
JSP的答案参见:x:\www\html\JKToys\jspSolutions\jktoys_display_order_soln.jsp。
Studio5:WebSphere Studio Servlet Wizards
在这个练习里,你将使用IBM WebSphere Studio的一个向导来创建一个客户管理界面。产生的servlet和JSP页面是让站点管理员能查看数据库里所有JKToys客户的记录。按照这个这个练习,你将能用Studio servlet wizard来建立更复杂的servlets和JSP的骨架。
对所有的练习,确信你用USEID为id和PASSWORD为口令登录进去的。
1. 你将用IBM WebSphere Studio,version 1.0(从此以后用Studio指代),建立一个简单的管理应用。选择Start,Programs,IBM WebSphere,Studio 1.0,WebSphere Studio,启动Studio。这将带来Developer Workbench,Studio的主窗口。Workbench给出一个基于项目的网站视图。从File菜单选择New Project选项创建一个新的项目。在Name域,输入JKToys,按“确定”按钮。
2. 建立管理应用的第一步是建立一个SQL查询对象。为了做到这个,你将利用Workbench提供的SQL向导。从Tools菜单选择SQL Wizard...项目。
3. 向导显示为一个对话框,有一个”tabbed”象notebook的外观。当它最初弹出时,对话框显示Welcome页面,问将要产生的SQL命令文件的名字。输入ViewAllCustomer到name输入域,按Next按钮。
4. 在下一页(Logon),输入jdbc:db2:JKToys到数据库URL输入域;USERID到用户输入域;PASSWORD到口令输入域。在Driver输入域选择IBM DB2 UDB local。输入这些值以后,按Connect按钮。这会连接数据库,取得JKToys数据库的元数据。
5. 确信Select Statement 类型被checked。还check USERID.CUSTOMER表。按Next按钮。
6. 因为只有一个表,Join是不需要的。按Next按钮。
7. 对Columns入口,先按Select all按钮,然后是Add按钮。然后按Next.
8. 你在建立的查询要从数据库取得所有的行。所以,你不要where子句。按Next按钮。
9. 按Finish来完成SQL语句。
10. 接着我们将运行Data Access Servlet Wizard。为了启动向导,从Tools菜单选择Studio Wizard...项目。Studio Wizard是一个同SQL wizard相似的对话框。
11. 在Welcome tab,选择Data Access Servlet,按Next按钮。
12. 在“第二个”Welcome tab,输入ViewCustomer到Name输入域,按Next。
13. 在SQL语句页面,“select from an active project”选项应该被选中,ViewAllCustomers.sql应该被选中。按Next。
14. 在输入页,确信”Yes please”被选中。按Next。
15. 对InputLayout,输入:为Page title输入View All Customers;清除User prompt的输入;Check Submit button check box,把文字改为View All Customers;uncheck Reset button 输入。按Next。
16. 对输出页面接受缺省值(所有列)。按Next。
17. 在Heading输入域增加文字JKToys Customers.然后选择输出字段(每次一个),用上下箭头移动字段,使得它们可以以以下的顺序出现:LNAME,FNAME,AGE,ADDR,CITY,STATE,ZIP,CUSTNO。按Next。
18. 选择不要创建一个custom Error Page。按Next。
19. 按Finish来生成Servlet,DataBean,Output JSP和Input HTML文件。一旦确认对话框消失,你应该看到以下文件在Workbench在JKToys项目里:
ViewAllCustomers.sql;ViewCustomersOutputPage.jsp;ViewcustomersInputPage.aspl。如果你看
classes/JKToys文件夹,你还会发现:
ViewCustomersServlet.java;
ViewCustomersServlet.servlet;
ViewCustomersServletBean.java;
ViewCustomersServlet.class;
ViewCustomersServletBean.class。
20.在发表这个应用之前,编辑ViewCustomersServlet.servlet,在Workbench里双击这个文件。这个文件是XML的servlet配置文件。我们要改变”default-page”的路径。在第5行,在<URL>后面,插入”/JKToys/html”。缺省页面的路径现在应该是/JKToys/html/ViewCustomersOutputPage.jsp。
21. 下一步是发表到JKToys站点。为了作这个,先创建一个“Publishing Server”。从Options菜单里选择Publishing servers...选项。
22. 按Add按钮。在New Publishing Server Settings对话框,输入JKToys到Name输入域。Check Local radio button。然后,选择html目标,按“浏览”按扭。在文件浏览器里,定位/打开x:\www\html\JKToys\html(x是IBM HTTP Server文件根所在的驱动器字母)。然后,选择html目标,按“浏览”按扭。在文件浏览器里,定位/打开x:\WebSphere\Appserver\servlets。最后,按“确定”按钮。
23. 为了发表,在Workbench左手的树视图里选择JKToys站点。从File菜单选择Publish选项。当Select Publishing Server对话框弹出来,选择JKToys作为服务器;按Continue按钮。然后按Publish按钮。最后按“确定”让对话框消失。
24. 为了测试这个应用,我们将在VA Java外面运行,使用IBM HTTP Server。确信SERunner被停止。然后启动IBM HTTP Server。
25. 在一个浏览器,打开URL http://127.0.0.1/JKToys/html/ViewCustomerInputPage.aspl。按View All Customers按钮。这将调用servlet,它将创建一个访问bean的实例,ViewCustomersServletBean,然后调用执行Bean的方法来发布SQL查询。Bean被放在请求范围内,键是viewCustomersServletBean。Servlet对ViewCustomersOutputPage.jsp执行一个callPage,在一个HTML表格里显示SQL查询的输出。
26. 最后的步骤是看产生的代码。尤其是,看输出JSP和ServletBea |
|