领先一步
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 和键盘功能的工作原理。养成在有疑问时使用“hint”的习惯,尤其是在您的前几个 Roo 项目中。
让我们开始我们的婚礼项目。在将“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.*中。有一个“数据库属性列表”命令可以显示数据库配置。
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使用“数据库属性设置”命令的一个原因是,您正在创建一个稍后可以重放的独立脚本。您可以使用“脚本文件名.roo”命令执行脚本,这些脚本只是标准文本文件格式中的Roo命令。为了方便起见,我在Roo 1.0.0发行版中包含了wedding.roo脚本。请注意,还可以使用普通的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的跨类型声明(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://127.0.0.1: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的未来版本中看到更多“安装”命令(欢迎您将安装程序请求添加到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
最后的命令将一个Spring MailSender字段添加到PublicRsvpController中,并提供了一个方法向我们展示如何使用它。
关于电子邮件集成的主题,我的同事Stefan Schmidt刚刚发布了一篇单独的博文,展示了如何将Roo电子邮件和JMS加载项一起使用。文章向您展示了更高级的配置选项,例如如何使用Gmail发送电子邮件。
roo> perform eclipse
(Maven console output condensed)
最后,让我们将项目导入 Eclipse/STS。您可以通过加载 Eclipse/STS,然后选择文件 > 导入 > 将现有项目导入工作区,并选择项目的目录来完成此操作。如果您没有使用 STS 2.3.0 或更高版本,请确保您已单独安装了 AJDT 1.6.5 或更高版本。当 AJDT 提示您是否要启用 JDT 编织时,请选择启用编织。这将在使用 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> 应该被删除。还应在此文件中添加一些登录.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,该 WAR 准备好部署到生产服务器环境(例如 SpringSource tc Server 或 SpringSource dm Server)。