领先一步
VMware 提供培训和认证,助您加速进步。
了解更多Java 企业应用程序可以有多种形式。根据需求,开发者需要决定应用程序需要哪些特定的架构层。直到现在,Spring Roo 一直采用务实的方法,以减少服务门面、仓库或 DAO 层引入的通常不必要的复杂性。最新发布的 Spring Roo 1.2.0.M1(参见公告)包含了经常请求的对架构层的支持,这些架构层可以根据应用程序的需求进行定制。本文概述了 Roo 新的服务层和仓库层功能。
虽然有一些新的分层和持久化选项可用,但 Roo 默认将继续支持 JPA Active Record Entity。但是,您可以通过添加更多的服务层或仓库层来轻松更改现有应用程序(详情如下)。如果您添加新的层,Roo 将分别在消费者层或服务层自动更改其 ITD。例如,对于给定的域类型,Roo 将自动更改您的应用程序,以便在现有的 MVC 控制器、GWT 定位器、集成测试或按需数据中注入并调用新的服务层。
随着 Roo 1.2.0.M1 的发布,Roo 核心现在有三种选项支持数据持久化:JPA Entities(Active Record 风格)、JPA Repositories 和 MongoDB Repositories。对 Spring Data Neo4J 的支持目前正在开发中,很快将作为一个 Roo 插件可用。
Active record 风格的 JPA Entities 自 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 的支持,Cloud Foundry 是免费开发和托管 Spring Roo 应用程序的绝佳场所。除了 MongoDB,您还可以将 MySQL 和 PostgreSQL 与 Cloud Foundry 一起使用。要为 MongoDB 持久化配置项目,您可以使用 mongo setup 命令
roo> mongo setup
这将配置您的 Spring 应用上下文,以使用运行在本地主机和默认端口上的 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 Services。更详细的讨论请参阅 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 团队始终欢迎社区的反馈。