Webx学习笔记周建旭 2014-08-01

Webx工作流程

图 3.2. Webx Framework如何响应请求

当Webx Framework接收到一个来自WEB的请求以后,实际上它主要做了两件事:

1. 首先,它会增强request、response、session的功能,并把它们打包成更易使用

的RequestContext对象。

#macro (registerMessage $field)

#if (!$field.valid) $field.message #end

#end

<form action="" method="post">

<input type="hidden" name="action" value="UserAccountAction"/>

#set ($group = $form.register.defaultInstance)

//form.xml中加上<group name="register" extends="csrfTokenCheckGroup">

<p> 用户注册 </p>

<dl>

<dt> 用户名 </dt>

<dd>

<div>

<input type="text" name="$group.userId.key" value="$!group.userId.value"/>

</div>

<div class="errorMessage">

#registerMessage ($group.userId)

</div>

</dd>

<dt> 密码 </dt>

<dd>

<div>

<input type="password" name="$group.password.key" value="$!group.password.value"/>

</div>

<div class="errorMessage">

#registerMessage ($group.password)

</div>

</dd>

<dt> 再输一遍密码 </dt>

<dd>

<div>

<input type="password" name="$group.passwordConfirm.key" value="$!

group.passwordConfirm.value"/>

</div>

<div class="errorMessage">

#registerMessage ($group.passwordConfirm)

</div>

</dd>

</dl>

<p>

<input type="submit" name="event_submit_do_register" value= "立即注册!" />

//这个doRegister 方法写在了要提交的action中

</p>

</form>

HTML form的action值为空,意思是把表单提交给当前页面。

这样,当用户填写表单有错时,应用会停留在当前表单页面,将表单数据连同错误提示一

起显示给用户,要求用户修改。如果表单验证通过,应用必须通过重定向操作来转向下一

个页面。

创建一个register group的实例。其实就是在.vm页面中创建了一个register实例指向group,

不过不用像以前登陆注册那样必须写register类和login类,webx中不需要, 只要用户类即可.

利用新创建的group对象来生成表单字段,包括生成字段的名称$group.field.key,以及

字段的值为$!group.field.value。

定义velocity宏:仅当field验证通过时(即$group.field.valid=true),才显示错误信

息。

对于空白表单和通过验证的字段而言,$group.field.valid为true。

如果验证失败的话,显示验证出错消息。这里通过前面所定义的velocity宏来简化代码。

根据这参数,表单将会被交给UserAccountAction来处理。Action的职责是调用表单验证

过程。假如验证通过,就保存数据,并重定向到下一个页面。

根据这个参数,表单被提交以后,系统会调用当前action(即UserAccountAction)

的doRegister()方法。每个action类中,可以包含多个处理数据的动作,例

如doCreate、doUpdate、doDelete等。

上面的Velocity页面模板演示了怎样利用表单验证服务创建一个帐户注册的HTML表单。关键技

术解释如下:

创建group实例

$form.register.defaultInstance将会对register group创建一个默认的实例。绝大多

数情况下,只需要创建唯一的default instance就足够了。但后面我们会讲到创建多实例的

例子。

所创建的group instance(如register)必须先在规则配置文件(form.xml)中被定义。

9.3.1.3. 创建Java代码(action)

用户提交表单后,由服务器端的Java代码读取并验证用户的数据。

在Webx中,这个功能通常由action来完成。前文已经提到,在HTML表单中,设

置action字段,以及event_submit_do_register提交按钮,就可以让Webx框架调

用UserAccountAction.doRegister()方法。

下面是UserAccountAction类的实现代码:

表单验证服务指南

153

例 9.7. 创建用于处理提交数据的action代码

public class UserAccountAction {

@Autowired

//FormService是webx自带的接口, 你可以看源码

private FormService formService;

public void doRegister(Navigator nav) throws Exception {

Form form = formService.getForm();

if (form.isValid()) {

//获取表单 register 对象的数据, 即 group.field.key的value值

Group group = form.getGroup("register");MyUser user = new MyUser();

group.setProperties(user);//把表单数据装入bean

save(user);

//  跳转到注册成功页面

nav.redirectTo("registerSuccess");

}

}

}

注入form服务。

取得form对象,form对象中包含若干groups。

仅当表单验证成功时,才执行下去。

取得group对象。Group对象的名称必须和配置文件以及模板中的group名称相同。

将group中的数据灌入bean中。

处理完数据以后,利用Webx navigation接口跳转到“注册成功”页面。

例子中的MyUser对象是一个简单的Java Bean:

例 9.8. 被灌入group数据的Java Bean

public static class MyUser {

private String userId;

private String password;

public String getUserId() {

return userId;

}

public void setUserId(String userId) {

this.userId = userId;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

}

Group.setProperties()方法将fields的值映射到同名的Java Bean properties中。然而这个

对应关系是可以改变的,后文会再次讲到该问题。

Webx的表单验证总结

• 验证表单,如果失败则不执行action,否则执行doRegister方法。

• 取得form和register group对象,并将group中的数据注入到MyUser对象中。

9.3.2. 修改老数据

在前面的例子中,我们利用表单创建了一个新数据 —— 注册新帐户。它是从一个空白表单开始

的,也就是说,在用户填写表单之前,表单是没有内容的,或只包含默认值的。另一种常见情况

是修改老数据。例如“修改帐户资料”。和创建新数据的例子不同,在用户填写表单之前,表单

里已经包含了从数据库中取得的老数据。

在创建新数据的模板和代码中,稍微添加一点东西,就可以实现修改老数据的功能。

9.3.2.1. 用screen来读取数据,在screen类中使用execute方法

/*

通过service层去掉用dao得到数据返回,

注意:为了方便我把当前登陆的用户直接与ThreadLocal绑定, 没有放到session中即通过session.setAttribute(“”, object);来实现, 具体的参见PetstoreUser类

*/

public class UserAccount {

@Autowired

private UserManager userManager;//这是我定义的接口,也是当前项目采用的命名规范

public void execute(Context context) throws Exception {

User user = userManager.getUser(getCurrentUser().getId());

//把所取得的user对象放到context中,就可以在.vm模板中用$user来引用它。

context.put("user", user);

}

}

用来修改数据的页面模板,这里我只解释$group.mapTo($user) 因为在前面“register表单”的页面上,加上和修改一点内容就多了$group.mapTo($user)这个

#set ($group = $form.userAccount.defaultInstance)

$group.mapTo($user)

...

<input type="hidden" name="$group.userId.key" value="$!group.userId.value"/>

...

<input type="text" name="$group.lastName.key" value="$!group.lastName.value"/>

...

#userAccountMessage ($group.lastName)

...

<input type="submit" name="event_submit_do_update" value= "修改" />

9.3.2.2 mapTo的功能是填充表单。说白了就是 表单数据回显

这行代码的意思是:用screen中所取得的user对象的值来填充表单,作为表单的初始值。

和Group.setProperties()方法相反,mapTo将Java Bean properties的值映射到同名的

fields中。

9.3.2.3. 用action来处理数据, 说白了就是保存修改后的页面, 注意webx中一切动作都要由action来完成, action中的方法名自己起, 编辑后保存, 所以我就起名 doUpdate

修改老数据的action代码和创建新数据的action代码几乎相同,而且它们可以共享同一

个UserAccountAction类:

用来保存提交数据的action

public class UserAccountAction {

public void doRegister(...) throws Exception {

...

}

//userAccount是.vm中传过来的并且封装好了数据

public void doUpdate(@FormGroup("userAccount") MyUser user,

Navigator nav) throws Exception {

save(user);

nav.redirectTo("updateSuccess");

}

}

下面介绍批量修改数据,注意一个screen类中只能有一个execute方法所一个方法要一个对应的screen类

思路:

1.从后台读取所有数据放到集合中, 然后将集合放入context对象中, 由screen类的 execute来完成

2.在.vm中foreach集合

#foreach($user in $users)//users是screen类中通过context对象传过来的

#set ($group = $form.userAccount.getInstance($user.id))

$group.mapTo($user)

注意$form.userAccount.getInstance($user.id) 不使用默认的创建而 使用getInstance方法 传入用户id修改不同表单

3.用action来处理数据

public class UserAccountAction {

@Autowired

//FormService是webx的接口

private FormService formService;

public void doBatchEdit(Navigator nav) throws Exception {

Form form = formService.getForm();

if (form.isValid()) {

//userAccount批量修改的.vm表单中的#set ($group = $form.userAccount.getInstance($user.id))

Collection<Group> groups = form.getGroups("userAccount");

for (Group group : groups) {

MyUser user = new MyUser();

group.setProperties(user);

save(user);

}

nav.redirectTo("success");

}

}

}

有关Form的API

Group API

9.4.5. 外部验证

表单验证服务是被设计成供一个应用的内部使用的服务。它所生成的压缩格式的field key,例

如“_fm.r._0.p”,是不稳定的。它和配置文件中的group、field的名称、排列顺序有关,可

能随着配置的变化而变化。即便是非压缩的格式,例如“_fm.register._0.password”,也

会因配置文件中group、field命名的改变而改变。如果需要让外界系统来提交并验证表单,最好

提供一个相对稳定的接口。所以外界系统最好不要依赖于这些内部的field keys。

如果真的需要让外界系统来提交并验证表单,可以做一个screen来转发这个请求。Screen的代

码像这个样子:

例 9.70. 转发外部表单请求

9.5. 本章总结

表单服务是一个比较复杂但也相当强大的服务。虽然目前它还不支持客户端验证和服务端异步验证功能,但下一步会加上这些功能。

表单服务最重要的设计思想是:将验证规则与页面以及业务逻辑完全分离(就是不在.vm中创建group实例即:#set ($group = $form.userAccount.defaultInstance),使验证规则的扩展和维护变得非常容易。

Webx开发时注意的部分:

Webx-模块名.xml 要加载 模块名包下的 form.xml

webx学习笔记的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  4. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  5. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  6. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  7. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  8. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  9. DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记

    今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...

随机推荐

  1. 【几何模板加点小思路】hdu-4998 Rotate

    用几何模板敲的,也有直接公式推的,追求短代码的可以点右上角小红了...... 题意就是想想一个物体分别做绕某一点(给出坐标)旋转p度(给出角度)后,其位置等价于绕哪一点旋转多少度,输出该等价点及其等价 ...

  2. Tire树

    Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种. 典型应用是用于统计和排序大量的字符串(但不仅限于字符串), 所以经常被搜索引擎系统用于文本词频统计. 字典树(Trie)可以保存 ...

  3. Linux 内核配置和编译

    Linux 内核配置和编译 一.配置内核 (1). 为什么要配置内核 1. 硬件需求 2. 软件需求 选出需要的,去掉不要的 (2). 如何配置内核 1. make  config 基于文本模式的交互 ...

  4. javascript+dom 做javascript图片库

    废话不多说 直接贴代码 <!DOCTYPE html><html lang="en"><head> <meta charset=" ...

  5. Servlet & JSP - UrlRewriteFilter

    重写 URL 的好处有很多: 静态化页面,有利于搜索引擎收录. 隐藏真实的 URL,提高安全性. 当网站的结构发生变化时,无需要求用户修改书签. UrlRewriteFilter 的简单应用 1. M ...

  6. 在ASP.NET项目中使用CKEditor +CKFinder实现图片上传功能

    前言 之前的项目中一直使用的是FCKeditor,昨天突然有个想法:为什么不试一下新的CKEditor呢?于是花了大半天的时间去学习它的用法,现在把我的学习过程与大家分享一下. 谈起FCKeditor ...

  7. 第四十六篇、UICollectionView广告轮播控件

    这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构. #import <UIKit/UIKit.h> # ...

  8. 高性能CSS(二)

    避免CSS表达式 CSS表达式是动态设置CSS属性的强大(但危险)方法.Internet Explorer从第5个版本开始支持CSS表达式.下面的例子中,使用CSS表达式可以实现隔一个小时切换一次背景 ...

  9. CAF(C++ actor framework)使用随笔(同步发送 异步与同步等待)(三)

    c). 同步发送, 等待响应, 超时后收到1个系统消息. 贴上代码 #include <iostream> #include "caf/all.hpp" #includ ...

  10. JSON的使用

    最近在项目中大量的使用了JSON, 发现JSON和XML的功能相近,都是一种数据传输格式.只是与XML相比JSON显得更加轻量级,使用也更加容易. JSON依赖的第三方jar包: commons-be ...