webx学习笔记
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学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
随机推荐
- Hashtable 和 HashMap 的比较
Hashtable HashMap 并发操作 使用同步机制, 实际应用程序中,仅仅是Hashtable本身的同步并不能保证程序在并发操作下的正确性,需要高层次的并发保护. 下面的代码试图在ke ...
- poj 1523 求割点
思路:对于所有节点,每次找的子树,key[root]++;输出时,对于根节点就输出key[root],对于其它节点i,输出key[i]+1; #include<iostream> #inc ...
- Sharepoint2010之父子表实现
在Sharepoint的实际运用中会经常使用到父子表来建立2个表之间的关系.通常父表为表头,存储公共的数据项目,子表存储细分的项目. 例如通过下面2个表实现图书借阅功能,表1为图书的基础信息,表2为图 ...
- AngularJS学习手册
看书和视频结合是学习的最高效方式,看了这本书之后对angularjs才算是有一定的理解了.这本书以搭建一个博客为线索讲解了angularjs的知识点和实际项目开发流程.非常适合初学者!下面是我的读书笔 ...
- 实现类似 QQ音乐网页版 的单页面总结
最近需要对创业团队的网站进行改版,而我负责前端设计和实现. 下面是一些总结与体会: 当设计完成之前,我就跟和我配合的Java 后台说用iframe实现,结果说麻烦不肯,到最后突然对我说还是用ifram ...
- 使用python发送Email
import smtplib from email.mime.text import MIMEText def SendEmail(): email = "" #设置收件地址 ma ...
- 验证hashmap非线程安全
http://www.blogjava.net/lukangping/articles/331089.html final HashMap<String, String> firstHas ...
- Tomcat上配置连接池{ connect error=Name [jdbc/OracleDB] is not bound in this Context. Unable to find [jdbc]}
. 在学习期间,从未实践过在tomcat上配置连接池,今天终于实现一次,在tomcat玩了一把,不知道你是否现在有和我一样的困境.废话少说直接上代码 java public static Con ...
- day 0.
/* 嗯 就要结束了. OI生涯 2015.12-2016.11. 认识了很多人. 然后我这个学渣跟你们混在一起 感觉自卑至极啊. 好了 先不说这些伤心的话. Gryz小伙伴儿们NOIP RP++吧. ...
- 模板与继承之艺术——奇特的递归模板模式(CRTP)
一.什么是CRTP 奇特的模板递归模式(Curiously Recurring Template Pattern)即将派生类本身作为模板参数传递给基类. template<typename T& ...