当前位置: 首页 > 知识库问答 >
问题:

Spring MVC+Hibernate:数据验证策略

郁和通
2023-03-14

我们都知道,Spring MVC与Hibernate验证器和JSR-303集成得很好。但正如有人所说的,Hibernate验证器仅用于Bean验证,这意味着更复杂的验证应该推送到数据层。这类验证的例子:业务密钥唯一性、记录内依赖性(这通常指向DB设计问题,但我们都生活在一个不完美的世界中)。即使是像字符串字段长度这样的简单验证也可能由某些DB值驱动,这使得Hibernate验证器无法使用。

所以我的问题是,Spring或Hibernate或JSR提供了什么来执行如此复杂的验证吗?在基于Spring和Hibernate的标准Controller-Service Repository设置中,是否有一些既定的模式或技术来执行这样的验证?

更新:让我说得更具体一点。例如,有一个表单向控制器的save方法发送AJAX保存请求。如果发生了一些验证错误--简单的或“复杂的”--我们应该返回到浏览器,使用一些表示有问题的字段和相关错误的json。对于简单的错误,我可以从bindingresult中提取字段(如果有)和错误消息。什么基础设施(可能是特定的,而不是特别的例外?)你会提议“复杂”错误吗?在我看来,使用异常处理程序似乎不是一个好主意,因为在save方法和@exceptionhandler之间分离单个验证进程会使事情变得复杂。目前我使用一些特殊异常(如validationexception):

public @ResponseBody Result save(@Valid Entity entity, BindingResult errors) {
    Result r = new Result();
    if (errors.hasErrors()) {
        r.setStatus(Result.VALIDATION_ERROR);     
        // ...   
    } else {
        try {
            dao.save(entity);
            r.setStatus(Result.SUCCESS);
        } except (ValidationException e) {
            r.setStatus(Result.VALIDATION_ERROR);
            r.setText(e.getMessage());
        }
    }
    return r;
}

你能提供一些更好的方法吗?

共有1个答案

夹谷硕
2023-03-14

是的,这里有一个很好的Java模式,即抛出异常。
Spring MVC很好地集成了它(对于代码示例,您可以直接跳到我回答的第二部分)。

您所说的“复杂验证”实际上是例外:业务密钥唯一性错误、低层或DB错误等。

验证应该发生在表示层上。它基本上是关于验证提交的表单字段的。

1)轻度验证(使用JSR-303/Hibernate验证):检查提交的字段是否具有给定的@size/@lengty,是否为@notnull@notempty/@notblank,检查是否具有@email格式,等等。

2)重验证或复杂验证更多地是关于字段验证的特定情况,例如跨字段验证:

  • 示例1:表单具有fieldafieldbfieldc。每个字段都可以为空,但其中至少一个字段不能为空。
  • 示例2:如果UserAge字段的值小于18,则ResponsibleUser字段不能为null,并且ResponsibleUser的年龄必须大于21。

这些验证可以通过Spring验证器实现或自定义注释/约束来实现。

现在我明白了,有了所有这些验证工具,再加上Spring完全不具有侵扰性,并且允许您做任何您想做的事情(不管是好是坏),您可能会倾向于使用“验证锤”来处理与错误处理模糊相关的任何事情。
而且它会起作用:仅使用验证,您就会检查验证器/注释中的每个可能的问题(并且几乎不会在较低层抛出任何异常)。这很糟糕,因为你祈祷你想过所有的案子。您没有利用Java异常来简化逻辑,并通过忘记检查某个东西是否存在错误来减少犯错误的机会。

因此,在Spring MVC世界中,不应将验证(也就是说,UI验证)误认为低层异常,如服务异常或DB异常(密钥唯一性等)。

有些人认为“哦,上帝啊,所以在我的控制器中,我必须逐个检查所有可能的检查异常,并为每个异常考虑一个消息错误?不可能!”。我就是那种人。:-)

对于大多数情况,只需使用一些通用的检查异常类,所有异常都将扩展这些类。然后只需在Spring MVC控制器中使用@ExceptionHandler和一个通用错误消息来处理它。

public class MyAppTechnicalException extends Exception { ... }

而且

@Controller
public class MyController {

    ...

    @RequestMapping(...)
    public void createMyObject(...) throws MyAppTechnicalException {
        ...
        someServiceThanCanThrowMyAppTechnicalException.create(...);
        ...
    }

    ...

    @ExceptionHandler(MyAppTechnicalException.class)
    public String handleMyAppTechnicalException(MyAppTechnicalException e, Model model) {

        // Compute your generic error message/code with e.
        // Or just use a generic error/code, in which case you can remove e from the parameters
        String genericErrorMessage = "Some technical exception has occured blah blah blah" ;

        // There are many other ways to pass an error to the view, but you get the idea
        model.addAttribute("myErrors", genericErrorMessage);

        return "myView";
    }

}

简单、快捷、轻松、干净!

对于需要为某些特定异常显示错误消息的情况,或者由于无法修改设计不佳的遗留系统而无法拥有通用顶级异常的情况,只需添加其他@exceptionhandler
另一个技巧:对于不太杂乱的代码,您可以使用

@ExceptionHandler({MyException1.class, MyException2.class, ...})
public String yourMethod(Exception e, Model model) {
    ...
}
    null
  • 将错误从服务层传回视图
  • 关于bean验证的内容非常丰富的博客文章
 类似资料:
  • 本文向大家介绍详解SpringMVC学习系列(6) 之 数据验证,包括了详解SpringMVC学习系列(6) 之 数据验证的使用技巧和注意事项,需要的朋友参考一下 在系列(4)、(5)中我们展示了如何绑定数据,绑定完数据之后如何确保我们得到的数据的正确性?这就是我们本篇要说的内容 —> 数据验证。 这里我们采用Hibernate-validator来进行验证,Hibernate-validator

  • 本文向大家介绍SpringMVC Validator验证示例,包括了SpringMVC Validator验证示例的使用技巧和注意事项,需要的朋友参考一下 SpringMVC服务器验证一种是有两种方式,一种是基于Validator接口,一种是使用Annotaion JSR-303标准的验证,下面主要是学习这两种,工作中推荐后者,方便很多 一.基于Validator接口的验证. 首先创建User实例

  • 我需要应用一个双值验证,这需要与圆周率匹配。我正在考虑使用@pattern(regex=“3.14159265359”)。这是使用Hibernate验证约束应用这样一个约束的最佳方式吗?谢谢

  • 我现在把这两者搞混了。我知道Hibernate Validator6是Bean验证2.0规范的参考实现。它支持分组、错误消息国际化、自定义方法验证等。问题是Spring5支持这些特性还是我只剩下Hibernate Validator6了? 网上所有的参考例子都建议使用Hibernate验证器,没有什么关于Spring验证的发现,请建议或指向其他链接。

  • 编写验证器 验证器是一个可调用的对象,它接受一个值,并在不符合一些规则时抛出ValidationError异常。验证器有助于在不同类型的字段之间重复使用验证逻辑。 例如,这个验证器只允许偶数: from django.core.exceptions import ValidationError def validate_even(value): if value % 2 != 0:

  • 简介 Lumen 提供了数种不同的方法来验证传入应用程序的数据。默认情况下,Lumen 的基控制器类使用名为 ProvidesConvenienceMethods 的 trait,其提供了一种便捷的方法来使用各种强大的验证规则验证传入的 HTTP 请求。 一般来说,Lumen 中的数据验证与 Laravel 中的数据验证并无多大区别,因此你应该查阅 完整的 Laravel 数据验证文档 以熟悉其使