简体   繁体   中英

PrimeFaces <p:fileUpload mode="advanced"> validator not fired

since fileLimit doesn't exist in primefaces 3.4 anymore I'm trying a work around implementing a validator, the problem is that the method validate is never invoked. That's my Validator:

@FacesValidator(value ="fileLimitValidator")
public class FileLimitValidator implements Validator {

    @Override
    public void validate(final FacesContext context, final UIComponent component,
            final Object value) throws ValidatorException {

        final String fileLimit = (String)component.getAttributes().get("fileLimit");
        final String size = (String)component.getAttributes().get("size");

        if (fileLimit!=null && size!=null) {
            if (Integer.valueOf(size) >= Integer.valueOf(fileLimit)) {
                FacesUtils.throwErrorExceptionFromComponent(component,"fichero_confidencialidad_error");
            }
        }
    }
}

and in my facelet I've tried:

    <p:fileUpload id="#{id}FileUpload"
        fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
        multiple="true" allowTypes="#{allowTypes}" showButtons="false"
        update="#{id}ListaDocs #{id}MsgError" auto="true"
        label="#{fileuploadmsg.label_boton}"
        invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" >

        <f:validator validatorId="fileLimitValidator"/>
        <f:attribute name="fileLimit" value="#{fileLimit}"/>
        <f:attribute name="size" value="#{listaDocumentos.size}"/>
    </p:fileUpload>

and:

    <p:fileUpload id="#{id}FileUpload"
        fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
        multiple="true" allowTypes="#{allowTypes}" showButtons="false"
        update="#{id}ListaDocs #{id}MsgError" auto="true"
        label="#{fileuploadmsg.label_boton}"
        invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" 
        validator="fileLimitValidator">

        <f:attribute name="fileLimit" value="#{fileLimit}"/>
        <f:attribute name="size" value="#{listaDocumentos.size}"/>
    </p:fileUpload>

and:

    <p:fileUpload id="#{id}FileUpload"
        fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
        multiple="true" allowTypes="#{allowTypes}" showButtons="false"
        update="#{id}ListaDocs #{id}MsgError" auto="true"
        label="#{fileuploadmsg.label_boton}"
        invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" 
        validator="#{fileLimitValidator}">

        <f:attribute name="fileLimit" value="#{fileLimit}"/>
        <f:attribute name="size" value="#{listaDocumentos.size}"/>
    </p:fileUpload>

and:

    <p:fileUpload id="#{id}FileUpload"
        fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
        multiple="true" allowTypes="#{allowTypes}" showButtons="false"
        update="#{id}ListaDocs #{id}MsgError" auto="true"
        label="#{fileuploadmsg.label_boton}"
        invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" 
        validator="#{fileLimitValidator.validate}">

        <f:attribute name="fileLimit" value="#{fileLimit}"/>
        <f:attribute name="size" value="#{listaDocumentos.size}"/>
    </p:fileUpload>

but the validate method is never called. What is the correct way to do it?

According to the FileUpload and FileUploadRenderer source code, the validator is only invoked when mode="simple" is been used (note: this in turn requires ajax="false" on command). The advanced mode will namely not set the uploaded file as component's submitted value, causing it to remain null until the listener method is invoked. As long as the submitted value is null , the validators are not invoked.

I'm not sure if this is intentional. Theoretically, it should be possible to set UploadedFile as submitted value and have the validator to rely on it. You might want to create an enhancement report at PrimeFaces issue tracker .

In the meanwhile, in spite of it being a poor practice , your best bet is really performing the validation in fileUploadListener method. You can just trigger validation failure add faces messages through the FacesContext like follows:

if (fail) {
    context.validationFailed();
    context.addMessage(event.getComponent().getClientId(context), new FacesMessage(
        FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
}

Otherwise, you'd need to create a custom renderer for the <p:fileUpload> which sets the submitted value during the decode() (I however don't guarantee that it would work in practice, you'll maybe stumble upon a peculiar problem which may turn out to be the reason why PrimeFaces didn't initially implement it like that).

By the way, your first and second validator attempt are correct. The third attempt works only if you used @ManagedBean instead of @FacesValidator ( which is often done when injection of an @EJB is mandatory — which isn't possible in a @FacesValidator ). The fourth attempt is invalid.

For validating a required primefaces file upload in mode advanced (ajax) it is possible to use this:

<f:metadata>
    <f:event listener="#{bean.processValidations()}" type="postValidate" />
</f:metadata>

Where the implementation of the bean.processValidations() method would be something along the lines of:

public void processValidations() {
        FacesContext context = FacesContext.getCurrentInstance();
        UIInput fileUploadComponent = fileUploadsBean.getFileUploadComponent();
        if (fileUploadComponent!=null && !isFileUploaded()) {
            fileUploadComponent.setValid(false);
            context.addMessage(fileUploadComponent.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
            context.validationFailed();
        }
    }

Where fileUploadsBean would be a REQUEST scoped CDI bean (won't work with standard JSF ManagedBeans) which you inject to your bean which has the processValidations() method defined, the method fileUploadsBean.getFileUploadComponent() returns the primefaces file upload component (you will use <p:fileUpload binding="#{fileUploadsBean.fileUploadComponent}" ...> for that). The method isFileUploaded() will determine if the file has been uploaded or not (probably just a null check on a member variable which you fill from fileUploadListener).

If you want to highlight the file upload button you can of course conditionally add a styleClass which you can then use for adding a red border for example.

styleClass="#{fileUploadsBean.fileUploadComponent.valid ? '' : 'validationFailed'}"

As a result the validation failed message for the primefaces file upload will be displayed along with all other jsf validation messages. You might have problem with maintaining order of the validation messages (will be always at the end), but it still beats displaying the failed upload file validation after user dealt with all the standard jsf validation messages from different fields and your action in a backing bean has been finally reached.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM