Skip to content

2. Struts 人员应用程序

我们之前曾采用经典方法(Servlet 和 JSP 页面)处理过一个人员管理应用程序。现在,我们将通过这个应用程序来介绍 Struts。

2.1. 应用程序的工作原理

在此回顾一下我们之前开发的“person”应用程序的工作原理。它由以下部分组成:

  • 一个Servlet。它负责处理应用程序的所有业务逻辑。
  • 三个页面:JSP、formulaire.personne.jspreponse.personne.jsperreurs.personne.jsp

该应用程序的工作原理如下。可通过 URL http://localhost:8080/personne/main 访问。在该 URL 下,会显示由页面 formulaire.personne.jsp 提供的表单:

Image

用户填写表单后,点击提交按钮 [Envoyer]。重置按钮 [Rétablir] 用于将文档恢复至接收时的初始状态。 按钮 [Effacer] 属于普通按钮类型。用户必须提供有效的姓名和年龄。若未满足此条件,系统将通过页面 JSP erreurs.personne.jsp 向用户发送错误页面。以下为示例:

交互示例 1

demande
réponse

如果点击链接 [Retour au formulaire],会发现该页面仍保持着我们离开时的状态:

第2次交换

demande
réponse

如果用户发送了正确的数据,应用程序将通过页面 JSP reponse.personne.jsp 向其发送响应。

交换 1

demande
réponse

如果点击链接 [Retour au formulaire],会发现它仍处于我们离开时的状态:

第2次交换

demande
réponse

2.2. 应用程序的 Struts 架构

我们将采用以下 Struts 架构:

  • 将包含三个视图
  • 控制器将采用Struts提供的控制器
  • FormulaireBean 是负责存储由视图 formulaire.personne.jsp 呈现的表单值的类
  • FormulaireAction 是负责处理 FormulaireBean 的值并指定要发送的响应页面的类:
    • 若表单数据有误,则返回视图 erreurs.personne.jsp
    • 否则,则返回视图 reponse.personne.jsp

对于开发人员而言,工作内容是编写以下代码:

  • 三个视图
  • 与表单关联的 FormulaireBean Bean
  • 负责处理表单的 FormulaireAction

2.3. 编译 Struts 应用程序所需的类

为了编译我们应用程序所需的类,我们将使用JBuilder。该工具使用的是JDK,其中并不包含Struts应用程序所需的类。我们可以按以下方式配置JBuilder:

  • 选项 Tools(工具)/Configure JDKs(配置 JDK)

Image

  • 使用“[Add/Ajouter]”按钮,将Struts提供的.jar文件添加到JBuilder的类库中。如果已将Struts压缩包解压到磁盘上,则可以将<struts>/lib文件夹中的所有.jar文件添加到JBuilder中:

Image

可以将上述所有 .jar 文件添加到 JBuilder 的项目库中。 我们之前已经提到,Tomcat 同样需要访问 Struts 的文件。对于 Tomcat 4.x,可以将 Struts 的 .jar 文件放置在 <tomcat4>\common\lib 目录下。对于 Tomcat 5.x,则可将其放置在 <tomcat5>\shared\lib 目录下。 随后可以设置让 JBuilder 在与 Tomcat 相同的位置查找 Struts 的 .jar 文件。这正是上文展示 JBuilder .jar 文件的屏幕截图中所做的操作。这些文件是从 <tomcat5>\shared\lib 目录中获取的

因此,如果在编译某个类时,JBuilder提示找不到某个Struts类,请检查以下两点:

  • 类名的拼写
  • JBuilder所使用的.jar文件。所有Struts的.jar文件都应包含在内。

2.4. strutspersonne 应用程序的视图

该应用程序的三个视图如下:

  • formulaire.personne.jsp:显示用于输入个人姓名和年龄的表单
  • reponse.personne.jsp:若输入值有效,则显示这些值
  • erreurs.personne.jsp:若存在错误,则显示错误信息

2.4.1. 视图 erreurs.personne.jsp

该视图用于显示错误列表,定义如下:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
        <html:errors/>
    <html:link page="/formulaire.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

该代码中有两处新内容:

  1. 出现了 <html:XX/> 标签,而这些并非 HTML 标签。 实际上,我们可以创建 JSP 标签库,当将页面 JSP 转换为 Servlet 时,这些标签会被转换为 Java 代码。
  2. JSP页面必须声明其使用的标签库。此处通过以下代码行进行声明
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

该行提供了两项信息:

  • uri:管理库使用规则的文件位置。文件 struts-html.tld 包含在 Struts 发行版中。在上例中,该文件将放置在 WEB-INF 文件夹内。
  • prefix:代码中用于为库标签添加前缀的标识符。这有助于避免在同时使用多个标签库时可能出现的命名冲突。不同库中可能存在同名的标签。通过为每个库指定不同的前缀,可以消除所有歧义。
  • <html:errors> 标签用于显示 Struts 控制器传递给它的错误列表。
  • <html:link> 标签生成一个指向 /C/page 的链接,其中
    • C 是应用程序的上下文
    • page 是标签 page 属性中指定的 URL

标签

    <html:link page="/formulaire.do">
            Retour au formulaire
        </html:link>

标签将生成以下代码 HTML:

<a href="/C/formulaire.do">Retour au formulaire</a>

其中 C 是应用程序的上下文

2.4.2. 视图测试 erreurs.personne.jsp

  • 文件 erreurs.personne.jsp 位于 strutspersonne 应用程序的 views 文件夹中:

Image

  • 文件 struts-html.tld 取自 Struts 发行版(<struts>/lib),并放置在 WEB-INF 中:

Image

  • 文件 struts-config.xml 被修改如下:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <action-mappings>
      <action
          path="/main"
          parameter="/vues/main.html"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/erreurs"
          parameter="/vues/erreurs.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
    </action-mappings>
</struts-config>

我们在配置文件中创建了一个新的 URL /errors,供 Struts 控制器处理。 URL /erreurs.do 将被重定向到视图 /vues/erreurs.personne.jsp。 文件 struts-config.xml 被放置在文件夹 WEB-INF 中。

  • 我们重启 Tomcat 以使新文件 struts-config.xml 生效,然后访问网址 http://localhost:8080/strutspersonne/erreurs.do

Image

<html:errors/> 标签未输出任何内容。这是正常的,因为 ForwardAction 操作并未生成该标签所期望的错误列表。 不过,上述响应表明我们的视图 JSP 至少在语法上是正确的,否则我们会看到一个错误页面。让我们检查浏览器接收到的代码 HTML(查看/源代码):

<html>
    <head>
      <title>Personne - erreurs</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>        
    <a href="/strutspersonne/formulaire.do">Retour au formulaire</a>    
  </body>
</html>

请注意由 <html:link> 标签生成的链接。上下文 /strutspersonne 已自动包含在链接中。这使得应用程序可以在不同上下文之间迁移(例如更换机器)时,无需修改由 <html:link> 生成的链接。

2.4.3. 视图 reponse.personne.jsp

该视图用于确认表单中输入的值,如下所示:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<%
     // 获取姓名、年龄数据
  //String 姓名 = (String)request.getAttribute("姓名");
  String nom="jean";

   //String age=(String)request.getAttribute("age"); 
  String age="24"; 
%>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Personne - réponse</h2>
    <hr>
    <table>
        <tr>
          <td>Nom</td>
        <td><%= nom %>
      </tr>
        <tr>
          <td>Age</td>
        <td><%= age %>
      </tr>
    </table>      
    <br>
    <html:link page="/formulaire.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

该页面显示两条信息 [nom] 和 [age],这些信息将由控制器通过预定义的 request 对象传递给它。 在此,我们进行一项测试,其中控制器将无法设置 [nom] 和 [age] 的值。因此,我们使用任意值初始化这两个信息。此外,此处的表单返回链接也是由 <html:link> 标签生成的。

2.4.4. 测试视图 reponse.personne.jsp

  • 文件 reponse.personne.jsp 位于 strutspersonne 应用程序的 views 文件夹中:

Image

  • 文件 struts-config.xml 已按以下方式修改:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <action-mappings>
      <action
          path="/main"
          parameter="/vues/main.html"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/erreurs"
          parameter="/vues/erreurs.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/reponse"
          parameter="/vues/reponse.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
    </action-mappings>
</struts-config>

我们在配置文件中创建了一个新的 URL /reponse,供 Struts 控制器处理。 URL /reponse.do 将被重定向到视图 /vues/reponse.personne.jsp。 文件 struts-config.xml 被放置在文件夹 WEB-INF 中。

  • 我们重启 Tomcat 以使新文件 struts-config.xml 生效,然后访问网址 http://localhost:8080/strutspersonne/erreurs.do

Image

结果与预期一致。

2.4.5. 视图 formulaire.personne.jsp

该视图展示了用于输入用户姓名和年龄的表单。其代码 JSP 如下:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
    <meta http-equiv="pragma" content="no-cache"> 
    <head>
      <title>Personne - formulaire</title>
    <script language="javascript">
        function effacer(){
          with(document.frmPersonne){
            nom.value="";
          age.value="";
        }
      }
    </script>
  </head>

  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <html:form action="/main" name="frmPersonne" type="istia.st.struts.personne.FormulaireBean">
          <table>
            <tr>
              <td>Nom</td>
            <td><html:text property="nom" size="20"/></td>
          </tr>
          <tr>
              <td>Age</td>
            <td><html:text property="age" size="3"/></td>
          </tr>
            <tr>
        </table>
        <table>
            <tr>
              <td><html:submit value="Envoyer"/></td>
            <td><html:reset value="Rétablir"/></td>
            <td><html:button property="btnEffacer" value="Effacer" onclick="effacer()"/></td>
          </tr>
        </table>
      </html:form>
    </center>
  </body>
</html>

我们再次看到了在错误视图中使用的 struts-html.tld 标签库。出现了新的标签:

html:form
既用于生成标签 HTML <form>,也用于向负责处理此表单的控制器提供信息:
action
表单值将被发送到的 URL
name
表单名称 HTML。这也是将存储该表单值的 Bean 的名称
type
用于获取表单存储 Bean 所需实例化的类名
需要注意的是,将表单参数(GET/POST)发送至控制器的方法并未明确指定。 可以通过 method 属性来指定。如果未指定该属性,则默认使用方法 POST
html:text
用于生成 <input type="text" value="..."> 标签:
property
表示表单 Bean 中将与输入框关联的字段名称。当表单提交至服务器(客户端 → 服务器)时,Bean 字段将取输入框的值。当显示表单(服务器 → 客户端)时,Bean 字段中的值将显示在输入框中。
html:submit
用于生成 HTML <input type="submit"...> 标签
html:reset
用于生成标签 HTML <input type="reset"...>
html:button
用于生成标签 HTML <input type="button"...>

2.4.6. 与表单关联的 Bean formulaire.personne.jsp

  • 在 Struts 中,每个表单都必须关联一个 Bean,该 Bean 负责存储表单的值并将其保存在当前会话中。Bean 是一个必须遵循特定语法的 Java 类。与表单关联的 Bean 必须继承 Struts 库中定义的 ActionForm 类:
public class FormulaireBean extends ActionForm {
  • Bean 的属性名称必须与表单字段(即表单中 html:text 标签的 property 属性)相对应。根据前面的表单代码,该 Bean 必须包含两个名为 nom age 的字段。
  • 对于表单中的每个字段 XX,Bean 必须定义两个方法:
    • public void setXX(Type 值):用于将值赋给属性 XX
    • public void getXX():用于获取字段 XX 的值

与上述表单关联的 Bean 可能如下所示:

package istia.st.struts.personne;

import org.apache.struts.action.ActionForm;

public class FormulaireBean extends ActionForm {
   // 姓名
  private String nom = null;
  public String getNom() {
    return nom;
  }
  public void setNom(String nom) {
    this.nom = nom;
  }

   // 年龄
  private String age = null;
  public String getAge() {
    return age;
  }
  public void setAge(String age) {
    this.age = age;
  }
}

我们将使用JBuilder来编译该类。

2.4.7. 测试视图 formulaire.personne.jsp

文件 formulaire.personne.jsp 已放置在 strutspersonne 应用程序的 views 文件夹中:

Image

  • 文件 struts-config.xml 修改如下:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <action-mappings>
      <action
          path="/main"
          parameter="/vues/main.html"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/erreurs"
          parameter="/vues/erreurs.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/reponse"
          parameter="/vues/reponse.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/formulaire"
          parameter="/vues/formulaire.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
    </action-mappings>
</struts-config>

我们在配置文件中创建了一个新的 URL /表单,供 Struts 控制器处理。 URL /formulaire.do 将被重定向到视图 /vues/formulaire.personne.jsp。 文件 struts-config.xml 被放置在文件夹 WEB-INF 中。

  • 我们将类 FormulaireBean 放置在 WEB-INF/classes 中:

Image

  • 我们重启 Tomcat 以便新文件 struts-config.xml 生效,然后访问网址 http://localhost:8080/strutspersonne/formulaire.do

Image

我们成功获取了表单。出于好奇,我们可以查看散布在表单代码 JSP 中的 <html:XX> 标签是如何被“翻译”的:

<html>
    <meta http-equiv="pragma" content="no-cache"> 
    <head>
      <title>Personne - formulaire</title>
    <script language="javascript">
        function effacer(){
          with(document.frmPersonne){
            nom.value="";
          age.value="";
        }
      }
    </script>
  </head>

  <body>
      <center>

        <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" method="post" action="/strutspersonne/main.do">
          <table>
            <tr>
              <td>Nom</td>
            <td><input type="text" name="nom" size="20" value=""></td>
          </tr>

          <tr>
              <td>Age</td>
            <td><input type="text" name="age" size="3" value=""></td>
          </tr>
            <tr>
        </table>
        <table>
            <tr>

              <td><input type="submit" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" name="btnEffacer" value="Effacer" onclick="effacer()"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>

在生成的表单中,[恢复] 和 [Effacer] 按钮均可正常使用。提交按钮 [Envoyer] 跳转至 URL /strutspersonne/main.do。 根据应用程序中的 web.xml 文件,Struts 控制器将处理该请求。根据 struts-config.html 文件,控制器应将请求重定向至 /vues/main.html 视图。让我们试一试:

Image

一切如预期进行。接下来我们需要真正处理表单的值,即 c.a.d。编写一个 Action 类型的类,该类将接收表单数据并将其存储在 FormulaireBean 对象中。