如何处理 REST Web 服务中的资源验证?

2022-09-02 04:40:02

我正在使用Spring,Jersey和Hibernate(JPA)在Java中构建REST Web服务。

现在,我正在尝试在我的资源中添加对验证的支持。JSR-303(Bean验证)自然是一个合适的选择(我使用的是Hibernate Validator,它是JSR-303的参考实现)。但是,我首先尝试整合一些概念。

在我看来,至少有两种可能的验证:

  • 对字段进行定期验证,例如,检查属性是否为空,检查属性是否为有效的电子邮件,检查属性是否大于 等。这按预期工作。我已经注册了一个JAX-RS ExceptionMapper,它将 的 映射到正确的HTTP响应中。StringInteger10javax.validation.ConstraintViolationException
  • 数据完整性验证

我将通过一个示例来解释“数据完整性验证”的确切含义。当两个或多个资源之间存在关系时,会发生这种情况。想象两个资源:a 和 .A 一个 .当客户端向服务器发送要创建的表示形式(一个POST HTTP请求)时,它必须通知产品。当然,客户必须事先知道类别。想象一下,在JSON中,类似如下:ProductCategoryProductCategoryProductCategory

{
   "quantity": "10",
   "state": "PRODUCED",
   "category": {
      "id": "123"
   }
}

好吧,带有id的类别可能不存在。如果我们尝试将其插入到数据库中,显然我们会得到一个与外键相关的异常。因此,我假设我们必须验证这些问题并向客户端返回正确的消息,就像在常规属性验证中一样。123


现在,我的主要问题是:

  1. 现在,我正在通过 JPA 与 Bean 验证的集成,在数据访问级别执行验证。验证应该在序列化过程之前/之后数据库操作之前/之后还是两者兼而有之
  2. 如何处理数据完整性验证手动地?(即明确咨询数据库检查数据完整性)或者我们是否应该尝试插入它,然后捕获数据库(或DAO)异常?豆类验证与这种验证无关,对吧?
  3. 如果您对 JAX-RS/REST 和 Bean 验证有任何经验,如果您告诉我,我会很高兴。使用组?

这些问题与Java有些关系,但我也希望从这些问题中获得一些新的观点。一些技术独立的。:)如果您可以在REST Web服务上为这些问题提供自己的解决方案,那就太好了。


答案 1

该解决方案最终是将Jackson的子类化,该子类化实现了JAX-RS和.我受到令人惊叹的Dropwizard方法的启发。在这个提供程序中,我们需要以某种方式注入一个验证器实例(我使用Spring for Injection和Hibernate Validator来实现JSR-303)。如果您使用Hibernate ORM,请不要忘记禁用实体验证,否则您将验证同一实体两次。不过,这可能是我们想要的。JacksonJaxbJsonProviderMessageBodyReaderMessageBodyWriter

然后,在这个子类化中,我验证对象并抛出一个带有验证器错误的自定义。我还创建了一个 JAX-RS,它将每个都映射到正确的 HTTP 响应中。在我的情况下,我返回了一个错误的请求和一个包含错误描述的JSON对象。MessageBodyReaderInvalidEntityExceptionExceptionMapper<InvalidEntityException>InvalidEntityException

请注意,此 MessageBodyReader 检查和注释。这意味着它正确地支持组。这很重要,因为我们可能不希望在整个应用程序中执行相同类型的验证。例如,当我们想要进行部分更新(PUT)时。或者,例如,id 属性在 POST 请求中必须为 null,但在其他所有位置都必须为非 null。@Valid@Validated

数据完整性验证尚未完全处理。但是我计划捕获数据库异常并将其转换为我自己的域异常(例如a),因为它对我来说似乎更有效且松散耦合。DataIntegrityException


更新:

从 JAX-RS 2 开始,建议的方法是使用其 Bean 验证支持。检查这里: https://jersey.java.net/documentation/latest/bean-validation.html


答案 2

现在,您可以使用 Jersey 2.0 通过 JSR-303/JSR-349 验证资源参数。

https://jersey.java.net/documentation/latest/bean-validation.html#d0e9301