9

新しいブラウザウィンドウで開いたインラインPDFを表示しようとしています。私は次のシナリオを持っています:

  1. ajaxによって呼び出される一部のActionListenでは、PDFコンテンツを生成し、データをセッションに入れ、実行するJavascriptを送信します(window.openPDFを表示するために新しいページを開くため)
  2. 開いたページには、値が指すp:mediaタグが含まれています。h:bodyStreamedContent

さて、そのページでは私のPDFは生成されません。ログには、次の2行が表示されます。

org.primefaces.application.PrimeResourceHandler handleResourceRequest
SEVERE: Error in streaming dynamic resource. Expression cannot be null

私はデバッグを開始し、いくつかのことを見つけました。

まず、Bean@PostConstructのメソッドにブレークポイントを追加しました。RequestScoped興味深いのは、ブレークポイントに2回到達したことです。その後、PDFが完全に表示されたので、驚いたことになります。

いくつかのデバッグをPrimeResourceHandler行った後、場合によってValueExpressionは計算されないことがわかりました。実際にはがスローされますNullPointerException。また、デバッグ中に2つのリクエストが送信dynamicContentIdされ、最初のリクエストで削除されたために2番目のリクエストが失敗し、2番目の呼び出しはhandleResourceRequest失敗することがわかりました。意味があります。

Firebugを介して、2つのリクエストを確認できます。1つはPDFデータに適しています。もう1つはコンテンツタイプのapplication / pdfにありますが、サイズが0の空です。

xhtmlページ:

<html>
  <h:head></h:head>
  <h:body>
    <p:media value="#{reportBean.streamedContent}" player="pdf" width="500" height="500"/>
  </h:body>
</html>

バッキングビーン:

@RequestScoped
public class StampaListeBackingBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private StreamedContent streamedContent;

    @PostConstruct
    public void init() {
        Map<String, Object> session = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
        byte[] b = (byte[]) session.get("reportBytes");
        if (b != null) {
            streamedContent = new DefaultStreamedContent(new ByteArrayInputStream(b), "application/pdf");
        }
    }

    public StreamedContent getStreamedContent() {
        if (FacesContext.getCurrentInstance().getRenderResponse()) {
            return new DefaultStreamedContent();
        } else {
            return streamedContent;
        }
}

    public void setStreamedContent(StreamedContent streamedContent) {
        this.streamedContent = streamedContent;
    }
}

2つのリクエストがp:mediaタグ付きのページで送信される理由を理解し、これを機能させる方法を理解する必要があります。バッキングBeanはリクエストスコープであり、メソッドで作成StreamedContentされ@PostConstruct、そのフィールドにゲッターとセッターがあります。Primefacesのバージョンは3.4.2で、Mojarra2.1.14を使用しています。

追加した:

私の問題を再現するのは簡単です。メソッド内のコードがinit次のように置き換えられた場合:

FileInputStream fis = new FileInputStream(new File("C:\\samplexxx.pdf"));
streamedContent = new DefaultStreamedContent(fis, "application/pdf");

問題を再現できます。

4

3 に答える 3

10

私はあなたの問題を再現することができます。実際、Firefoxでは機能しません(IE9でも機能しませんが、Chromeでは機能します)。PrimeFacesのリードであるCagatayも、何度か言及しています。

これがPrimeFacesリソースハンドラーのバグなのかブラウザのバグなのかわかりません。真ん中に残しておきます。

その間、最善の策は、その仕事のための単純なWebサーブレットです。このクラスを作成するだけです。

@WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] content = (byte[]) request.getSession().getAttribute("reportBytes");
        response.setContentType("application/pdf");
        response.setContentLength(content.length);
        response.getOutputStream().write(content);
    }

}

そして、次のように呼び出します。

<p:media value="/report.pdf" ... />

それでおしまい。XML構成は必要ありません。それはすべてのブラウザで私のために働きます。機能要件によっては、ブラウザーのキャッシュに関連する応答ヘッダーをさらに微調整することをお勧めします。

于 2013-01-23T20:52:28.533 に答える
6

これはブラウザやプライムフェイスの問題ではなく、面白​​いゲティア問題です。

ゲッターはp:mediaによって2回呼び出されます(またはページを複数回更新した場合)が、最初の呼び出しのみが正しいデータを取得します。StreamedContentは、InputStreamをカプセル化します。これには、ストリームがファイルの最後にある場合はバイトを与えないというプロパティがあります。初めて最後まで読み取られますが(データは問題ありません)、次の呼び出しごとにデータは取得されません。:)

inputStream.read()のjavadocストリームがファイルの最後にあるために使用可能なバイトがない場合、値-1が返されます。それ以外の場合は、少なくとも1バイトが読み取られてbに格納されます。

解決策

            private StreamedContent streamedContent;
            private InputStream stream;


            public void somewhere(){
                byte[] b = ...
                stream = new ByteArrayInputStream( b );
                stream.mark(0); //remember to this position!
                streamedContent = new DefaultStreamedContent(stream, "application/pdf");
            }


            public StreamedContent getStreamedContent() {
                if (streamedContent != null)
                    streamedContent.getStream().reset(); //reset stream to the start position!
                return streamedContent;
            }
于 2014-06-17T06:13:50.277 に答える
3

私の小さな貢献が、FirefoxでPDFプレビューを表示できない人に役立つことを願っています。Primefaces 6 + Springを使用していて、同じ問題が発生しましたが、同じ理由ではない可能性があります。実際、私はBalus Cによって提案されたソリューションを試しました。これは、ChromeとIE11でPDFを表示するのに役立ちましたが、Firefox52ではまだ機能していませんでした。

Firefoxコンソールでエラーに気づきました:X-Frameによってロードが拒否されました-オプション:http:// localhost:8080 /myapp/はフレーミングを許可しません

私の場合、これは、spring-securityの構成と解決策がspring-context.xmlを次のように編集したためです。

<sec:http ...>
...
<sec:headers>        		
         <sec:frame-options policy="SAMEORIGIN" />
</sec:headers>
...
</sec:http>

于 2017-04-02T00:04:14.053 に答える