原文:Developing with CUBA - a big shift from Spring?

翻译:CUBA China

CUBA-Platform 官网 : https://www.cuba-platform.com

CUBA China 官网 : http://cuba-platform.cn

欢迎转载,转载请注明来源。

  企业级软件开发人员通常会面对如下需求组合(至少我经常遇到的是):设计优良的数据存储结构(有时候是已有的旧数据库模型),大量的数据录入表单,非常复杂的业务逻辑、报表功能、与许多公司其他系统(财会、CRM等)集成,数千并发量。对此,你首先考虑的是什么?

  “首先,采用主流的关系数据数据库管理(RDBMS)、Hibernate / JPA + Spring Boot、REST API,并且使用我最喜欢的或者最新的JS框架来实现UI。”

  “嗯~,还需配置Spring Security ,也许还需要写一部分代码来实现行级别的数据保护功能。如何实现呢?也许会用到数据库视图或虚拟专用数据库。“

  “所有这些DAO代码都非常相似且枯燥,但我还是需要一一实现。”

  “可以使用类似ModelMapper的东西将JPA实体转换为REST的DTO。”

  “别忘了跟实习生强调下懒加载和JPA关联查询。”

  “唉,其实都是雷同登录界面、千篇一律的实体到DTO的转换,有没有办法能让我摆脱所有这些乏味的东西 ,只需要专注于关键的业务逻辑实现呢?”

本文适合使用Spring框架(包括Spring Boot)从头开始做过几个项目、并且正在考虑怎么提高自己工作效率的开发人员。在文章中,我将向您展示如何使用CUBA平台摆脱常见的耗时枯燥任务。

又一个框架?

  开发人员在听到新框架时提出的第一个问题往往是:“为什么我需要这个?Spring Boot就能很好地帮助我从头开始实现所有内容”。 没错,新平台意味着新的规则、新的限制,之前积累的其他框架的经验便失去了意义。就算是目前使用的框架不完美,但是对它足够了解,知道有哪些坑,和哪些变通的方法。

  但是,从Spring切换到CUBA,并不需要重头学习规则,甚至没有什么变化,只要稍微前进一步就可以摆脱枯燥的开发任务,摆脱数百行DTO架子代码和转换工具的困扰,摆脱实现数据分页或数据过滤组件、创建Spring Security配置文件(JPA,Cache,...)等等些基础功能的麻烦。

  本文中,我们将从头开始展示CUBA如何遵循几乎所有基于Spring的开发模式,开发人员在Spring中积累的经验能被充分利用,同样的研发投入却能交付更多。为了使情景更清晰简洁,本文侧重于后端代码。

Spring应用程序架构

  Spring应用程序的典型架构可以很容易搜索到,很多情况下,它可以表示为具有一些交叉区域的典型三层应用程序。让我们来看看“经典”的Spring应用程序:

  领域模型(Domain Model) - 通常需要手动创建。但是,有一些工具可基于数据存储结构创建领域模型。

  数据存储层(Repository Layer) - 与数据存储一起使用的类。也称为“DAO”,“存储库(Repositories)”等。这块是ORM框架(及其兄弟姐妹们)的领地。它通常包含功能域模型中的一个实体执行CRUD操作的类。

  服务层(Service Layer) - 有时开发人员会创建一个额外的层来分离业务逻辑和数据CRUD操作。如果项目业务逻辑复杂,涉及不同类型的数据源,或者涉及外部服务集成,这一层会很有用。

  Web /控制器层(REST / MVC) - 用来处理REST API(将由基于浏览器的应用程序使用)或使用JSP实现的视图,或是模板框架(thymeleaf, velocity)、JVM前端框架(GWT, Vaadin,Wicket等)。由于API结构或前端界面展示不同,通常控制器是操作DTO而不是实体对象。因此,开发人员通常必须在实体模型和DTO模型之间实现双向转换。

  如果您对以上描述很熟悉(甚至觉得是显而易见) - 那么恭喜,您可以毫无障碍地开始使用CUBA。

参考应用 - 宠物诊所

  话不多说,接下来看code怎么写。在GitHub上,有一个众所周知的Spring的“参考”应用程序 - Pet Clinic(宠物诊所)。下面我们将展示如何使用你的Spring技能加上CUBA框架开发一个新的宠物诊所程序。Antoine Rey的参考程序有非常好的、详细的说明; 我们将在本文中重复一些内容。

数据模型

  图中显示了数据库的ER图。应用程序代码中实际的对象域模型有点复杂并且包含一些继承,您可以在上面提到的演示文稿中找到UML模型。

存储层

  有四个Repository来处理主要实体:Owner(主人),Pet(宠物),Visit(拜访)和Vet(兽医)。这些Repository基于Spring JPA框架,由于Spring JPA的特性,这些Repository几乎不包含什么代码,但在Owner Repository里面有一个自定义的查询,用来获取宠物主人和他们各自的宠物。

UI界面

  该应用程序包含九个界面,我们可以通过这些界面查看数据,并进行一些编辑:宠物主人,宠物和拜访。本文不讨论它们,但需要指出的是,这些界面都是面向数据的应用程序里常见的CRUD表单。

附加功能

  除了简单的CRUD功能外,该应用程序还包括一些能展示Spring Framework之强大的功能:

  l 缓存(Caching) - 兽医列表已缓存,因此在刷新兽医列表时不会有DB读取。

  l 验证器(Validator) - 检查在创建有关宠物的新记录时是否填写了所有字段。

  l 格式化程序(Formatter) - 用于正确显示宠物类型。

  l 多语言支持(i18n) - 该应用程序提供英语和德语版本。

  l 事务管理 - 某些数据库查询是只读的。

感想

  我非常喜欢这张图片,因为它精准表达了我的看法:要有效地使用任何框架,都需要了解它内部的工作原理。例如,Spring Boot隐藏了很多东西,如果你知道一个简单的JPA接口初始化背后有多少个类,你会吓一跳。以下是关于Spring Boot Pet Clinic应用程序中“神奇”的部分:

  l @Caсheable - 除了这个注解之外没有任何缓存配置代码,但Spring Boot“知道”如何设置缓存实现(在我们的例子中将是EhCache)。

  l @Transactional -  Repository没有这个注解(它们的父类org.springframework.data.repository.Repository也没有),但所有save()方法都可以正常工作。

  虽然存在这么多隐晦的地方,但是由于Spring Boot的透明性和可预测性,Spring Boot还是一个非常流行的框架。Spring Boot还有非常详细的文档,而且是开源的,所以你可以深入研究它的原理和任何方法的实现,研究里面的逻辑。我想每个人都喜欢透明且易于管理的框架,因为它们可以使您的应用程序更加易于维护。

宠物诊所与CUBA

  现在,让我们看看使用CUBA平台的Pet Clinic,根据我们的Spring知识来审视它,并找出我们都能在哪些地方节约开发时间。

  在GitHub上可以找到Pet Clinic实现的源代码。CUBA平台有非常好的文档,其中可以找到几乎有关CUBA的所有东西(大多数情况都有代码片段或者代码实例,都能在GitHub上找到)。在本文中,我们将更多的引用CUBA文档,以避免重复描述。

CUBA应用程序架构

                         

  CUBA应用程序包含以下模块(请参见图表)。

  l Global - 包含可以在其他模块中使用的数据库实体、CUBA视图和服务接口。

  l Core - 所有与数据库一起工作并实现业务逻辑的服务实现都应该放在这里。需要注意的是,Core模块里面的类在其他模块中并不可用,这样设计的目的是,可以独立部署Core和GUI模块到不同的服务器,给系统提供了很好的可扩展性。而想要将Core模块的服务注入其他模块,您应该使用Global模块中声明的接口。

  l GUI,Web,Desktop,Portal - 这些模块包含负责UI事件处理的GUI相关类(控制器,监听器等)。您可以在此处创建自定义REST控制器,以补全CUBA为您生成开箱即用的REST API

  为了提高开发人员效率,CUBA提供了Studio - 一个漂亮小巧的图形化工具,用于创建和注册实体,并且可以为您更新所有配置,帮助创建服务的架子代码,并具有功能界面的可视化编辑器。

  因此,基于CUBA平台的应用程序包含两个(或更多)单独的模块:可以单独部署的Core和GUI,以及一个跨功能域的Global模块。下面我们详细介绍一下CUBA的GlobalCore模块及其内容。

Global模块

实体模型(Entity Model)

  任何使用过与JPA标准兼容的ORM框架或者Spring的开发人员都应该熟悉CUBA应用程序中的实体模型。同样是用@Table,@Entity等注释的类,并在persistence.xml文件中注册。

  在Pet Clinic应用程序的实体模型中,您可以重用Spring版本中的代码,但您需要记住以下几点:

  1. CUBA 为使用此平台创建的每个组件(Component)引入了一个“命名空间”,以防止不同组件之间的名称冲突。这就是为什么每个实体名称都有一个“petclinic$”前缀。

  2. 建议对实体使用@NamePattern注释,这样在界面可以得到实体更有意义命名。

  问题是,除了前缀和声明实体的“字符串式”表示之外,CUBA还提供了什么其他功能?其他功能包括:

  1. 支持ID生成功能的基类:从整数ID到UUID

  2. 一组有用(但可选)的接口:

    l Versioned - 支持实体版本。

    l SoftDelete - 支持实体的“软”删除,或者说是“逻辑”删除。

    l Updatable - 添加实体更新日志记录的字段。

    l Creatable - 添加实体创建日志记录的字段。

    您可以在文档中阅读有关这些接口的更多信息。

  3. CUBA Studio可以自动生成数据库创建和更新脚本。

  在应用程序开发期间,我只是从Spring版本复制了现有实体模型,并添加了上面提到的CUBA特定功能,从程序的参考版本中删除了BaseEntity类。

视图(Views)

  CUBA的“视图”概念可能令人困惑,但很容易解释。视图是一种声明性方法,用于指定应提取哪些数据(属性和嵌套实例/集合)。

  让我们假设您需要获取Owner及其宠物或兽医的属性 - 用于在同一个界面上显示依赖的子实体和父实体。在纯Spring实现的情况下,您需要定义JPA关联查询:

  @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") public Owner findById(@Param("id") int id);

  ...或定义正确的EAGER / LAZY FETCH类型以获取事务上下文中的实体的依赖集合。

  @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id")) private Set specialties;

  在CUBA版本中,您可以使用EntityManager和JPQL或视图和DataManager:

  1. 定义一个指定我们想要提取的内容的视图:

  

  2. 使用DataManager bean获取此数据

  

  您可以为不同的任务创建不同的视图,选择要获取的属性,是否获取集合以及定义对象树的深度。在Mario David的博客中有一篇关于视图的精彩文章

  在宠物诊所程序中,我们为不同的场景定义了六个视图。这些视图主要用于UI表单,其中之一是在服务中用来获取数据,上面显示了这个代码片段。

服务接口

  由于Global模块在CUBA的应用程序架构中属于交叉支撑的模块,因此您应该把服务的接口定义在Global模块中,以便能够通过使用Spring的注入在其他模块中使用服务。您需要做的就是在Web模块的“web-spring.xml”文件中注册服务。CUBA平台在应用程序模块中创建代理,采用Spring配置XML文件的方法进行完全透明的实体序列化和反序列化。此功能使我们可以从其他模块调用Core模块中实现的服务,即使在分布式部署的情况下也只需要很少的额外工作。

  因此,在使用CUBA进行实体模型开发方面,它与纯Spring完全相同,但是在插入数据后你不需要关心实体和关联实体的ID是怎么生成的,也不需要写额外的代码去实现实体版本化,软删除和实体变更日志。相比较于JPA关联查询,您还可以利用创建CUBA视图来节省一些时间。

Core模块

  在Global模块中声明的服务接口都在Core模块实现。一般来说,CUBA应用程序中的每个服务都使用@Service注解,但您可以使用所有Spring里面可用的注解来处理bean。不过,由于CUBA的特殊架构,存在一些限制:

  l 如果希望在Web模块中使用服务,则需要使用@Service做服务注解。

  l 建议为服务创建服务名,以避免不同加载项中的Bean命名冲突。

  除此之外,您的Core模块代码库是一个“纯粹的”基于Spring的后端应用程序。您可以使用与以前相同的方式从数据存储中获取数据,调用第三方Web service等。唯一重要的区别是与数据库的交互:

  EntityManager和DataManager

  CUBA平台使用自己的EntityManager,将其部分功能委托给实际的javax.persistence.EntityManager实例。CUBA的EntityManager主要提供低级别实体操作,不支持安全功能。所以在大多数情况下,还是推荐使用提供额外功能的DataManager

  1. 行级和属性级安全性支持。

  2. 可以采用CUBA的实体视图获取数据。

  3. 支持动态属性

  有关DataManager和EntityManager的更多信息,请参阅文档。值得注意的是,您不需要在GUI中直接使用这些bean,而可以使用数据源

  顺便谈谈PetClinic - 我(几乎)没有在Core模块中编写很多代码,因为没有特别复杂的业务逻辑。

CUBA实现的Spring宠物诊所的功能

  在上一节中,基于Spring的Pet Clinic应用程序中我们总结了一个额外功能列表,CUBA中也提供了相同的功能:

缓存(Caching)

  CUBA原生支持实体和查询缓存。这些缓存在文档中有详细描述,在使用时应首先考虑,因为它们支持分布式部署等所有平台功能。除此之外,您还可以使用Spring的@Cacheable启用缓存,并启用Spring 文档中所述的cach provider。

验证器(Validator)

  CUBA使用BeanValidation作为标准验证引擎。如果内置验证不够,您可以定义自定义验证代码。而且还可以通过描述定义Validator类来提供验证UI数据的选项在这里

格式化(Formatter)

  CUBA平台为GUI组件提供了几种格式化程序,但除标准格式化程序外,您还可以定义自己的格式化程序。对于默认实体命名的格式化,使用@NamePattern注释。

国际化(I18n)

  CUBA平台支持国际化的方式与其他java应用程序相同:使用message.properties文件,所以这里没什么新东西。

事务管理

  CUBA平台提供以下事务管理选项:

  l 熟悉的Spring @Transactional注释

  l 如果在某些复杂情况下需要细粒度的事务管理,那么可以采用CUBA的持久层接口。

  当我开发宠物诊所时,我只考虑过一次事:那就是在开发允许编辑Owner、Pet以及在同一屏幕上添加Visit的表单的时候。此时我需要了解何时提交事务并刷新界面然后统一的显示数据。

真的几个小时就完成了宠物诊所

  我能够在不到一天的时间内使用“标准”CUBA UI创建一个与Spring的Pet Clinic具有相同功能的应用程序。我不会说我是CUBA的专家(自我开始以来仅仅几周),但我有很长的时间在使用Spring。脑海中回想一下Spring程序的架构,然后我们看一下基于CUBA的架构:

  l 领域模型 - Global模块中的实体。创建实体模型是每个程序中都需要的过程。由于使用BaseIntegerIdEntity类,在ID生成方面可以节省时间。

  l 数据存储层 - 我不需要Repository,甚至连一个接口也不需要。我只是使用CUBA Studio 创建了一些视图。通过使用这个工具,我也不需要在配置文件中编写XML。

  l 服务层 - 在我们的应用程序中,我们只有两个服务用来导出JSON和XML格式的Vets,这些Vets是可缓存的。我根据文档将接口放到Global模块,将接口实现放到Core模块。除了阅读有关DataManager以熟悉其API之外,这基本只是一个“正常”的开发过程。

  l 控制器层 - CUBA Pet Clinic在Web模块中仅包含一个用于JSON和XML feed的自定义的REST控制器。这里没有特别要说的,只是一个采用了Spring注解的控制器。

  l 应用程序GUI - 使用CUBA Studio创建“标准”CRUD表单非常简单。

    在实现的过程中,我完全没有考虑如何将实体传递给Web UI,也没有考虑表单提交,也没有相关的控制器和Repository。CUBA为我提供了界面上一个比较好用的表格组件以及一个数据过滤组件,因此我不再需要解析查询语句,也不需要特意做分页。我花了大部分时间来实现界面的流程流转,以及调整页面样式。

  我的个人体验如下表所示:

 

CUBA中易于理解的部分

CUBA中需要阅读文档的部分

实体

实体建模

数据库创建脚本

标准基类

软删除等的附加功能

EntityManager

视图

DataManager

服务

Bean管理

事务管理

安全性和用户管理

持久层接口

控制器

自定义REST控制器

请求URL映射

服务方法发布

UI

标准表格

自定义UI

  显然Pet Clinic程序没有使用所有CUBA提供的特性,可以在站点上找到CUBA特性的完整列表,这里可以看到该平台可以怎样解决其他的一些常见任务。

  我的个人观点 - 如果您使用企业软件的标准界面,CUBA可以简化后端实施并做得很好。如果你需要一个精美的界面,那么CUBA也会帮你节省在后端开发上的时间。

这么多优点!有没有什么缺点?

  好吧,我想在本节中提到一些问题,这些问题的存在不影响使用CUBA,但是我发现这些问题会给第一次接触CUBA的人带来不好印象:

  l 在介绍部分,CUBA平台说自己带有IDE,能简化项目的创建和管理。但有时在Studio和IDE之间切换可能会有点烦人。CUBA平台现在正在重新开发它,因此Studio很快就会转变为IDEA的插件。

  l 在CUBA中,我们使用了比典型的Spring Boot应用程序更多的XML配置文件,因为平台提供的服务更多,各个模块之间需要一些XML来作为连接。

  l 应用程序的单个页面都没有“友好”的URL。您可以使用屏幕链接直接访问屏幕,但这也非常不直观。

  l 您必须处理CUBA的DataManager和EntityManager并学习它们的API而不是Spring JPA或JDBC(但如果需要,仍然可以使用它们)。

  l 使用关系数据库时,使用CUBA将达到开发的最佳效率。而如果要使用NoSQL,CUBA的表现和Spring一样,都有很多需要自己写代码的地方。

结论

  如果您有一个需要以关系型数据库作为数据储存,并且以数据为中心的应用程序的需求,您可能需要尝试使用CUBA平台作为基础来开发,因为:

  1. CUBA是透明的。源代码可用,您可以调试所有内容。

  2. CUBA很灵活(但是也有一定限度)。您可以继承并注入自己的bean而不采用标准CUBA bean,也可以发布自定义REST API并使用您自己的前端框架实现与用户交互。

  3. CUBA就是Spring。80%的后端代码都是纯Spring应用程序。

  4. 使用CUBA可以加快项目启动。在第一个实体和UI屏幕创建之后,应用程序就可以使用了。

  5. CUBA为您完成了很多日常枯燥的工作。

  因此,通过使用CUBA,您将在枯燥的工作上节省不少时间,以便真正投入地处理复杂的业务相关逻辑,也可以实现与其他系统的无缝集成。

链接

CUBA-Platform 官网 :

   https://www.cuba-platform.com

CUBA China 官网 :

  http://cuba-platform.cn

 

CUBA与Spring相比,有很大的不同吗?的更多相关文章

  1. 《Spring MVC学习指南》怎么样?答:书名具有很大的欺骗性

    2016年6月21日 最近,因为工作需要,我从网上买了一本<Spring MVC学习指南>,ISBN编号: 978-7-115-38639-7,定价:49.00元.此书是[美]Paul D ...

  2. CUBA 使用 Spring 查询接口

    原文链接:https://www.cuba-platform.com/blog/spring-query-interfaces-in-cuba 翻译:CUBA China CUBA-Platform ...

  3. Slave延迟很大的优化方法总结(MySQL优化)

    [http://www.cstor.cn/textdetail_9146.html] 一般而言,slave相对master延迟较大,其根本原因就是slave上的复制线程没办法真正做到并发.简单说,在m ...

  4. [MySQL优化案例]系列 — slave延迟很大优化方法

    备注:插图来自网络搜索,如果觉得不当还请及时告知 :) 一般而言,slave相对master延迟较大,其根本原因就是slave上的复制线程没办法真正做到并发.简单说,在master上是并发模式(以In ...

  5. slave延迟很大优化方法

    一般而言,slave相对master延迟较大,其根本原因就是slave上的复制线程没办法真正做到并发.简单说,在master上是并发模式(以InnoDB引擎为主)完成事务提交的,而在slave上,复制 ...

  6. [转帖]5G网速那么快,基站辐射会很大吗?

    5G网速那么快,基站辐射会很大吗? 鲜枣课堂 2019-04-20 21:19收藏55评论6社交通讯     题图来自东方IC,本文来自微信公众号:鲜枣课堂(ID:xzclasscom),作者:小枣君 ...

  7. 李洪强iOS经典面试题30-一个区分度很大的面试题

    李洪强iOS经典面试题30-一个区分度很大的面试题 考察一个面试者基础咋样,基本上问一个 @property 就够了: @property 后面可以有哪些修饰符? 线程安全的: atomic,nona ...

  8. elasticsearch的store属性跟_source字段——如果你的文档长度很长,存储了_source,从_source中获取field的代价很大,你可以显式的将某些field的store属性设置为yes,否则设置为no

    转自:http://kangrui.iteye.com/blog/2262860 众所周知_source字段存储的是索引的原始内容,那store属性的设置是为何呢?es为什么要把store的默认取值设 ...

  9. Java 学习之路让我帮助很大的书籍

    笔主目前从事Java工作已经5年,满打满算下来,从大二上学期接触 Java 到现在也快走过了 7 个年头.在学习 Java 过程中,网上的一些视频还有一些书籍对我帮助都很大.下面就我自己看过的一些书籍 ...

随机推荐

  1. 构建命令maven install 打包不是最新的代码

    问题: 之前一直用的是mvn install 命令来构建项目,但是最近发现最新的代码没有在war包中.之前看的说 mvn install 命令会执行之前的所有阶段,会被编译,测试,打包. 经查最后采用 ...

  2. 10-11Linux用户管理规则及用户管理函数

    用户管理: useradd, userdel, usermod, passwd, chsh, chfn, finger, id, chage 组管理: groupadd, groupdel, grou ...

  3. IEqualityComparer的使用

    当我们用Linq操作我们自定义的对像数组时,我们会发现有些方法直接使用的话根本不起作用,比如:Distinct.Except.Intersect等扩展方法. 对于我们自定义的对象的比较,我们必须实现I ...

  4. RFID

    RFID 物联网必不可少会接触到RFID,国内比较常见的RFID读卡驱动芯片有两款.一款是NXP的RC522这系列的,非常稳定,当然也相对较贵,另一款是复旦微电子的FM1702系列,国产的便宜没得说, ...

  5. H - Graphics(dfs)

    H - Graphics   Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submi ...

  6. Ajax请求的参数

    post请求和get请求存放参数位置 post请求和get请求存放参数位置是不同的: post方式参数存放在请求数据包的消息体中. get方式参数存放在请求数据包的请求行的URI字段中,以?开始以pa ...

  7. 洛谷P5280 [ZJOI2019]线段树(线段树)

    题面 传送门 题解 考场上就这么一道会做的其它连暴力都没打--活该爆炸-- 首先我们得看出问题的本质:有\(m\)个操作,总共\(2^m\)种情况分别对应每个操作是否执行,求这\(2^m\)棵线段树上 ...

  8. Maven的Mirror和Repository 的详细讲解

    1 Repository(仓库) 1.1 Maven仓库主要有2种: remote repository:相当于公共的仓库,大家都能访问到,一般可以用URL的形式访问 local repository ...

  9. 【vue】——vue.js 获取当前 自定义属性值

    假设有一个标签h5, 我们给它添加了一个自定义属性值,(item.id是从动态添加的) 点击h5 标签,如何才能获取当前对应的自定义属性值呢? 想当然的我最开始这样写: <h5 class=&q ...

  10. webpack 中文文档

    webpack 最强最详细中文文档 https://doc.webpack-china.org/guides/getting-started/#- webpack多页应用架构系列 http://web ...