一个实体只允许一个 @PrePersist 和一个 @PreUpdate 方法,因此在运行以上代码前,必须注释 recalculateDeliveryDays() 中的 @PrePersiste 和 @PreUpdate 注解,方法如下:
// @PrePersist @PreUpdate // 注释这些注解
private void recalculateDeliveryDays() {
setDeliveryDays(getEstimatedDeliveryDays());
}
别担心,我们稍后会取消注释。尽管 JPA 只允许一个 @PrePersist 和 @PreUpdate 方法,但还是可以只创建一个回调方法并从中调用其他所需的方法,不过在此案例不需要,因为我们不会保留这验证的方法。
现在,试着在发票添加未送达的订单,可以看到如上一章所显示一样的验证错误。
在 setter 中验证
另一种进行验证的方法是将验证逻辑放在 setter 方法中,这是一个简单的方法。
首先,我们先取消 recalculateDeliveryDays() 中 @PrePersist 和 @PreUpdate 的注释,同时从 Order 实体中删除 validate() 方法:
@PrePersist @PreUpdate // 将注解添加回来
private void recalculateDeliveryDays() {
setDeliveryDays(getEstimatedDeliveryDays());
}
// 刪除 validate() 方法
// @PrePersist @PreUpdate // 在新建或更改之前
// private void validate() throws Exception {
// if (invoice != null && !isDelivered()) { // 验证逻辑
// // Bean Validation 的验证异常
// throw new javax.validation.ValidationException(
// XavaResources.getString(
// "order_must_be_delivered",
// getYear(),
// getNumber()
// )
// );
// }
// }
再来将以下 setter:setInvoice() 方法添加到 Order:
public void setInvoice(Invoice invoice) {
if (invoice != null && !isDelivered()) { // 验证逻辑
// Bean Validation 的验证异常
throw new javax.validation.ValidationException(
XavaResources.getString(
"order_must_be_delivered",
getYear(),
getNumber()
)
);
}
this.invoice = invoice; // 常规的setter
}
这与上两个方法的运作方式完全相同。这一个很像 @PrePersist/@PreUpdate 的方案,只是它不依赖 JPA,它是一个基本 Java 的实现。
使用 Bean Validation 进行验证
作为最后一个选项,也是最短的一个:是将验证逻辑放在一个使用数据校验 @AssertTrue 注解的布尔方法(boolean)。
要实现这个方案,首先删除 setInvoice() 方法:
// 移除 setter 方法
// public void setInvoice(Invoice invoice) {
// if (invoice != null && !isDelivered()) { // 验证逻辑
// // Bean Validation 的验证异常
// throw new javax.validation.ValidationException(
// XavaResources.getString(
// "order_must_be_delivered",
// getYear(),
// getNumber()
// )
// );
// }
// this.invoice = invoice; // 常规的setter
// }
然后将 isDeliveredToBeInvoice() 方法添加到您的 Order 实体:
@AssertTrue( // 在保存之前會確認此方法是否返回 true,不是的話則抛出异常
message="order_must_be_delivered" // 如果为 false 的错误消息
)
private boolean isDeliveredToBeInInvoice() {
return invoice == null || isDelivered(); // 验证逻辑
}
在之前的验证方法中,错误的消息是使用两个参数构造的(year 和 number),它们在 i18n 文件中,分别代表 {0}/{1}。而对于带有@AssertTrue 的验证方法,我们不能使用这两个参数来构造我们的错误消息,但我们可以在消息的定义中声明 已验证 bean 的属性和合格属性(properties 和 qualified properties),因此须在 invoicing-messages_zh.properties 中,把:
order_must_be_delivered=订单 {0}/{1} 必须已送达才能添加到发票中
更改为:
order_must_be_delivered=订单 {year}/{number} 必须已送达才能添加到发票中
可以看到我们将 {0}/{1} 更改为 {year}/{number}。 OpenXava 将使用那些正要更新但不满足验证条件的 Order 的 year 和 number 值填充 {year}/{number}。
这是最简单的验证方法,因为只需对带有验证的方法进行注解。数据校验会负责在保存时调用该方法,如果验证不成功则抛出相应的 ValidationException。
总结
在本章,您学到了几种在 OpenXava 应用程序中进行验证的方法。在下一课中,您将学习如何在移除时进行验证,由此您将已探索所有类型的验证。