【问题标题】:JSR 303 Bean Validation + Javascript Client-Side ValidationJSR 303 Bean 验证 + Javascript 客户端验证
【发布时间】:2011-01-31 14:45:09
【问题描述】:

在服务器端使用 JSR 303 bean 验证时,使用 Javascript 执行客户端表单验证(代码重复最少)的最佳方式是什么?我目前正在使用Spring 3Hibernate Validator

【问题讨论】:

    标签: java javascript spring validation bean-validation


    【解决方案1】:

    我建议您查看严重依赖 Dojo 的 Spring JS。教程可以在here找到。

    开始使用它的最简单方法是下载Spring Roo,使用示例脚本之一创建宠物诊所示例应用程序(这需要您 5 分钟),然后尝试如何集成 javascript。 Spring Roo 使用您使用的相同技术堆栈创建应用程序(Spring+hibernate+jsr 303 的实现)

    【讨论】:

      【解决方案2】:

      我找到了这个开源项目,但它看起来已经死了,也许值得复活。

      http://kenai.com/projects/jsr303js/pages/Home

      该库提供基于 JSR-303 和 Hibernate Validator 注释的 HTML 表单的客户端验证,并与 Spring MVC 集成。该库提供了一个 JavaScript 验证代码库,用于处理与 HTML 表单的基本交互,以及实现 Hibernate Validator 支持的验证注释的 JavaScript 函数(包括那些不来自 JSR-303 规范的那些)。该 JavaScript 代码库可以通过使用提供的 taglib 或通过从 jar 中提取 JavaScript 文件并使用标记包含它来包含在页面中。一旦这个代码库被包含在一个页面中,第二个 taglib 被用来生成 JavaScript 代码来验证一个 HTML 表单。您还可以在标签正文中提供 JSON 对象以指定其他配置信息。

      【讨论】:

      • 肯定会测试这个。在 bean 上设置验证并将其自动复制到客户端是可行的方法
      【解决方案3】:

      这是我使用Spring MVC + JQuery + Bootstrap 的方法,部分基于a recent blog post at SpringSource

      AddressController.java

      @RequestMapping(value="/validate")
      public @ResponseBody ValidationResponse processForm(Model model, @Valid AddressForm addressForm, BindingResult result) {
          ValidationResponse res = new ValidationResponse();
          if (result.hasErrors()) {
              res.setStatus("FAIL");
              for (ObjectError error : result.getAllErrors()) {
                  if (error instanceof FieldError) {
                      FieldError fieldError = (FieldError) error;
                      res.addError(fieldError.getField(), fieldError.getDefaultMessage());
                  }    
              }
          }
          else {
              res.setStatus("SUCCESS");
          }
          return res;
      }
      

      AddressForm.java

      public class AddressForm {
          @NotNull
          @Size(min=1, max=50, message="Address 1 is required and cannot be longer than {max} characters")
          private String address1;
      
          @Size(max=50, message="Address 2 cannot be longer than {max} characters")
          private String address2;
      
          // etc
      }
      

      ValidationResponse.java:

      public class ValidationResponse {
          private String status;
          private Map<String,String> errors;
          // getters, setters
      }
      

      地址.jsp:

      <f:form commandName="addressForm">
          <div class="control-group">
              <label for="address1">Address 1</label>
              <div class="controls">
                  <f:input path="address1" type="text" placeholder="Placeholder Address 1" class="wpa-valid" />
                  <span class="help-inline"></span>
              </div>
          </div>
          <!-- etc -->
          <div class="form-actions">
              <button type="submit" class="btn btn-primary">Save</button>
              <button type="button" class="btn">Cancel</button>
          </div>
      </f:form>
      
      <script type="text/javascript">
      function collectFormData($fields) {
          var data = {};
          for (var i = 0; i < $fields.length; i++) {
              var item = $($fields[i]);
              data[item.attr("id")] = item.val();
          }
      
          return data;
      }
      
      function clearErrors($fields) {
          for (var i = 0; i < $fields.length; i++) {
              var item = $($fields[i]);
              $("#"+item.attr("id")).parents(".control-group").removeClass("error");
              $("#"+item.attr("id")).siblings(".help-inline").html("");
          }
      }
      
      function markErrors(errors) {
          $.each(errors, function(key, val) {
              $("#"+key).parents(".control-group").addClass("error");
              $("#"+key).siblings(".help-inline").html(val);
          });
      }
      
      $(document).ready(function() {
          var $form = $("form.validate");
          $form.bind("submit", function(e) {
              var $fields = $form.find(".validate");
      
              clearErrors($fields);
              var data = collectFormData($fields);
      
              var validationUrl = "validate";
              $.get(validationUrl, data, function(response) {
                  $("#alert").removeClass();
      
                  if (response.status == "FAIL") {
                      markErrors(response.errors);
      
                      $("#alert").addClass("alert alert-error");
                      $("#alert").html("Correct the errors below and resubmit.");
                  } else {
                      $("#alert").addClass("alert alert-success");
                      $("#alert").html("Success!");
      
                      $form.unbind("submit");
                      $form.submit();
                  }
              }, "json");
      
              e.preventDefault();
              return false;
          });
      });
      </script>
      

      它可以使用一些重构,但这将使用表单数据执行 ajax GET 并根据结果更新页面。

      【讨论】:

        【解决方案4】:

        Richfaces 支持这一点。他们有一个small demo on their site

        【讨论】:

          【解决方案5】:

          PrimeFaces 客户端验证框架支持 Bean 验证。

          http://blog.primefaces.org/?p=2874

          【讨论】:

            【解决方案6】:

            这是 JSR-303 的开源替代方案。

            此解决方案可以执行请求消息的所有验证,但无需繁琐的编码。

            https://github.com/ckpoint/CheckPoint

            使用 Check-Point,只需更改 Controller 方法的注解,即可进行所有验证,无需进一步的代码。

            之后,所有验证设置都可以在管理页面中轻松进行。

            我认为这个视频可以帮助您理解。 https://youtu.be/I1aEIztXlhE

            Check-Point Admin-Page Setting Screen

            【讨论】:

              【解决方案7】:

              编辑:

              确实,JSR 303 是处理客户端验证的最佳方式 (IMO)。最好的事情是,如果你在前端有适当的 js 库,你可以在服务器上使用相同的验证(相同的代码)(如果你使用 node.js)。 为此,我创建了库 @stopsopa/validation 我正在验证这样的表单(在 React.js 中):

              import React, { Component } from "react";
              import ReactDOM from "react-dom";
              
              import validator, {
                Collection,
                Required,
                Optional,
                NotBlank,
                Length,
                Email,
              } from "@stopsopa/validator";
              
              class App extends Component {
                constructor(...args) {
                  super(...args);
                  this.state = {
                    data: {
                      name: "",
                      email: ""
                    },
                    errors: {},
                    validate: false
                  };
                }
                onSubmit = async e => {
                  e.preventDefault();
              
                  const errors = await validator(this.state.data, new Collection({
                    name: new Required([
                      new NotBlank(),
                      new Length({min: 3}),
                    ]),
                    email: new Required([
                      new NotBlank(),
                      new Email(),
                    ])
                  }));
                  this.setState({
                    errors: errors.getFlat(),
                    validate: true,
                  });
              
                  if ( ! errors.count()) {
              
                    console.log('send data to server', this.state.data);
                  }
                };
                onChange = (name, value) => {
                  this.setState(state => ({
                    ...state,
                    data: { ...state.data, ...{ [name]: value } }
                  }));
                };
                render() {
                  const s = this.state;
                  return (
                    <form onSubmit={this.onSubmit}>
                      <label>
                        name:
                        <input
                          value={s.data.name}
                          onChange={e => this.onChange("name", e.target.value)}
                        />
                      </label>
                      {s.validate && s.errors.name && (
                        <div className="error">{s.errors.name}</div>
                      )}
                      <br />
                      <label>
                        email:
                        <input
                          value={s.data.email}
                          onChange={e => this.onChange("email", e.target.value)}
                        />
                      </label>
                      {s.validate && s.errors.email && (
                        <div className="error">{s.errors.email}</div>
                      )}
                      <br />
                      <input type="submit" value="submit" />
                    </form>
                  );
                }
              }
              
              ReactDOM.render(<App />, document.getElementById("root"));
              

              现场示例可在此处获得:https://codesandbox.io/s/ymwky9603j

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-01-10
                • 2013-11-23
                • 1970-01-01
                • 2011-07-24
                • 2012-02-08
                • 2016-06-21
                • 2012-05-12
                • 1970-01-01
                相关资源
                最近更新 更多