【问题标题】:Returning validation errors as JSON with Play! framework使用 Play 以 JSON 形式返回验证错误!框架
【发布时间】:2011-11-27 17:32:36
【问题描述】:

我想构建一个应用程序,其中通过 Ajax 提交表单而无需重新加载完整的页面。要显示服务器端验证错误,服务器应将验证错误作为 JSON 和适当的 HTTP 状态 (400) 返回。

如何通过 Play 实现这一点!框架?

【问题讨论】:

    标签: java ajax json validation playframework


    【解决方案1】:

    您是否正在寻找比这更复杂的东西:

    public static void yourControllerMethod() {
        ... // your validation logic
    
        if (validation.hasErrors()) {
           response.status = 400;
           renderJSON(validation.errors);
        }
    }
    

    【讨论】:

      【解决方案2】:

      查看 samples-and-tests 文件夹和验证应用程序。其中一个示例 (Sample7) 使用名为 jQueryValidate 的自定义标记(您可以在示例中看到)完全按照您的要求进行操作。

      如果你尝试这个示例,你会发现它是一个非常简洁的解决方案,在我看来,这种验证方法应该是 Core Playframework 的一部分。

      【讨论】:

        【解决方案3】:

        在 Play Framework 2.x 和 Scala 中,您可以使用以下示例:

        import play.api.libs.json._
        
        case class LoginData(email : String, password: String)
        
        implicit object FormErrorWrites extends Writes[FormError] {
          override def writes(o: FormError): JsValue = Json.obj(
            "key" -> Json.toJson(o.key),
            "message" -> Json.toJson(o.message)
          )
        }
        
        val authForm = Form[LoginData](mapping(
          "auth.email" -> email.verifying(Constraints.nonEmpty),
          "auth.password" -> nonEmptyText
          )(LoginData.apply)(LoginData.unapply))
        
        def registerUser = Action { implicit request =>
         authForm.bindFromRequest.fold(
          form => UnprocessableEntity(Json.toJson(form.errors)),
          auth => Ok(Json.toJson(List(auth.email, auth.password)))
         )
        }
        

        我看到这个问题标有 java 标签,但我想这可能对 Scala 开发人员有用。

        【讨论】:

        • 上述的导入语句应该包括import play.api.libs.json._,并且当您转换表单错误时,隐式对象很可能作为可重用实体存在于您的控制器中(注意表单点错误)而不是任何东西案例类本身独有。一旦你知道了这一切,那就很明显了,但 stackoverflow 可以帮助那些不知道的人:)
        • 感谢提示,我已添加导入。
        【解决方案4】:

        为了对您的请求执行服务器端验证,Play 框架提供了一个内置验证模块,该模块在后台使用 Hibernate Validator

        假设你有一个对应传入请求的 POJO 类,

        import play.data.validation.Constraints;
            public class UserRequest{       
            @Constraints.Required
            private String userName;
        
            @Constraints.Required
            private String email;
        }
        

        可以从控制器执行请求验证,如下所示。

        public class UserController extends Controller{
        Form<UserRequest> requestData = Form.form(UserRequest.class).bindFromRequest();
            if(requestData.hasErrors()){
                return badRequest(requestData.errorsAsJson());
            } else{
                //... successful validation
            }
        }
        

        如果请求验证失败,将产生以下响应。

        {
          "userName": [
            "This field is required"
          ],
          "email": [
            "This field is required"
          ]
        }
        

        除此之外,您还可以将多个约束应用于类字段。其中一些是,

        • @Constraints.Min()
        • @Constraints.Max()
        • @Constraints.Email

        【讨论】:

          【解决方案5】:

          既然您提到了[java] 标签,我暗示您使用的是Java 版本的Play 框架。此外,我看不到任何指向无法使用任何第三方库的前提。基于此,您可以使用validol 验证库,鼓励declarative style

          考虑以下请求,它可以是一种注册请求,但为简洁起见,由单个 payment 块组成:

          {
              "payment":{
                  "card_number":12345612341234,
                  "expires_at":"12/29"
              }
          }
          

          验证逻辑是一个不可变的表达式,表示为一个类:

          public class ValidatedRegistrationRequest implements Validatable<RegistrationRequest>
          {
              private String jsonRequestString;
              private Connection dbConnection;
          
              public ValidatedRegistrationRequest(String jsonRequestString, Connection dbConnection)
              {
                  this.jsonRequestString = jsonRequestString;
                  this.dbConnection = dbConnection;
              }
          
              @Override
              public Result<RegistrationRequest> result() throws Exception
              {
                  return
                      new FastFail<>(
                          new WellFormedJson(
                              new Unnamed<>(Either.right(new Present<>(this.jsonRequestString)))
                          ),
                          requestJsonObject ->
                              new UnnamedBlocOfNameds<>(
                                  List.of(
                                      new FastFail<>(
                                          new IsJsonObject(
                                              new Required(
                                                  new IndexedValue("payment", requestJsonObject)
                                              )
                                          ),
                                          paymentJsonObject ->
                                              new NamedBlocOfNameds<>(
                                                  "payment",
                                                  List.of(
                                                      new ValidThrueIsNotExpired(
                                                          new AsString(
                                                              new Required(
                                                                  new IndexedValue("valid_thru", paymentJsonObject)
                                                              )
                                                          )
                                                      ),
                                                      new CardNumberIsNotBlacklisted(
                                                          new CardNumberSatisfiesLuhnAlgorithm(
                                                              new Required(
                                                                  new IndexedValue("card_number", paymentJsonObject)
                                                              )
                                                          ),
                                                          this.dbConnection
                                                      )
                                                  ),
                                                  Payment.class
                                              )
                                      )
                                  ),
                                  RegistrationRequest.class
                              )
                      )
                          .result()
                      ;
              }
          }
          

          没有方便的方法在 SO 上显示行号,但这里是上面代码的line-by-line analysis

          与 JSON Schema 相比,这种方法通常需要更少的行,并且在用于非常复杂的请求时确实非常出色。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-04-08
            • 2020-01-23
            • 1970-01-01
            • 1970-01-01
            • 2018-10-26
            • 1970-01-01
            • 1970-01-01
            • 2016-10-30
            相关资源
            最近更新 更多