【发布时间】:2011-11-27 17:32:36
【问题描述】:
我想构建一个应用程序,其中通过 Ajax 提交表单而无需重新加载完整的页面。要显示服务器端验证错误,服务器应将验证错误作为 JSON 和适当的 HTTP 状态 (400) 返回。
如何通过 Play 实现这一点!框架?
【问题讨论】:
标签: java ajax json validation playframework
我想构建一个应用程序,其中通过 Ajax 提交表单而无需重新加载完整的页面。要显示服务器端验证错误,服务器应将验证错误作为 JSON 和适当的 HTTP 状态 (400) 返回。
如何通过 Play 实现这一点!框架?
【问题讨论】:
标签: java ajax json validation playframework
您是否正在寻找比这更复杂的东西:
public static void yourControllerMethod() {
... // your validation logic
if (validation.hasErrors()) {
response.status = 400;
renderJSON(validation.errors);
}
}
【讨论】:
查看 samples-and-tests 文件夹和验证应用程序。其中一个示例 (Sample7) 使用名为 jQueryValidate 的自定义标记(您可以在示例中看到)完全按照您的要求进行操作。
如果你尝试这个示例,你会发现它是一个非常简洁的解决方案,在我看来,这种验证方法应该是 Core Playframework 的一部分。
【讨论】:
在 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 可以帮助那些不知道的人:)
为了对您的请求执行服务器端验证,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"
]
}
除此之外,您还可以将多个约束应用于类字段。其中一些是,
【讨论】:
既然您提到了[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 相比,这种方法通常需要更少的行,并且在用于非常复杂的请求时确实非常出色。
【讨论】: