読者の皆様、ご挨拶! この記事では、開発中に発生した問題の1つと、その解決方法の概要を説明しました。 もちろん、解決策は最も完璧ではありませんが、あるべき場所があります。 気に入らない場合、または解決策をよく知っている場合は、私はまだ小さくて緑なので、大きなきゅうりで私を倒さないでください。 コメントと教えで小さなものを打ち負かしてください。
タスクは次のとおりです。レポートが表示されるページがあるシステムがあります。 そこで、Excelファイルの形成を実装し、それをユーザーにアップロードする必要があります。
このページの構造は次のようになっており、上の画像に表示されています。
さらに、機能はテーブルが非常に大きく、Excelで多くのレコードをアップロードする必要があることです。
また、行をクリックすると、レコードを編集するためのパネルが表示されます。
コード生成ファイル:
public void generatePatientsExcel() { try{ log.info("Generating patients excel"); FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); HttpServletResponse response = (HttpServletResponse) externalContext.getResponse(); //Create excel file Workbook wb = new HSSFWorkbook(); // // // // // // Header response.setHeader("Content-disposition", "attachment; filename=1.xls"); response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.ms-excel"); //Send Response ServletOutputStream responseOutputStream = response.getOutputStream(); wb.write(responseOutputStream); responseOutputStream.flush(); responseOutputStream.close(); facesContext.responseComplete(); log.info("Generating patients excel comlplete"); } catch (Exception ex) { ex.printStackTrace(); } }
まあ、実際には問題
問題は、ファイルがアップロードされると、その形成に時間がかかることです。その瞬間に行をクリックすると、次のようになります。
org.jboss.seam.ConcurrentRequestTimeoutException: Concurrent call to conversation
これを防ぐには、ローダーを表示するJavaScriptファイル関数を生成する前にonclickをハングアップする必要があります。 そして、アクションの後、JavaScript関数をoncompleteでハングさせて非表示にします。 すべてがシンプルなようですね。
落とし穴
ファイルを動的に生成するため、ディスクに保存しないため、ファイルが置かれているHttpServletResponseではなく、ファイルがディスクに保存されているリンクをクリックすることでタスクを簡単にすることができます。 ただし、これにはサーバーのディスク領域が必要になるため、ファイルを動的に形成することが必要です。
問題は、h:commandButtonボタンにoncompleteがないことです。 一般に、すべての「h:」要素にはこのイベントはありません。 少し考えて:「一般的に、なぜこのh:commandButtonが必要なのですか? 結局のところ、魔法のようなa4j:commandButtonがあります。
a4j:commandButtonを介してファイルをアップロードします。次のようになります。
<a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.getExcelFile()}" oncomplete="hideLoader();"/>
そして、すべてがうまくいくようですが、これは一見しただけです。 a4j:commandButtonはHttpServletResponseを現在のページにアンロードするため。
ユーザーはファイルをExcel形式でアンロードし、ずさんなページを開きます。 「障害」とユーザーは言って、キーボードをpunchり、誓った。 そして、私たちの人生のシステムに失望しました。
h4 a:のh:commandButtonのサポートを試すことができます。これは、onsubmitでローダーを表示し、アクション中にファイルを形成し、oncompleteでローダーを非表示にします。 ただし、問題はa4j:サポートがサーバーからHttpServletResponseを返すことができないことです。 彼はページでもこれを行います。 すべてのa4j要素がHttpServletResponseをページに返すため。
運が悪い。 何をすべきか、誰も知らない、インターネットが沈黙している、ユーザーが泣いている、あなた自身が曲がったように座っている。 しかし、そのような単純なイベントですが、それはとても欠けています。
ソリューション、CrutchesおよびjQuery
決定は同僚に下されました。 すべてが非常に簡単です。
- ファイルを生成する手順は、リクエストの生成と返却の2つに分けられます。
- a4j:commandButtonを作成します。このボタンは、ファイルを返さずに作成し、ローダーを表示して非表示にします。
<a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.generateExcel()}" oncomplete="hideLoader()"/>
- ファイルを返す隠しh:commandButtonを作成し、さらに検索するためにidを割り当てます。
<h:commandButton id="exelFileButton" style=" visibility: hidden;" action="#{importToExcelBean.returnResponse()}" />
- jQueryを使用して、idで非表示のh:commandButtonを見つけてクリックするJavaScript関数を作成します。
<script type="text/javascript" > function clickButtonGetExelFile(){jQuery("#exelFileButton").click();} </script>
- ローダーを非表示にしてからJavaScript関数を添付します。
<a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.generatePatientsExcel()}" oncomplete="hideLoader();clickButtonGetExelFile();"/>
完了、ユーザーは受信する形式でファイルを受信します。 重大な状況は解決されました。