使用Bean验证扩展PrimeFaces CSV

你们中有些人已经知道我和我的合著者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 cards
    String 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> {

    @Override
    public void initialize(ValidCVC validCVC) {
    }

    @Override
    public 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";

    @Override
    public 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;
    }

    @Override
    public 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 value
        var forCardMenu = element.data('forcardmenu');
        var selOption = forCardMenu ?
            PrimeFaces.expressions.SearchExpressionFacade.
                resolveComponentsAsSelector(forCardMenu).find("select").val() : null;

        var valid = false;
        if (selOption && selOption === 'MCD') {
            // MasterCard
            valid = value > 0 && value.toString().length == 3;
        } else if (selOption && selOption === 'AMEX') {
            // American Express
            valid = 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带有我们的自定义注释@ValidCVCforCardMenu的属性forCardMenu指向列出可用银行卡的p:selectOneMenu的样式类。

@Named
@ViewScoped
public class ExtendCsvBean implements Serializable {

    @NotNull
    private 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:selectOneMenup:inputText指定必需的属性。 我们可以实现的转变@NotNull注释与价值所需要的属性, true ,如果我们设置的参数范围内primefaces.TRANSFORM_METADATAtrue

在最后一步中,所有必需JavaScript文件都必须包含在页面上。

<h:outputScript library="js" name="chapter10/lang_en.js"/>
<h:outputScript library="js" name="chapter10/validators.js"/>

下两张图片显示验证失败时会发生什么

3427_10_04

3427_10_05

如果一切正常,则出现一个带有已保存文本的警告框。 向用户显示。

3427_10_06

怎么运行的…

消息密钥invalid.cvc.message和文本应放在名为ValidationMessages资源包中,例如ValidationMessages_en.propertiesValidationMessages是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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值