使用BeanEditForm来创建用户表单

前面章节中,我们学会了Tapestry如何处理普通链接以及事件链接的传值。本节,我们会学习一样的东西,不过,要学习一些HTML表单的操作。

Tapestry 对表单的支持很好,用一节来讲解是太少了。这里我们学习一些基本功能,包括一些常用的开发模式。让我们创建一个地址簿项目来开始学习。

我们先来创建一些存储信息的实体类。这些类我们放在叫 entities 的包中。和pages(放置组件类的包)包不同,entities 不是Tapestry必须的包,只是一个惯例(方便,快捷)

Tapestry 认为public属性才是JavaBeans 属性;因为 Address 对象只是'沉默的对象',没必要去写getter以及setter方法。这里,我们定义实体类所有属性为公共的:

src/main/java/com/example/tutorial/entities/Address.java
package com.example.tutorial1.entities;
 
import com.example.tutorial1.data.Honorific;
 
public class Address
{
     public Honorific honorific;
     public String firstName;
     public String lastName;
     public String street1;
     public String street2;
     public String city;
     public String state;
     public String zip;
     public String email;
     public String phone;
}

我们需要定义枚举类型的Honorific:

src/main/java/com/example/tutorial/data/Honorific.java
package com.example.tutorial1.data;
 
public enum Honorific
{
     MR, MRS, MISS, DR
}

地址页面

接下来创建地址相关的页面:新建地址,编辑地址,搜索并列表展示。我们需要创建一个子文件夹来保存这些文件。先来创建第一个页面:"address/Create" (需要带着路径--我们会用一分钟来讲解如何映射到相应类和模板).

首先,修改Index.tml,增加一个创建地址的链接:

src/main/resources/com/example/tutorial/pages/Index.tml (局部代码)
< h1 >地址簿</ h1 >
 
< ul >
     < li >< t:pagelink page = "address/create" >新建地址</ t:pagelink ></ li >
</ ul >

现在,我们需要 address/Create 页,先创建一个空白模板来测试我们的链接是否生效。

src/main/resources/com/example/tutorial/pages/address/CreateAddress.tml
< html t:type = "layout" title = "新建地址"
 
     < em >即将到来....</ em >
 
</ html >

(注意: Tapestry 5.4,使用 tapestry_5_4.xsd 替换.)

接着,响应类:

src/main/java/com/example/tutorial/pages/address/CreateAddress.java
package com.example.tutorial1.pages.address;
 
public class CreateAddress
{
 
}

那么 ... 为什么不直接命名类为"Create"而是 "CreateAddress" ? 实际上我们命名为 "Create", 系统依旧可以工作,但是较长的类名同样有效。Tapestry 自动裁剪多余的类名后缀(com.example.tutorial1.pages.address.CreateAddress) 。

Tapestry 实际上为页面创建了许多类别名;其中任意一个都可以用于页面链接。你可以在控制台中看到这些信息:

[INFO] TapestryModule.ComponentClassResolver Available pages ( 12 ):
               (blank): com.example.tutorial1.pages.Index
    ComponentLibraries: org.apache.tapestry5.corelib.pages.ComponentLibraries
              Error404: com.example.tutorial1.pages.Error404
       ExceptionReport: org.apache.tapestry5.corelib.pages.ExceptionReport
              GameOver: com.example.tutorial1.pages.GameOver
                 Guess: com.example.tutorial1.pages.Guess
                 Index: com.example.tutorial1.pages.Index
           PageCatalog: org.apache.tapestry5.corelib.pages.PageCatalog
PropertyDisplayBlocks: org.apache.tapestry5.corelib.pages.PropertyDisplayBlocks
    PropertyEditBlocks: org.apache.tapestry5.corelib.pages.PropertyEditBlocks
         ServiceStatus: org.apache.tapestry5.corelib.pages.ServiceStatus
           T5Dashboard: org.apache.tapestry5.corelib.pages.T5Dashboard
        address/Create: com.example.tutorial1.pages.address.CreateAddress
address/CreateAddress: com.example.tutorial1.pages.address.CreateAddress

Tapestry 构造URL时,使用最短的别名。

以后,你的应用可能会有很多实体类:也许你会有个 "user/Create" 页和 "payment/Create" 页以及"account/Create"页。你可以拥有很多不同包内的类命名为Create, 在Java中是合法的,但是使用上不太理想。也许你会错误的编辑Payment Create页而你实际想修改Account Create页。

Tapestry 建议您使用具有描述性的类名: CreateAddress, 而不是 Create,这样不会带来很多麻烦 (从又长又丑的URL角度来看).  URL依然为 http://localhost:8080/tutorial1/address/create.

记住, Tapestry指定了组件名称和模板名称对应,模板名称也应该像Java类一样命名:CreateAddress.tml.

首页也是这样工作的。一个类命名为 com.example.tutorial1.pages.address.AddressIndex 可以作为 "address/Index"来访问.但是,Tapestry对于命名为Index的页渲染有个特殊的规则,可以使用 http://localhost:8080/tutorial1/address/. 换句话说,你可以在任意文件夹放置Index页,Tapestry会为它构建一个较短的URL... 没必要为类命名为Index(多个包下,使用同一个名字让人迷惑;你可以在每个包中包含它来解决这个问题。Tapestry 使用一种智能便捷方式来保证指向正确的URL。

使用BeanEditForm

现在开始组合逻辑表单。 对于客户端表单,Tapestry 有一个特殊组件: Form 组件, 当然还有表单控制的组件比如 Checkbox 和 TextField. 稍后我们来详细介绍...现在通过 Tapestry的BeanEditForm 组件,来完成一些重要的东西。

为CreateAddress 模板添加以下代码 (替换 "即将到来..."):

CreateAddress.tml (局部代码)
< t:beaneditform object = "address" />

 在 CreateAddress 类添加属性:

CreateAddress.java (局部代码)
@Property
private Address address;

刷新页面,你可能会在页面顶部看到如下警告:

如果看到了警告,意味着你的应用需要创建一个HMAC密码。只需要编辑 AppModule.java 类 (在 services 包里),添加如下代码到 contributeApplicationDefaults 方法:

// Set the HMAC pass phrase to secure object data serialized to client
configuration.add(SymbolConstants.HMAC_PASSPHRASE, "" );

但是,不要使用空字符串,使用一个长的随机字符串(比如非常长的起码30位的密码)私自保存。

完成后,重启应用,点击新建地址链接,你会看到类似的效果:

在这里,Tapestry 完成了很多工作。已经创建了包含每个属性的表单,而且枚举Honorfic属性已经提供了下拉列表。

此外,Tapestry 将属性名("city", "email", "firstName")转换成易读模式 ("City", "Email", "First Name"). 实际上,这些都是 <label> 元素,点击标签,光标会成为第一响应者。

很厉害吧;多么简洁美观的用户界面。多么美丽的表单,让我们开始对它自定义吧。

修改顺序

BeanEditForm 必须知道如何正确的排序,对应Public属性,按字母排序。对于标准JavaBean属性,BeanEditForm默认以类中的getter方法顺序排序 (如果可能,使用行号).

以下是一个较好的排序方式:

  • honorific
  • firstName
  • lastName
  • street1
  • street2
  • city
  • state
  • zip
  • email
  • phone

我们可以使用 BeanEditForm的reorder参数来实现排序,以逗号隔开:

CreateAddress.tml (partial)
< t:beaneditform object = "address"
     reorder = "honorific,firstName,lastName,street1,street2,city,state,zip,email,phone" />

自定义标签

对于Tapestry来说,自定义标签非常容易。只需要为它创建一个 message 目录 .

在Tapestry 里,允许每个页面和组件拥有自己message目录。这是一个标准的Java properties 文件,需要和页面或组件同名,扩展名为.properties。一个message目录由很多行组成,每一行都有一个key和一个value以等号连接。

所有这些会创建一个特殊命名的message entry,带有"-label"后缀。和其它地方一样,Tapestry 忽略大小写。

src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties
street1-label=Street 1
street2-label=Street 2
email-label=E-Mail
zip-label=Zip Code
phone-label=Phone Number

也许你需要重启应用来强迫Tapestry加载改变,因为这里新建了文件:

当然我们也可以自定义下拉列表名称。我们只需要在message目录添加一些entry来匹配现有的枚举类型。修改CreateAddress.properties 并添加:

MR=Mr.
MRS=Mrs.
DR=Dr.

注意,我们没必要包含所有枚举类型,默认自动转换 。每个选项标签都会单独去.properties查找。

最后,默认的提交按钮是 "Create/Update" (BeanEditForm 不知道如何使用).我们来修改成 "Create Address".

这是一个BeanEditForm组件。它不是一个属性,我们也就没办法在message目录修改名称,因为那只对属性有效。幸好,BeanEditForm组件包含一个可改变名称的参数,只需要修改 CreateAddress 组件模板:

< t:beaneditform submitlabel = "Create Address" object = "address"
     reorder = "honorific,firstName,lastName,street1,street2,city,state,zip,email,phone" />

submitlabel 默认参数值是 "Create/Update",但我们可以重写成特殊的值。

最终效果:


在继续之前,我们说说message目录。Message 目录不只是重命名标签或下拉选项,稍后章节我们会讲到message目录如何使用在本地化和国际化中。

接下来我们来设置标签引用来替换模板内设置提交按钮标签;标签的实际内容会存储在Message 目录。

在 Tapestry 中, 当绑定一个参数时,也许你提供的值是包含前缀的。前缀指引Tapestry如何识别参数值...是属性的名字?组件的id?消息Key值?大多数都有默认前缀: "prop:",当你没提供时,默认就是这个 (这会使模板页尽可能精简).

这里我们从message目录引用,因此我们使用 "message:" 前缀:

< t:beaneditform object = "address" submitlabel = "message:submit-label"
     reorder = "honorific,firstName,lastName,street1,street2,city,state,zip,email,phone" />

我们在message 目录设置 submit-label :

submit-label=Create Address

最后,正确的HTML发送到客户端,不管你包含标签文本或正确的在message目录设置。从长远的角度看,后面的方法维护起来更方便。

增加校验

在考虑存储地址对象前,我们需要确保填写的值是有效的。比如,一些值是必须的,手机号和电子邮件有特殊的格式。

BeanEditForm 使用Tapestry特殊的注解 @Validate 来检查,可添加在每个属性的getter 或setter方法 。

编辑实体类Address, 为 lastName, firstName, street1, city, state 和 zip fields, 添加 注解 @Validate :

@Validate ( "required" )
public String firstName;

"required"字符串是什么?它就是你的特殊期望校验。包含一些期望校验类型名称。许多的校验器被构建,比如 "required", "minLength" 和 "maxLength". 和其它地方一样,Tapestry 忽略大小写。

使用逗号分割开校验名称可以完成多重校验。一些校验是可以配置的(使用等号)。所以你可以写成 "required,minLength=5" 来校验不为空,最少5个字符。

当改变一个实体类时,你可能会被自己迷惑到。比如添加了@Validate注解,没有在浏览器看到效果。不要担心,在Tapestry中,只有组件类和大部分服务类是不需要重启服务的。对于数据和实体类则行不通,所以这里你需要停止应用,重启Jetty来看运行效果。

重启,刷新,点击新建地址按钮:

这只是点击新建地址按钮后的提示;所有的属性都被校验并进行错误提示。每个属性的错误提示都使用了红色高亮提示用户,不符合条件的输入框也都成了红色高亮,这样用户就能一眼看出哪里有问题了。光标也聚焦到第一个错误输入框。所有这些到在客户端完成,不需要和服务端进行交互。

一旦错误被更正,表单就可以提交,所有的校验也会在服务端进行(当客户端禁用JS时)

那么 ... 我们来谈谈比"required or not"更好用的东西. Tapestry 构建了属性长度校验支持,包括正则表达式。邮编这样的东西非常适合使用正则。

@Validate ( "required,regexp=^\\d{5}(-\\d{4})?$" )
public String zip;

我们来试一下;重启应用,输入邮编"abcd".


在输入后,点击新建地址按钮,你会看到以上结果。

当提交表单时,现代浏览器会自动校验表单属性的正则,就像上面展示的一样。老版的浏览器不支持,但仍旧可以使用上面说到的注解方法校验输入框。

无论如何,正确的校验行为需要正确的提示信息。你的用户也行不知道什么是正则。

幸好, 我们可以自定义校验提示信息。我们只需要知道属性名称(zip)和校验名称(regexp)。我们可以在Message目录添加一下信息:

zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 90125-1655.

刷新,提交表单:

该方法不仅仅适用于正则,任意的校验方法都可以使用。

让我们进一步学习。我们可以移除正则匹配模式。如果你在属性前只提供了注解@Validate,Tapestry会搜索页面容器message目录的限制条件以及错误提示信息。

@Validate ( "required,regexp" )
public String zip;

现在,添加正则表达式到 CreateAddress message 目录:

zip-regexp=^\\d{5}(-\\d{4})?$
zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 90125-1655.

重启应用,你将看到 ... 同样的效果. 当构建复杂的应用时,这样的写法会变的很漂亮。在Message目录,你可以修改正则表达式来调整校验方式,这样的好处是不需要重启应用。

这里我们还可以为手机号和电子邮件添加正则表单式(你自己来完成吧!)。我们还没能自定义 BeanEditForm 的组件.

现在你也许会很好奇提交成功后该怎么做,让我们下一节来讨论吧!

接下来: 结合Hibernate使用Tapestry


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值