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>