Skip to content

9. MVC Web 应用程序 [person] – 第 4 版

此版本使用了前面介绍的 JSTL 标签库。

9.1. Eclipse 项目

要为 Web 应用程序 [/personne4] 创建 Eclipse 项目 [mvc-personne-04],请按照第 78 页第 6.2 节所述的步骤复制 [mvc-personne-03] 项目。

9.2. 配置 [personne4] Web 应用程序

/personne4 应用程序的 web.xml 文件如下:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>mvc-personne-04</display-name>
    ...

除第 6 行外,此文件与上一版本中的文件完全相同,该行中 Web 应用程序的显示名称已更改为 [mvc-personne-04]。

主页 [index.jsp] 发生如下变化:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
 
<c:redirect url="/main"/>
  • 第 5 行:页面 [index.jsp] 将客户端重定向至 URL [/main],该 URL 指向应用程序 [/personne4] 的控制器 [ServletPersonne]。<c:redirect> 标签属于 JSTL / Core 库。它具有一项特殊功能,即通过添加:
  • 前缀 [/context],其中 [context] 表示应用程序上下文,本例中为 [personne4]。
  • 后缀 [?jsessionid=id_session](如果发起请求的浏览器未发送会话 Cookie)。标识符 [jsessionid] 指代 Web 服务器发送给客户端的会话令牌标识符。它取决于具体的 Web 服务器。此处采用的是 Tomcat 服务器的标识符。[id_session] 即会话令牌本身。

因此,[index.jsp] 第 5 行中的实际重定向 URL 是 [/person4/main?jsessionid=XX],其中 XX 是会话令牌。如下图所示,这是在最初请求 URL [http://localhost:8080/personne4] 后获得的页面:

Image

<c:redirect> 标签与会话令牌之间的关系相当微妙。现在深入探讨还为时过早,但我们稍后会有机会再次探讨。

9.3. 视图代码

9.3.1. [表单]视图

该视图未作更改:

Image

它由以下 JSP 页面 [formulaire.jsp] 生成:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
 
<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
...
      </script>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" method="post">
        <table>
          <tr>
            <td>Nom</td>
            <td><input name="txtNom" value="${nom}" type="text" size="20"></td>
          </tr>
          <tr>
            <td>Age</td>
            <td><input name="txtAge" value="${age}" type="text" size="3"></td>
          </tr>
          <tr>
        </table>
        <table>
          <tr>
            <td><input type="submit" value="Submit"></td>
            <td><input type="button" value="[Envoyer]" onclick="envoyer()"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="[Effacer]" onclick="effacer()"></td>
          </tr>
        </table>
        <input type="hidden" name="action" value="validationFormulaire">
      </form>
    </center>
  </body>
</html>
 

最新动态:

  • 第 4 行:声明 JSTL / Core 标签库
  • 第 21、25 行:从页面模板中获取 [name, age] 属性。请注意,系统将依次在 JSP 页面的请求、会话和应用程序中搜索这些属性。在本例中,控制器会将它们存入会话中。
  • 由于之前的实现,JSP 页面开头不再包含用于获取页面模型的 Java 代码。

9.3.2. 视图 [响应]

此视图未发生变化:

新的 JSP 页面 [response.jsp] 如下所示:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
 
<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Personne - réponse</h2>
    <hr>
    <table>
        <tr>
          <td>Nom</td>
        <td>${nom}</td>
      </tr>
        <tr>
          <td>Age</td>
        <td>${age}</td>
      </tr>
    </table>      
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>
 

最新动态:

  • 第 4 行:声明 JSTL / Core 标签库
  • 第 16、20、28 行:在页面模板中获取 [name、age、formSubmitLink] 属性。JSP 页面顶部不再需要任何 Java 代码来获取这些属性。

9.3.3. [errors] 视图

此视图未发生变化:

新的 JSP 页面 [errors.jsp] 如下所示:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
 
<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
    </ul>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>
 

最新动态:

  • 第 4 行:声明 JSTL / Core 标签库
  • 第 13–15 行:使用 JSTL 显示错误列表
  • JSP 页面顶部不再包含用于获取其模板的 Java 代码。

9.4. 视图测试

要测试上述视图,我们将它们的 JSP 页面复制到 Eclipse 项目的 /WebContent/JSP 文件夹中:

Image

然后,在 JSP 文件夹中,对页面进行如下修改:

[form.jsp]:


...
<%
  // -- test : on crée le modèle de la page
  session.setAttribute("nom","tintin");
  session.setAttribute("age","30");
%>
 
<html>
  <head>
 

第4–5行是为创建该页面所需的模板而添加的。

[response.jsp]:


...
<%
  // -- test : on crée le modèle de la page
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
 
 
<html>
  <head>
 
...

第4至6行是为生成该页面所需的模板而添加的。

[errors.jsp]:


 
<%
  // -- test : on crée le modèle de la page
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
 
<html>
  <head>
 

第4至8行是为生成该页面所需的模板而添加的。

如果尚未启动 Tomcat,请先启动它,然后访问以下 URL:

 

我们获得了预期的浏览量。

9.5. [ServletPersonne] 控制器

[/personne3] Web 应用程序的 [ServletPersonne] 控制器将处理以下操作:

否。
请求
来源
处理
1
[GET /person4/main]
用户输入的 URL
- 发送空的 [form] 视图
2
[POST /person4/hand]
并携带参数 [txtName,
txtAge,
action=validateForm]
已发布
点击
[提交] 按钮
[表单]
- 检查 [txtName, txtAge] 参数的值
- 若值不正确,则发送 [errors(errors)] 视图
- 如果值正确,则返回 [response(name,age)] 视图
3
[POST /person4/main]
带参数
[action=returnForm]
已提交
点击 [返回
表单]
[响应]和[错误]中。
- 发送已预先填入最新输入值的 [表单] 视图

[ServletPersonne] 控制器的骨架与上一版本完全相同。我们将回顾对 [doInit、doValidationFormulaire、doRetourFormulaire] 方法所做的修改;[init、doGet、doPost] 方法保持不变。

9.5.1. [doInit] 方法

该方法处理请求 #1 [GET /personne4/main]。其代码如下:

1
2
3
4
5
6
    // empty form display
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
}

新增内容:

  • 第 3 行:渲染 [form] 视图。该视图期望其模板中包含 "name" 和 "age" 属性。由于控制器未提供这些属性,因此视图无法找到它们。 在这种情况下,JSTL 库将为这些属性检索 null 指针。这不会引发任何错误,且 [form] 视图中的 ${name} ${age} 元素将显示为空值。这正是我们所需要的。因此,我们无需初始化 [form] 视图的模型。

9.5.2. [doValidationFormulaire] 方法

该方法处理请求 #2 [POST /person4/main],其中提交的元素包含 [action, txtName, txtAge]。其代码如下:

    // form validation
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
                // parameters are retrieved
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
        // stored in the session
        HttpSession session = request.getSession(true);        
        session.setAttribute("nom", nom);
        session.setAttribute("age", age);
        // parameter verification
...
        // parameters are correct - send response page
        request.setAttribute("lienRetourFormulaire", (String)params.get("lienRetourFormulaire"));
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }

更新内容:

  • 第 15 行:[doValidationFormulaire] 方法返回 [response] 视图。该视图的模型中包含 [name、age、formReturnLink] 这三个元素。[formReturnLink] 是通过请求在第 14 行添加到模型中的。[name、age] 这两个元素是通过会话在第 8–10 行放入模型的。 在之前的版本中,我们在发送 [response] 视图时,也曾将 [name, age] 元素放入请求中,因为该视图期望它们位于那里。在此,借助 JSTL 库,我们知道系统会搜索各种上下文(请求、会话、应用程序)来查找模型元素。因此,由于控制器已将它们放入会话中(第 8–10 行),它们将在会话中被找到。

9.5.3. [doRetourFormulaire] 方法

该方法处理第 3 个请求 [POST /person4/main],其提交数据中包含 [action=retourFormulaire]。其代码如下:

1
2
3
4
5
6
7
    // display pre-filled form
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // the form is displayed
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

新增内容:

  • 第 4 行:显示 [form] 视图。该视图期望其模型中包含“name”和“age”这两个属性。它将在会话中找到这些属性,因为 [doValidationForm] 方法已将它们存入会话,而该方法必然在 [doReturnForm] 方法之前执行。 因此,在第 4 行显示 [form] 表单之前,无需初始化其模型。结果,[doInit] 和 [doReturnForm] 方法完全相同,我们可以移除 [returnForm] 操作,并用 [init] 操作替换它。这样,[doReturnForm] 方法就会消失。

9.6. 测试

在此新版本中,仅视图发生了变化。[ServletPersonne] 控制器保持不变。使用 JSTL 仅仅使我们能够更轻松地在 JSP 页面中利用控制器构建的模型。

集成 Eclipse 项目 [personne-mvc-04] 后,启动或重启 Tomcat。访问 URL [http://localhost:8080/personne4]。