Struts 是 Apache 软件基金会(Apache Software Foundation)资助的一个开放源代码框架。您可以用它来维护和扩展 Web 应用程序。 IBM® WebSphere® Studio Application Developer 版本 5.0(以下称 WebSphere Studio)对 Struts 有内建支持,支持 Struts 1.02 和 1.1(beta 2)。WebSphere Studio 中的 Struts Configuration 编辑器使您可以很容易地修改 struts-config.xml
文件。这篇文章描述了怎样用 WebSphere Studio 中的内建支持创建一个 Struts 示例。
Struts 框架完全是用 Java 写的,写时用了标准 J2EE API。另外,它还采用了几种著名的 J2EE 设计模式,比如模型-视图-控制器(Model-view-controller)和 FrontController。
通过明确区分各个层,MVC 允许组成每个层的各个组件间松散地耦合。这使它更加灵活,并且可以重用代码。例如,如果您为一个应用程序开发了几个用户界面,那么就需要开发视图组件,因为各应用层间是松散耦合的。
图 1. MVC 和 Struts 框架
第 1 步:开始一个新的 Struts Web 项目
创建一个 1.3 EAR 项目(不包含 EJB / Client 或 Web 项目):
- 选择 New =>Projects =>Enterprise Application Project。
- 选择 Create 1.3 J2EE Enterprise Application Project。按 Next。
- 取消对全部三个子项目(Application Client Project、EJB Project 和 Web Project)的选择。
- 输入
StrutsEAR
作为项目名。
- 单击 Finish。
创建一个 Web 项目并添加 Struts 支持:
- 选择 New =>Projects =>Web =>Web Project。
- 输入
StrutsSampleWeb
作为 Web 项目。
- 选择 Add Struts support复选框。单击 Next。
- 选择 ExistingEnterprise Application Project。
- 浏览查找新建的 EAR 项目。两次单击 Next。
- 在 Struts Setting 页面中选择 Override default settings,并在下拉框中选择 1.1 (beta 2),如图 2 所示。前面已经提到过,表单被提交时,HTML 表单数据被自动植入 Struts ActionForm。Struts 1.0.1 只支持简单的 Java 类型。而 Struts 1.1(beta 2)还支持 java.util.HashMap或其他的 Collection 类型。这一点我们将在 本文的后面部分讨论。
- 单击 Finish。
图 2 .覆盖 Web 项目创建向导中的缺省设置
检查图 3 中的 Struts 文件结构。
图 3 .支持 Struts 的 web 项目
您将稍后修改下面的文件:
-
ApplicationResources.properties
是 Struts 应用程序的资源绑定。语言环境的详细信息和错误消息都放在这个属性文件中。
-
struts-config.xml
是 Struts 的 xml 配置文件。WebSphere Studio 为这个文件提供了一个 GUI 编辑器。
现在,请执行下列操作:
- 检查
web.xml
文件。
- 展开 StrutsSampleWeb 项目并双击 Web Deployment Descriptor来打开编辑器。
- 转到 Servlets页面。请注意下面两点:
- 名为 action的 Struts org.apache.struts.action.ActionServlet的定义。
- 到这个 servlet 的 URL 映射, *.do。
请注意,在 Initialization部分, validate被设为 true。 ActionServlet用 XML 解析器来验证和处理配置文件。它与表单验证无关,稍后在 本文中您将看到这一点。
*.do 怎样获得正确的 Action类?
前面已经提到过, ActionServlet和 Action类是 MVC 模型中控制器层的核心。该控制器负责处理用户的请求,把请求路由到业务逻辑,并选择视图来响应用户(请参阅 Struts 用户指南,第 4.4 节)。表单提交给 submit.do后,Struts ActionServlet 会根据 struts-config.xml 文件中的 <action-mapping>
选择正确的 Action类来用。
Struts Action 子类负责处理用户数据。在这个示例中,创建一个名为 SubmitAction
的 Struts Action子类。它由诸如读和处理表单数据之类的操作组成。每一个表单都和该 Struts ActionForm子类的一个实例关联在一起。请创建这个继承 ActionForm的表单类。SubmitForm 是 ActionForm的一个子类,它是用域的 getter 和 setter 方法创建的。getter 和 setter 方法在 ActionForm子类中都是必须有的。
SubmitForm 怎样发挥作用?
每一个 Struts Action类都必须和一个 Struts ActionForm类关联在一起。您可以在 WebSphere Studio 中的 struts-config.xml 编辑器的 FormBean 页面中定义 SubmitForm 类。然后可以把它与 struts-config.xml 文件中的 SubmitAction 映射关联在一起。一个请求提交后, ActionServlet 把从 Web 浏览器上的实际表单中得到的数据自动植入 SubmitForm。在 SubmitAction 类中,用 SubmitForm f = (SubmitForm) form
来访问表单数据。
第 2 步:用 Struts taglib 构建一个 JSP 表单
Struts 为输入域提供了许多 HTML 标记并为 JSP 表单提供了许多超链接。下面列出了常用的几个:
- 复选框 -
<html:checkbox property="name"/>
- 隐藏域 -
<html:hidden property="name"/>
- 密码输入域 -
<html:password property="name"/>
- 单选按钮 -
<html:radio property="name"/>
- 重设按钮 -
<html:reset/>
- 选项(下拉框)
<html:select property="name"/>
<html:option value="a"/>choice1</html:option>
</html:select>
- 提交按钮 -
<html:submit/>
- 文本输入域 -
<html:text property="name"/>
- 文本区输入域 -
<html:textarea property="name"/>
大多数 HTML 标记都支持 Javascript 事件,如 onmouseclick、onmouseover 等事件。关于更多信息,请参阅 HTML Bean API。
下面我们来为这个示例创建一张 JSP 页面。在 Web Perspective 中,用 Struts 模型创建一张 JSP 页面:
- 展开 StrutsSampleWeb项目直到看到 /Web Content文件夹。右键单击 /Web Content。
- 选择 New =>JSP File。
- 在 Name 中输入
submitpage.jsp
。
- 从下拉框中选择 Struts JSP作为 Model。
- 单击 Next,注意只添加了 HTML 和 Bean 的 taglib。如果您想使用其他标记库中的 taglib,如 Logic taglib,请选择 Add Tag Libraries,然后选择 /WEB-INF/struts-logic.tld。
- 单击 Finish。
图 4.JSP 创建向导 - Struts 标记库
用源代码编辑器中的下面这些代码修改 submitpage.jsp
页并保存:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html locale="true">
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="theme/Master.css" rel="stylesheet"
type="text/css">
<TITLE>Pizza Order Page</TITLE>
</HEAD>
<BODY>
<P><h1>Pizza Order Page </h1></P>
<html:form action="/submit.do">
Name: <html:text property="customer.name"/><br>
Address: <html:text property="customer.address"/><br>
Size: <html:radio property ="size" value="S"/>Small
<html:radio property ="size" value="M"/>Medium
<html:radio property ="size" value="L"/>Large
Toppings: <br>
Pepperoni<html:checkbox property="topping(Pepperoni)"/><br>
Onion<html:checkbox property="topping(Onion)"/><br>
Mushroom<html:checkbox property="topping(Mushroom)"/><br>
Hot Pepper<html:checkbox property="topping(Hot Pepper)"/><br>
Bacon<html:checkbox property="topping(Bacon)"/><br>
<html:select property ="type">
<html:option value="a">Delivery</html:option>
<html:option value="b">Pickup</html:option>
</html:select>
<html:submit/>
<html:reset/>
</html:form>
</BODY>
</html:html>
忽略任务列表中关于 submit.do 不存在的警告消息。为 Struts Action 类创建一张 /confirm.jsp
页面用来进行转发。
在 Web Perspective 中,创建 confirm.jsp 页面:
- 右键单击 /Web Content。
- 选择 New =>JSP File。
- 在 Name 域中输入
confirm.jsp
。
- 单击 Finish。
用下面的代码修改 JSP 文件:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="theme/Master.css" rel="stylesheet"
type="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
<P>Thank you <%=request.getAttribute("name")%></P>
</BODY>
</html:html>
在 submitpage.jsp 中, customer.name
属性引用对象内的一个域。 topping(Pepperoni)
属性是 java.util.HashMap
的一个键/值对。Struts 1.1(beta 2)HTML taglib 支持嵌套的属性。
第 3 步:创建一个 Struts ActionForm SubmitForm 类
您必须定义一个继承 Struts ActionForm类的子类。它必须有用于所有表单域的 setter 和 getter。前面已经提到过,提交表单后, ActionForm类被预先植入表单数据。 ActionForm类有验证方法和重设方法(可选)分别用来验证表单输入和重新设置表单。稍后将在 本文中讨论它们。
如果您的应用程序有一个跨多个 Web 页面的表单,那么就可以只用一个 ActionForm。定义一个包含所有域的属性的 ActionFormbean,不管域实际显示在哪一张页面上。同样,可以把同一个表单的各个页面提交给同一个 Action类。使用这种设计,Web 站点设计者不必改动业务逻辑就可以重新安排域。
创建一个 Java 类,它继承 Web 项目下 /Java Source 文件夹中的 org.apache.struts.action.ActionForm。
- 在 Web Perspective 中,右键单击 StrutsSampleWeb项目下的 /Java Source文件夹。
- 选择 New =>Other =>Web。展开 Web =>Struts。选择 ActionForm Class并单击 Next。
图 5.启动 Struts ActionForm 类向导
- 输入
com.ibm.sample.struts
作为 Java Package的名称。
- 输入
SubmitForm
作为类的 Name。单击 Next。
- 这张页面让您选择想为 setter 和 getter 选择的域。像图 6 那样展开目录树。选择这些项:
customer.name、size、topping(Pepperoni) 和 type
。
图 6. 为 HTML 表单选择新的访问程序(setter 和 getter)
- 单击 Next。
- 将
customer.name
改为 customer(不用引号)并把它的类型改为 Customer。
- 把
topping(Pepperoni)
改为 toppings(注意复数形式),并把其类型改为 java.util.HashMap。
- 把
String[]
改为 String类型。
- 添加
name
,类型为 String。
- 添加
address
,类型为 String。
图 7. 修改访问程序
- 单击 Next。 ActionServlet用 struts-config.xml 文件来决定把控制权转交给哪个 Action类及与之相关联的 ActionForm类。这张页面自动在 Struts 配置 xml 文件中定义 submitForm ActionFormbean。
图 8. 在 struts-config.xml 中为 ActionForm 配置映射。
- 单击 Finish。
ActionForm包含表单中所有的域,并且每个域必须有一个 getter 和一个 setter。您需要手工更改 Customer对象以及 toppingsHashMap 的 getter 和 setter 的实现。请照下面这样修改您刚创建的 SubmitForm 中的黑体代码:
package com.ibm.sample.struts;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class SubmitForm extends ActionForm {
private Customer customer = new Customer();
private String size = null;
private java.util.HashMap toppings = new java.util.HashMap();
private String type = null;
private String name = null;
private String address = null;
public String getSize() {
return size;
}
public HashMap getToppings() {
return toppings;
}
public void setSize(String size) {
this.size = size;
}
public void setToppings(HashMap toppings) {
this.toppings = toppings;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public String getAddress() {
return customer.getAddress();
}
public String getName() {
return customer.getName();
}
public void setAddress(String address) {
customer.setAddress(address);
}
public void setName(String name) {
customer.setName(name);
}
public void setTopping(String key, Object value) { //*new* method
toppings.put(key, value);
}
public Object getTopping(String key) { //*new* method
return toppings.get(key);
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.customer = new Customer();
name = new String();
address = new String();
size = new String();
toppings.clear();
type = new String();
}
}
因为 SubmitForm 要用 Customer bean,请在 com.ibm.sample.struts
包下创建一个名为 Customer的 java 类:
- 在 Web Perspective 中,右键单击 Web 项目下的 /Java Source文件夹。
- 选择 New =>Class。
- 输入或浏览选择
com.ibm.sample.struts
作为 Package的名称。
- 输入
Customer
作为类的 Name。
- 单击 Finish。
- 为该类输入下面的代码:
package com.ibm.sample.struts;
public class Customer {
private String name;
private String address;
public String getAddress() {
return address;
}
public String getName() {
return name;
}
public void setAddress(String address) {
this.address = address;
}
public void setName(String name) {
this.name = name;
}
}
要把表单中的 input 文本域映射为 customer 对象的 name 域,请使用 HTML 标记中的 <html:text property="customer.name"/>
。要访问 HashMap 的键/值对或任何 Collections,请使用 HTML 标记中的 property="toppings(key)"
,其中 toppings 是示例中 HashMap 的名称。 注意:只有 Struts 1.1(beta 2)支持使用 HashMap 或其他 Collections 属性。
按下 reset 按钮后,就调用了 reset() 方法。
第 4 步:创建一个 Action SubmitAction 类
Struts Action类是应用程序逻辑。它进行 JDBC 调用、调用其他的业务 bean 并调用 EJB 等等。我们建议把业务逻辑与其他的 bean 分开,而不要把它嵌入这个 Action类。这个类调用有业务逻辑的 bean。您应该实现 execute() 方法。它返回一个标识下一张页面(比如一张 JSP 页面)的 ActionForward对象。
public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response)
execute() 方法能够访问您可以使用的表单数据。因为所有的请求都被路由到 Action类的一个实例,所以请确保您的代码可以在多线程环境中正确执行。当返回一个标识 JSP 页面的 ActionForward时,在 struts-config.xml 编辑器中为该 JSP 页面定义一个逻辑名。例如,为 /confirm.jsp定义逻辑名 success。在 execute() 方法中, return (mapping.findForward("success"));这行代码把控制权转交给 /confirm.jsp页面。
在 /Java Source 文件夹下创建一个名为 SubmitAction的 Action类:
- 在 Web Perspective 中,右键单击 Web 项目下的 /Java Source文件夹。
- 选择 New =>Other =>Web =>Struts =>Action Class。
- 输入
com.ibm.sample.struts
作为 Package 的名称。
- 输入
SubmitAction
作为类的 Name。按下 Next。
- 在 Forwards 部分,按下 Add来添加转交(forwards),这次转交的 Name为 success,Path 为 /confirm.jsp。
- 选择 submitForm作为 Form Bean Name 域的值。
- 选择 session作为 Form Bean Scope 域的值。
- 单击 Finish。
图 9. 创建 Action 类向导。
在 SubmitAction 类中输入下列代码:
package com.ibm.sample.struts;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
/**
* @version 1.0
* @author
*/
public class SubmitAction extends Action {
/**
* Constructor
*/
public SubmitAction() {
super();
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
ActionErrors errors = new ActionErrors();
ActionForward forward = new ActionForward();
// return value
SubmitForm submitForm = (SubmitForm) form;
try {
// Getting the value from the form
<B>String name = submitForm.getCustomer().getName();
System.out.println ("The name is: " + name);
request.setAttribute("name",name);</B>
} catch (Exception e) {
// Report the error using the appropriate name and ID.
errors.add("name", new ActionError("id"));
}
// If a message is required, save the specified key(s)
// into the request for use by the <struts:errors> tag.
if (!errors.empty()) {
saveErrors(request, errors);
}
// Write logic determining how the user should be forwarded.
forward = mapping.findForward("success");
// Finish with
return (forward);
}
}
第 6 步:验证
您可以在 Struts ActionForm中进行验证。一个表单被提交后, SubmitForm中的 validate() 方法被实现。请把下面的 validate() 方法添加到 SubmitForm中:
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if ((customer.getName()==null)|| (customer.getName().equals(""))) {
// if the name is empty --> errors
errors.add("Name", new ActionError ("error.customer.name"));
System.out.println("errors....");
}
return errors;
}
保存了 SubmitForm 类后,请注意 ActionError 编译错误并没有解决。右键单击 ActionError => Source => Organize imports。
error.customer.name 属性是从资源绑定中获得的。在一个编辑器中从 /Java Source 文件夹打开 ApplicationResources.properties。把下面的代码行添加到这个属性文件中:
# Optional header and footer for <errors/> tag.
title=Pizza Store
errors.header=<hr><h3>Errors</h3><ul>
errors.footer=</ul><hr>
error.customer.name=<li>Name is empty
当错误在 JSP 页面中显示出来时,是用 <hr><h3>Errors</h3><ul>
和 </ul>
括起来的。您必须用 errors.header 和 errors.footer 为错误消息定义头(header)和脚(footer)。错误被检测出后,它们被返回表单,同时输入值被保存。
您需要在 JSP 文件中添加代码行 <html:errors/>
,这样错误才能显示出来。在 submitpage.jsp 文件的开头处(就在<html:form> 之前),输入 <html:errors/>
。
在 struts-config.xml 编辑器中修改 /input 域:
- 在编辑器中打开 struts-config.xml 文件。这个文件在 /Web Content 文件夹中。
-
Action和 ActionForm bean 由 Struts 创建向导来配置,但 Actions 页面中的 input 域除外。为使验证能正常进行,这个域是必需的。
- 在 struts-config.xml 编辑器的 Actions 页面下,在 Input 域中选择 /submit 并输入
/submitpage.jsp
。保存所做的修改。
您可以把错误消息和其他消息放在 ApplicationResources.properties 文件中。例如,您可以用 <bean:message key="title"/>在 JSP 中显示标题,内容可以从资源绑定中获得。
资源绑定还支持国际化(i18n -在 i和 n之间有 18 个字符)。您可以为 ISO 语言代码为 xx 的其他语言创建 ApplicationResources_xx.properties。
再次运行样本并进行验证
既然我们已经修改了 Web 项目,那么就来重新启动一下服务器并再次尝试运行该样本。要重新启动服务器,请转到服务器视图,右键单击并选择 Restart。
如果提交后名称为空,将返回到表单页面,属性文件中列出错误消息。
图 10. 运行样本并进行验证
图 11. Struts Web 图表