我们的第一个Struts程序将是一个用户注册程序。用户将看到一个注册屏幕,包含3个字段:用户名,密码和密码确认。成功的注册要求两次密码相符。如果注册成功,控制将转向一个页面,显示注册成功successful!.。如果两次输入密码不同,控制流将转向一个显示失败的页面。
这个简单的练习将展示以下内容:
l 创建HTML 表单;
l 从HTML 表单获取输入;
l 处理输入(业务逻辑);
l 根据动态输入改变控制流;
为完成这个程序,你需要建立:
l 一个ActionForm
l 一个Action
l struts-config.xml 文件
l 三个页面
就这些!
创建ActionForm
ActionForm 是一个JavaBean ,扩展了 org.apache.struts.ActionForm类。这个对象捕获通过请求传送的输入。当浏览器提交一个表单,它在请求中为每个表单中的字段创建一个参数。ActionForm 针对每个HTML表单中的字段具有一个对应的属性。ActionServlet 匹配请求中的参数和ActionForm中的属性。当匹配好后,ActionServlet 为属性调用setter方法,并将请求中的值传入。在我们的练习中,表单中的username 字段需要一个setUsername(String)方法。password 字段需要setPassword1(String) 和 setPassword2(String)方法。这些方法负责组装隐藏在RegisterForm JavaBean中的实例变量。RegisterForm 的源代码显示在清单1中。
创建 RegisterAction
Action 一个 Java 类,扩展了 org.apache.struts.Action。ActionServlet 组装ActionForm ,然后将其传递给Action。Action 通常负责输入校验,存取业务信息,以及决定向Servlet返回哪个ActionForward 。
现在,创建一个文件,命名为RegisterAction.java,其内容为代码清单2的内容:
PACKAGE APP; IMPORT ORG.APACHE.STRUTS.ACTION.*; PUBLIC CLASS REGISTERFORM EXTENDS ACTIONFORM { PROTECTED STRING USERNAME; PROTECTED STRING PASSWORD1; PROTECTED STRING PASSWORD2; PUBLIC STRING GETUSERNAME () {RETURN THIS.USERNAME;}; PUBLIC STRING GETPASSWORD1() {RETURN THIS.PASSWORD1;}; PUBLIC STRING GETPASSWORD2() {RETURN THIS.PASSWORD2;}; PUBLIC VOID SETUSERNAME (STRING USERNAME) {THIS.USERNAME = USERNAME;}; PUBLIC VOID SETPASSWORD1(STRING PASSWORD) {THIS.PASSWORD1 = PASSWORD;}; PUBLIC VOID SETPASSWORD2(STRING PASSWORD) {THIS.PASSWORD2 = PASSWORD;}; } |
代码清单 1.1 RegistrationForm
创建 RegisterAction
Action 一个 Java 类,扩展了 org.apache.struts.Action。ActionServlet 组装ActionForm ,然后将其传递给Action。Action 通常负责输入校验,存取业务信息,以及决定向Servlet返回哪个ActionForward 。
现在,创建一个文件,命名为RegisterAction.java,其内容为代码清单1.2的内容:
package app;
import org.apache.struts.action.*; import javax.servlet.http.*; import java.io.*; public class RegisterAction extends Action { public ActionForward perform (ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) { // ①Cast the form to the RegisterForm RegisterForm rf = (RegisterForm) form; String username = rf.getUsername(); String password1 = rf.getPassword1(); String password2 = rf.getPassword2(); // ②Apply business logic if (password1.equals(password2)) { try { // ③Return ActionForward for success UserDirectory.getInstance().setUser(username,password1); return mapping.findForward("success"); } catch (UserDirectoryException e) { return mapping.findForward("failure"); } } // ④Return ActionForward for failure return mapping.findForward("failure"); } } |
代码清单 1.2 RegisterAction.Java
虽然很简单,但是我们的RegisterAction 却做了Action 的典型事情。在①,输入ActionForm 被转换为RegisterForm。我们就可以获取username, password1, 和 password2的内容。如果两次密码匹配②,我们将用户添加到 UserDirectory 中③,并返回与success 对应的ActionForward 。UserDirectory 是一个 helper 类,它记录usernames 和passwords 到一个标准的属性文件之中。否则,返回与failure 对应的ActionForward 。
当我们在下一步创建struts-config 文件时,我们将标识代表success和 failure的ActionForward 对象。
创建Struts 配置文件 (struts-config.xml)
struts-config.xml 文件包含了ActionServlet 需要用来处理对应用请求的详细信息。为了练习,我们创建一个空壳的struts-config.xml 文件。你需要做的是填入一些细节。
文件存储在<BaseDirectory>/webapps/register/WEB-INF/目录下,需要改变的是:
首先,添加/register 到<action>元素的 path 属性。ActionServlet 使用Web容器转发给它的URI来选择正确的Action 类。URI 和ActionMapping 的path 属性匹配。这里,请求给出的路径必须在去除前缀和后缀后和/register 匹配。前缀或后缀通常是/do/ 或者 .do。 我们的练习中,将后缀设置为.do。当URI 具有一个.do 扩展名,容器就知道将请求转发给ActionServlet。Struts会自动去除 扩展名,所以我们在配置时不必加上它们。
下一步添加
registerForm
到<action> 元素的 name 属性。<action> 元素使用name 属性来识别哪个ActionForm 将被创建,并将提交的表单组装给他。
然后,添加
app.RegisterAction
到<action> 元素的 type 属性。ActionServlet 使用这个属性来识别将用来处理请求的Action 类。
接下来,在<forward> 元素下,添加
success
到 name 属性,并且
/success.html
到 path 属性。最后,再在另一个<forward>下添加
failure
到 name 属性,
/failure.html
到 path 属性。
这些元素将创建ActionForward 对象,我们将用它来选择程序的控制流。<forward> 元素定义了在RegisterAction中使用的逻辑名称之间的关联。
Struts-config.xml 源代码见代码3。
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"> <struts-config> <form-beans> <form-bean name="registerForm" type="app.RegisterForm"/> </form-beans> <action-mappings> <action path="/register" type="app.RegisterAction" name="registerForm"> <forward name="success" path="/success.html"/> <forward name="failure" path="/failure.html"/> </action> </action-mappings> </struts-config>
|
代码清单 1.3 Struts-Config.XML
Struts框架将struts-config.xml 文件视为部署描述符使用。它使我们可以创建和改变ActionMapping 和路径的关联而不用重新编译java类。我们也可以改变页面之间的连接,而不改变JSP模板。
创建页面
最后的步骤是创建success.html, failure.html, 以及register.jsp 页面。
3个文件的源代码如下,见代码清单1. 4,1. 5,1.6。存放在<Base Directory>/webapps/register目录下。
<HTML> <HEAD> <TITLE>SUCCESS</TITLE> </HEAD> <BODY> Registration succeeded! <P><A href="register.jsp">try another?</A></P> </BODY> </HTML> |
代码清单 1.4 Success HTML
<HTML> <HEAD> <TITLE>FAILURE</TITLE> </HEAD> <BODY> Registration failed! <P><A href="register.jsp">try again?</A></P> </BODY> </HTML> |
代码清单 1.5 Failure.html
<%@ taglib uri="/WEB-INF/struts-form.tld" prefix="form" %> <form:form action="register.do"> UserName:<form:text property="username"/><br> enter password:<form:password property="password1"/><br> re-enter password:<form:password property="password2"/><br> <form:submit value="Register"/> </form:form> |
代码清单 1.6 Register.jsp
这时,所有构建一个简单Struts应用的工作都做完了。
它如何工作
当你知识浏览器到地址http://localhost:8080/register/register.jsp,Tomcat按通常情况加工这个页面。输入username 和password,点击Register 提交页面。浏览器在请求中post表单的内容。容器检查请求将送到哪一个注册的路径去。然后请求被转发到ActionServlet ,并由RegisterAction来处理。在返回成功或失败之前,RegisterAction 校验输入的有效性。最后servlet将控制根据返回的ActionForward转发到响应页面。
再看看代码1.6中的Register.jsp, 可以看到表单是提交给URI /register。但是如果你观察正提交的页面,会发现是提交给register.do。Struts 表单标记自动加上.do 前缀。当我们设置程序骨架时,我们要求所有匹配*.do的请求都传递给ActionServlet。
当接收到一个请求, ActionServlet 做的第一件事情就是查找ActionMapping来匹配请求的路径。ActionMapping是Struts根据 struts-config.xml 文件创建的JavaBean.。我们给出了XML 的具体文件,但运行时,Struts 引用的是对象,而不是XML 文档。
从代码1.3中可以看到,我们使用这个元素创建了一个到path /register的映射:
<action path="/register" type="app.RegisterAction" name="registerForm" input="/register.jsp"> |
然后,ActionServlet 检查是否有name 属性和这个映射相关:
<action path="/register" type=" app.RegisterAction" name="registerForm" input="/register.jsp"> |
这里 /register 映射通过registerForm的名称标识了一个form bean。ActionServlet 使用这
个名字属性来查找相应的ActionFormBean 对象。由From Bean标识的类型(type)用来创建ActionForm 对象:
<form-beans> <form-bean name="registerForm" type="RegisterForm"/> </form-beans> <action-mappings> <action path="/register" type=" app.RegisterAction" name="registerForm" input="/register.jsp"> <forward name="success" path="/success.html"/> <forward name="failure" path="/failure.html"/> </action> </action-mappings> |
这里,servlet将使用RegisterForm 类:
<form-beans> <form-bean name="registerForm" type="app.RegisterForm"/> </form-beans> |
一旦RegisterForm 被实例化, ActionServlet 就试图为请求中的输入域调用RegisterForm 的setter方法。在例子中,它们是setUsername, setPassword1, 和setPassword2。如果某个setter方法不存在,该参数就会被忽略。
ActionMapping 对象的type 属性是ActionServlet 用来实例化ActionForm的类名。这里,将使用你创建的RegisterAction 对象。RegisterAction对象的perform 方法被调用,并传递一个到在前面一步中创建和组装的RegisterForm的引用:
<action path="/register" type="app.RegisterAction" name="registerForm" input="/register.jsp"> <forward name="success" path="/success.html"/> <forward name="failure" path="/failure.html"/> </action> |
依赖于perform 方法的执行结果,将返回两个ActionForward之一。findForward() 方法使用一个String 参数来查找与name属性相匹配的forward 对象。而path 属性则由ActionServlet 用来决定用哪个页面来完成响应:
<forward name="success" path="/success.html"/> <forward name="failure" path="/failure.html"/> |