領先一步
VMware 提供培訓和認證,以加速您的進展。
了解更多更新:「Spring Roo 介紹」部落格系列的第三篇現已發布,詳細介紹 Roo 的內部架構。
今天,我很高興宣布我們剛剛發布了 Spring Roo 1.0.0.M1。此版本不僅具有眾多修復、增強功能和 31% 的效能提升,還有一系列令人興奮的新功能,包括 電子郵件服務、JMS、Spring Web Flow、簡化的安裝以及自動 Selenium 支援。這是在 alpha 版本中已存在的許多功能之上新增的,正如我在之前的部落格文章中提到的。
除了致力於第一個里程碑版本之外,在過去的一個月中,我們還建立了開源專案典型的公共專案基礎架構。我們現在提供社群支援論壇、Jira issue 追蹤、公共 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 專案中。
讓我們開始我們的婚禮專案。在您在 Roo shell 中輸入「create project」命令後,您應該會收到以下輸出
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 命令。為了您的方便,我在 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 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 Specification 和 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 操作,例如 persist、remove、find、merge 等是否都有效。每個實體總共執行八個測試,並且全部基於 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
您現在可以使用瀏覽器造訪 http://localhost: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 issue 追蹤器)。
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,因此您可以省去麻煩,而是使用動態 Finder。
動態 Finder 為您提供了幾乎無限範圍的預先定義查詢。這些查詢全部在內部使用 JPA QL,提供最大的基於標準的相容性和可移植性。所有動態 Finder(和其他 Roo 方法)都實作為格式正確、類型安全的 Java 方法 - 帶來熟悉度、IDE 程式碼輔助、偵錯程式整合和顯著執行階段效能的所有正常優勢。您可以使用如下命令列出可用的動態 Finder
roo> finder list --class ~.domain.Rsvp --filter code,equ
findRsvpsByCodeEquals(String code)
findRsvpsByCodeNotEquals(String code)
請注意,「--filter」引數將輸出限制為僅包含「code」和「equ」字串的那些建議的方法簽章。您可以指示 Roo 您想要查看更多組合,方法是省略「-filter」引數,或指定「-depth 2」(或 3、4 等,如果您想要查詢中包含更多屬性)。
找到您想要使用的動態 Finder 後,只需新增它即可
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 完成此操作,然後選擇「檔案」>「匯入」>「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,該 WAR 已準備好部署到生產伺服器環境,例如 SpringSource tc Server 或 SpringSource dm Server。