根本原因

开发人员通常不喜欢改变他们编码的习惯。当我刚才是接触 CUBA 的时候,发现不需要学很多新的东西,创建应用程序的过程也是非常顺利的。但是其中有一样是需要重新学习的,那就是如何使用数据。

在Spring框架中,有好几个库可以用来处理数据,其中最流行的一个就是 spring-data-jpa,使用这个库可以使开发人员在很多情况下避免编写SQL或者JPQL。只需要创建一个接口类,然后在接口中创建 带有特殊名称 的方法,Spring会自动帮你创建和执行查询语句。

比如,这里有一个接口,其中有个方法是统计有多少客户是同一个姓的:

interface CustomerRepository extends CrudRepository<Customer, Long> {long countByLastName(String lastName);
}

可以直接将这个接口注入到service中,然后就可以在需要的地方调用这个方法了(注意,不需要写实现类)。

CUBA提供了很多开箱即用的数据操控方法,比如加载实体的部分属性以及成熟的数据安全子系统 - 可以限制数据访问权限至实体属性和表数据的行级别。并且这些所有的功能都带有API,但是跟大家都知道的Spring Data或者JPA/Hibernate的略有不同。

所以,为什么在CUBA中没有上面说的查询接口?有没有可能添加呢?

CUBA中使用数据的方式

CUBA的API中有三个主要的类用来处理数据:DataStore,EntityManager 和 DataManager。

DataStore 的抽象是提供处理持久化存储的API,比如RDBMS,文件系统或者云存储。可以通过DataStore执行基本的数据操作,但是,不推荐直接使用DataStore,除非需要开发自定义的持久化存储或者需要对底层存储进行非常特殊的访问。

EntityManager 很大程度上只是JPA EntityManager 的拷贝,但是有额外的方法用来处理 CUBA视图、软删除以及 CUBA 查询语句。作为CUBA开发人员,很少在日常工作中使用这个类,除非需要克服CUBA的安全限制。

下一个要说的,DataManager,是在CUBA中处理数据主要使用的类。此类提供了处理数据的API并且支持到属性和行级别的 CUBA安全模型 。当查询数据的时候,DataManager会隐式的修改查询语句。比如,在关系型数据库中,它会更改“select”语句,排除那些受限的属性,然后自动添加“where”语句来筛选那些当前用户不能看到的数据行。这种安全感知的行为是很有帮助的,开发人员不需要死记在查询语句中需要添加哪些关于安全方面的条件。

这里有个CUBA类交互的图,展示使用DataManager从RDBMS中获取数据的过程。

使用DataManager可以相对容易的查询实体(或者使用CUBA视图查询实体层级结构)。最简单的查询是这样:

dataManager.load(Customer.class).list()

DataManager会自己过滤掉“软删除”的记录、受限制访问的实体属性或实体,也会自己创建数据库事务。

但是如果需要执行带有复杂“where”条件的查询语句,就需要写JPQL了。

看看最开头那个例子,如果需要按姓统计客户人数,在CUBA中需要写这样的:

public Long countByLastName(String lastName){return dataManager.loadValue("select count(c) from sample$Customer c where c.lastName = :lastName", Long.class).parameter("lastName", lastName).one();
}public Long countByLastName(String lastName){LoadContext<Person> loadContext = LoadContext.create(Person.class);loadContext.setQueryString("select c from sample$Customer c where c.lastName = :lastName").setParameter("lastName", lastName);return dataManager.getCount(loadContext);
}

这里可以看到,需要将JPQL语句丢给DataManager去执行。在CUBA API里,JPQL需要用字符串来定义(目前还不支持Criteria API)。JPQL有很好的可读性,也能清晰的定义一个查询语句,但是如果出问题,可能不是很好调试。另外,JPQL字符串不像Criteria API那样能在构建编译时进行验证,或者在Spring上下文初始化的时候验证。

比较一下Spring Data JPA 的接口:

interface CustomerRepository extends CrudRepository<Customer, Long> {long countByLastName(String lastName);
}

这个接口只有三分之一的代码量而且不包含任何显式的字符串。此外,countByLastName 方法会在部署阶段验证。如果方法名敲错了,比如,敲成 countByLastNome,则会有异常抛出:

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property LastNome found for type Customer!

由于CUBA也是基于Spirng框架构建的,所以可以将Spring-data-jpa添加为CUBA项目的依赖库然后使用这个功能。唯一的问题,Spring的查询接口底层使用JPA的EntityManager,所以查询语句不会被CUBA的EntityManager或者DataManager处理。因此,需要找到合适的方法在CUBA中添加查询接口 - 需要自定义,所有调用EntityManager的地方都需要用CUBA的DataManager相应的方法替换,并且添加对CUBA视图的支持。

也有人会说,使用Spring的方案不如CUBA的方案可控,因为不能控制生成查询语句的过程。这是在便利性和抽象化级别之间的平衡问题,需要开发者决定到底使用那个方案。但是有个额外的处理数据的简单方法总是没坏处,尽管这也不是唯一的方法。

如果需要更多的控制,Spring里也有方法为接口指定查询语句,所以这个方法也需要添加到CUBA。

实施

查询接口使用 spring-data-commons 实现,构建为CUBA应用程序组件。这个库包含实现自定义查询接口的类,比如,Spring的spring-data-mongodb 库就是基于这个实现的。Spring-data-commons利用代理技术来为声明式查询接口创建正确的实现。

在CUBA的上下文初始化期间,查询接口的引用都会被生成的代理bean隐式替换。当开发人员调用接口方法时,相应的代理会进行拦截。然后代理根据方法名称生成JPQL查询,替换参数值,并交给DataManager执行。下图展示了模块关键组件之间的简单交互过程。

在CUBA中使用查询接口

需要在项目的构建文件中添加新的应用程序组件才能使用CUBA的查询接口:

appComponent("com.haulmont.addons.cuba.jpa.repositories:cuba-jpa-repositories-global:0.1-SNAPSHOT")

XML配置文件也需要修改启用查询接口:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:repositories="http://www.cuba-platform.org/schema/data/jpa"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.cuba-platform.org/schema/data/jpa      http://www.cuba-platform.org/schema/data/jpa/cuba-repositories.xsd"><!-- Annotation-based beans --><context:component-scan base-package="com.company.sample"/><repositories:repositories base-package="com.company.sample.core.repositories"/></beans:beans>

如果习惯使用注解而不是创建XML配置文件,可以用下面的方法启用查询接口:

@Configuration
@EnableCubaRepositories
public class AppConfig {//Configuration here
}

启用查询接口后,可以在应用程序中创建并使用。下面是示例:

public interface CustomerRepository extends CubaJpaRepository<Customer, UUID> {long countByLastName(String lastName);List<Customer> findByNameIsIn(List<String> names);@CubaView("_minimal")@JpqlQuery("select c from sample$Customer c where c.name like concat(:name, '%')")List<Customer> findByNameStartingWith(String name);
}

可以在接口方法上使用 @CubaView 和 @JpqlQuery 注解。第一个注解定义需要使用的视图(如果没有使用这个注解,默认使用“_local”视图)。第二个注解是用来设置JPQL的,用在查询语句不能通过方法名表示的时候。

查询接口的应用程序组件是绑定到CUBA的“global”模块,所以可以在“core”和“web”模块定义和使用查询接口,只是别忘了在相应的配置文件中启用接口。接口使用的示例:

@Service(CustomerService.NAME)
public class CustomerServiceBean implements PersonService {@Injectprivate CustomerRepository customerRepository;@Overridepublic List<Date> getCustomersBirthDatesByLastName(String name) {return customerRepository.findByNameStartingWith(name).stream().map(Customer::getBirthDate).collect(Collectors.toList());}
}

结论

CUBA很灵活。如果觉得需要为应用程序添加新的功能,又不想等CUBA的新版本,很容易在不修改CUBA核心的情况下实施并添加到项目中。通过为CUBA添加查询接口,我们希望能帮助开发人员更加有效的工作,更快的交付可靠的代码。这个库的第一个版本可以在GitHub找到,目前支持CUBA 6.10和更高版本。

CUBA使用Spring查询接口相关推荐

  1. CUBA 使用 Spring 查询接口

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

  2. boot spring 接口接收数据_在 Spring Boot 中使用 Dataway 配置数据查询接口

    Dataway介绍 Dataway 是基于 DataQL 服务聚合能力,为应用提供的一个接口配置工具.使得使用者无需开发任何代码就配置一个满足需求的接口. 整个接口配置.测试.冒烟.发布.一站式都通过 ...

  3. 换一种方式编写 Spring MVC 接口

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 通常我们编写 Spring MVC 接口的范 ...

  4. 利用MyBatis的动态SQL特性抽象统一SQL查询接口

    1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...

  5. 护网必备技能:Spring Boot 接口数据加解密 功能实现

    护网必备技能:Spring Boot 接口数据加解密 功能实现 文章目录 护网必备技能:Spring Boot 接口数据加解密 功能实现 1. 尽量少改动,不影响之前的业务逻辑: 2. 考虑到时间紧迫 ...

  6. SpringBoot调用第三方IP查询接口(Https)

    一:需求简介. 1.1项目中天添加IP归属地查询功能,前后端分离.后端返回给前端json字符串.      1.2使用阿里云免费的IP归属地查询接口.官网一下不太好找.下面图解演示一下,尽量节省时间吧 ...

  7. 数据查询接口Springboot

    需求: 1.使用微博数据提供数据查询接口,通过微博编号查询微博,将热门数据缓存到redis中 基于Spring的网页端口查询,MVC分层构架 数据库数据 1001    [#蛇头将孩子扔过美墨边境墙# ...

  8. mysql2013年8月怎么打出来_2020年8月31日,上周完成了一个查询接口来检查mysql的数据,速度很慢,20200831,从,MySQL,中查,贼...

    2020-08-31 上周完成一个查询接口,从MySQL中查数据,速度贼慢, 原因是数据5000万+,所以真正接触优化的机会来了,所以决定好好研究一下,做一个记录. 事情是这样的,mysql表中只有两 ...

  9. 怎样调用php的足球联赛接口,足球赛事查询接口调用文档

    足球赛事查询接口,目前支持 英超,西甲,德甲,意甲,法甲,中超等赛事 接口平台:api 接口地址:http://op.juhe.cn/onebox/football/combat 支持格式:json/ ...

  10. 快递物流查询接口介绍

    快递查询接口是指快递查询网对外开放的应用程序接口,开发人员能够通过调用该接口与快递查询网进行交互,并基于该接口开发自己的快递查询应用程序.目前比较常用的接口有快递鸟.快递100.快递网等. 应用场景 ...

最新文章

  1. bzoj1503 郁闷的出纳员(平衡树,思维)
  2. 0. 正规鞅的混沌及可料表示
  3. 在servlet中设置的字符编码集为什么还会出现乱码(亲测)
  4. android 重置画布,android-自定义视图:重按视图画布
  5. linux内核2018,CVE-2018-1000001 linux kernel
  6. Spring Boot 5:应用程序启动时初始化资源
  7. java、oracle对CLOB处理
  8. java.util.Scanner简单应用
  9. 进程间通信——Queue
  10. 详解CSS中:nth-child的用法
  11. 获取最顶层的ViewController top ViewController swift
  12. esp8266教程:定时器之原理基础
  13. git 的详细使用 操作暂存区
  14. VUE中fetch结合支付宝API验证银行卡号
  15. stata 求输出相关系数矩阵命令_Stata|①Get a foot in the door
  16. 最新版大学英语六级词汇打印版
  17. axios接口报错-参数类型错误解决
  18. Tableau图例:利用单独图例实现条件格式
  19. 深富策略:降准落地 年初大概率有行情
  20. mysql中文排序,自定义排序(一科,二科,三科,四科等等)

热门文章

  1. 苹果宣布前CEO史蒂夫·乔布斯逝世
  2. Github代码复现-IVIX中国波指计算
  3. 我的生活所感悟出的杂句
  4. 浅析SEO搜索引擎优化
  5. b365老掉线 h3c路由器_H3C路由器频繁断线的原因及解决方法
  6. C# WPF如何设置oxyplot的折线图禁止鼠标滚轮缩放
  7. Xcode 8.0 Beta发布,详解Swift语言的重大变化
  8. S-LIME阅读笔记(有实验代码)
  9. 台式机主板常见接口资料
  10. Android 字体引入