如何实现与JSF commandButton功能相同的纯前端JS按钮?
Absolutely! You can replicate the exact functionality of that JSF <p:commandButton> with a pure JavaScript button—no REST interface required. Here's how it works and how to build it:
How the Original JSF Button Works
First, let's break down what your original button does:
- With
ajax="false", it triggers a synchronous POST form submission to the current JSF page. - The JSF framework recognizes the action
#{reporting.downloadPaymentsReport}, runs that backend method, and sends back a download response (with headers likeContent-Dispositionto prompt the browser to save the file).
Pure JS can mimic this exact flow by manually creating/submitting a form with all the parameters JSF expects.
Implementation Options
Option 1: Use an Existing JSF Form
If your page already has a JSF <h:form> (most JSF pages do), you can reuse it to trigger the download:
- Add a plain HTML button to your page:
<button onclick="downloadPaymentsReport()">Скачать</button>
- Add this JavaScript function:
function downloadPaymentsReport() { // Grab your existing JSF form (replace "reportForm" with your form's actual ID) const form = document.getElementById('reportForm'); // Add hidden inputs to tell JSF to execute the download action const actionParams = [ { name: 'javax.faces.source', value: 'downloadBtn' }, { name: 'javax.faces.partial.execute', value: '@all' }, { name: 'javax.faces.event', value: 'action' }, // Explicitly specify the action method (adjust the name to match your bean's setup) { name: 'javax.faces.action', value: '#{reporting.downloadPaymentsReport}' } ]; // Append each parameter to the form actionParams.forEach(param => { const input = document.createElement('input'); input.type = 'hidden'; input.name = param.name; input.value = param.value; form.appendChild(input); }); // Submit the form (this triggers the backend action) form.submit(); // Clean up the temporary inputs after submission setTimeout(() => { actionParams.forEach(param => { const input = form.querySelector(`input[name="${param.name}"]`); if (input) form.removeChild(input); }); }, 100); }
Option 2: Create a Temporary Form (No Existing Form Needed)
If you don't have an existing JSF form, you can dynamically create one with JS:
function downloadPaymentsReport() { // Create a hidden temporary form const form = document.createElement('form'); form.method = 'POST'; form.action = window.location.pathname; // Submit to the current JSF page form.style.display = 'none'; // Get the JSF ViewState (critical for JSF to process the request) const viewState = document.querySelector('input[name="javax.faces.ViewState"]'); if (!viewState) { alert('Could not find JSF ViewState. Ensure this page is a valid JSF page.'); return; } // Build all required parameters const formInputs = [ { name: 'javax.faces.ViewState', value: viewState.value }, { name: 'javax.faces.source', value: 'downloadBtn' }, { name: 'javax.faces.partial.execute', value: '@all' }, { name: 'javax.faces.event', value: 'action' }, { name: 'javax.faces.action', value: '#{reporting.downloadPaymentsReport}' } ]; // Add all inputs to the form formInputs.forEach(inputData => { const input = document.createElement('input'); input.type = 'hidden'; input.name = inputData.name; input.value = inputData.value; form.appendChild(input); }); // Add the form to the page and submit it document.body.appendChild(form); form.submit(); // Remove the temporary form after submission setTimeout(() => document.body.removeChild(form), 100); }
Then add the same HTML button as in Option 1.
Key Notes
- ViewState is Mandatory: JSF requires the
javax.faces.ViewStateparameter to validate the request—don't skip this, or your backend will throw an error. - Match Existing Parameters: If your original JSF button relied on other form inputs (like date ranges or filters), make sure those inputs are included in the form you submit (either by reusing an existing form or adding hidden inputs for their values).
- JSF Version Compatibility: The parameter names (
javax.faces.source, etc.) work for most modern JSF versions (2.x+). If you're on an older version, you might need to adjust the parameter names slightly, but the core idea remains the same.
This approach will behave exactly like your original JSF button: it triggers the backend downloadPaymentsReport method, and the browser will handle the download response just as before.
内容的提问来源于stack exchange,提问作者Roberto

