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还提供了其他的事宜:

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

我们都可以从字面意思举行明白。

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

如下为验证效果:

Spring Data REST不完全指南(三)

响应统一处置

有时候我们需要对响应效果举行统一处置,好比,我们希望我们的响应效果中包罗当前时间的时间戳又或者我们希望我们的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,看到响应效果:

Unity 游戏框架搭建 2019 (三十、三十一) MenuItem 显示顺序问题 & 类的提取

{
  "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的官方文档查看更多关于Spring Data REST的特征及信息。

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

Spring Data REST不完全指南(三)

原创文章,作者:7h28新闻网,如若转载,请注明出处:https://www.7h28.com/archives/5844.html