用了一段时间的seam,感觉seam有很多先进的思想值得发扬,但这段时间内我正一步一步地变得不喜欢JSF;因为它的组件开发很困难,还因为JSF本身许多已实现的组件——像richFaces或iceFaces——也有很多很多让人眼花缭乱的属性在使用的过程中需要学习,熟悉,感觉还是很麻烦,不如直接使用HTML和JS的知识来作view方便。
我在这里没有带任何感情色彩地针对JSF,我只是实话实说我认为的JSF的缺点;
并且,更重要的,我想让seam脱离JSF也能使用,而且因为比较着急,我从上个星期开始,就在抽时间做一件事情——Seam-Velocity;并且到现在,这个工具(我暂且叫它工具吧),已经能胜任大部分的seam-web开发工作了,虽然可能会有一些bug;seam手册自带的前几个例子是没问题的;
好了,说说这个seam-velocity到底是个什么东西吧:
它当然是一个抛弃JSF,转而使用velocity,用传统的HTML、JS来开发seam应用的东西,彻底替换seam中view的开发技术,算是个小小的表现层——控制层框架。
介绍一些大致的信息:
首先,请求处理流程:
那么,front-controller的代码骨架就差不多是这样:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
/*
* if value binding exists, update values in contexts, except
* conversationId, 'action' param and converter setting params
*/
this.updateValue(req, exList);
// if action event exists, execute the action
if (StringUtils.isNotEmpty(req.getParameter(FORM_ACTION_PARAM))) {
// invoke action
String target = this.doAction(req);
// action invoke returned non-null value
if (StringUtils.isNotEmpty(target)) {
// need redirect, doing redirect
if (target.startsWith(REDIRECT_PREFIX)) {
resp.sendRedirect(StringUtils.substringAfter(target, REDIRECT_PREFIX));
return;
// end request
} else {
/*
* need no redirect, merge returned page and context vars,
* send out conversation id, write response
*/
try {
this.mergeContextVarsAndConversationIdAndWriteResponse(target, req, resp);
} catch (Exception e) {
log.error(e);
}
return;
// end request
}
}
/*
* action invoke returned empty, doing the same as
* 'no-action-event-request'
*/
}
/*
* no action event, merge requesting page and context vars, send out
* conversation id, write response.
*/
String requestingPageVm = this.getRequestingPageVm(req);
try {
this.mergeContextVarsAndConversationIdAndWriteResponse(requestingPageVm, req, resp);
} catch (Exception e) {
log.error("Write response failed!");
log.error(e);
}
return;
// end request
}
也就是在一个SeamVelocityController的Servlet中描述了上图中所画出的请求处理流程。
以及我简单实现的一个小例子,跟手册里的第一个例子——registration差不多:
这个例子的页面写起来就是这样——完全是velocity的页面,没有JSF:
#set($entries=$pullTool.pull("entries"))
<html>
<head>
<title>Seam Without JSF Demo</title>
<script language="javascript">
function deleteEntry(id){
document.form1.entry_id.value = id;
form1.submit();
}
</script>
</head>
<body>
#if(${cid})
<h1>ConversationId: ${cid}</h1>
#end
<hr />
Add new entry:
<form>
<lable for="title">Entry Title:</lable>
<input id="title" type="text" name="entry_title" value=""><br />
<lable for="entryContent">Entry Content:</lable>
<TEXTAREA id="entryContent" name = "entry_content"></TEXTAREA>
<input type="hidden" name="action" value="entryAction_createNewEntry"><br />
<input type="submit" value="Add">
</form>
#if(${entries}&&${entries.size()}!=0)
<table border="1" cellpadding="0" cellspacing="0" width="500">
<tr>
<td>
<h6>Id</h6>
</td>
<td>
<h6>Title</h6>
</td>
<td>
<h6>Action</h6>
</td>
</tr>
<form name="form1">
#foreach(${e} in ${entries})
<tr>
<td>
${e.id}
</td>
<td>
${e.title}
</td>
<td>
<input type="hidden" name="action" value="entryAction_deleteEntry">
<input type="button" value="Delete" onclick="deleteEntry(${e.id})">
</td>
</tr>
#end
<input type="hidden" name="entry_id" value="">
</form>
</table>
#else
<h2>There are no entries.</h2>
#end
</body>
</html>
可以从页面源码里面看到,已经支持了表单值绑定、action方法提交、pullTool工具;
这个例子很简单,以后我会用它实现更多手册里的示例;
这个小框架的目标是保留seam的所有功能,但砍掉JSF;
对于这个表现层本身,这里列一下我想要让他支持的功能:
1)数据单向绑定,提交时更新
2)表单提交时,可执行action方法
3)提供“拉(pullTool)”工具,让velocity页面里也能写EL表达式从服务端“拉”数据
4)表单提交值转换(converter),以及自定义converter
5)分模块开发,seam-velocity并不会因为失去了Facelets而失去了分页面模块开发的功能
以后可能会再增加;
目前在googleCode上的项目地址:
http://code.google.com/p/seam-velocity/
svn中有一个毛坯实现,基本能用,不过可能会有一些bug;暂不提供release下载,还需成熟。
接下来这段时间要忙论文的事情,所以要等到7月初的时候我再来推这个项目;
也正好,在这段停滞时间中可以听听圈子里的意见,我相信还有人跟我有类似的想法,想用别的东西来代替JSF。
欢迎大家讨论,最好能多提点意见。