取得進展
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 並且可以在未安裝的情況下執行,但 Roo 建立的專案目前使用 Maven。此外,如果您安裝了早期 Roo alpha 版本之一,請務必刪除 ROO_HOME 變數。
儘管有線上 RSVP,我們仍然寄出了紙質婚禮請柬。每張請柬的背面都有一個小小的“邀請碼”。這些碼不容易猜到,但很容易閱讀和輸入(不是 UUID!)。婚禮請柬的文字邀請賓客訪問我們的婚禮 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”關鍵字或透過像 Hibernate 這樣的 ORM 建立的類。您甚至可以使用“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 跨型別宣告 (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
現在您可以使用瀏覽器訪問 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。回想一下應用程式需求,我們希望使用邀請碼(印在卡片背面)來確保只有被邀請的賓客才能回覆。幸運的是,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> 應該被刪除。還應在該檔案中新增一些適當的文字,向賓客解釋他們可以在卡片的哪個位置找到他們的邀請碼。
現在安全性已經設定好了。現在讓我們開啟 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}”。
接下來將 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”命令,以生成一個可部署到生產伺服器環境(例如 SpringSource tc Server 或 SpringSource dm Server)的 WAR 檔案。