【问题标题】:Spring MVC with hibernate Validator to validate single basic type带有休眠验证器的 Spring MVC 来验证单个基本类型
【发布时间】:2014-07-15 20:03:41
【问题描述】:

下面是我遇到问题的映射方法,无论我传递给它什么值,验证都会返回“通过验证”。

@RequestMapping(value = "test", method = RequestMethod.POST)
@ResponseBody
public String getTest(@RequestBody @Valid @Max(32) long longValue, BindingResult result) {
  if (result.hasErrors()) {
    return "failed validation";
  } else {
    return "passed validation";
  }
}

我知道@Max 适用于我的应用程序,因为我使用它来验证自定义对象,这些对象会向控制器返回大量数据。它只是在我调用@Valid 和方法参数中对象的验证类型的情况下不运行验证。

hibernate-validator 不允许这样做吗?

我希望不必定义一个只包含长值的对象,以便我可以对其进行验证。

【问题讨论】:

    标签: java spring-mvc hibernate-validator


    【解决方案1】:

    我希望不必定义一个只包含 long 的对象 值,以便我可以对其进行验证。

    恕我直言,定义一个包装 bean 是最明智的做法,因为 hibernate-validator 完全围绕 bean 的概念,并且毕竟是 bean 验证规范的参考实现。该规范的主要动机之一是承认验证是跨越不同应用程序层的横切关注点,并提供一种机制来优雅地处理这个问题。这就是它以 bean 为中心的原因,它是通过层的对象。

    另一方面,以编程方式验证基元毕竟不是什么大问题,您的代码可以简单地类似于

    @RequestMapping(value = "test", method = RequestMethod.POST)
    @ResponseBody
    public String getTest(@RequestBody long longValue, BindingResult result) {
      if (longValue > 32) {
         result.rejectValue("longValue", "error.longValue", "longValue max constrained failed");
        return "failed validation";
      } else {
        return "passed validation";
      }
    }
    

    所以在我看来,如果足够简单,要么进行程序验证,要么简单地包装值。

    【讨论】:

    • 我不认为包装器选项在我的情况下是最好的选择,因为我应该为每个适用于原语、字符串和所有其他单一基本类型的注释都有一个包装器。并在代码中验证它我认为这很好,但我想在验证对象的方式上保持一些连贯性。我想用休眠验证器或其中任何一个来验证所有类型的对象......所以我不准备听休眠验证器不验证这种事情:P 无论如何感谢您的回答!
    【解决方案2】:

    不,这是不允许的。我明白你的意思,但是 JSR-303 规范(hibernate 验证器实现)用于 bean 验证,请参阅here

    【讨论】:

      【解决方案3】:

      首先,正如其他答案所述,Hibernate Validator 不允许像问题中的示例那样直接验证原语。为了使用 Hibernate Validator,定义一个包含 long 值的新类正是使用 Hibernate Validator 所需要的。

      第二,也是最重要的,虽然程序验证是可行的,而且非常简单,但它并不干净和可维护。让我用一些例子来说明这一点:

      @RequestMapping(value = "testA", method = RequestMethod.POST)
      @ResponseBody
      public String getTestA(@RequestBody long longValue, BindingResult result) {
         if (longValue > 32) {
           result.rejectValue("longValue", "error.longValue", "longValue max constrained failed");
           return "failed validation for test A";
         } else {
           return "passed validation for test A";
         }
      }
      
      
      @RequestMapping(value = "testB", method = RequestMethod.POST)
      @ResponseBody
      public String getTestB(@RequestBody long longValue, BindingResult result) {
         if (longValue > 32) {
           result.rejectValue("longValue", "error.longValue", "longValue max constrained failed");
           return "failed validation for test B";
         } else {
           return "passed validation for test B";
         }
      }
      
      
      @RequestMapping(value = "testC", method = RequestMethod.POST)
      @ResponseBody
      public String getTestC(@RequestBody long longValue, BindingResult result) {
         if (longValue > 32) {
           result.rejectValue("longValue", "error.longValue", "longValue max constrained failed");
           return "failed validation for test C";
         } else {
           return "passed validation for test C";
         }
      }
      

      首先要注意的是,有3个简单的函数,所有的验证码都是重复的。

      其次,如果在某个时候您的验证要求发生了变化,并且现在所有长值必须大于 35,您需要更改每个验证函数,在这个示例中非常简单,因为只有 3 个函数相同的验证,但想象一下,有 100 个函数在其中执行相同的验证,这很痛苦。

      因此,只需定义一个具有长值和验证注释的新类,并在每个方法上使用该类,您就消除了代码重复,而且当您的验证要求发生变化时,在一个地方应用更改,您就可以做到代码。

      此外,必须为一项特定任务定义类并没有错,事实上,这正是 Single Responsability Principle 告诉您要做的。

      编辑:添加了指向 SRP 描述的链接。

      【讨论】:

        猜你喜欢
        • 2019-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-20
        • 1970-01-01
        • 2023-03-16
        • 2023-03-08
        • 2012-09-13
        相关资源
        最近更新 更多