VIRGIN FOREST OF JAVA
不要埋头苦干,要学习,学习,再学习。。。。。
powered by R.Zeus
3.1 纵览

这一章关注构造程序的View(视图)部件的任务,主要是由JavaServer Pages(JSP)技术完成的。特别的,Struts提供对编写国际化程序的支持,同时也支持和(用户)输入的Form交互。其他几个和View(视图)有关的主题也会被简要的涉及。

3.2 Internationalized Messages

几年前,程序开发者们只期望支持他们自己国家的国民,只使用一种(有时候是两种)语言,也只有一种表达日期,数字,钱币的格式。然而,基于Web技术的,在internet和其他一些可以被广泛访问的网络上的程序开发有了爆炸性的增长,让国界问题浮现在我们的眼中。这个问题被理解为对于支持国际化(经常被称为i18n,因为在"国际化"一词internationalization中i和n之间有18个字母)和本地化程序的需要。

Struts 在Java平台上编写,可以辅助支持编写国际化和本地化的程序。需要熟悉的概念有:

  • Locale (国籍,地区) - 支持国际化的最基本的Java类是java.util.Locale。每一个Locale表示一个特定的国家和语言(包括一种可选的不同语言),和一套对于数字,日期之类的字符串的格式化方案。
  • ResourceBundle (资源包) - java.util.ResourceBundle类提供了支持不同语言的信息的基本支持。参阅ResourceBundle的Javadoc和在你的JDK版本中的国际化支持的信息来得到进一步的帮助。
  • PropertyResourceBundle (属性资源包) - 一个ResourceBundle的标准实现,它允许你用和properties文件一样的"name=value"的格式来定义资源。这对于在web程序中准备信息资源宝石很方便的,因为大部分的信息都是文本。
  • MessageFormat (信息格式) - java.text.MessageFormat 类允许你在运行时用参数的方式替代一个信息字符串(在这种情况下,是从reousece bundle中取出的)。有时候你要编写一个句子,但是在不同的语言中词语出现的顺序不一样,这就很有用了。字符串中的占位符{0}会被第一个运行时参数取代,{1}会被第二个取代,其它的也是这样。
  • MessageResources (信息资源) - Struts类org.apache.struts.util.MessageResources让你把一套resource bundle当成数据库,允许你得到某种特定的Locale(一般是当前用户的Locale)中的特定信息字符串,而非服务器自己正在使用的Locale。

请注意在一个Struts之类的框架中i18n的支持只限于显示国际化的字符串和图像给用户。支持地区相关的输入法(在日语,中文,或者韩文之类的语言中使用)被留给客户端设备,一般是一个web浏览器。

对于一个国际化程序来说,请遵循JDK中附带的国际化文档中描述的步骤来为你的平台创建每一种语言的properties文件。下面的例子更深入的说明这一点:

假设你的源代码位于com.mycompany.mypackage包,所以它保存在com/mycompany/mypackage目录中(相对于你的源代码目录)。要创建一个名为com.mycompany.mypackage.MyResources的资源包,你应该在com/mycompany/mypackage下创建下列文件:

  • MyResources.properties - 包含了使用你的服务器所在的语言的文本。如果你的默认语言是英语,你可能会有如下的条目: prompt.hello=Hello
  • MyResources_xx.properties - 包含了ISO代码为"xx"的语言的文本(参阅ResourceBundle的Javadoc得到最新的代码列表)。对于一个上面所示文本的法语版本,你可能会有如下的条目: prompt.hello=Bonjour 你可以编写所以你愿意支持的语言的资源包。

当你配置你web程序中controller servlet的发布描述时,你需要定义的一个国际化参数是程序的基本资源包的名字。在我们上面举的例子中,它就是com.mycompany.mypackage.MyResources

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
    <param-name>application</param-name>
    <param-value>com.mycompany.mypackage.MyResources</param-value>
  </init-param>
  <.../>
</servlet>

一件重要的事情是要让你的资源包在你程序可以访问的class path中。另一个方法是把MyResources.properties放在你的程序的classes目录下,你就可以简单的用“myResource”作为程序的值。但是要注意如果你的编译脚本为了保证一个“干净”的编译目标,会删除整个classes目录,这时要保证这个资源文件不被删除。

如果是这种情形,这儿有一段Ant任务可以包含在你的编译脚本中,它把src/conf目录中的内容拷贝到classes目录去。

        <!-- Copy any configuration files -->
        <copy todir="classes">
            <fileset dir="src/conf"/>
        </copy>
       
3.3 Forms 和 FormBean 的交互

以前,大多数web开发者使用标准的HTML能力来编写Forms,比如使用<input>标签。用户希望和程序互动,产生某种特定的行为,其中之一和错误处理有关——如果用户犯了个错误,程序应该允许他们改正需要改正的地方——而非重新填写页面上所有的字段。

使用标准的HTML和JSP页面来满足这种需求是非常繁琐和粗笨的,举个例子,一个username字段的输入框可能是这样的(在JSP里):

<input type="text" name="username"
      value="<%= loginBean.getUsername() %>"/>

如果HTML程序员并没有编程基础知识的话,这很难输入正确,而且也会对页面编辑者带来麻烦。基于JSP1.1中的自定义标签库,Struts为编写form提供了很大的方便,可以取代原始的方法。上面的例子用Struts来编写的话会是这样:

<html:text property="username"/>

并不需要显式的引用一个JavaBean以取得初始值。框架自动完成这些事情。

HTML form有时候被用来上传一些文件。大部分浏览器通过<input type="file"> 元素来支持这一点,它会显示一个浏览文件的按钮,但是(在Server端--译者注)下面就轮到开发者来处理这些(上传)来的文件了。Struts可以用和普通的form一致的方式来处理这些"multipart" form.在下一节里,我们会谈到用Struts来创建一个简单的login页面,还包括一个简单的multipart form。

3.3.1 在Struts里编写Form

一个完整的login页面有助于展示Struts如何用比直接的HTML和标准JSP方式更轻松的方式来处理form。考虑如下的页面(基于Struts附带的示例程序),名字是logon.jsp:


<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld"
        prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld"
        prefix="bean" %>
<html:html>
<head>
<title>
  <bean:message key="logon.title"/>
</title>
<body bgcolor="white">
<html:errors/>
<html:form action="/logon" focus="username">
<table border="0" width="100%">
  <tr>
    <th align="right">
      <html:message key="prompt.username"/>
    </th>
    <td align="left">
      <html:text property="username"
                     size="16"/>
    </td>
  </tr>
  <tr>
    <th align="right">
      <html:message key="prompt.password"/>
    </th>
    <td align="left">
      <html:password property="password"
                         size="16"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <html:submit>
        <bean:message key="button.submit"/>
      </html:submit>
    </td>
    <td align="right">
      <html:reset>
        <bean:message key="button.reset"/>
      </html:reset>
    </td>
  </tr>
</table>
</html:form>
</body>
</html:html>

根据上面的例子,下面描述了Struts里form处理的关键特性:

  • taglib指令告诉JSP页面编译器如何去寻找关于Struts标签库的标签库描述。在这里,我们用bean作为表示struts-bean标签库的前缀代号,而"html"是struts-html的前缀代号。你可以用任何你希望使用的前缀。
  • 这个页面使用了几个message 来从包含这个程序所有可用资源的MessageResources对象中查找国际化信息串。下列文本关键字必须在资源文件中定义,这个页面才能正常工作:
    • logon.title - logon 页面的标题
    • prompt.username - "Username:" 询问用户名的标签
    • prompt.password - "Password:" 询问密码的标签
    • button.submit - "Submit" "提交表单"的按钮的标签
    • button.reset - "Reset" "重置"按钮的标签
    当用户登录的时候,程序会在用户的session中保存一个Locale对象。这个Locale对象会被用来选择合适的语言信息。这样让用户自己选择语言会变得很容易——简单的改变这个保存的Locale对象,所有的文本都会自动切换。
  • 错误标签显示任何保存在商业逻辑部件中的可能的错误信息,如果没有错误,那么就不显示。关于这个标签,下面会详细讨论。
  • 根据指定的属性,form标签展开为一个HTML <form>元素。它也让所有在这个form内部的字段值被存放到一个session范围的FormBean中去,它在session中的关键字是logonForm。Struts开发者会给出关于这个form bean的Java实现,它是一个Struts类ActionForm的字类。这个bean用来给出所有的输入字段的初始值,只要字段名和bean的属性名一致。如果合适的bean没有找到,会自动用指定的Java类名字来创建一个新的。
  • 这个formbean也需要在Struts配置文件中指明。这里名字和类型可以被省略。参阅"Action Mappings (动作映射)配置文件"得到详细信息。
  • Text标签展开成为HTML里的<input>元素,它的类型是"text"。在这里,在浏览器中显示时占据多少个字符空间也被指明了。当这个页面被执行的时候,对应的bean的username属性的值会被作为初始值(就是getUsername()的返回值)。
  • password 标签用起来很简单。不同之处是当用户输入自己的密码时浏览器会显示星号而非用户输入值。.
  • submit和reset标签生成form中对应的按钮。其上的标签文字是用message 标签生成的,所以它们显示的是国际化的字符串。

处理multipart form也是很简单的。显而易见,当你编写一个multipart form的时候你创建的form中具有至少一个"file"类型的input输入框。编写一个multipart的form的第一步是使用struts-html标签库来创建显示页面:


<%@page language="java">
<%@taglib uri="/WEB-INF/struts-html.tld"
       prefix="html">
<html:form action="uploadAction.do">
  Please Input Text:
  <html:text property="myText"><br/>
  Please Input The File You Wish to Upload:<br/>
  <html:file property="myFile"><br />
  <html:submit />
</html:form>

下一步是创建你的ActionForm bean:


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
public class UploadForm extends ActionForm {
  protected String myText;
  protected FormFile myFile;
  public void setMyText(String text) {
    myText = text;
  }
  public String getMyText() {
    return myText;
  }
  public void setMyFile(FormFile file) {
    myFile = file;
  }
  public FormFile getMyFile() {
    return myFile;
  }
}

Javadocs里查阅FormFile可以看到在文件上传时它提供的处理文件的方法。也要看Javadoc里面的ActionServlet 和ActionMapping的不同的参数,你可以指定它们来指明文件如何上传。基本上你在你的Action类的perform()方法中需要调用((UploadForm) form).getMyFile()得到你的文件并且做出你的处理。

3.3.2 支持的Input 字段的类型

下面列出了Struts定义的所有的input字段的类型,带有指向手册的连接。

在任何情况下,字段标签都必须内置在form标签中,这样这些字段才知道用哪个bean来得到初始值。

3.3.3 其它有用的表示层标签

有好几个有用的tag用来创建表示层,请查阅它们的标签库的文档和Tag Develipers Guide得到更多的信息:

  • [逻辑] iterate 枚举 为一个列表中的所有元素重复输出标签。(这个列表可能是 Enumeration,Hashtable, Vector, 或者对象数组)。
  • [逻辑] present 存在 根据一个指定的属性,这个tag在当前的request中检查,如果这个属性存在的话就显示它所包含的页面内容。每次使用这个标签的时候只能指定一个属性,名字是必需的。属性可以包括cookie, header,name,parameter,property,role,scopr还有user。
  • [逻辑] notPresent 不存在 和present作用相反的标签,当指定的属性不存在的时候显示。
  • [html] link 连接 创建一个 <a> HTML元素,作为一个锚点或者指向指定URL的超链接,它会自动进行URL编码,以在不支持cookie的时候维护session状态。
  • [html] img 图像 创建一个 <img> HTML元素,它可以动态改变"src"和"lowurl"中指定的URL,和<html:link>的方式相同。
  • [bean] parameter 参数 获取特定的request 参数的值,把结果作为一个page范围的属性,类型是字符串或者字符串数组。
3.3.4 自动form检查

除了上文提到的form和bean之间的交互之外,Struts还提供了附加的机制来检查它接收到的输入字段。要使用这个特性,在你的ActionForm中重载下面的这个类:

public ActionErrors
  validate(ActionMapping mapping,
    HttpServletRequest request);

validate() 方法在bean的属性被自动填充之后,在对应的Action类的porform()方法调用之前由controller servlet自动调用。validate()方法有下面几个选择:

  • 进行了恰当的检查,没有发现任何问题——返回null或者长度为零的ActionError实例,Controller servlet会继续调用对应的Action类的的perform()方法。
  • 进行了恰当的检查,发现了问题。——返回一个包含ActionError的ActionErrors实例,它包含了应该显示错误信息的关键字(位于程序的MessageResources 信息资源库中的关键字)。controller servlet会把这个数组保存为request的属性,以便<html:errors>标签使用,并且流程会重新转回到输入form(通过ActionMappinginput属性得到)。

前面曾经提到过,这个特性完全是可选的。默认的validate()方法返回null,controller servelt会认为对应的Action类会做必要的检查。

另一个常用的方式是在ActionForm的validate()方法中进行简单的主要的检查,在Action里面做“商业逻辑”检查。

在夜间编译包和下列地址还有一个可选的ActionForm检查的包可以使用:David Winterfeldt的网站

3.4 其他表示层技术

虽然你的程序的观感可以完全用标准的JSP和Struts的自定义标签库创建,你也许会考虑动用其他技术来增加部件重用,减少维护工作,并且/或者减少错误。下面几节讨论了几种可选项。

3.4.1 针对程序的自定义标签

除了Struts定义的自定义标签,你针对你正在编写的程序创建标签也很容易,这会帮助你编写用户界面。通过针对下面的程序编写tag,Struts附带的示例程序描绘了基本原理:

  • checkLogon - 检察是否存在一个特定的session对象,并且如果没有的话就转向到登录页面。这可以防止用户在使用你的程序到一半的时候,把页面用书签记录下来,试图以后跳过登录这一步。或者防止session失效。
  • linkSubscription - 生成一个指向明细页面的超连接,它传递需要的主键的值作为request属性。这在列出用户拥有的订阅纪录时有用,它提供了编辑或者删除订阅信息的链接。
  • linkUser - 生成一个指向用户详细信息页面的超链接,把需要的主键信息作为request属性传递。

这些tag的源代码都在src/example目录下,位于org.apache.struts.example包中,和其它在程序中需要的java类在一起。

3.4.2 用Include(引用)来组合页面

用一个JSP页面(包括子定义标签和Bean来取得必要的动态数据)在生成整个表现是一个很普通的方式,在Struts的示例程序中也出现过。然而,很多程序需要在同一个页面中显示多个不同的单一逻辑部分的组合。

举例,一个门户站点可能在门户的主页上有以下几个功能部分:

  • 显示门户的搜索引擎
  • 一个或多个"新闻"显示部分,根据用户登记的个性文件中的兴趣组合。
  • 显示关于这个门户的讨论主题
  • 一个“有邮件在等待”提示,如果你的门户提供免费邮件账户。

如果你能把工作分成不同的部分,为每个部分分配不同的开发者,开发工作会容易些。那么你需要用JavaServer Pages技术中的include(包含)能力,或者Struts提供的include 标签来把不同的页面结果组合到一起去。取决于你需要在什么时候组合你的输出,有三种不同的include可供选择:

  • 一个 <%@ include file="xxxxx" %>指令可以包含一个包括Java代码或者JSP标记的页面。其中的代码甚至可以访问父页面之前定义的变量。在JavaServer Page编译之前,这段代码已经被包含了,所以它可以包含的不只是HTML代码。
  • include action(动作,这里指JSP中的标准指令)(<jsp:include page="xxxxx" flush="true" />)在请求时被处理,服务器会透明的处理它。除此以外,这意味着你通过在一个类似equals这样使用参数的标签中编写这条请求,可以有条件的进行包含。
  • bean:include读取一个"forward"参数通过一个逻辑名字映射到一个被包含的jsp页面,或者读取"id"参数,打印一个页面上下文的字符串变量到jsp页面上。

另一个方法是使用Struts Template Tag library(模版标签库)。察看Developer's Guide得到详细信息。

Tiles是一个原来的Template Tag library的替代品,提供几处增强和新功能。Tiles位于夜间编译包,或者在Cedric Dumoulin的网站

3.4.3 图像生成部件

有一些程序需要动态生成图像,比如价格图或者股票报告等等。一般有两种不同的方法满足这个需求:

  • 显示一个指向servlet请求的超链接。这个servlet会使用一个图像库来渲染出图像,把输出改为合适的内容类型(比如image/gif),并送出图像的字节流到浏览器。浏览器会像一个静态图像一样显示它。
  • 生成必要的HTML代码来下载一个Java applet来创建需要的图像。通过在生成的代码中传送初始化参数,你可以决定图像。或者applet也可以自行和server连结以取得这些参数。
3.4.4 生成文字

有些程序需要动态生成文本或者打包的文本,例如XML.如果整个页面都是被生成的,可以用PrintWriter输出,从Action里可以很容易的办到:

           response.setContentType("text/plain"); // or text/xml
           PrintWriter writer = response.getWriter();
           // use writer to render text
           return(null);
posted on 2005-08-13 03:46 R.Zeus 阅读(377) 评论(0)  编辑  收藏 所属分类: STRUTS

只有注册用户登录后才能发表评论。


网站导航: