【问题标题】:Should validators in spring access the database?spring 中的验证器应该访问数据库吗?
【发布时间】:2010-11-05 23:07:52
【问题描述】:

我不确定让验证器根据数据库状态验证命令是否是一个好的设计决策。例如,如果除了检查电子邮件和用户名是否为空等之外,我还需要验证用户 bean。如果它们已被使用,我还需要拒绝这些值。这种逻辑应该放在验证器还是服务对象中?

【问题讨论】:

    标签: java validation spring spring-mvc


    【解决方案1】:

    好吧,您的验证器只是 spring bean,对,所以它们可以被注入处理数据访问的服务对象。您可以让您的验证器从数据库中获取数据,而不会影响设计。

    【讨论】:

    • 嗯...仅仅因为你可以做某事并不一定意味着你应该去做。我可以在错误的地方注入很多讨厌的东西,这肯定会影响系统的设计。
    【解决方案2】:

    这在很大程度上取决于您如何定义验证。考虑一下:您正在买东西,然后输入您的信用卡号。如果校验位不匹配,则验证失败。没有尝试过交易。但是,如果它是一个有效的信用卡号,但它与您的邮政编码不匹配(需要 DB/第三方交互),那么这是一个付款错误。

    现在考虑一下:您正在输入您的地址,并且您输入 Mastiffica 作为您的国家。为什么系统甚至允许您输入 - 他们应该将界面限制为仅有效条目(无需 DB 后条目)。

    或者您在银行付款屏幕的金额字段中输入“五十”。为什么它允许那里的字母 - 验证失败(不需要数据库)。但是您随后在金额字段中输入 50,结果您的帐户中没有 50 英镑。那是验证错误吗?还是交易失败?

    现在,假设您已通过所有基本输入验证(信用卡校验和、国家/地区、数字、邮政编码)并且交易失败,因为您的信用卡已过期。是验证错误,还是交易失败?

    您可以将验证视为用户不会输入完全野蛮数据的基本保证,或者您可以将验证视为“我可以使用已提供的数据完成此交易”。我个人倾向于前者,但同样,这是定义问题。

    然后是作为安全措施的第一行验证方面 - 通过您的顶级 UI 层接受的野数据可能是安全风险(例如 SQL 注入)

    【讨论】:

      【解决方案3】:

      不,恕我直言,验证器应该很小,side-effect free 以便让它们轻松组合。确实,验证器应该与持久层解耦

      【讨论】:

      • 当您想检查引用是否指向真实实体时,您会怎么做?他们不应该更改数据,但有时您至少需要进行身份验证。
      • 我以前听过或读过这个,这正是我问这个问题的原因。但是我不确定如果我不能让他们从数据库中读取(没有副作用)我应该做什么。我对这个话题有点困惑,因为在 Java 世界中似乎很多人都同意你的观点,而在 Django 和 RoR 中,将验证与数据库联系起来是完全正常的。
      • 你在哪里检查注册表中的用户名是否已经给出?
      • 从数据库读取过程中会发生什么副作用?
      【解决方案4】:

      我检查了我的一个,我正在从验证器调用服务层:

      @Service
      public final class StartFormValidator {
      private FacilityService facilityService;
      private AdminService adminService;
      
      /**
       * Verify that they've selected a facility. Verify that they've selected a
       * valid facility. Verify that they've selected a view and that it's a valid
       * view.
       * 
       * @param startForm
       * @param errors
       * @return true if no errors were set
       */
      public boolean isValid(final StartForm startForm, final Errors errors) {
          if (startForm.getFacilityId() == 0) {
              errors.rejectValue("facilityId", "facilityIdEmpty",
                      "Select a facility.");
          }
      
          if (!this.facilityService.isFacilWaitlistEnabled(startForm
                  .getFacilityId())) {
              errors.rejectValue("facilityId", "facilityInvalid",
                      "Invalid facility");
          }
      
          if (StringUtils.isBlank(startForm.getPassword())) {
              errors.rejectValue("password", "passwordEmpty",
                      "Enter the password.");
      
              return (false);
          }
      
          if (!this.adminService.validateAdmin(startForm.getPassword()))
              errors.rejectValue("password", "passwordInvalid",
                      "Incorrect password");
      
          return (!errors.hasErrors());
      }
      
      /**
       * @param _facilityService
       */
      @Autowired
      public void setFacilityService(final FacilityService _facilityService) {
          this.facilityService = _facilityService;
      }
      
      /**
       * @param _adminService
       */
      @Autowired
      public void setAdminService(final AdminService _adminService) {
          this.adminService = _adminService;
      }
      

      }

      【讨论】:

        【解决方案5】:

        如果你真的相信“MVC”,那么我不这么认为,你会希望你的验证器进入数据库。验证是一个从业务逻辑的角度验证数据的阶段。

        数据库不需要知道验证器将如何使用它,验证器也不应该知道数据库是什么样的。这不适合 MVC 模型。明天,如果您有来自多个来源的数据,您是否仍会继续告诉您的验证器,它应该在什么条件下访问具体的哪个来源。这本身将构成甚至不需要的逻辑。在应用中。

        您正在寻找的验证类型将作为业务对象的一部分使用,这将确保在服务对象甚至被调用之前;这种组合尚不存在。

        Service 对象也不应该包含业务验证,因此它既不属于验证器也不属于 Service 对象。但是,是的,如果应用程序足够小而不必担心太多层,那么偏斜的方法就可以了,但只要“始终遵循它作为标准”即可。

        简而言之,我觉得 Spring 验证器是用于基本验证而不是真正的业务验证。

        【讨论】:

          【解决方案6】:

          由于最终用户的可用性,我赞成使用数据库的验证。

          在提交注册表单时,您要检查用户名在语法上是否正确以及该用户名是否尚未提供(需要数据库访问权限)。

          表单可以立即返回所有错误。它可以向用户显示所有问题。用户可以修复它并再次发送表单。

          我知道您可以使用 ajax 等更智能地做到这一点,这不是重点。

          我总是检查一切。我检查此表格是否将由即将进行的交易处理。如果没有,我会因为一些可以轻松处理的并发访问而出现异常。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-30
            • 2013-04-22
            • 2018-12-29
            • 2013-06-14
            • 2021-06-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多