你们中有些人已经知道我和我的合著者MertÇalışkan正在研究PrimeFaces Cookbook的2.版。 Packt Publishing允许我从新章节“客户端验证”的一个食谱中摘录一小部分摘录。 这将有助于使读者知道这本书的内容。 在此博客文章中,我想讨论使用Bean验证扩展的PrimeFaces客户端验证(CSV)。
Bean Validation是一个验证模型,可作为Java EE 6平台的一部分使用,它允许通过约束将字段,方法或类上的批注形式的验证。 JSF 2.2支持对托管bean以及Spring或CDI bean中的字段(属性及其getter / setter)的验证。 只要不使用OmniFaces之类的实用程序,尚不支持在类级别进行验证。
PrimeFaces的CSV具有与Bean验证的内置集成。 注释定义的约束可以通过CSV框架在客户端进行验证。 尽管Bean Validation API定义了一整套标准约束注释,但可以轻松想到这些标准注释不足的情况。 对于这些情况,您可以为特定的验证要求创建自定义约束。 PrimeFaces中的客户端验证API与自定义约束无缝协作。
在本食谱中,我们将开发一种特殊的自定义约束和验证器,以验证卡验证码( CVC )。 CVC用作带有银行卡号的安全功能。 它是一个长度在三到四位数之间的数字。 例如,万事达卡或维萨卡要求输入三位数,而美国运通卡要求输入四位数。 因此,CVC验证将取决于所选的银行卡。 用户可以通过p:selectOneMenu
选择银行卡,然后在p:inputText
中输入CVC,然后提交输入。
怎么做…
我们将从用于CVC字段的自定义注释开始。
import org.primefaces.validate.bean.ClientConstraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;@Constraint(validatedBy = CvcConstraintValidator.class)
@ClientConstraint(resolvedBy = CvcClientConstraint.class)
@Target({FIELD, METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCVC {String message() default "{invalid.cvc.message}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};// identifier of the select menu with cardsString forCardMenu() default "";
}
@Constraint是Bean验证API的常规注解,而@ClientConstraint
是PrimeFaces CSV框架的注解,它有助于解析元数据。 开发的注释定义消息密钥invalid.cvc.message
并且具有Custom属性forCardMenu
。 此属性的值是任何有关PrimeFaces Selectors (PFS)
搜索表达式,用于引用银行卡的选择菜单。 这是必需的,因为有效的CVC值取决于所选的卡。
CvcConstraintValidator
的目标是验证输入长度。
public class CvcConstraintValidator implements ConstraintValidator<ValidCVC, Integer> {@Overridepublic void initialize(ValidCVC validCVC) {}@Overridepublic boolean isValid(Integer cvc, ConstraintValidatorContext context) {if (cvc == null || cvc < 0) {return false;}int length = (int) (Math.log10(cvc) + 1);return (length >= 3 && length <= 4);}
}
CvcClientConstraint
的目标是准备元数据。
public class CvcClientConstraint implements ClientValidationConstraint {private static final String CARDMENU_METADATA = "data-forcardmenu";@Overridepublic Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) {Map<String, Object> metadata = new HashMap<String, Object>();Map attrs = constraintDescriptor.getAttributes();String forCardMenu = (String) attrs.get("forCardMenu");if (StringUtils.isNotBlank(forCardMenu)) {metadata.put(CARDMENU_METADATA, forCardMenu);}return metadata;}@Overridepublic String getValidatorId() {return ValidCVC.class.getSimpleName();}
}
让我们转到客户端实现。 首先,我们必须创建一个JavaScript文件,说validators.js
,并命名空间中的注册有自己的验证PrimeFaces.validator
名为ValidCVC
。 此名称是由getValidatorId()
方法返回的唯一ID(请参阅类CvcClientConstraint
)。 要实现的功能称为validate()
。 它有两个参数:元素本身和要验证的当前输入值。
PrimeFaces.validator['ValidCVC'] = {MESSAGE_ID: 'invalid.cvc',validate: function (element, value) {// find out selected menu valuevar forCardMenu = element.data('forcardmenu');var selOption = forCardMenu ?PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(forCardMenu).find("select").val() : null;var valid = false;if (selOption && selOption === 'MCD') {// MasterCardvalid = value > 0 && value.toString().length == 3;} else if (selOption && selOption === 'AMEX') {// American Expressvalid = value > 0 && value.toString().length == 4;}if (!valid) {throw PrimeFaces.util.ValidationContext.getMessage(this.MESSAGE_ID);}}
};
其次,我们必须为本地化消息创建一个JavaScript文件,例如lang_en.js
。
PrimeFaces.locales['en'] = {messages : PrimeFaces.locales['en_US'].messages
};$.extend(PrimeFaces.locales['en'].messages, {...'invalid.cvc':'Card Validation Code is invalid'
});
Bean具有两个必需属性,并用@NotNull
注释。 另外,属性cvc
带有我们的自定义注释@ValidCVC
。 forCardMenu
的属性forCardMenu
指向列出可用银行卡的p:selectOneMenu
的样式类。
@Named
@ViewScoped
public class ExtendCsvBean implements Serializable {@NotNullprivate String card;@NotNull@ValidCVC(forCardMenu = "@(.card)")private Integer cvc;public void save() {RequestContext.getCurrentInstance().execute("alert('Saved!')");}// getters / setters...
}
在XHTML片段中,我们有一个带有两个银行卡的选择菜单和一个CVC输入字段。 p:commandButton
验证字段并在回发时执行方法save()
。
<h:panelGrid id="pgrid" columns="3" cellpadding="3" style="margin-bottom:10px;"><p:outputLabel for="card" value="Card"/><p:selectOneMenu id="card" styleClass="card"value="#{extendCsvBean.card}"><f:selectItem itemLabel="Please select a card"itemValue="#{null}"/><f:selectItem itemLabel="MasterCard"itemValue="MCD"/><f:selectItem itemLabel="American Express"itemValue="AMEX"/></p:selectOneMenu><p:message for="card"/><p:outputLabel for="cvc" value="CVC"/><p:inputText id="cvc" value="#{extendCsvBean.cvc}"/><p:message for="cvc"/>
</h:panelGrid><p:commandButton validateClient="true" value="Save"process="@this pgrid" update="pgrid" action="#{extendCsvBean.save}"/>
注意:如您所见, p:selectOneMenu
和p:inputText
指定必需的属性。 我们可以实现的转变@NotNull
注释与价值所需要的属性, true
,如果我们设置的参数范围内primefaces.TRANSFORM_METADATA
至true
。
在最后一步中,所有必需JavaScript文件都必须包含在页面上。
<h:outputScript library="js" name="chapter10/lang_en.js"/>
<h:outputScript library="js" name="chapter10/validators.js"/>
下两张图片显示验证失败时会发生什么
如果一切正常,则出现一个带有已保存文本的警告框。 向用户显示。
怎么运行的…
消息密钥invalid.cvc.message
和文本应放在名为ValidationMessages
资源包中,例如ValidationMessages_en.properties
。 ValidationMessages
是Bean验证规范中指定的标准名称。 属性文件应位于应用程序类路径中,并包含以下条目: invalid.cvc.message=Card Validation Code is invalid
。 此配置对于服务器端验证很重要。
类CvcClientConstraint
中的getMetadata()
方法提供了一个具有名称,值对的映射。 元数据在呈现HTML中公开。 可以通过element.data(name)
在客户端访问这些值,其中element是基础本机HTML元素的jQuery对象。 具有元数据的CVC字段呈现为
<input type="text" data-forcardmenu="@(.card)"data-p-con="javax.faces.Integer" data-p-required="true"...>
最有趣的部分是客户端验证器的实现。 要验证的值已经是数字,因为首先它由PrimeFaces的内置客户端转换器针对数据类型java.lang.Integer
转换。 我们只需要检查该值是否为正且具有有效长度。 有效长度取决于菜单p:selectOneMenu
中所选的卡片,PrimeFaces JavaScript API可以使用PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(selector)
对其进行访问,其中选择器是任何PrimeFaces选择器,在我们的示例中为@(.card)
。 如果验证失败,则通过引发throw PrimeFaces.util.ValidationContext.getMessage(text, parameter)
引发异常。
通过在p:commandButton
上设置validateClient=”true”
来触发客户端验证。
翻译自: https://www.javacodegeeks.com/2015/01/extending-primefaces-csv-with-bean-validation.html