上一篇我们介绍了使用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还提供了其他的事件:

  • BeforeCreateEvent
  • AfterCreateEvent
  • BeforeSaveEvent
  • AfterSaveEvent
  • BeforeLinkSaveEvent
  • AfterLinkSaveEvent
  • BeforeDeleteEvent
  • AfterDeleteEvent

我们都可以从字面意思进行理解。

方法中的第二个参数,就是指定我们要注册的校验器,如上代码中,我们对我们刚刚创建的校验器进行注册。

如下为验证效果:


响应统一处理

有时候我们需要对响应结果进行统一处理,比如,我们希望我们的响应结果中包含当前时间的时间戳又或者我们希望我们的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不完全指南(三)的更多相关文章

  1. Spring Data REST不完全指南(二)

    上一篇文章介绍了Spring Data REST的功能及特征,以及演示了如何在项目中引入Spring Data REST并简单地启动演示了Spring Data REST项目.在本文中,我们将深入了解 ...

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

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

  3. ElasticSearch(十三):Spring Data ElasticSearch 的使用(三)——NativeSearchQuery 高亮查询

    在Elasticsearch的实际应用中,经常需要将匹配到的结果字符进行高亮显示,此处采取NativeSearchQuery原生查询的方法,实现查询结果的高亮显示. /** * 高亮查询 */ @Te ...

  4. Spring Data JPA教程, 第二部分: CRUD(翻译)

    我的Spring Data Jpa教程的第一部分描述了,如何配置Spring Data JPA,本博文进一步描述怎样使用Spring Data JPA创建一个简单的CRUD应用.该应用要求如下: pe ...

  5. spring mvc Spring Data Redis RedisTemplate [转]

    http://maven.springframework.org/release/org/springframework/data/spring-data-redis/(spring-data包下载) ...

  6. Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解

    一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...

  7. Spring Data Elasticsearch 用户指南

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

  8. Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)

    在本人的Spring Data JPA教程的第二部分描述了如何用Spring Data JPA创建一个简单的CRUD应用,本博文将描述如何在Spring Data JPA中使用query方法创建自定义 ...

  9. spring-boot (三) spring data jpa

    学习文章来自:http://www.ityouknow.com/spring-boot.html spring data jpa介绍 首先了解JPA是什么? JPA(Java Persistence ...

随机推荐

  1. word加上尾注之后参考文献下面的横线去除

    Word 尾注上面的横线叫“××分隔符”,去掉的步骤是: 1. 先“视图”——“普通视图”: 2. 进入“引用”——“脚注”——“显示备注”: 3. 窗口下面出现了“尾注”,点击下拉菜单“所有尾注”那 ...

  2. Samba centos7文件共享服务器搭建教程,可以更改任意需求操作配置详解。

    先安装软件   yum -y install samba-client 请看如下配置文件说明 [gongxiang]       comment = This is my shared folder  ...

  3. 《Mathematical Analysis of Algorithms》中有关“就地排列”(In Situ Permutation)的算法分析

    问题描述 把数列\((x_1,x_2,\cdots,x_n)\)变换顺序为\((x_{p(1)},x_{p(2)},\cdots,x_{p(n)})\),其中\(p\)是\(A=\{1,2,3,\cd ...

  4. 面试都在问的微服务、服务治理、RPC、下一代微服务框架... 一文带你彻底搞懂!

    文章每周持续更新,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 单体式应用程序 与微服务相对的另一个概念是传统的单体式应用程序( ...

  5. [codevs]1250斐波那契数列<矩阵乘法&快速幂>

    题目描述 Description 定义:f0=f1=1, fn=fn-1+fn-2(n>=2).{fi}称为Fibonacci数列. 输入n,求fn mod q.其中1<=q<=30 ...

  6. Django之环境安装

    什么是Django Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架,由 ...

  7. nginx 安装教程

    Nginx 安装教程 本教程在CentOS6.7中安装nginx 1.8.0,Nginx中加入了taobao的concat模块,nginx-upload-module模块,pcre 以及nginx-u ...

  8. 002_Three.js 中添加阴影 - [Three.js] - [阴影效果]

    在Three.js中设置阴影效果,有多个地方需要设置属性. ![](https://img2018.cnblogs.com/blog/1735896/201912/1735896-2019123116 ...

  9. JavaScript基本数据类型及其转换规则

    ECMAScript 数据类型 ECMAScript中有五种基本数据类型:Undefined, Null, Boolean, Number, String 一种复杂数据类型:Object 数据类型检测 ...

  10. Linux - ubuntu下Vim安装失败,报The following packages have unmet dependencies: vim : Depends: vim-common

    错误命令行 root@ubuntu:/etc/apt# apt install vim Reading package lists... Done Building dependency tree R ...