领先一步
VMware 提供培训和认证,助您加速进步。
了解更多更新:“Spring Roo 介绍”博客系列的第三部分现已推出,并详细介绍了 Roo 的内部架构。
今天我很高兴地宣布,我们刚刚发布了 Spring Roo 1.0.0.M1。此版本不仅包含大量修复、增强和 31% 的性能提升,还包含一系列令人兴奋的新功能,包括电子邮件服务、JMS、Spring Web Flow、简化的安装和自动的 Selenium 支持。这还不包括我在之前的博客文章中提到的 Alpha 版本中已有的许多功能。
除了在第一个里程碑版本上进行工作,过去一个月我们还建立了开源项目典型的公共项目基础设施。我们现在已经拥有一个社区支持论坛、Jira问题追踪、公共Subversion仓库、FishEye源代码监控以及等等。过去一个月在#roo Twitter频道上的一些评论包括“给我留下了深刻印象”、“喜欢它”、“自定义roo插件[非常]容易”、“创新来了”、“第一个里程碑版本会很酷!”、“Roo看起来很有趣并且有效”、“非常棒的工具”、“非常酷”等等。我们也开始看到第一个社区制作的插件,这强调了用您自己的自定义功能扩展Roo的便利性。
本月早些时候,我们还结束了社区项目命名竞赛,其中“Spring Roo”轻松胜出。总共收到了952张有效投票,其中Spring Roo(467)、Spring Boost(180)、Spring Spark(179)、Spring HyperDrive(64)和Spring Dart(62)。感谢所有投票的人!
这篇博客将假设您正在使用独立的 Spring Roo shell。除非另有说明,所有命令在标准 Spring Roo 和 STS 2.3.0 或更高版本中都以相同方式工作。主要区别之一是,在使用 Roo shell 时,您按 TAB 键进行补全选项,而在 STS 中,TAB 键被 CTRL + SPACE 替换。我们使用 CTRL + SPACE 是因为它在基于 Eclipse 的 IDE 中是更传统的补全键组合。
您还应该验证您是否安装了 Maven 2.0.9 或更高版本。虽然 Roo 本身不使用 Maven,并且可以在未安装 Maven 的情况下运行,但由 Roo 创建的项目目前使用 Maven。此外,如果您安装了较早的 Roo alpha 版本,请务必删除 ROO_HOME 变量。
尽管有在线 RSVP,我们仍然发出了纸质婚礼请柬。每张请柬的背面都有一个小小的“邀请码”。这些邀请码不容易猜到,但很容易阅读和输入(不是UUID!)。婚礼请柬文字邀请宾客访问我们的婚礼 RSVP 网站进行 RSVP。当他们访问婚礼 RSVP 网站时,系统会要求宾客输入他们的邀请码。
一旦宾客输入他们的邀请码,任何现有的RSVP记录都将被检索并允许他们进行编辑。如果他们之前没有RSVP过,他们将看到一个新的RSVP表格进行填写。表格将简单地询问宾客有多少人参加,以及任何特殊请求(例如饮食需求)。他们还将需要输入他们的电子邮件地址,如果提供了一个电子邮件地址,应用程序将发送一封基于电子邮件的RSVP确认。我们还将记录他们RSVP的日期和时间,如果他们多次更改RSVP,这将很有用。
$ mkdir wedding
$ cd wedding
$ roo
如果您遵循了上述安装说明,您应该会看到下方所示的 Roo 徽标。如果您没有看到类似这样的消息,请返回检查您的安装是否正确。
Roo 内部有相当多的可用性功能。如果您输入“hint”,将显示分步说明。如果您输入“help”,将看到当前所有可用的命令(这些命令会随着项目生命周期的不同阶段而变化)。此外,在几乎所有情况下,您都可以按 TAB 键获取补全服务。 如果您正在学习 Roo,“hint”是您的朋友。它不仅会教您命令,还会教您关于 shell 以及键盘功能如何工作。无论何时有疑问,尤其是在您的前几个 Roo 项目中,养成使用“hint”的习惯。
让我们开始我们的婚礼项目。在您将“create project”命令输入 Roo shell 后,您应该会收到以下输出:
roo> project --topLevelPackage com.wedding
Created /home/balex/wedding/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
如控制台输出所示,Roo 已创建了一个 Maven 2 项目结构。即使您此时退出 Roo 并且再也不重新加载它,此时您也拥有一个配置正确的 Spring 3 Web 应用程序,其中包含 URL 重写、基于注解的类路径扫描和任何类的依赖注入——甚至是通过“new”关键字或通过 ORM(如 Hibernate)创建的类。您甚至可以使用“mvn tomcat:run”并启动一个嵌入式 Tomcat 容器。
如果您此时输入“hint”,Roo 会建议您安装 JPA 提供程序和数据库。我们现在就来做这件事。
roo> persistence setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed ROOT/pom.xml
请注意,我们在命令中选择了 Hibernate 和持久化的 Hypersonic 数据库。此选择是通过 TAB 键完成的,因此我们实际上不需要完整输入这些命令和参数。还要注意底部的两个“Managed”语句。这些表示 Roo 正在管理的文件或目录。Roo 具有内置的文件撤销服务,因此如果出现问题,它将自动回滚有问题的命令。
由于 Roo 使用 JPA,我们享受跨不同 JPA 实现的可移植性优势。如果您查看 Roo 生成的代码,您会发现没有一行代码是特定于某个持久化提供程序的。您还会发现 Roo 提供的代码效率极高。 Java 的巨大优势之一是其显著的性能,Roo 会尽一切努力,从避免反射到优化您的 toString() 方法中的字符串操作(以及介于两者之间的一切),以最大限度地提高您应用程序的运行时性能。
因为我们请求了一个持久化数据库,所以默认情况下它存储在 ~/wedding.* 中。有一个“database properties list”命令可以显示数据库配置。
roo> database properties list
database.driverClassName = org.hsqldb.jdbcDriver
database.password =
database.url = jdbc:hsqldb:${user.home}/wedding
database.username = sa
虽然默认位置运行良好,但我们还是把它改到别处。
roo> database properties set --key database.url --value jdbc:hsqldb:/home/balex/our-wedding
Managed SRC_MAIN_RESOURCES/META-INF/spring/database.properties
如控制台输出所示,Roo 所做的只是编辑一个标准的 database.properties 文件。您也可以使用文本编辑器或 IDE 有效地编辑您的项目文件。Roo 不介意。它从一开始就设计成您可以同时使用其他工具和 Roo,并且一切仍然可以正常工作。
您可能希望通过 Roo 使用“database properties set”命令的一个原因是,您正在制作一个可以稍后重放的独立脚本。您可以使用“script filename.roo”命令执行脚本,这些脚本只是标准文本文件格式的 Roo 命令。为方便起见,我已将 wedding.roo 脚本包含在 Roo 1.0.0 分发版中。请注意,注释也可以使用普通的 Java 注释语法(//、/* 和 */)包含在脚本中。
roo> entity --class ~.domain.Rsvp
Created SRC_MAIN_JAVA/com/wedding/domain
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp.java
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Entity.aj
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_ToString.aj
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Configurable.aj
此时我想象有些人会疑惑,“那些 .aj 文件是什么?”。简而言之,这些是 AspectJ inter-type declarations (ITD),它们非常有效地实现了关注点分离,同时还保持了与相关 Roo 附加组件未来版本的兼容性。.aj 文件由 Roo 自动创建、维护和删除,允许最终用户安全地忽略它们。实际上,STS 2.1.0+ 默认会自动隐藏它们,就像基于 Eclipse 的 IDE 隐藏 .classpath、.project 和 .settings 资源一样。毕竟,这些资源只是工具的内部输出,您甚至很少会打开它们——更不用说自己维护它们了。我将在下一篇博客文章中更详细地讨论这些以及其他 Roo 内部结构,所以在此之前我将推迟进一步讨论。
您可能已经注意到,我们在“.domain”包中创建了 Rsvp 实体。“”字符会自动扩展到您的项目顶层包,您可能还记得我们在最初创建项目时指定了该包。因此,Roo 完全理解 Java 包的概念,并允许您以您认为最直观的方式组织项目包。
自然,一个实体通常会包含一些字段,所以我们来添加它们(Roo 的输出已省略,因为它只是管理上面列出的相同文件)。
roo> field string code --notNull --sizeMin 1 --sizeMax 30
roo> field string email --sizeMax 30
roo> field number attending --type java.lang.Integer
roo> field string specialRequests --sizeMax 100
roo> field date confirmed --type java.util.Date
在第一行中,您会注意到我们使用了 --notNull 参数,以及 --sizeMin 和 --sizeMax 参数。这些参数指的是新的 Bean Validation 标准,也称为 JSR 303。这个特定标准提供了自动的 Web 和持久层验证,包括为数据库中的表创建正确的 DDL。使用 Roo 的优势之一是,您无需额外努力即可获得相关标准(如 JSR 303、JPA、Servlet 规范和 REST)带来的好处。 当然,如果您不希望使用 JSR 303 参数,则无需使用。
从上面的字段命令中需要注意的另一点是,我们没有指定要将字段插入哪个实体。Roo 会自动判断您可能希望将字段添加到 Rsvp,因为这是您上次处理的实体。如果您希望明确或将字段定向到另一个实体,也可以指定“--class ~.SomeEntity”参数(在这种情况下,该实体将成为后续实体相关命令的默认实体)。
让我们从 JUnit 集成测试开始。您可以通过一个命令获取一个集成测试:
roo> test integration
Created SRC_TEST_JAVA/com/wedding/domain
Created SRC_TEST_JAVA/com/wedding/domain/RsvpDataOnDemand.java
Created SRC_TEST_JAVA/com/wedding/domain/RsvpIntegrationTest.java
Created SRC_TEST_JAVA/com/wedding/domain/RsvpDataOnDemand_Roo_Configurable.aj
Created SRC_TEST_JAVA/com/wedding/domain/RsvpDataOnDemand_Roo_DataOnDemand.aj
Created SRC_TEST_JAVA/com/wedding/domain/RsvpIntegrationTest_Roo_Configurable.aj
Created SRC_TEST_JAVA/com/wedding/domain/RsvpIntegrationTest_Roo_IntegrationTest.aj
此集成测试将验证常见的 JPA 操作,如持久化、删除、查找、合并等是否都正常工作。每个实体总共执行八个测试,所有这些都基于 Spring Framework 广泛的集成测试基础设施。虽然我们可以在这个阶段运行集成测试,但添加一个 Web 层也很简单。
roo> controller scaffold ~.web.RsvpController
Created SRC_MAIN_JAVA/com/wedding/web
Created SRC_MAIN_JAVA/com/wedding/web/RsvpController.java
Created SRC_MAIN_WEBAPP/WEB-INF/config
Created SRC_MAIN_WEBAPP/WEB-INF/config/webmvc-config.xml
Created SRC_MAIN_JAVA/com/wedding/web/RsvpController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/images
Created SRC_MAIN_WEBAPP/images/banner-graphic.png
Created SRC_MAIN_WEBAPP/images/springsource-logo.png
Created SRC_MAIN_WEBAPP/images/resultset_first.png
Created SRC_MAIN_WEBAPP/images/resultset_next.png
Created SRC_MAIN_WEBAPP/images/resultset_previous.png
Created SRC_MAIN_WEBAPP/images/resultset_last.png
Created SRC_MAIN_WEBAPP/images/us.png
Created SRC_MAIN_WEBAPP/images/de.png
Created SRC_MAIN_WEBAPP/images/list.png
Created SRC_MAIN_WEBAPP/images/add.png
Created SRC_MAIN_WEBAPP/styles
Created SRC_MAIN_WEBAPP/styles/roo-menu-left.css
Created SRC_MAIN_WEBAPP/styles/roo-menu-right.css
Created SRC_MAIN_WEBAPP/WEB-INF/classes
Created SRC_MAIN_WEBAPP/WEB-INF/classes/left.properties
Created SRC_MAIN_WEBAPP/WEB-INF/classes/right.properties
Created SRC_MAIN_WEBAPP/WEB-INF/layouts
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/layouts.xml
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/default.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views
Created SRC_MAIN_WEBAPP/WEB-INF/views/dataAccessFailure.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/resourceNotFound.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/uncaughtException.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/tags
Created SRC_MAIN_WEBAPP/WEB-INF/tags/pagination.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/language.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/theme.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/i18n
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/messages.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_de.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_de.properties
Created SRC_MAIN_WEBAPP/images/show.png
Created SRC_MAIN_WEBAPP/images/update.png
Created SRC_MAIN_WEBAPP/images/delete.png
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp
Managed SRC_MAIN_WEBAPP/WEB-INF/config/webmvc-config.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/create.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/update.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/urlrewrite.xml
Created SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed ROOT/pom.xml
Roo 提供的自动 Web 层建立在 Spring Framework 3 出色的 REST 支持之上。所有端点都是完全 RESTful 的,并使用简洁、格式正确的 URL。 Roo 的自动 Web 层在多种情况下都很有用,尤其是在以下情况下:
roo> selenium test --controller ~.web.RsvpController
Created SRC_MAIN_WEBAPP/selenium
Created SRC_MAIN_WEBAPP/selenium/test-rsvp.xhtml
Created SRC_MAIN_WEBAPP/selenium/test-suite.xhtml
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Managed ROOT/pom.xml
好的,让我们通过运行以下命令来查看应用程序的实际运行情况。
roo> perform test
(Maven console output condensed)
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.wedding.domain.RsvpIntegrationTest
Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.726 sec
roo> quit
$ mvn tomcat:run
现在您可以使用浏览器访问 https://:8080/wedding。当您准备好测试 Web 层时,请保持 Tomcat 服务器运行,然后执行以下命令:
$ mvn selenium:selenese
在执行 Selenium 测试期间,您应该会看到类似以下的图像:
roo> logging setup --package WEB --level DEBUG
Created SRC_MAIN_RESOURCES/META-INF/spring/log4j.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
现在让我们关注安全性。目前,任何人都可以访问我们的网站并使用现有的 RESTful 管理后端来创建、更新和删除 RSVP。回想一下应用程序要求,我们希望使用邀请码(印在卡片背面)来确保只有受邀宾客才能 RSVP。幸运的是,Spring Security 为我们提供了一种非常快速的方法来满足这一要求,而且 Roo 可以一行安装 Spring Security。
roo> security setup
Managed ROOT/pom.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext-security.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/login.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/views/views.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
还有类似的命令,如“web flow”和“jms setup”,但我们不会在本篇博客文章中探讨它们。您可以预期在 Roo 的未来版本中会看到更多“install”命令(欢迎您将安装程序请求添加到 Roo 问题跟踪器)。
roo> controller class --class ~.web.PublicRsvpController
Created SRC_MAIN_JAVA/com/wedding/web/PublicRsvpController.java
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed ROOT/pom.xml
PublicRsvpController 将响应 HTTP GET 和 POST 请求。PublicRsvpController.java 源文件中已自动提供了用于这些操作的两个存根方法。
如果我们考虑GET用例,我们的目标是检索特定邀请码的正确RSVP。其工作方式是Spring Security将要求人们登录才能使用应用程序,并且我们将把每个邀请码视为一个唯一的登录名。因此,GET方法需要从Spring Security中获取当前登录用户的名称,然后从数据库中检索相应的RSVP。通常您会在此时编写JPA QL查询来获取具有匹配代码的特定Rsvp实例,但由于您正在使用Roo,您可以省去麻烦,转而使用动态查找器。
动态查找器为您提供了几乎无限范围的预设查询。这些查询内部都使用 JPA QL,提供最大的基于标准的兼容性和可移植性。所有动态查找器(以及其他 Roo 方法)都作为格式正确、类型安全的 Java 方法实现——带来熟悉性、IDE 代码辅助、调试器集成和显著运行时性能等所有常规优势。您可以使用以下命令列出可用的动态查找器:
roo> finder list --class ~.domain.Rsvp --filter code,equ
findRsvpsByCodeEquals(String code)
findRsvpsByCodeNotEquals(String code)
请注意,“--filter”参数将输出限制为仅包含“code”和“equ”字符串的建议方法签名。您可以通过省略“-filter”参数或指定“-depth 2”(或3、4等,如果您希望查询涉及更多属性)来指示 Roo 您希望查看更多组合。
一旦找到您想使用的动态查找器,只需添加即可。
roo> finder add --finderName findRsvpsByCodeEquals
Managed SRC_MAIN_JAVA/com/wedding/domain/Rsvp.java
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Finder.aj
Managed SRC_MAIN_JAVA/com/wedding/web/RsvpController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/findRsvpsByCodeEquals.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/views/rsvp/views.xml
如果我们考虑 PublicRsvpController 的 POST 用例,我们的要求规定我们应该向宾客发送一封电子邮件以确认他们的 RSVP。通常我们会翻阅 Spring 参考指南并找到配置电子邮件支持的部分,但相反,我们只需让 Roo 为我们处理。
roo> email sender setup --hostServer 127.0.0.1
Created SRC_MAIN_RESOURCES/META-INF/spring/email.properties
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed ROOT/pom.xml
roo> field email template --class ~.web.PublicRsvpController
Managed SRC_MAIN_JAVA/com/wedding/web/PublicRsvpController.java
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed SRC_MAIN_JAVA/com/wedding/web/PublicRsvpController.java
最后一条命令在 PublicRsvpController 中添加了一个 Spring MailSender 字段,并提供了一个方法来展示如何使用它。
说到电子邮件集成,我的同事Stefan Schmidt刚刚发布了一篇单独的博客文章,展示了如何同时使用 Roo 电子邮件和 JMS 插件。文章向您展示了更高级的配置选项,例如如何使用 Gmail 发送电子邮件。
roo> perform eclipse
(Maven console output condensed)
最后,让我们将项目导入 Eclipse/STS。您可以通过加载 Eclipse/STS,然后选择 File > Import > Existing Projects into Workspace,并选择项目目录来完成此操作。如果您未使用 STS 2.3.0 或更高版本,请确保已单独安装 AJDT 1.6.5 或更高版本。当 AJDT 提示您是否要启用 JDT weaving 时,选择启用 weaving。这将在使用 Eclipse 的 Java 编辑器时获得更好的 Roo 体验。

首先编辑 applicationContext-security.xml。进行一些小的更改,使其类似于以下文件:
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/static/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/static/j_spring_security_logout"/>
<intercept-url pattern="/rsvp/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/static/**" access="permitAll" />
<intercept-url pattern="/login**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin1234" password="ignored" authorities="ROLE_ADMIN"/>
<user name="user12345" password="ignored" authorities="ROLE_USER"/>
<user name="user67890" password="ignored" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
上面的文件显示,邀请码实际上是用户名,我们忽略了密码。Spring Security 并不知道我们忽略了密码,所以我们需要编辑 src/main/webapp/WEB-INF/views/login.jspx,并在表单内添加一行 <input name="j_password" type="hidden" value="ignored"/>。当然,包含“j_password”标签和输入元素的现有 <div> 应该被删除。还应该在此文件中添加一些适当的文本,在 login.jsp 中向客人解释他们可以在卡的哪个位置找到邀请码。
安全现已设置完毕。现在我们打开 PublicRsvpController.java 文件。如所示,Roo 已经存根了电子邮件功能,并为您提供了空的 Spring MVC 方法来完成。这是整个应用程序中唯一实际需要的 Java 编程,并且由于这些使用 Spring MVC 的正常功能和 Spring 的 MailSender 类,我在这里不再进一步讨论它们。
@RequestMapping("/publicrsvp/**")
@Controller
@SessionAttributes("rsvp")
public class PublicRsvpController {
@Autowired
private transient MailSender mailTemplate;
@RequestMapping
public String get(ModelMap modelMap) {
modelMap.put("rsvp", getRsvp());
return "publicrsvp";
}
@RequestMapping(method = RequestMethod.POST)
public String post(@ModelAttribute("rsvp") Rsvp rsvp, ModelMap modelMap) {
rsvp.setConfirmed(new Date());
if (rsvp.getId() == null) {
rsvp.persist();
} else {
rsvp.merge();
}
if (rsvp.getEmail().length() > 0) {
sendMessage("Ben Alex <[email protected]>", "RSVP to our wedding", rsvp.getEmail(), "Your RSVP has been saved: " + rsvp.toString());
}
modelMap.put("rsvp", rsvp);
return "thanks";
}
private Rsvp getRsvp() {
Rsvp rsvp = new Rsvp();
try {
String code = SecurityContextHolder.getContext().getAuthentication().getName();
rsvp.setCode(code);
// Cast due to http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#getSingleResult()
rsvp = (Rsvp) Rsvp.findRsvpsByCodeEquals(code).getSingleResult();
} catch (DataAccessException ignored) { /* no Rsvp for this code was found, so start a new Rsvp */ }
return rsvp;
}
private void sendMessage(String mailFrom, String subject, String mailTo, String message) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(mailFrom);
simpleMailMessage.setSubject(subject);
simpleMailMessage.setTo(mailTo);
simpleMailMessage.setText(message);
mailTemplate.send(simpleMailMessage);
}
}
请注意,在“get”和“post”方法中,我们返回一个字符串,该字符串应与我们希望渲染的 JSP 视图名称相关联。因此,我们的下一步是提供这两个 JSP。幸运的是,Roo 构建了一些 JSP 文件,这些文件将作为有用的模板。
首先将 src/main/webapp/WEB-INF/index.jsp 重命名为 thanks.jsp。这将是“post”方法返回时显示的页面。您可能希望添加类似“您的 RSVP 已确认:${rsvp}”之类的文本。
接下来,将 src/main/webapp/WEB-INF/views/rsvp/create.jspx 复制到 src/main/webapp/WEB-INF/views/publicrsvp.jspx。然后应编辑此页面。您可以安全地删除“code”和“confirmed”部分,因为它们都由 PublicRsvpController 处理。您还应该将“form_url”变量赋值更改为 <c:url value="/publicrsvp" var="form_url"/>。
由于 Spring Roo 使用 Tiles 允许轻松地对每个 Web 视图进行品牌化,您需要编辑 src/main/webapp/WEB-INF/views/views.xml 文件。您需要将“index”定义重命名为“thanks”,并为新的 publicrsvp.jspx 添加一个新的“publicrsvp”定义。最终文件应类似于:
<tiles-definitions>
<definition extends="public" name="thanks">
<put-attribute name="body" value="/WEB-INF/views/thanks.jspx"/>
</definition>
<definition extends="public" name="dataAccessFailure">
<put-attribute name="body" value="/WEB-INF/views/dataAccessFailure.jspx"/>
</definition>
<definition extends="public" name="resourceNotFound">
<put-attribute name="body" value="/WEB-INF/views/resourceNotFound.jspx"/>
</definition>
<definition extends="public" name="uncaughtException">
<put-attribute name="body" value="/WEB-INF/views/uncaughtException.jspx"/>
</definition>
<definition extends="public" name="login">
<put-attribute name="body" value="/WEB-INF/views/login.jspx"/>
</definition>
<definition extends="public" name="publicrsvp">
<put-attribute name="body" value="/WEB-INF/views/publicrsvp.jspx"/>
</definition>
</tiles-definitions>
最后一步是编辑 src/main/webapp/WEB-INF/urlrewrite.xml 并更改 / 的 URL 重写规则。/app/index 应该修改为 /app/publicrsvp/,这表示默认情况下执行新的 PublicRsvpController 的 GET 请求。
现在您应该可以测试部署了。您有几个选项:
自然,在此阶段,我们通常会整理应用程序中公开可见部分的外观和感觉。然后,我们将运行“perform package”以提供一个 WAR 文件,该文件已准备好部署到生产服务器环境,例如 SpringSource tc Server 或 SpringSource dm Server。