随着 Seam 2.1 的发布,seam-gen 也获得了一些增强。这些更改是我在 seam-gen 项目中进行的修改的汇总,这些修改构成了《Seam in Action》示例代码的基础。也许在阅读完这篇博客后,您会认为这些增强远不止适度。

seam-gen 的改进可以分为四个类别

  • 外观
  • 功能
  • 项目结构/构建
  • seam 脚本

由于我们都喜欢新鲜事物,让我们从样式升级开始,并辅以一些截图进行讨论。

刷新 seam-gen 的外观

由于 RichFacesICEfaces 的 seam-gen 项目都包含了一些优雅的风格,归功于两个库中捆绑的基于 CSS 的主题(即皮肤)控制的组件样式。主题导入的样式在 JSF 组件集的丰富布局组件中最为明显(例如,<rich:panel><ice:panelTab>)。但是,页面中还有一些区域没有得到覆盖,例如表单元素和状态消息。我找到了一种方法,使用 RichFaces 的主题扩展和一些更好的默认样式(不幸的是,主题扩展目前仅适用于 RichFaces 项目)来将主题扩展到整个页面。

尽管关注应用程序的外观可能看起来微不足道,但这些样式改进是确保您的应用程序在未来看起来更加美观的重要第一步(让您在项目早期少一些烦恼)。

扩展 RichFaces 皮肤

RichFaces 使用皮肤来装饰其内置组件。但最棒的是,这种可皮肤化特性完全开放,可供扩展。皮肤只不过是一个消息包,它将颜色和字体大小映射到键名(例如,panelBorderColor)。每个富组件(例如,<rich:dataTable>)都包含动态生成的 CSS,这些 CSS 引用这些键名以根据主题样式化组件。

CSS 是从一个基于 XML 的 CSS 文件生成的,该文件使用 .xcss 文件扩展名。该文件中使用的语法包括标准元素和属性以及特殊皮肤感知元素,它们可以转换为 CSS。要扩展主题,您只需创建一个自定义的 .xcss 文件,并使用来自 Ajax4jsf 组件集的<a:loadStyle>将其导入到您的页面中。如果您需要自定义颜色和字体大小,甚至添加额外的皮肤属性,您只需创建一个名为 %SKIN_NAME%.skin.properties 的文件,并将其放置在类路径的根目录。您将 %SKIN_NAME% 替换为 RichFaces 皮肤名称(例如,emeraldTown)。

细节,细节,细节。这有什么好处?嗯,通过 CSS 的力量,我们可以使非 RichFaces 组件看起来富有!这不仅仅是关于颜色的问题。使用 xcss 中的特殊元素之一(<f:resource>)甚至可以生成渐变图像。这意味着我们可以制作看起来很酷的表单元素。在 seam-gen 项目中,这些额外的主题相关样式在 theme.xcss 文件中定义,该文件位于现有的 theme.css 文件旁边。以下是从该文件中摘录的用于样式化文本输入的代码

<u:selector name="input[type=text], input[type=password], textarea, select">
  <u:style name="background-color" skin="controlBackgroundColor"/>
  <u:style name="color" skin="controlTextColor"/>
  <u:style name="background-position" value="left top"/>
  <u:style name="background-repeat" value="repeat-x"/>
  <u:style name="background-image">
    <f:resource f:key="org.richfaces.renderkit.html.images.SliderFieldGradient"/>
  </u:style>
  <u:style name="border" value="1px solid"/>
  <u:style name="border-color" skin="tableBorderColor" />
</u:selector>

以下是该 XML 标记生成的 CSS(对于 DEFAULT RichFaces 主题)

input[type="text"], input[type="password"], textarea, select {
  background-color:#FFFFFF;
  background-image:url(/appname/a4j/g/3_2_2.GAorg.richfaces...SliderFieldGradient...);
  background-position:left top;
  background-repeat:repeat-x;
  border:1px solid #C0C0C0;
  color:#000000;
}

以下是使用普通旧<h:inputText>生成的输入的外观

请注意,输入的样式将与 RichFaces 主题相协调。这对于所有表单元素以及一般的字体颜色和链接颜色都是正确的。在下一节中亲自看看。

展示新外观

以下是来自 seam-gen 项目的一组截图,该项目是根据用于测试 seam-gen 的 vehicles 架构生成的。这些截图展示了新样式与各种 RichFaces 主题一起看起来如何。RichFaces 主题是通过在 web.xml 中定义的org.richfaces.SKINServlet 上下文参数控制的。

<context-param>
  <param-name>org.richfaces.SKIN</param-name>
  <param-value>classic</param-value>
</context-param>

当您部署 seam-gen 2.1 项目时,您首先会注意到有一个新的主页,上面有 Seam 标志。除此之外,您应该注意到每个页面下面的元素都与所选主题协调一致。

您会注意到在这些接下来的两个截图中,我已经自定义了状态消息,这对于 ICEfaces 项目也是如此。根据其级别(警告、错误和消息),每个状态消息前面都使用适当的图标。在我修复 JBSEAM-1517 的过程中,我确保了消息看起来很有吸引力,并且不会重叠。(信不信由你,消息仍然使用原始 seam-gen 的橙色样式,这与 RichFaces 或 ICEfaces 主题完全不匹配)。

所有这些的“甜点”是 Seam 标志的 favicon,它在主 Facelets 模板中定义,并出现在 URL 地址栏中。我认为这是最甜的增强,因为它让你有那种自豪感,那就是你在使用 Seam。

新主题的唯一缺点是 JBossTools 中的视觉编辑器无法理解 xcss 文件。这就是为什么我留下了一个改进的 theme.css 文件版本,它仍然在主 Facelets 模板中使用。在其中,我定义了不依赖于皮肤属性的静态 CSS 样式。如果视觉编辑器能够像处理 CSS 文件一样解释 xcss 文件,那么当扩展 RichFaces 主题时,它将使开发者更加高效。 目前,在更改 xcss 文件后,您必须重启应用程序才能让 RichFaces 重新加载生成的 CSS(并且在一些浏览器中,您还必须清除浏览器缓存)。

关于样式的讨论就到这里。还有一些其他的功能性改进,我们将稍后查看。

这正是老板想要的

在讨论 seam-gen 的增强功能时,重要的是要记住 seam-gen 的目的,这样我们才不会失去方向。seam-gen 提供两项关键服务

  1. Seam 开发的起点,让您免于入门的繁琐
  2. Seam 特性的广泛展示,您可以在此基础上开始构建

seam-gen 不会为您的工作代劳。话虽如此,生成的项目和其他许多方面都存在不一致性,而 seam-gen 可以做得更好。以下是 seam-gen 项目中实施的功能性变更列表,这些变更主要是为了满足管理层提出的需求

  • 使用驼峰命名法将属性名称转换为可读标签(即,camelCase => Camel case)
  • 在输出属性值(例如日期、时间、数字)时,始终应用适当的转换器
  • 在详情页面的标签页中使用图标来表示父级和子级关联
  • 使用 Facelets 组合模板简化了在列表页面列标题上的排序链接的标记
    <ui:include src="layout/sort.xhtml">
      <ui:param name="entityList" value="#{personList}"/>
      <ui:param name="propertyLabel" value="Name"/>
      <ui:param name="propertyPath" value="person.name"/>
    </ui:include>
  • 在详情页面上启用了子级关联表中的列的客户端排序(利用 RichFaces 表)
  • 在列表页面上启用了对组件或复合键属性(例如,vehicle.id.state)的激活排序
  • 用于排序的 JPQL 现在是兼容的
  • 在列表页面上的每一行都添加了一个链接来编辑记录(之前只能在详情页面进行)
  • 将默认用户名更改为 admin,但仍允许密码为任何值。现在可以轻松触发失败登录场景。
  • 一对一关联在 UI 中的链接方式与多对一关联相同
  • 在主 Facelets 模板(view/layout/template.xhtml)中引入了名为 head 的插入,用于添加额外的标记到<head>元素,以按页面方式添加
    <ui:define name="head">
      <script type="text/javascript">
        window.onload = function() { ... }
      </script>
    </ui:define>
  • <h:messages globalOnly="true">声明移动到主 Facelets 模板,并条件性地检查名为 showGlobalMessages 的 Facelets 参数,以按页面方式关闭它们
  • 主菜单栏中的链接不会传播会话(即,propagation="none")
  • 在列表页面上添加了一个重置搜索的按钮
  • 在编辑记录时将实体管理器切换到手动刷新模式
  • 在调试页面上添加了一个 UI 命令链接来销毁选定的会话(并非特定于 seam-gen)

我确信还有其他一些小的增强功能我忘记了,这些我将留给您去发现。让我们继续讨论项目结构和构建变更。

从语义上讲

seam-gen项目仍然使用Ant构建,它们的基本结构(有点古怪)仍然相同。不过,我修复了一个语义错误。我改变了源目录,使它们更好地反映它们的构建方式,而不是它们包含的类。在Seam 2.0中,两个主要源目录是

  • src/action
  • src/model

src/action中的组件在开发模式下运行时会被添加到可热部署的类路径中,而src/model目录中的组件和常规类最终会出现在主(静态)类路径上。在生产模式下,当然,这两个目录中的资源都会出现在相同的类路径上。问题是,可热部署的组件不一定是action组件,不可热部署的组件也不一定是model类。为了解决这种语义混乱,源目录现在变为

  • src/hot
  • src/main

我相信你可以立即理解这两个源目录的目的,因此会感到更舒适地为你即将创建的类找到一个位置。不幸的是,JBossTools目前仍然使用旧的传统。尽管有差异,但由于它依赖于目录名和功能之间的映射(seam-gen准备了映射配置以反映这一新约定),它没有问题地使用新文件夹名消费seam-gen项目。

当然,项目构建脚本已被更新,以适应这些源目录的新名称。但我的构建干预产生了一些其他更改。

底层更多力量

首先,扩展SeamTest的测试现在可以使用Java 6运行!这对我来说是个巨大的挫折,我很高兴找到了解决方案。真正的问题是嵌入式JBoss容器严重过时,在Java 6上崩溃。在准备好的新嵌入式JBoss版本出现之前,解决方案是使用推荐JAR文件来解决与JAX-WS的冲突,并允许特定于Sun JDK的特殊数组语法。你可以在构建文件中的测试目标中查看具体细节。

Groovy的爱好者将很高兴得知,现在可以在EAR项目中使用Groovy组件。EAR项目的构建使用groovyc在类路径上编译Groovy脚本,使它们成为真正的Java字节码。(要使seam-gen EAR项目在运行时解释.groovy文件还需要更多研究)。但更令人兴奋的是,你现在可以使用Groovy编写测试(再次使用groovyc编译)并且测试Groovy编写的组件。实际上,这只是一个将构建逻辑放入位置的问题,但重要的是要知道你可以直接获得Groovy支持。为了使Groovy支持更优雅,还需要做更多的工作,但至少目前它是全面的。

以下是构建中添加的一堆其他好东西

  • seam-gen WAR项目现在有一个统一的编译目标
  • 两个新目标,reexplode和redeploy,执行clean unexplode explodeclean undeploy deploy,分别
  • 重启目标现在会检测你是否已部署了展开或打包的存档,并相应地重启应用程序(如果已部署打包的存档,以前会崩溃)
  • 在测试执行期间将视图文件夹添加到类路径,以便在细粒度页面描述符(即.page.xml)中定义的页面操作得到正确调用(以前测试只读取全局页面描述符(即pages.xml))
  • 一个名为javadoc的新目标可以从项目源生成JavaDoc API

如果你对控制seam-gen项目的依赖项感兴趣,请查看我的关于如何使用Ivy管理seam-gen项目的依赖项的文章。

这就总结了对 seam-gen 项目的大部分更改。总的来说,这些升级应该会使您的 Seam 示例看起来更加美观,并且在开发过程中为您提供更多的工具。显然,还有很多可以改进的地方,所以请随时贡献您的想法。使用svn diff生成的补丁更受欢迎。

在最后一部分,我想谈谈对 seam 脚本所做的更改以及现在可以以不同方式调用的不同方法。

解放 seam-gen 的束缚

我们所有人都称之为 seam-gen 的 seam 脚本最终得到了自由。在过去,与 Grails 等其他项目生成工具相比,seam 脚本的使用并不那么舒适,因为开发人员必须从 Seam 发行目录中执行它。Grails 采用的方法是将 grails 脚本的路径添加到您的 PATH 中,设置 GRAILS_HOME,并像系统命令一样使用脚本。我有一个介于两者之间的方法,我认为它更灵活。

多亏了启动脚本的变化,您现在可以从计算机上的任何目录运行 seam,并且它将像现在一样工作(这意味着您的当前工作目录可以是任何地方)。seam 脚本仍然必须位于 Seam 发行目录中,或者如果没有设置,必须设置 SEAM_HOME 环境变量。但现在您还有一个从您路径上的目录(例如 ~/bin)创建 seam 脚本符号链接的第三个选项。内部,脚本会确定您的当前目录和相对于脚本位置的 SEAM_HOME 环境变量(没有必要让开发人员设置 SEAM_HOME 环境变量,尽管如果存在,它仍然会被尊重)。关于当前工作目录的更多内容将在下一部分讨论。到目前为止,重点是 seam 脚本可以从任何地方运行。不再有愚蠢的限制。

顺便提一下,我想提到,我在启动例程中添加了一个验证检查,以验证用户是否已定义 JAVA_HOME 环境变量,并且它解析到有效的 JDK 安装。否则,Ant 构建将失败。

自从 Seam 2.0 以来,seam create-project命令一直将seam setup的响应保存到项目根目录下的 build.properties 文件。但我们还没有处理这个文件……直到现在。这是您一直要求并等待的大增强。

如果您的当前工作目录中有一个 seam-gen.properties 文件和一个 build.xml 文件,那么 seam 脚本会识别出您正在 seam-gen 项目中,并使用该目录中的 seam-gen.properties 文件而不是 Seam 发行目录中的 seam-gen/build.properties 文件进行操作。如果您将 seam 脚本(或 seam 脚本的符号链接)添加到您的 PATH 中,那么您只需进入项目并运行seam generate即可。如果 seam 脚本不在您的 PATH 中,那么您必须运行类似~/projects/seam-2.1.0.GA/seam generate的东西。实际上,它的调用方式并不重要。这适用于 Linux、Windows 和 Mac。顺便说一句,编写跨平台脚本是一个巨大的痛苦。

当您的当前目录是 seam-gen 项目时,您实际上有两个选择:使用 seam 脚本或 ant 命令来运行目标。如果您的路径中安装了 Ant,那么 seam 脚本只是中间人。也就是说,除非您正在执行代码生成目标(例如,new-form、generate),那么您确实需要使用 seam 脚本。

所以,您现在可以使用 seam-gen 来管理多个项目,并且您可以在项目内部执行代码生成!但等等,还有更多!如果您还没有创建 seam-gen 项目,您可以使用-Dseam-gen.properties标志

seam -Dseam-gen.properties=seam-gen/myproject-build.properties

属性的值必须是绝对文件路径或相对于Seam发行版的路径。您还可以使用以下方式覆盖seam-gen目录的位置或甚至仅覆盖seam-gen模板(如果您保留自定义版本):-Dseam-gen.dir-Dtemplates.dir分别。可能需要传递-D标志到seam脚本中,但这给了您所需的强大功能。

我希望您对我在这篇文章中介绍的所有的增强功能感到兴奋,并且它帮助您在使用seam-gen项目时更加高效。还有很多工作要做,包括对seam-gen构建系统进行的主要重构,我将在下面的维基页面上开始记录。但现在,您应该有足够的新玩具来玩耍。


回到顶部