上一篇我们介绍了使用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. MySQL优化之执行计划

    前言 研究SQL性能问题,其实本质就是优化索引,而优化索引,一个非常重要的工具就是执行计划(explain),它可以模拟SQL优化器执行SQL语句,从而让开发人员知道自己编写的SQL的运行情况. 执行 ...

  2. 倒影box-reflect(可图片可文字)

    需要写兼容写法: -webkit-box-reflect:below 3px -webkit-(repeating)linear/redial-gradient(...): 1.先写direction ...

  3. 基于Doc2vec训练句子向量

    目录 一.Doc2vec原理 二.代码实现 三.总结   一.Doc2vec原理 前文总结了Word2vec训练词向量的细节,讲解了一个词是如何通过word2vec模型训练出唯一的向量来表示的.那接着 ...

  4. 吴恩达最新TensorFlow专项课程开放注册,你离TF Boy只差这一步

    不需要 ML/DL 基础,不需要深奥数学背景,初学者和软件开发者也能快速掌握 TensorFlow.掌握人工智能应用的开发秘诀. 以前,吴恩达的机器学习课程和深度学习课程会介绍很多概念与知识,虽然也会 ...

  5. iOS NSDateFormatter性能

    一.探究 NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat: ...

  6. Matlab——m_map指南(2)

    3.海岸线和深度测量 3.1.1 海岸线选项 m_coast('line', ...optional line arguments ); m_coast('line', ...optional lin ...

  7. Material Design 组件之 FloatingActionButton

    Material Design 设计规范在 Google I/O 2014 推出,这种设计理念一经推出就受到广大开发者的喜爱,主要侧重于纸墨化创作和突出设计的实体感,使得设计更接近于真实世界,力求平滑 ...

  8. 8.MSFvenom

    Meterpreter 01 Meterpreter API调用 Meterpreter提供了多种APl调用,在编写自己的脚本时可以使用这些API来提供额外功能或定制功能. 关于ruby的更多信息,请 ...

  9. 1.Metasploit介绍与基本命令

    Metasploit体系框架介绍 Metasploit是目前世界上领先的渗透测试工具,也是信息安全与渗透测试领域最大的开源项目之一.它彻底改变了我们执行安全测试的方式. Metasploit之所以流行 ...

  10. 直播回顾 | IOT、AI、云计算等融合技术推进制造业产业转型(二)

    3月31日,BoCloud博云.京东智联云.海尔集团联手,以“制造”到“智造”为主题,进行了IT赋能企业数字化转型实践分享. 博云售前解决方案架构师尹贺杰,京东云与AI企业云业务部高级业务技术经理吴世 ...