作者简介: Michael Yuan,技术专家,《JBoss Seam: Simplicity and Power Beyond Java EE》、《Lightweight Java Web Application Development》等书的作者,软件顾问,目前就职于JBoss。
摘要: 本文介绍了JBoss Seam如何集成业务流程、使用iText和任务调度,并且总结了Seam编程模型中的关键要素。
本文是《JBoss Seam:一个深度集成框架》一文的最后一部分。
大部分企业级应用存在许多业务流程和规则。例如,在一个简单的电子商务网站(以”在线购物”为例)中,客户登录后进行购物流程,商店管理人员登录后 进行审批流程,仓库职员登录后进行发货流程。不同的人员站在不同的角度,去执行不同的任务,然而,他们又同时合作完成同一个业务场景。
在企业级应用中,业务分析人员通常定义业务流程和规则。他们使用专业的业务流程软件绘制这些流程和规则,然后应用开发人员实现这些设计。
然而,由于大部分Web应用框架没有集成流行的业务流程和规则引擎,开发人员只能通过自己的方式进行业务流程的整合。这样势必会造成开发人员和业务分析人员工作的脱节,使得业务分析人员很难去审核和验证。
Seam通过jBPM和JBoss Rules(以前的Drools)对业务流程和规则的整合提供了极好的支持。
在Seam应用中,你可以指定UI动作(例如按钮点击)来触发业务流程。你只需要通过@CreateProcess注解来标记UI事件处理方法。业 务流程是不同的用户以相应顺序来完成的一系列任务。你可以用@BeginTask和@EndTask标注任务的开始和结束。当前任务结束时,jBPM引擎 将自动把进程前移,进行下一个任务。
@Name(”ticketSystem”)
public class TicketSystemAction {
@CreateProcess(definition=”TicketProcess”)
public String newTicket() {
return “home”;
}
@BeginTask
public String reply() {
return “reply”;
}
@EndTask
public String sendAnswer() {
System.out.println(”Answered”);
return “home”;
}
}
Seam让每个用户可以查看他/她的当前任务列表以及完成任务的下一个动作。这些任务列表是基于当前登录的用户角色生成的,并且通过用户认证和授权的方式紧密地整合到Seam安全框架中。
<h1>Assigned Tickets - #{login.user.username}</h1>
<h:dataTable value=”#{taskInstanceList}” var=”task”>
<h:column>#{task.description}</h:column>
<h:column>Title: #{ticket.title}</h:column>
<h:column>
<h:commandLink action=”#{ticketSystem.reply}”>
<h:commandButton value=”Reply”/>
<f:param name=”taskId” value=”#{task.id}”/>
</h:commandLink>
</h:column>
</h:dataTable>
在整合jBPM/JBoss Rules的Seam应用中,开发人员可以直接使用Seam注解和组件驱动业务流程和规则引擎,而不需要单独掌握特定的jBPM和JBoss Rules的Java APIs。
iText库是一套被广泛用于生成PDF文档的开源Java库。然而,使用iText API创建PDF文档是十分耗时的(想想用DOM创建XML文档或者用Swing写UI的经历)。
Seam整洁地整合了iText、JSF和Facelets,开发人员可以通过和生成JSF页面一样简单的方式,将动态的内容生成PDF页面,你甚至可以在PDF页面中使用模板。
Seam为PDF元素创建了特殊的XHTML标记库,然后在生成页面的时候透明地调用iText。下面的示例显示了如何在Seam应用中,生成有数字签名支持的PDF页面。
<p:document … title=”Why Seam” keywords=”mykeyword”
subject=”seam” author=”Seam Team” creator=”Seam PDF example app”>
<p:image alignment=”right” wrap=”true” value=”/jboss.jpg” />
<p:font size=”24″><p:paragraph spacingBefore=”16″ spacingAfter=”40″>
Order #{currentOrder.orderId}
</p:paragraph></p:font>
<p:paragraph>Dear #{currentOrder.customerName},</p:paragraph>
<p:paragraph>… </p:paragraph>
<p:barCode type=”code128″ code=”My BarCode” />
<p:signature field=”My Signature” size=”200 200 400 400″ />
</p:document>
通过代码,我们可以看到整合是无缝的,页面不依赖于iText。实际上,将iText替换成其他的商业PDF库,页面仍然可以工作,这就是Seam整合的魅力。
在许多企业级应用中,对自动重复任务的支持是相当重要的。在标准的EJB中,你可以使用EJB Timer API在固定的时间间隔内调度重复的事件。然而,在实际的应用中,我们需要比固定的时间间隔触发更高级的调度服务。
目前流行的开源Java调度库是Quartz库。但是如果要使用Quartz的话,开发人员仍需要自己写”胶水”代码来整合Quartz特定的APIs和对象模型。
Seam整合了Quartz,用于调度异步重复任务。你只需要在重复工作的方法上添加@Asynchronous注解。你可以传入任务的开始/结束 时间、间隔或者克龙表达式(cron string)的字符串作为参数,也可以在方法定义中注解这些特定目的的参数。指定的方法将返回QuartzTriggerHandler对象,你可以稍 后使用这个QuartzTriggerHandler对象暂停或取消任务,你也可以将这个QuartzTriggerHandler对象保存到数据库,以 供稍后使用。
@Asynchronous
public QuartzTriggerHandle schedulePayment(
@Expiration Date when,
@IntervalCron String cron,
@FinalExpiration Date stoptime
… any other call parameters …) {
// do the repeating or long running task
}
下面的例子中,schedulePayment()方法设定在下午2点10分和三月每个星期三的下午2点44分运行。你可以在Web UI事件处理方法中加入这段调用的代码,这样当按钮按下时,重复事件将被安排到调度程序中。
QuartzTriggerHandle handle =
processor.schedulePayment(payment.getPaymentDate(),
“0 10,44 14 ? 3 WED”,
payment.getPaymentEndDate(),
payment);
payment.setQuartzTriggerHandle( handle );
// Save payment to DB
// later …
// Retrieve payment from DB
// Cancel the remaining scheduled tasks
payment.getQuartzTriggerHandle().cancel();
从例子可以看出,开发人员不需要手动启动Quartz调度程序、创建Quartz触发器和任务,而只需要使用Seam注解POJOs就可以了。
目前为止,我们已经介绍了很多Seam通过一致的编程模型整合不同框架的例子。除了上面介绍的这些,还有许多其他的框架。但是限于篇幅,我们不可能介绍所有的框架。下面我们将总结一下Seam整合这些框架的方法。Seam编程模型中关键的三要素是:
注解POJOs:Seam应用中所有的Java组件都是注解的POJO类。Seam通过双向依赖注入管理它们之间的交互。除此之外,Seam中没有其他的组件模型。
XHTML显示页面:所有视图(UI)页面都是通过XHTML文件显示出来,除去标准JSF标签,Seam还定义了许多自己的UI标签,包括PDF UI标签等。Seam同时也加入了Ajax JSF库,比如Ajax4jsf、RichFaces和IceFaces。
表达式语言:XHTML页面通过JSF表达式语言(EL)引用Seam中的Java组件。Seam增强了标准的EL语法,使它支持方法参数等,并且使EL可以用于所有的XML配置文件和测试脚本。
有了这些Cool的特性,Seam的编程模型将变成异常简便。只要有一些JSF基础,你的学习曲线将非常平坦。
下载Seam,看看实例,快乐地编写Seam代码,一切就这样简单!
转自:http://www.dojochina.com/index.php?q=blog/8377