Spring Data REST不完全指南(三)
上一篇我们介绍了使用Spring Data REST时的一些高级特性,以及使用代码演示了如何使用这些高级的特性。本文将继续讲解前面我们列出来的七个高级特性中的后四个。至此,这些特性能满足我们大部分的接口开发场景。
需要满足的一些要求:
1.针对字段级别,方法级别,类级别进行限制(禁止某些字段,方法,接口的对外映射)。
2.对数据增删改查的限制(禁止某些请求方法的访问)。
3.能个性化定义请求的路径。
4.对所传参数进行值校验。
5.响应统一处理。
6.异常处理。
7.数据处理的切面。
➡️本文,将演示7个要求中的其余四个要求。
对所传参数进行值校验
对于值校验,Spring 提供了Validator接口,Spring Data REST提供了使用Validator来进行值校验的功能。
首先我们通过实现Validator接口来创建一个校验器,然后在实现RepositoryRestConfigurer或Spring Data REST的RepositoryRestConfigurerAdapter的子类的配置中,重写configureValidatingRepositoryEventListener方法,并在ValidatingRepositoryEventListener上调用addValidator,传递要触发此校验器的事件和校验器的实例。以下示例显示了如何执行此操作:
public class SaveTenantValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Tenant.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Tenant tenant = (Tenant) target;
if (StringUtils.isEmpty(tenant.getMobile())) {
errors.rejectValue("mobile", "1001", "手机号不能为空");
}
}
}
如上,我们声明了一个Validator类,作为对手机号校验的Validator。接着我们通过以下代码注册我们的校验器。
@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeCreate", new SaveTenantValidator());
}
}
validatingListener.addValidator("beforeCreate", new SaveTenantValidator());我们使用validatingListener.addValidator()来注册我们的校验器。该方法传入两个参数,第一个代表着要校验的事件,"beforeCreate"即代表着在插入新纪录之前,对插入数据进行校验。spring Data REST还提供了其他的事件:
BeforeCreateEventAfterCreateEventBeforeSaveEventAfterSaveEventBeforeLinkSaveEventAfterLinkSaveEventBeforeDeleteEventAfterDeleteEvent
我们都可以从字面意思进行理解。
方法中的第二个参数,就是指定我们要注册的校验器,如上代码中,我们对我们刚刚创建的校验器进行注册。
如下为验证效果:

响应统一处理
有时候我们需要对响应结果进行统一处理,比如,我们希望我们的响应结果中包含当前时间的时间戳又或者我们希望我们的HAL格式的响应数据中增加其他的链接。这时候,我们可以通过响应统一处理来完成这种看似重复性的工作。但是Spring Data REST并没有提供现成的功能,不过我们可以通过覆盖Spring Data REST响应处理程序,来实现这一目标。
@RepositoryRestController
public class TenantController {
private final TenantRepository tenantRepository;
@Resource
private RepositoryEntityLinks entityLinks;
@Autowired
public TenantController(TenantRepository tenantRepository) {
this.tenantRepository = tenantRepository;
}
@GetMapping(value = "/tenantPath/search/mobile")
public ResponseEntity<?> getByMobile(@RequestParam String mobile) {
Tenant tenant = tenantRepository.findFirstByMobile(mobile);
EntityModel<Tenant> resource = new EntityModel<>(tenant);
resource.add(linkTo(methodOn(TenantController.class).getByMobile(mobile)).withSelfRel());
resource.add(entityLinks.linkToSearchResource(Tenant.class, LinkRelation.of("findAllByIdCardContaining")));
return ResponseEntity.ok(resource);
}
}
如上代码,我们使用了@RepositoryRestController注解来创建了一个控制器,并定义了一个路径的请求,以此我们覆盖了之前Spring Data REST自动为我们提供的相同路径的接口。我们给接口的响应增加了两个链接。
注意:上述代码中用到了Spring HATEOAS的库,所以我们需要增加Spring HATEOAS的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.atteo</groupId>
<artifactId>evo-inflector</artifactId>
</dependency>
现在我们访问http://localhost:8080/tenantPath/search/mobile?mobile=186****3331,看到响应结果:
{
"name": "王一",
"mobile": "186****3331",
"rentDateTime": "2020-04-22 17:48:40",
"_links": {
"self": {
"href": "http://localhost:8080/tenantPath/search/mobile?mobile=186****3331"
},
"findAllByIdCardContaining": {
"href": "http://localhost:8080/tenantPath/search/findAllByIdCardContaining{?idCard,page,size,sort,projection}",
"templated": true
}
}
}
可以看到,links属性中链接已经变成我们指定的链接了。
异常统一处理
Spring Data REST中并没有提供异常处理的功能,但是我们可以使用Springboot中自带的异常处理功能来实现我们的要求。
@Slf4j
@ControllerAdvice
public class ExceptionTranslator {
@ExceptionHandler
public ResponseEntity<Object> handleEmailAlreadyUsedException(NullPointerException ex, NativeWebRequest request) {
log.info("遇到空指针");
return ResponseEntity.ok(List.of("拦截到空指针异常"));
}
}
如上,我们声明了一个异常处理器。接下来我人为制造一个错误。
@RepositoryRestController
public class TenantController {
private final TenantRepository tenantRepository;
@Autowired
public TenantController(TenantRepository tenantRepository) {
this.tenantRepository = tenantRepository;
}
@GetMapping(value = "/tenantPath/search/mobile")
public ResponseEntity<?> getByMobile(@RequestParam String mobile) {
if (1 == 1) {
throw new NullPointerException();
}
Tenant tenant = tenantRepository.findFirstByMobile(mobile);
EntityModel<Tenant> resource = new EntityModel<>(tenant);
resource.add(linkTo(methodOn(TenantController.class).getByMobile(mobile)).withSelfRel());
return ResponseEntity.ok(resource);
}
}
此时,我们请求此接口:
[
"拦截到空指针异常"
]
可以看到,我们的异常被我们的异常处理器拦截掉了。
数据切面处理
Spring Data REST提供了类似的Aop切面操作,虽然不能和Spring的原生aop相比,但是其简洁性也能满足需求。Spring Data REST提供的是基于事件的切面。如下我们声明了一个切面。
@Component
@Slf4j
@RepositoryEventHandler
public class TenantEventHandler {
@HandleBeforeDelete
protected void onBeforeDelete(Tenant entity) {
log.info("现在要开始删除操作了,删除对象:{}", entity);
}
@HandleAfterDelete
protected void onAfterDelete(Tenant entity) {
log.info("删除对象完成,删除对象:{}", entity);
}
}
如上,我们声明了一个切面,我们可以在删除操作之前和之后进行额外的逻辑处理,示例中很简单,我们使用日志记录事件的发生。
此时,我们访问项目的删除接口curl --location --request DELETE 'http://localhost:8080/tenantPath/1'
我们可以看到控制输出了相应的日志:
2020-04-23 17:26:29.950 INFO 38077 --- [nio-8080-exec-1] c.e.d.configuration.TenantEventHandler : 现在要开始删除操作了,删除对象:Tenant(id=1, name=王一, idCard=3305221, mobile=1863331, rentDateTime=2020-04-22T17:24:46.105897, house=House(id=2, houseNumber=1101, owner=张三, idCard=3305211))
2020-04-23 17:26:30.035 INFO 38077 --- [nio-8080-exec-1] c.e.d.configuration.TenantEventHandler : 删除对象完成,删除对象:Tenant(id=1, name=王一, idCard=3305221, mobile=1863331, rentDateTime=2020-04-22T17:24:46.105897, house=House(id=2, houseNumber=1101, owner=张三, idCard=3305211))
此时,我们的数据切面处理生效了,除此之外,Spring Data REST还提供了如下几个基于事件的切面:

总结
至此,我们先前列出的所有功能特性三篇文章中都有涉及到,通过引入这些功能特性,我们能更加轻松的使用Spring Data REST,并且也能满足我们大部分接口开发的场景。当然三篇文章不能涉及Spring Data REST的全部,有兴趣的小伙伴可以访问Spring Data REST的官方文档查看更多关于Spring Data REST的特性及信息。
本系列文章演示代码地址:https://gitee.com/jeker8chen/spring-data-rest-in-practice.git
关注笔者公众号,推送各类原创/优质技术文章 ⬇️

Spring Data REST不完全指南(三)的更多相关文章
- Spring Data REST不完全指南(二)
上一篇文章介绍了Spring Data REST的功能及特征,以及演示了如何在项目中引入Spring Data REST并简单地启动演示了Spring Data REST项目.在本文中,我们将深入了解 ...
- Spring Data REST不完全指南(一)
简介 Spring Data REST是Spring Data项目的一部分,可轻松在Spring Data存储库上构建超媒体驱动的REST Web服务. Spring Data REST 构建在 Sp ...
- ElasticSearch(十三):Spring Data ElasticSearch 的使用(三)——NativeSearchQuery 高亮查询
在Elasticsearch的实际应用中,经常需要将匹配到的结果字符进行高亮显示,此处采取NativeSearchQuery原生查询的方法,实现查询结果的高亮显示. /** * 高亮查询 */ @Te ...
- Spring Data JPA教程, 第二部分: CRUD(翻译)
我的Spring Data Jpa教程的第一部分描述了,如何配置Spring Data JPA,本博文进一步描述怎样使用Spring Data JPA创建一个简单的CRUD应用.该应用要求如下: pe ...
- spring mvc Spring Data Redis RedisTemplate [转]
http://maven.springframework.org/release/org/springframework/data/spring-data-redis/(spring-data包下载) ...
- Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解
一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...
- Spring Data Elasticsearch 用户指南
https://www.jianshu.com/p/27e1d583aafb 翻译自官方文档英文版,有删减. BioMed Central Development Team version 2.1.3 ...
- Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)
在本人的Spring Data JPA教程的第二部分描述了如何用Spring Data JPA创建一个简单的CRUD应用,本博文将描述如何在Spring Data JPA中使用query方法创建自定义 ...
- spring-boot (三) spring data jpa
学习文章来自:http://www.ityouknow.com/spring-boot.html spring data jpa介绍 首先了解JPA是什么? JPA(Java Persistence ...
随机推荐
- Trie树的简单实现
import java.util.ArrayList; import java.util.TreeMap; import util.FileOperation; public class Trie { ...
- 文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于肽段鉴定中错误发生率估计的能体现重复性的诱饵数据库)
文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于 ...
- matplotlib.pyplot库函数关于坐标轴显示的支持
matplotlib.pyplot库函数关于坐标轴显示的支持 https://blog.csdn.net/Stark_595/article/details/80787005?depth_1-utm_ ...
- OpenCV-Python 光流 | 四十八
目标 在本章中, 我们将了解光流的概念及其使用Lucas-Kanade方法的估计. 我们将使用cv.calcOpticalFlowPyrLK()之类的函数来跟踪视频中的特征点. 我们将使用cv.cal ...
- TensorFlow系列专题(十三): CNN最全原理剖析(续)
目录: 前言 卷积层(余下部分) 卷积的基本结构 卷积层 什么是卷积 滑动步长和零填充 池化层 卷积神经网络的基本结构 总结 参考文献 一.前言 上一篇我们一直说到了CNN[1]卷积层的特性,今天 ...
- 阿里云ECS(Ubuntu)单节点Kubernetes部署
参考资料: kubernetes官网英文版 kubernetes官网中文版 前言 这篇文章是比较久之前写的了,无聊翻了下博客发现好几篇博文排版莫名其妙的变了... 于是修改并完善了下.当初刚玩k8s的 ...
- 解决pycharm不能导入bs4模块问题
问题描述: 在导入bs4模块时有报错提示 “ Traceback (most recent call last): File "E:/project/code/py-pengfu/py-pf ...
- 求第 k 小:大元素
#include<bits/stdc++.h> using namespace std; void swap_t(int a[],int i,int j) { int t=a[i]; a[ ...
- Sublime Text 2 Install Package Debug
本文转载自CSDN空间freshlover的博客<Sublime Text 无法使用Package Control或插件安装失败的解决方法>,转载请注明出处,谢谢! Sublime Tex ...
- c期末笔记(4)
未命名易错点 1.0<y<10 在c语言中,0<y<10不是一个正确的表达式,应该利用逻辑运算符替换(y>0&&y<10或者!(y<=0||y ...