Seam应用程序框架

Seam通过编写带有注解的简单Java类来让创建应用程序的工作变得非常简单,不需扩展任何特定接口和父类。但常见的编程任务还能进一步简化,这是通过一组预先创建的组件进行的,它们能够由 component.xml 文件配置(最简单的情况)或者类扩展而实现复用。

在一个Web应用程序中使用Hibernate或者JPA进行基本的数据库操作时,Seam Application Framework(Seam应用程序框架) 能够减少你需要书写的代码量。

我们需要强调的是,这个框架非常的简单,只是少量的易于理解和扩展的简单类。 “魔力”来自于Seam自身 — 即使没有用这个框架来创建任何Seam应用程序的时候,你也同样用到这一“魔力”。

11.1. 简介

有两种不同的方法使用Seam Application Framework所提供的组件。第一种方法是像处理其他种类的Seam内置组件一样,在 components.xml 中安装和配置组件的实例。 举例来说,下列 components.xml 中的片段安装了一个能够为 Person 实体执行基本的CRUD(创建(Create)、读取(Retrieve) 、更新(Update)和删除(Delete))操作的组件:

<framework:entity-home name="personHome"entity-class="eg.Person"entity-manager="#{personDatabase}"><framework:id>#{param.personId}</framework:id>
</framework:entity-home>

如果上面的代码按你的口味来说太像“用XML编程”,你可以改为使用扩展:

@Stateful
@Name("personHome")
public class PersonHome extends EntityHome<Person> implements LocalPersonHome {@RequestParameter String personId;@In EntityManager personDatabase;public Object getId() { return personId; }public EntityManager getEntityManager() { return personDatabase; }}

第二种方法有一个很大的优点:你能够方便地添加额外的功能,覆盖内置的功能(框架的类都精心设计以便于扩展和定制)。

第二个优点是:如果你喜欢的话,你的类可以是有状态会话Bean(这不是必须的,也可以是普通的JavaBean组件,如果你喜欢的话)。如果你正在使用JBoss AS,你需要使用4.2.2.GA或更高的版本。

目前,Seam应用框架提供了四个内置的组件:用于CRUD操作的 EntityHomeHibernateEntityHome 以及用于查询的 EntityQueryHibernateEntityQuery

你得编写Home和Query组件,它们能在session、event或conversation作用范围中运行,至于选择哪个scope取决于你所希望在你的应用程序中使用的状态模型。

Seam应用框架仅在Seam管理的持久化上下文中工作。默认情况下,这些组件会寻找一个叫做 entityManager 的持久化上下文。

11.2. Home对象

Home对象对特定的实体类提供持久化操作,假设我们有个可靠的 Person 类:

@Entity
public class Person {@Id private Long id;private String firstName;private String lastName;private Country nationality;//getters and setters...
}

我们可以通过配置定义一个 personHome 组件:

<framework:entity-home name="personHome" entity-class="eg.Person" />

也可以通过类的扩展

@Name("personHome")
public class PersonHome extends EntityHome<Person> {}

Home对象提供了如下的操作:persist()remove()update()getInstance()。 在你能够调用 remove()update() 操作之前,你必须首先使用 setId() 方法定义你感兴趣的对象的标识符。

我们可以直接从一个JSF页面使用一个Home,如下例:

<h1>Create Person</h1>
<h:form><div>First name: <h:inputText value="#{personHome.instance.firstName}"/></div><div>Last name: <h:inputText value="#{personHome.instance.lastName}"/></div><div><h:commandButton value="Create Person" action="#{personHome.persist}"/></div>
</h:form>

通常,只用person 指明person漂亮得多,所以在 components.xml 中添加一行语句来实现。

<factory name="person"value="#{personHome.instance}"/><framework:entity-home name="personHome"entity-class="eg.Person" />

(如果我们使用配置的方法。) 或者,我们可以通过向 PersonHome 中添加一个 @Factory 方法来实现:

@Name("personHome")
public class PersonHome extends EntityHome<Person> {@Factory("person")public Person initPerson() { return getInstance(); }}

(如果我们使用类扩展的方法) 这个修改使我们的JSF页面简化如下:

<h1>Create Person</h1>
<h:form><div>First name: <h:inputText value="#{person.firstName}"/></div><div>Last name: <h:inputText value="#{person.lastName}"/></div><div><h:commandButton value="Create Person" action="#{personHome.persist}"/></div>
</h:form>

好,这就可以用来创建新的 Person 实体了。是的,这就是所需的全部代码!现在,如果我们想显示,更新,删除数据库中已经存在的 Person 实体,我们需要将实体标识符传递给 PersonHome。页面参数是一种非常好的实现方式:

<pages><page view-id="/editPerson.jsp"><param name="personId" value="#{personHome.id}"/></page>
</pages>

现在,我们可以向JSF页面中增加其他的操作:

<h1><h:outputText rendered="#{!personHome.managed}" value="Create Person"/><h:outputText rendered="#{personHome.managed}" value="Edit Person"/>
</h1>
<h:form><div>First name: <h:inputText value="#{person.firstName}"/></div><div>Last name: <h:inputText value="#{person.lastName}"/></div><div><h:commandButton value="Create Person" action="#{personHome.persist}" rendered="#{!personHome.managed}"/><h:commandButton value="Update Person" action="#{personHome.update}" rendered="#{personHome.managed}"/><h:commandButton value="Delete Person" action="#{personHome.remove}" rendered="#{personHome.managed}"/></div>
</h:form>

当我们没有带任何请求参数链接到该页面时,会显示"Create Person"页面,当我们为 personId 这个请求参数设定一个值时,会显示“Edit Person”页面。

假设我们需要创建一些 Person 实体,并且初始化这些人的国籍。我们可以通过配置很轻松地完成:

<factory name="person"value="#{personHome.instance}"/><framework:entity-home name="personHome"entity-class="eg.Person"new-instance="#{newPerson}"/><component name="newPerson"class="eg.Person"><property name="nationality">#{country}</property>
</component>

也可以通过扩展类

@Name("personHome")
public class PersonHome extends EntityHome<Person> {@In Country country;@Factory("person")public Person initPerson() { return getInstance(); }protected Person createInstance() {return new Person(country);}}

当然,Country 是一个被其它的Home对象管理的对象,比如说,CountryHome

为了增加更多复杂的操作(联合管理等等),我们可以向 PersonHome 中添加方法。

@Name("personHome")
public class PersonHome extends EntityHome<Person> {@In Country country;@Factory("person")public Person initPerson() { return getInstance(); }protected Person createInstance() {return new Person(country);}public void migrate(){getInstance().setCountry(country);update();}}

当事务成功之后(调用 persist()update()remove() 成功后),Home对象会发出一个 org.jboss.seam.afterTransactionSuccess 事件。 通过监听这一事件,我们可以在底层实体改变后,刷新查询。 如果我们只需要在特定的实体保存、修改或删除后刷新特定查询,我们可以监视 org.jboss.seam.afterTransactionSuccess.<name> 事件(<name> 是实体的名字)。

当一个操作成功时,Home对象可以自动地显示Faces信息,我们可以再一次通过配置来定制信息。

<factory name="person"value="#{personHome.instance}"/><framework:entity-home name="personHome"entity-class="eg.Person"new-instance="#{newPerson}"><framework:created-message>New person #{person.firstName} #{person.lastName} created</framework:created-message><framework:deleted-message>Person #{person.firstName} #{person.lastName} deleted</framework:deleted-message><framework:updated-message>Person #{person.firstName} #{person.lastName} updated</framework:updated-message>
</framework:entity-home><component name="newPerson"class="eg.Person"><property name="nationality">#{country}</property>
</component>

或者扩展:

@Name("personHome")
public class PersonHome extends EntityHome<Person> {@In Country country;@Factory("person")public Person initPerson() { return getInstance(); }protected Person createInstance() {return new Person(country);}protected String getCreatedMessage() { return "New person #{person.firstName} #{person.lastName} created"; }protected String getUpdatedMessage() { return "Person #{person.firstName} #{person.lastName} updated"; }protected String getDeletedMessage() { return "Person #{person.firstName} #{person.lastName} deleted"; }}

但是指定信息最好的方法是把信息置于Seam所知的resource bundle中(在默认情况下,这个bundle叫做 messages )。

Person_created=New person #{person.firstName} #{person.lastName} created
Person_deleted=Person #{person.firstName} #{person.lastName} deleted
Person_updated=Person #{person.firstName} #{person.lastName} updated

这样方便进行国际化,从表现层的角度考虑也保持了代码和配置的整洁。

最后一步是使用 <s:validateAll><s:decorate> 向页面中添加验证功能,我会把这个留给你们自己去实现。

11.3. Query对象

如果我们需要数据库中所有 Person 实例的列表,我们可以使用Query对象,例如:

<framework:entity-query name="people"ejbql="select p from Person p"/>

我们可以从一个JSF页面中使用它:

<h1>List of people</h1>
<h:dataTable value="#{people.resultList}" var="person"><h:column><s:link view="/editPerson.jsp" value="#{person.firstName} #{person.lastName}"><f:param name="personId" value="#{person.id}"/></s:link></h:column>
</h:dataTable>

我们可能需要支持分页:

<framework:entity-query name="people"ejbql="select p from Person p"order="lastName"max-results="20"/>

我们可以使用page参数来决定被显示的页面

<pages><page view-id="/searchPerson.jsp"><param name="firstResult" value="#{people.firstResult}"/></page>
</pages>

用于分页的JSF代码可能有点冗长,但仍然是便于管理的:

<h1>Search for people</h1>
<h:dataTable value="#{people.resultList}" var="person"><h:column><s:link view="/editPerson.jsp" value="#{person.firstName} #{person.lastName}"><f:param name="personId" value="#{person.id}"/></s:link></h:column>
</h:dataTable><s:link view="/search.xhtml" rendered="#{people.previousExists}" value="First Page"><f:param name="firstResult" value="0"/>
</s:link><s:link view="/search.xhtml" rendered="#{people.previousExists}" value="Previous Page"><f:param name="firstResult" value="#{people.previousFirstResult}"/>
</s:link><s:link view="/search.xhtml" rendered="#{people.nextExists}" value="Next Page"><f:param name="firstResult" value="#{people.nextFirstResult}"/>
</s:link><s:link view="/search.xhtml" rendered="#{people.nextExists}" value="Last Page"><f:param name="firstResult" value="#{people.lastFirstResult}"/>
</s:link>

真实的搜索界面能够通过让用户输入一系列的可选的搜索标准来缩小返回的结果列表。Query对象通过让你指定可选的“约束”来支持这个重要的用例。

<component name="examplePerson" class="Person"/><framework:entity-query name="people"ejbql="select p from Person p"order="lastName"max-results="20"><framework:restrictions><value>lower(firstName) like lower( concat(#{examplePerson.firstName},'%') )</value><value>lower(lastName) like lower( concat(#{examplePerson.lastName},'%') )</value></framework:restrictions>
</framework:entity-query>

注意“example”对象的使用。

<h1>Search for people</h1>
<h:form><div>First name: <h:inputText value="#{examplePerson.firstName}"/></div><div>Last name: <h:inputText value="#{examplePerson.lastName}"/></div><div><h:commandButton value="Search" action="/search.jsp"/></div>
</h:form><h:dataTable value="#{people.resultList}" var="person"><h:column><s:link view="/editPerson.jsp" value="#{person.firstName} #{person.lastName}"><f:param name="personId" value="#{person.id}"/></s:link></h:column>
</h:dataTable>

在底层实体发生改变后,可以通过监听 org.jboss.seam.afterTransactionSuccess 事件来刷新查询:

<event type="org.jboss.seam.afterTransactionSuccess"><action execute="#{people.refresh}" />
</event>

或者,在发生持久化、更新或者删除时,通过 PersonHome 来刷新查询:

<event type="org.jboss.seam.afterTransactionSuccess.Person"><action execute="#{people.refresh}" />
</event>

这个部分所有的例子都是通过配置来体现重用的,但是,对Query对象通过扩展来进行重用也是可行的。

11.4. Controller对象

Controller 类以及它的子类 EntityControllerHibernateEntityControllerBusinessProcessController 是Seam Application Framework的可选部分。 这些类只是提供了一些访问常用内置组件及这些组件方法的便利手段,它们能够减少一些键盘输入量,也为探索Seam内置丰富功能的初学者提供了一个非常好的跳板。

例如,这就是Seam注册实例中的 RegisterAction

@Stateless
@Name("register")
public class RegisterAction extends EntityController implements Register
{@In private User user;public String register(){List existing = createQuery("select u.username from User u where u.username=:username").setParameter("username", user.getUsername()).getResultList();if ( existing.size()==0 ){persist(user);info("Registered new user #{user.username}");return "/registered.jspx";}else{addFacesMessage("User #{user.username} already exists");return null;}}}

正如你所看到的一样,这不是什么惊世骇俗的提高...

转载于:https://www.cnblogs.com/cxccbv/archive/2009/01/25/1380908.html

SEAM学习(八)---Seam应用程序框架相关推荐

  1. 微信小程序学习笔记( 小程序框架 )

    必看 这个只是我的学习过程算是日记形式吧,过程是按微信的官方文档的循序来,从 指南中的小程序框架 开始,指南中这一节之前还有页面配置,目录结构,还有很多介绍,没有写但是是非常重要的,一定要看,像指南后 ...

  2. Seam - 无缝集成 JSF,第 1 部分: 为 JSF 量身定做的应用程序框架

    Seam - 无缝集成 JSF,第 1 部分: 为 JSF 量身定做的应用程序框架 发现 Seam 对 JSF 生命周期特有的增强 文档选项 未显示需要 JavaScript 的文档选项 打印本页 将 ...

  3. Seam框架学习之一(Seam vs Spring -- state vs stateless)

    Seam是JBoss 的新的框架,号称Java的ROR.下面我想对它的一些特性和Spring做一番比较. Seam的概念是基于Component的,集成了JSF+EJB3.0以及它选用的AJAX框架A ...

  4. SEAM学习(五)---Seam 组件

    Seam 组件 Seam 组件是POJO(Plain Old Java Objects).特别地,他们是JavaBean或者EJB 3.0 enterprise bean.Seam并不强求组件是EJB ...

  5. 吴恩达深度学习笔记7-Course2-Week3【超参数调试、Batch 正则化和程序框架】

    超参数调试.Batch 正则化和程序框架 一.超参数调试(hyperparameter tuning) 推荐的超参数重要性排序: 1.学习率(learning rate): α 2.隐藏神经单元(hi ...

  6. 深度学习笔记第二门课 改善深层神经网络 第三周 超参数调试、Batch正则化和程序框架...

    本文是吴恩达老师的深度学习课程[1]笔记部分. 作者:黄海广[2] 主要编写人员:黄海广.林兴木(第四所有底稿,第五课第一二周,第三周前三节).祝彦森:(第三课所有底稿).贺志尧(第五课第三周底稿). ...

  7. Sharepoin学习笔记—架构系列—Sharepoint服务(Services)与服务应用程序框架(Service Application Framework) 1

    Sharepoin学习笔记-架构系列-Sharepoint服务(Services)与服务应用程序框架(Service Application Framework) 1 Sharepoint服务是Sha ...

  8. PyTorch框架学习八——PyTorch数据读取机制(简述)

    PyTorch框架学习八--PyTorch数据读取机制(简述) 一.数据 二.DataLoader与Dataset 1.torch.utils.data.DataLoader 2.torch.util ...

  9. 应用程序框架实战十八:DDD分层架构之聚合

    前面已经介绍了DDD分层架构的实体和值对象,本文将介绍聚合以及与其高度相关的并发主题. 我在之前已经说过,初学者第一步需要将业务逻辑尽量放到实体或值对象中,给实体"充血",这样可以 ...

最新文章

  1. 炼个BERT别人花几分钟你花了快1天?谷歌:我这是4810亿参数的巨型BERT
  2. 计算机栈是什么,什么是数据栈?——线性表
  3. mysql ---- limit使用方式
  4. HALCON示例程序autobahn高速公路车道识别程序剖析
  5. 多线程的概念及实现方式
  6. 转贴:Josephus问题
  7. 打开文件、网页、文件夹等
  8. 5-21 求前缀表达式的值(25分)
  9. 兄弟连Linux教学——第三讲 给初学者的建议
  10. 如何进行宽带测速,教程来啦!怎样在电脑上对宽带进行测速?
  11. activemq_CVE-2015-5254_漏洞复现_源码分析
  12. Android仿QQ空间
  13. android接入facebook登陆
  14. python 解析excel表并排重输出到txt
  15. [MRCTF2020]Ez_bypass
  16. 猴子也能入门的Markdown
  17. 《Java核心技术:卷I 基础知识》第1章 Java 程序设计概述 阅读与重点标记
  18. EMAIL 如何发送给多人,如何CC,BCC?
  19. 毛玻璃之前世今生之filter与backdrop-filter
  20. 计算机公式大小写,excel大写金额公式

热门文章

  1. mmap拷贝文件与用常规文件IO拷贝文件效率对比
  2. 阶跃函数卷积自己_详细推导卷积算法
  3. 服务医学,基于目标检测模型实现细胞检测识别
  4. 虚拟服务器透传步骤,esp8266透传模式设置操作步骤
  5. 有道云笔记网页剪报(备)
  6. 小红书营销推广有何策略?
  7. UCML工作流更改JS
  8. 日常交际技巧经验总结99句(大全)
  9. JQuery之父John Resig带你了解无处不在的JavaScript
  10. 详解创建共享邮箱的步骤和方法