上一篇文章介绍了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使用注解来实现各级别的访问限制。

接口级别的访问限制:

@RepositoryRestResource(exported = false)
public interface TenantRepository extends CrudRepository<Tenant, Long> {
Page<Tenant> findAllByNameContaining(String name, Pageable page); Page<Tenant> findAllByIdCardContaining(String idCard, Pageable page); Tenant findFirstByMobile(String mobile); Tenant findFirstByIdCard(String idCard);
}

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

方法级别的访问限制:

public interface TenantRepository extends CrudRepository<Tenant, Long> {
Page<Tenant> findAllByNameContaining(String name, Pageable page); Page<Tenant> findAllByIdCardContaining(String idCard, Pageable page); Tenant findFirstByMobile(String mobile); @RestResource(exported = false)
Tenant findFirstByIdCard(String idCard);
}

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

字段级别的访问限制

@Entity
@Data
@Accessors(chain = true)
public class Tenant {
@Id
@GeneratedValue
private Long id; private String name; //隐私信息不需要暴露
@JsonIgnore
private String idCard; private String mobile; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime rentDateTime; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
private House house; public Tenant() {
} public Tenant(String name, String idCard, String mobile, LocalDateTime rentDateTime, House hous) {
this.name = name;
this.idCard = idCard;
this.mobile = mobile;
this.rentDateTime = rentDateTime;
this.house = hous;
}
}

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

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

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

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

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

此时,我们访问HAL Browser

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

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

{
"name": "王一",
"mobile": "186****3331",
"_links": {
"self": {
"href": "http://localhost:8080/tenants/1"
},
"tenant": {
"href": "http://localhost:8080/tenants/1{?projection}",
"templated": true
}
}
}

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

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

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

@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.getProjectionConfiguration().addProjection(TenantProjection.class);
}

数据内联

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

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

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

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

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

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

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

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

{
"name": "王一",
"house": {
"houseNumber": "1101",
"owner": "张三",
"idCard": "330521******1"
},
"_links": {
"self": {
"href": "http://localhost:8080/tenants/1"
},
"tenant": {
"href": "http://localhost:8080/tenants/1{?projection}",
"templated": true
},
"house": {
"href": "http://localhost:8080/tenants/1/house"
}
}
}

可以看到,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级别的限制:

@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
}
}

增删改查限制

在RESTful中定义:

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

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

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

DELETE(删除信息)

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

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

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

如下为请求测试:

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生成。

@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withEntityLookup()
.forRepository(TenantRepository.class)
.withIdMapping(Tenant::getMobile)
.withLookup(TenantRepository::findFirstByMobile);
}
}

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

配置REST URL路径

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

如下:

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

此时我们通过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. 基础的linux命令(一)

    我练习使用的 Linux 系统是 CentOS 7 它是通过把 RHEL 系统重新编译并发布给用户免费使用的 Linux 系统. 首先你需要一台Linux虚拟机,如果没有,也没关系,点这里 一.命令格 ...

  2. Python_matplotlib画图时图例说明(legend)放到图像外侧

    https://blog.csdn.net/Poul_henry/article/details/82533569 import matplotlib.pyplot as plt import num ...

  3. 洛谷5026 Lycanthropy 差分套差分

    题目链接 https://www.luogu.com.cn/problem/P5026 题意 在一个长度为m的序列中,每次给一个下标x,和一个权值v,然后从x-v*3到x-v*2单调递增,从x-v*2 ...

  4. 模块 subprocess 交互shell

    subprocess 交互shell 执行shell命令, 与操作系统交互 三种执行命令的方法 subprocess.run(*popenargs, input=None, timeout=None, ...

  5. 2019NYIST计科第四次周赛

    YZJ的牛肉干 Description 今年的ACM暑期集训队一共有18人,分为6支队伍.其中有一个叫做 YZJ的大佬,在共同的集训生活中,大家建立了深厚的友谊, YZJ准备做点什么来纪念这段激情燃烧 ...

  6. STL(六)——map、multimap

    STL--map.multimap 文章目录 STL--map.multimap 关联容器与map的介绍 map与set的异同 map与multimap的异同 map类对象的构造 map添加元素 ma ...

  7. 并发——详细介绍CAS机制

    一.前言   今天花了点时间了解了一下JDK1.8中ConcurrentHashMap的实现,发现它实现的主要思想就是依赖于CAS机制.CAS机制是并发中比较重要的一个概念,所以今天这篇博客就来详细介 ...

  8. 各种版本docker下载的中国开源地址

    最近在群里听说Docker很火,于是自己抱着试试的态度,想玩玩,可是遇到了一些问题,记录下来,方便备忘,也方便防止大家被坑. 我的虚拟机装的是centos 6.5,百度了好多教程,丫的,都不解释,就一 ...

  9. 浅谈Python导入外部文件

    import 和 from ... import * 有什么区别? 例如我写了个模块hello.py def print_func(args): print("Hello " + ...

  10. 理解 Hanoi 汉诺塔非递归算法

    汉诺塔介绍: 汉诺塔(港台:河内塔)是根据一个传说形成的数学问题: 最早发明这个问题的人是法国数学家爱德华·卢卡斯. 传说越南河内某间寺院有三根银棒,上串 64 个金盘.寺院里的僧侣依照一个古老的预言 ...