領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多Java 企業應用程式可以有多種形態和形式。根據其需求,開發人員需要決定應用程式需要哪些特定的架構層。到目前為止,Spring Roo 採取了實用方法,以減少服務門面、倉庫或 DAO 層引入的往往不必要的複雜性。新發布的 Spring Roo 1.2.0.M1(檢視公告)包含了頻繁請求的對可根據應用程式需求量身定製的架構層的支援。本文概述了 Roo 的新服務和倉庫層功能。

雖然有許多新的分層和持久化選擇,但Roo預設將繼續支援JPA Active Record實體。但是,您可以透過新增額外的服務或倉庫層(詳情如下)輕鬆更改現有應用程式。如果您新增新的層,Roo將自動更改其在消費層或服務層中的ITD。例如,Roo將自動更改您的應用程式,以在現有MVC控制器、GWT定位器、整合測試或給定域型別的資料點播中注入並呼叫新的服務層。
透過Roo 1.2.0.M1版本,Roo核心現在提供三種選項來支援資料持久化:JPA實體(Active Record風格)、JPA倉庫和MongoDB倉庫。對Spring Data Neo4J的支援目前正在開發中,很快將作為Roo外掛提供。
Active Record風格的JPA實體自Spring Roo的第一個版本以來一直是預設設定,並將保持不變。要為JPA持久化配置您的專案,您可以執行jpa setup命令
roo> jpa setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT
這會將您的專案配置為使用Hibernate物件關係對映器以及記憶體資料庫(HSQLDB)。Roo支援的Active Record風格的JPA實體使用@RooEntity進行註解,該註解負責提供持久化識別符號欄位及其訪問器和修改器。此外,此註解還會建立典型的CRUD方法以支援資料訪問。
roo> entity --class ~.domain.Pizza
此命令將建立一個Pizza域型別,以及用於持久化、更新、讀取和刪除實體的Active Record風格方法。以下示例還包含一些欄位,可以直接新增到Java原始檔,或透過Roo shell中的field命令新增。
@RooJavaBean
@RooToString
@RooEntity
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
需要倉庫/DAO層而不是預設Roo JPA“Active Record”持久化方法的開發人員可以透過為給定JPA域型別建立Spring Data JPA支援的倉庫來實現。透過jpa setup命令為JPA持久化配置專案後,此功能透過使用Roo的@RooJpaEntity註解域型別自動提供。
roo> entity --class ~.domain.Pizza --activeRecord false
透過定義--activeRecord false,您可以選擇退出預設的“Active Record”風格。以下示例還包含一些欄位,可以透過Roo shell中的field命令新增。
@RooJavaBean
@RooToString
@RooJpaEntity
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
有了域型別之後,您現在可以使用repository jpa命令為此型別建立新的倉庫
roo> repository jpa --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
這將建立一個利用Spring Data JPA的簡單介面定義
@RooRepositoryJpa(domainType = Pizza.class)
public interface PizzaRepository {
}
當然,您可以在任何介面上手動新增@RooRepositoryJpa註解,而無需在Roo shell中發出repository jpa命令。
新增@RooRepositoryJpa註解將觸發一個相當簡單的AspectJ ITD的建立,該ITD會向PizzaRepository介面新增一個extends語句,從而產生與此介面定義等效的結果
public interface PizzaRepository extends JpaRepository<Pizza, Long> {}
JpaRepository介面是Spring Data JPA API的一部分,並提供所有開箱即用的CRUD功能。
作為JPA持久化的替代方案,Spring Roo 1.2現在透過利用Spring Data MongoDB專案提供MongoDB支援。MongoDB受Cloud Foundry支援,這是一個免費開發和託管Spring Roo應用程式的好地方。除了MongoDB,您還可以使用MySQL和PostgreSQL與Cloud Foundry。要為MongoDB持久化配置專案,您可以使用mongo setup命令
roo> mongo setup
這將配置您的Spring應用程式上下文以使用執行在localhost和預設埠上的MongoDB安裝。可選的命令屬性允許您定義主機、埠、資料庫名稱、使用者名稱和密碼。如果您在Cloud Foundry上使用MongoDB,只需在“mongo setup”後新增--cloudFoundry,Roo就會自動為您配置所有內容
一旦應用程式配置了MongoDB支援,entity mongo和repository mongo命令就可用了
roo> entity mongo --class ~.domain.Pizza
此命令將建立一個用@RooMongoEntity註解的Pizza域型別。此註解負責觸發ITD的建立,該ITD提供一個Spring Data @Id註解欄位及其訪問器和修改器。以下示例還包含一些欄位,可以透過Roo shell中的field命令新增。
@RooJavaBean
@RooToString
@RooMongoEntity
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
有了域型別之後,您現在可以使用repository mongo命令為此型別建立新的倉庫(或透過將@RooRepositoryMongo註解應用於任意介面)
roo> repository mongo --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
這將建立一個利用Spring Data MongoDB的簡單介面定義
@RooRepositoryMongo(domainType = Pizza.class)
public interface PizzaRepository {
List<Pizza> findAll();
}
與上面看到的Spring Data JPA驅動的倉庫類似,此介面透過一個ITD進行增強,該ITD引入了Spring Data API提供的PagingAndSortingRepository,並負責提供所有必要的CRUD功能。此外,此介面定義了一個“自定義”查詢器,PagingAndSortingRepository實現不提供此查詢器:List findAll();。此方法是Spring Roo的UI腳手架所必需的,並由Spring Data MongoDB提供的查詢構建器機制自動實現。
與使用JPA持久化的應用程式類似(有關使用JPA與Postgres的詳細資訊,請參閱這篇部落格文章),MongoDB應用程式可以輕鬆部署到VMware Cloud Foundry。以下指令碼提供了一個Pizza Shop示例應用程式(參見/sample/pizzashop.roo)的示例,該應用程式已調整為與MongoDB支援的倉庫層一起使用
// Create a new project.
project com.springsource.pizzashop
// Create configuration for MongoDB peristence
mongo setup --cloudFoundry true
// Define domain model.
entity mongo --class ~.domain.Base --testAutomatically
field string --fieldName name --sizeMin 2 --notNull --class ~.domain.Base
entity mongo --class ~.domain.Topping --testAutomatically
field string --fieldName name --sizeMin 2 --notNull --class ~.domain.Topping
entity mongo --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2 --class ~.domain.Pizza
field number --fieldName price --type java.lang.Float
field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity mongo --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2 --class ~.domain.PizzaOrder
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --type ~.domain.Pizza
// Add layer support.
repository mongo --interface ~.repository.ToppingRepository --entity ~.domain.Topping
repository mongo --interface ~.repository.BaseRepository --entity ~.domain.Base
repository mongo --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
repository mongo --interface ~.repository.PizzaOrderRepository --entity ~.domain.PizzaOrder
service --interface ~.service.ToppingService --entity ~.domain.Topping
service --interface ~.service.BaseService --entity ~.domain.Base
service --interface ~.service.PizzaService --entity ~.domain.Pizza
service --interface ~.service.PizzaOrderService --entity ~.domain.PizzaOrder
// Create a Web UI.
web mvc setup
web mvc all --package ~.web
// Package the application into a war file.
perform package
// Deploy and start the application in Cloud Foundry
cloud foundry login
cloud foundry deploy --appName roo-pizzashop --path /target/pizzashop-0.1.0.BUILD-SNAPSHOT.war --memory 512
cloud foundry create service --serviceName pizzashop-mongo --serviceType mongodb
cloud foundry bind service --serviceName pizzashop-mongo --appName roo-pizzashop
cloud foundry start app --appName roo-pizzashop
“即時”示例應用程式目前部署在Cloud Foundry上:http://roo-pizzashop.cloudfoundry.com/
根據Roo的約定,所有功能都將透過AspectJ ITD引入,從而為開發人員提供了一個乾淨的畫布,用於實現不自然地適合域實體的自定義業務邏輯。服務層的其他常見用例是安全性或遠端整合,例如Web服務。有關更詳細的討論,請參閱Spring Roo參考指南中的架構章節。
服務層整合到Roo專案中與倉庫層類似,透過直接使用@RooService註解或Roo shell中的service命令
roo> service --interface ~.service.PizzaService --entity ~.domain.Pizza
此命令將在定義的包中建立PizzaService介面,並在同一包中建立PizzaServiceImpl(PizzaServiceImpl的名稱和包可以透過可選的--class屬性自定義)。
@RooService(domainTypes = { Pizza.class })
public interface PizzaService {
}
根據Roo約定,預設的CRUD方法定義可以在AspectJ ITD中找到
void savePizza(Pizza pizza);
Pizza findPizza(Long id);
List<Pizza> findAllPizzas();
List<Pizza> findPizzaEntries(int firstResult, int maxResults);
long countAllPizzas();
Pizza updatePizza(pizza pizza);
void deletePizza(Pizza pizza);
同樣,PizzaServiceImpl也相當簡單
public class PizzaServiceImpl implements PizzaService {}
透過AspectJ ITD,PizzaServiceImpl型別預設用@Service和@Transactional註解。此外,ITD將向目標型別引入以下方法和欄位
@Autowired PizzaRepository pizzaRepository;
public void savePizza(Pizza pizza) {
pizzaRepository.save(pizza);
}
public Pizza findPizza(Long id) {
return pizzaRepository.findOne(id);
}
public List<Pizza> findAllPizzas() {
return pizzaRepository.findAll();
}
public List<Pizza> findPizzaEntries(int firstResult, int maxResults) {
return pizzaRepository.findAll(new PageRequest(firstResult / maxResults, maxResults)).getContent();
}
public long countAllPizzas() {
return pizzaRepository.count();
}
public Pizza updatePizza(Pizza pizza) {
return pizzaRepository.save(pizza);
}
public void deletePizza(Pizza pizza) {
pizzaRepository.delete(pizza);
}
如您所見,Roo將檢測是否存在給定域型別的持久化提供程式層,並自動注入此元件以將所有服務層呼叫委託給此層。如果不存在持久化(或其他“較低級別”)層,服務層ITD將簡單地提供方法存根。
使用Spring Roo 1.2,向新的或現有的Spring Roo管理應用程式新增架構層或持久化選項變得幾乎微不足道。無需考慮為新的持久化提供程式配置應用程式,或將對新層的引用注入到Spring MVC控制器、GWT UI或整合測試中——Roo將為您完成所有這些工作!
隨著Spring Roo 1.2中可用的分層支援,我們預計未來會有更多的持久化提供程式。對Spring Data Neo4J的倉庫分層整合目前正在開發中,很快將作為Roo外掛提供。
如果您想輕鬆試用這些新功能,為什麼不構建您自己的MongoDB驅動的Pizza Shop應用程式版本並將其部署到Cloud Foundry呢?得益於這些新的Roo 1.2.0.M1功能,這隻需幾分鐘。
鑑於Spring Roo 1.2.0.M1是一個里程碑版本,您應該繼續將Roo 1.1.5用於生產專案。但是,我們相信Roo 1.2 M1適合探索新功能或快速專案。
Roo團隊始終歡迎社群的反饋。