PrimeFacesのファイルダウンロードを条件によってエラーにする

PrimeFacesにはファイルダウンロードのコンポーネントがあって、これは非常に便利なのですが、Ajax動作ができないのでダウンロードすべきデータがないときなどのエラー処理ができません。
そこで、別ボタン経由でダウンロード開始を行ってエラー処理を行うようにしてみます。


まずダウンロードデータをStreamedContentとして用意します。

    private StreamedContent content;
    
    public StreamedContent getContent() {
        return content;
    }

通常はここでデータを生成して返すのですが、ここでは用意されたデータを返すだけにしておきます。


ダウンロードコンポーネントを配置します。

<p:commandButton id="dlButton" value="ダウンロード(非表示)"
            ajax="false" style="visibility: hidden">
   <p:fileDownload id="dl" value="#{downloadBean.content}"/>
</p:commandButton>

ここで、ボタンを非表示にしておきます。また、idも指定しておきます。


実際に表示されるダウンロードボタンを置きます。

<p:commandButton value="ダウンロード" ajax="true" action="#{downloadBean.prepareContent()}"
                 oncomplete="if (!args.validationFailed) document.getElementById('form:dlButton').click()"
                 update="msg"/>

ここで、actionでデータ準備のためのprepareContentメソッドを呼び出すようにします。
準備が終わったらoncompleteで実際のダウンロードボタンを押すJavaScriptを実行します。
また、ここで「args.validationFailed」によってエラーがあったときにはJavaScriptを実行しないようにしています。


prepareContentメソッドでは次のようにエラー処理を行います。

    public void prepareContent() throws IOException{
        if(!check){//いろいろチェックを行う
            String msg = "チェックを入れてください";
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_WARN, msg, msg));
            RequestContext.getCurrentInstance().addCallbackParam("validationFailed", true);
            return;
        }

今回はチェックボックスに結びつけたchekuフィールドで判定していますが、実際にはデータの存在チェックなどの処理を行います。チェックボックスのチェックがついているかどうかであれば、required属性をつければいいので今回のような処理は必要ありません。


エラーメッセージはFacesContextに追加します。
このメッセージはメッセージコンポーネントで表示させます。

<p:messages id="msg"/>

ボタンに「update="msg"」としてボタン押下後に表示を更新するようにしています。


JavaScriptでの判定で使っていたvalidationFaildパラメータは、バリデーションフェーズでエラーになったときには自動的に設定されますが、処理中では改めてRequestContextに追加する必要があります。

RequestContext.getCurrentInstance().addCallbackParam("validationFailed", true);


以上で、チェックが通らなければ処理を中断してメッセージを出すことが実現できます。


全体のソースはこちら
DownloadBean.java

package pfsample;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import org.primefaces.context.RequestContext;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

/**
 *
 * @author naoki
 */
@ManagedBean
@ViewScoped
public class DownloadBean {
    private boolean check;
    public boolean isCheck() {
        return check;
    }
    public void setCheck(boolean check) {
        this.check = check;
    }
    
    private StreamedContent content;
    
    public StreamedContent getContent() {
        return content;
    }
    public void prepareContent() throws IOException{
        if(!check){//いろいろチェックを行う
            String msg = "チェックを入れてください";
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_WARN, msg, msg));
            RequestContext.getCurrentInstance().addCallbackParam("validationFailed", true);
            return;
        }
        
        BufferedImage bi = new BufferedImage(400, 300, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = (Graphics2D) bi.getGraphics();
        g.setColor(new Color(212,228,255));
        g.fillRect(0, 0, 400, 300);
        g.setColor(Color.ORANGE);
        g.fillOval(100, 50, 200, 200);
        g.setColor(Color.BLUE);
        g.fillRect(0, 160, 400, 140);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", baos);
        
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        content = new DefaultStreamedContent(bais, "image/png", "sample.png");
    }
}


sample.xml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">

    <f:view contentType="text/html">
        <h:head>
            <meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
            <title>PrimeFaces</title>
        </h:head>

        <h:body>
            <h:form id="form">
                <p:messages id="msg"/>
                <div>画像ダウンロード</div>
                <p:selectBooleanCheckbox itemLabel="ダウンロード許可"
                                         value="#{downloadBean.check}"/>
                <p:commandButton value="ダウンロード" ajax="true" action="#{downloadBean.prepareContent()}"
                                 oncomplete="if (!args.validationFailed) document.getElementById('form:dlButton').click()"
                                 update="msg"/>
                <p:commandButton id="dlButton" value="ダウンロード(非表示)"
                                 ajax="false" style="visibility: hidden">
                    <p:fileDownload id="dl" value="#{downloadBean.content}"/>
                </p:commandButton>
            </h:form>

        </h:body>

    </f:view>
</html>