上一篇文章介绍了Spring Data REST的功能及特征,以及演示了如何在项目中引入Spring Data REST并简单地启动演示了Spring Data REST项目。在本文中,我们将深入了解Spring Data REST的特性,以此来满足我们日常api开发工作的要求。

如果仅仅是上一篇文章中对Spring Data REST的使用,那无法做到在日常开发中使用Spring Data REST,所以在上一篇文章中,我们列出了日常api开发中的一些必要功能:

需要满足的一些要求:

1.针对字段级别,方法级别,类级别进行限制(禁止某些字段,方法,接口的对外映射)。

2.对数据增删改查的限制(禁止某些请求方法的访问)。

3.能个性化定义请求的路径。

4.对所传参数进行值校验。

5.响应统一处理。

6.异常处理。

7.数据处理的切面。

➡️本文,将演示这些要求中的前三个要求。


针对接口级别,方法级别,字段级别进行访问限制

所谓的访问限制,这里我们的目的是指定某些资源不对外暴露,Spring Data REST使用注解来实现各级别的访问限制。

接口级别的访问限制:

  1. @RepositoryRestResource(exported = false)
  2. public interface TenantRepository extends CrudRepository<Tenant, Long> {
  3. Page<Tenant> findAllByNameContaining(String name, Pageable page);
  4. Page<Tenant> findAllByIdCardContaining(String idCard, Pageable page);
  5. Tenant findFirstByMobile(String mobile);
  6. Tenant findFirstByIdCard(String idCard);
  7. }

Spring Data REST中我们在接口级别增加@RepositoryRestResource(exported = false)来实现接口及接口中的所有方法不对外暴露,从而限制访问。

方法级别的访问限制:

  1. public interface TenantRepository extends CrudRepository<Tenant, Long> {
  2. Page<Tenant> findAllByNameContaining(String name, Pageable page);
  3. Page<Tenant> findAllByIdCardContaining(String idCard, Pageable page);
  4. Tenant findFirstByMobile(String mobile);
  5. @RestResource(exported = false)
  6. Tenant findFirstByIdCard(String idCard);
  7. }

上述代码中,我们使用@RestResource(exported = false)注解在指定的方法上,从而实现该方法不对外暴露。

字段级别的访问限制

  1. @Entity
  2. @Data
  3. @Accessors(chain = true)
  4. public class Tenant {
  5. @Id
  6. @GeneratedValue
  7. private Long id;
  8. private String name;
  9. //隐私信息不需要暴露
  10. @JsonIgnore
  11. private String idCard;
  12. private String mobile;
  13. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  14. private LocalDateTime rentDateTime;
  15. @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
  16. private House house;
  17. public Tenant() {
  18. }
  19. public Tenant(String name, String idCard, String mobile, LocalDateTime rentDateTime, House hous) {
  20. this.name = name;
  21. this.idCard = idCard;
  22. this.mobile = mobile;
  23. this.rentDateTime = rentDateTime;
  24. this.house = hous;
  25. }
  26. }

在上述代码中,我们在idCard字段上增加了@JsonIgnore注解,从而实现该字段不对外暴露。

如上图,我们在HAL Browser中看到,输出的租客数据中不再包含idCard字段。

使用Projections和Excerpts来实现访问限制

  1. @Projection(name = "mobileAndName", types = {Tenant.class})
  2. public interface TenantProjection {
  3. String getName();
  4. String getMobile();
  5. }

如上,首先我们声明一个投影(Projection),在上面的投影中,我们使用指定字段的get方法来对外暴露需要暴露的字段name,mobile。

此时,我们访问HAL Browser

可以看到Spring Data REST此时提供了一个投影的链接。

此时我们查询指定租客类的投影http://localhost:8080/tenants/1?projection=mobileAndName

  1. {
  2. "name": "王一",
  3. "mobile": "186****3331",
  4. "_links": {
  5. "self": {
  6. "href": "http://localhost:8080/tenants/1"
  7. },
  8. "tenant": {
  9. "href": "http://localhost:8080/tenants/1{?projection}",
  10. "templated": true
  11. }
  12. }
  13. }

可以看到只显示了我们投影的字段。

⚠️:我们声明的投影接口需要和数据类在同一个包中。

⚠️:否则,我们需要增加配置类,来告诉Spring Data REST投影接口的位置,如下图

  1. @Component
  2. public class SpringDataRestCustomization implements RepositoryRestConfigurer {
  3. @Override
  4. public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
  5. config.getProjectionConfiguration().addProjection(TenantProjection.class);
  6. }

数据内联

有时候,我们可能需要单独对House类进行数据操作,所以我们会声明一个HouseRepository

  1. public interface HouseRepository extends CrudRepository<House, Long> {
  2. }

此时,我们访问某一租客数据(http://localhost:8080/tenants/1)时,

此时,house的数据就不会内联在Tenant里面。但是我们并不想要这种效果,我们希望house还是内联在Tenant中的。我们可以使用Projection来解决此问题。

  1. @Projection(name = "NameAndHouse", types = {Tenant.class})
  2. public interface OnlyNameProjection {
  3. String getName();
  4. House getHouse();
  5. }

如上,我们声明了一个NameAndHouse投影。然后我们使用@RepositoryRestResource(excerptProjection = OnlyNameProjection.class)注解放在TenantRepository接口上。

  1. @RepositoryRestResource(excerptProjection = OnlyNameProjection.class)
  2. public interface TenantRepository extends CrudRepository<Tenant, Long> {
  3. ...
  4. }

此时,我们访问NameAndHouse投影(http://localhost:8080/tenants/1?projection=NameAndHouse)

  1. {
  2. "name": "王一",
  3. "house": {
  4. "houseNumber": "1101",
  5. "owner": "张三",
  6. "idCard": "330521******1"
  7. },
  8. "_links": {
  9. "self": {
  10. "href": "http://localhost:8080/tenants/1"
  11. },
  12. "tenant": {
  13. "href": "http://localhost:8080/tenants/1{?projection}",
  14. "templated": true
  15. },
  16. "house": {
  17. "href": "http://localhost:8080/tenants/1/house"
  18. }
  19. }
  20. }

可以看到,House已经被内联进Tenant中。


对数据增删改查的限制

Spring Data REST提供了对资源请求的限制,比如对特定请求方法的限制,对特定资源访问的限制。

Repository对外暴露限制

有时候我们希望,我们在Repository中定义的某些数据操作方法不对外暴露。Spring Data REST提供了了四个级别的资源限制级别:

  • ALL:公开所有Spring Data存储库,无论其Java可见性或注释配置如何。
  • DEFAULT:公开公共Spring数据存储库或使用@RepositoryRestResource显式注释的存储库,并且其导出属性未设置为false。
  • VISIBILITY:无论注释配置如何,仅公开公共Spring Data存储库。
  • ANNOTATED:仅公开使用@RepositoryRestResource显式注释的Spring Data存储库,并且其导出属性未设置为false。

如下代码实现了ANNOTATED级别的限制:

  1. @Component
  2. public class SpringDataRestCustomization implements RepositoryRestConfigurer {
  3. @Override
  4. public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
  5. }
  6. }

增删改查限制

在RESTful中定义:

GET(GET方法返回单个实体)

PUT(PUT方法用提供的请求主体替换目标资源的状态(存在则修改,不存在则新建)。)

PATCH(PATCH方法类似于PUT方法,但是部分更新资源状态。)

DELETE(删除信息)

所以所谓的对增删改查的限制实际上就是对请求方法的限制。

如下,我们对Tenant类进行了两个操作

  1. PUT操作禁止新增,但可以修改。
  2. DELETE限制,也就是限制了删除操作。
  1. @Component
  2. public class SpringDataRestCustomization implements RepositoryRestConfigurer {
  3. @Override
  4. public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
  5. ExposureConfiguration exposureConfiguration = config.getExposureConfiguration();
  6. exposureConfiguration.forDomainType(Tenant.class)
  7. .disablePutForCreation()
  8. .withItemExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.DELETE));
  9. }
  10. }

如下为请求测试:

1.禁止DELETE请求

2.禁止PUT的新增操作

3.允许PUT的修改操作


个性化定义请求的路径

Spring Data REST提供了个性化请求路径的功能

自定义项目资源URI

默认情况下,项目资源的URI包含用于集合资源的路径段,并附加了数据库标识符。这样一来,您就可以使用存储库的findOne(…)方法来查找实体实例。从Spring Data REST 2.5开始,可以通过使用RepositoryRestConfiguration上的配置API(在Java 8上首选)或通过将EntityLookup的实现注册为应用程序中的Spring bean来自定义此属性。 Spring Data REST会选择它们并根据其实现来调整URI生成。

  1. @Component
  2. public class SpringDataRestCustomization implements RepositoryRestConfigurer {
  3. @Override
  4. public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
  5. config.withEntityLookup()
  6. .forRepository(TenantRepository.class)
  7. .withIdMapping(Tenant::getMobile)
  8. .withLookup(TenantRepository::findFirstByMobile);
  9. }
  10. }

如上,我们个性化地指定了Tenant的标识符为mobile字段,此时我们可以通过HAL Browser来看到路径中的标识符变成了mobile字段。

配置REST URL路径

我们使用@RepositoryRestResource@RestResource注解直接指定资源在路径中的名字。

如下:

  1. @RepositoryRestResource(path = "tenantPath")
  2. public interface TenantRepository extends CrudRepository<Tenant, Long> {
  3. @RestResource(path = "mobile")
  4. Tenant findFirstByMobile(String mobile);
  5. }

此时我们通过HAL Browser访问此资源:

可以看到,被我们注解的findFirstByMobile对应的资源路径已经被定制化。

另外我们看到"links"中的属性名还是findFirstByMobile,我们可以通过@RestResource(path = "mobile",rel = "mobile")来个性化指定其名字,例如此注解中,我们指定了"links"中的findFirstByMobile属性名为mobile。


总结

本文列出了接口开发常用的7个功能,并且演示如何实现针对接口级别,方法级别,字段级别进行访问限制,我们使用@RepositoryRestResource@RestResource@JsonIgnore分别实现接口,方法,字段级别的访问限制,并且我们利用了Projections和Excerpts来实现自定义数据格式。我们还是实现了对数据增删改查的限制,我们通过RepositoryDetectionStrategy的四个级别来控制数据接口的对外暴露,使用ExposureConfiguration来限制某些资源对特定请求方式的限制。最后我们使用RepositoryRestConfiguration以及@RepositoryRestResource@RestResource注解实现了个性化定义请求的路径

本文代码示例:https://gitee.com/jeker8chen/spring-data-rest-in-practice.git


关注笔者公众号,推送各类原创/优质技术文章 ⬇️

Spring Data REST不完全指南(二)的更多相关文章

  1. ElasticSearch(十二):Spring Data ElasticSearch 的使用(二)

    在前一篇博文中,创建了Spring Data Elasticsearch工程,并且进行了简单的测试,此处对Spring Data Elasticsearch进行增删改查的操作. 1.增加 在之前工程的 ...

  2. 一步步学习 Spring Data 系列之JPA(二)

    继上一篇文章对Spring Data JPA更深( )一步剖析. 上一篇只是简单的介绍了Spring Data JPA的简单使用,而往往在项目中这一点功能并不能满足我们的需求.这是当然的,在业务中查询 ...

  3. Spring Data REST不完全指南(一)

    简介 Spring Data REST是Spring Data项目的一部分,可轻松在Spring Data存储库上构建超媒体驱动的REST Web服务. Spring Data REST 构建在 Sp ...

  4. Spring Data REST不完全指南(三)

    上一篇我们介绍了使用Spring Data REST时的一些高级特性,以及使用代码演示了如何使用这些高级的特性.本文将继续讲解前面我们列出来的七个高级特性中的后四个.至此,这些特性能满足我们大部分的接 ...

  5. Spring Data 开发环境搭建(二)

    首先咱们先创建一个maven工程 在pom.xml加入以下 依赖 <!--Mysql 驱动包--> <dependency> <groupId>mysql</ ...

  6. Spring Data Elasticsearch 用户指南

    https://www.jianshu.com/p/27e1d583aafb 翻译自官方文档英文版,有删减. BioMed Central Development Team version 2.1.3 ...

  7. Spring Data(二)查询

    Spring Data(二)查询 接着上一篇,我们继续讲解Spring Data查询的策略. 查询的生成 查询的构建机制对于Spring Data的基础是非常有用的.构建的机制将截断前缀find-By ...

  8. Spring Data MongoDB 五:进阶文档查询(分页、Morphia)(二)

    Spring Data MongoDB 三:基本文档查询(Query.BasicQuery)(一) 学习MongoDB 六: MongoDB查询(游标操作.游标信息)(三) 一.简单介绍 Spring ...

  9. Spring Boot入门系列(二十六)超级简单!Spring Data JPA 的使用!

    之前介绍了Mybatis数据库ORM框架,也介绍了使用Spring Boot 的jdbcTemplate 操作数据库.其实Spring Boot 还有一个非常实用的数据操作框架:Spring Data ...

随机推荐

  1. 切比雪夫低副瓣阵列设计 MATLAB

    相控阵天线中,直线阵列作为重要的一种,有着极为广泛的应用.切比雪夫低副瓣阵列设计是一种典型的设计方法. 切比雪夫方法主要是实现低副瓣.窄波束: 其产生的核心如下: 我的理解:因为能量守恒,所有副瓣都一 ...

  2. 使用scrapy-selenium, chrome-headless抓取动态网页

        在使用scrapy抓取网页时, 如果遇到使用js动态渲染的页面, 将无法提取到在浏览器中看到的内容. 针对这个问题scrapy官方给出的方案是scrapy-selenium, 这是一个把sel ...

  3. centos7单机安装kafka

    基础要求操作系统:CentOS 7x 64位 kafka版本:kafka_2.11-0.8.2.1 #安装使用的jdk以及kafka的包我放到百度云了,需要自取. # 链接:https://pan.b ...

  4. kaggle入门——泰坦尼克之灾

    目录 引言 数据认识 总结 特征处理 建模预测 logistic分类模型 随机森林 SVM xgboost 模型验证 交叉验证 学习曲线 高偏差: 高方差 模型融合 总结 后记 引言 一直久闻kagg ...

  5. FME中按照ID值过滤块参照中的多个要素

  6. 《自拍教程52》Python_adb运行Shell脚本

    Android作为一款Linux终端,肯定是支持.sh后缀的Shell脚本的运行的, 有时候测试环境准备或者长时间截取复杂的日志等,开发会给到一些Shell脚本. Shell脚本的执行的优势: 快捷高 ...

  7. Jmeter 注册用户获取登录token值

    1. 打开jemeter,新建一个测试计划,>线程组 >新建一个 登录的 Http 请求. 2.填上相应的值 3.新建一个消息头管理器> content-Type  applicat ...

  8. IC设计流程概述

    芯片设计分为前端设计和后端设计,前端设计(也称逻辑设计)和后端设计(也称物理设计)并没有统一严格的界限,涉及到与工艺有关的设计就是后端设计. Front-end design flow 1. 规格制定 ...

  9. Chart控件的使用

    1.开启滚动条(ScaleView.Size除以Interval ,大概是中间出现纵线的数量,一般动ScaleView.Size) chart1.ChartAreas[0].CursorX.AutoS ...

  10. 使用Markdown编辑总结

    Markdown是轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档. Markdown可以导出HTML .Word.图像.PDF.Epub 等多种格式的文档. 后缀为.md或者.markdo ...