Introduction: –
When building PDF generation into a JSP application using JasperReports, a common bug shows up: every generated report is saved under the same file name, so each new PDF quietly overwrites the previous one. This typically goes unnoticed while testing solo, but becomes a serious issue in production once multiple users are generating documents like receipts or statements around the same time.
This document covers generating a report in JSP with JasperReports and Oracle data, saving it under a guaranteed-unique name, streaming it back to the browser as a download, and triggering the whole flow from an Oracle APEX page.
Technologies used: JSP, JasperReports, Java IO, Oracle Database, Servlet API, Oracle APEX.
Why we need to do: –
Relying on a hardcoded output name like Report.pdf causes real problems under concurrent, multi-user traffic:
- Lost data -an earlier user’s report gets silently replaced by a newer one before anyone downloads it.
- Wrong downloads-one user can end up retrieving a report that actually belongs to someone else.
- Corruption under load -simultaneous requests writing to the same file path can collide and produce broken output.
A better solution is generating a unique output file name on every request, eliminating overwrite collisions while keeping the report generation logic simple.
How do we solve: –
The fix is to stop using a static file name and instead generate a name that’s guaranteed unique on every request. The simplest way is to append the current time (in milliseconds) to the base name, since the millisecond clock is effectively never identical across two separate requests — even dozens of users hitting the endpoint in the same second still get distinct file names.
If you’d rather have more readable names for audit logs, the timestamp can be formatted instead of using raw milliseconds (unique down to the second rather than the millisecond).
| Requested name | Generated file |
| Receipt | Receipt_1748419200000.pdf |
| Statement | Statement_1748419201234.pdf |
| Payslip | Payslip_1748419205678.pdf |
Step 1: Accept the file name parameter
Read the filename parameter from the request. If it’s missing or blank, default it to “Report”.
Step 2: Generate a unique output name
Append System.currentTimeMillis() (or a formatted timestamp) to the base name so no two generated files can ever collide.
Step 3: Prepare the output folder
Check whether the target output folder (e.g. generated_pdfs) exists on disk. If it doesn’t, create it.
Step 4: Connect to the database
Load the Oracle JDBC driver and open a connection using the appropriate credentials and connection string.
Step 5: Fill the Jasper report
Load the compiled .jasper template and fill it with the required parameters and the database connection.
Step 6: Export the report to disk
Write the filled report out to the unique file path built in Step 2.
Step 7: Set the response headers
Set Content-Type to application/pdf and Content-Disposition to attachment with the generated file name, so the browser treats it as a download.
Step 8: Stream the file back to the browser
Read the PDF bytes from disk and write them to the response output stream. Close the file input stream and the output stream once finished, and close the database connection in a finally block.
Step 9: Trigger the flow from Oracle APEX
On the APEX side, build the request URL in JavaScript and open it in a new window/tab, called from a button’s Dynamic Action.
Source Code
Unique File Name Generation
String fileName = parameter1 + “_” + System.currentTimeMillis() + “.pdf”;
Example output: Receipt_1748419200000.pdf
Readable, Date-Formatted Alternative
SimpleDateFormat sdf = new SimpleDateFormat(“yyyyMMdd_HHmmss”);
String timestamp = sdf.format(new Date());
String fileName = parameter1 + “_” + timestamp + “.pdf”;
Example output: Statement_20260528_103045.pdf
Full JSP Implementation
This page accepts a filename parameter, fills a Jasper report from an Oracle query, writes the PDF to a generated_pdfs folder under a unique name, and streams it back to the browser as an attachment.
<%@ page import="java.io.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="net.sf.jasperreports.engine.*" %>
<%@ page import="javax.servlet.ServletOutputStream" %>
<%
Connection conn = null;
try {
String parameter1 = request.getParameter("filename");
if(parameter1 == null || parameter1.trim().equals("")) {
parameter1 = "Report";
}
String fileName =
parameter1 + "_" + System.currentTimeMillis() + ".pdf";
String folderPath =
application.getRealPath("/generated_pdfs");
File folder = new File(folderPath);
if(!folder.exists()) {
folder.mkdirs();
}
String fullPdfPath = folderPath + File.separator + fileName;
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:XE",
"username",
"password"
);
String jasperPath =
application.getRealPath("/reports/sample.jasper");
java.util.Map<String, Object> parameters =
new java.util.HashMap<String, Object>();
parameters.put("P_ID", 100);
JasperPrint jasperPrint =
JasperFillManager.fillReport(
jasperPath,
parameters,
conn
);
jasperPrint.setName(parameter1);
JasperExportManager.exportReportToPdfFile(
jasperPrint,
fullPdfPath
);
response.reset();
response.setContentType("application/pdf");
response.setHeader(
"Content-Disposition",
"attachment; filename=\"" + fileName + "\""
);
File pdfFile = new File(fullPdfPath);
response.setContentLength((int) pdfFile.length());
FileInputStream fis = new FileInputStream(pdfFile);
ServletOutputStream os = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
fis.close();
os.flush();
os.close();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if(conn != null) {
conn.close();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
%>
Triggering the JSP from Oracle APEX
Place this in the page’s Function and Global Variable Declaration (or the page’s JavaScript header), and call testScript() from a Dynamic Action on button click, passing the relevant item IDs.
<script type="text/javascript" language="javascript">
function testScript(a,schemaid){
var a1=document.getElementById(a).value;
var schemas=document.getElementById(schemaid).value;
var l_field = document.wwv_flow.pInstance.value;
var pdfnames="demo";
var subnames="";
var urls = window.location.href;
var urls1 = urls.substring(urls.indexOf('//'),urls.length);
var urls2=urls1.indexOf('//');
var urls3=urls1.indexOf(':');
var url = urls1.substring(urls2+Number(2),urls3);
window.open("http://"+url+":8080/doyenpdf.jsp?m1="+"&schema="+schemas+"&fieldId="+l_field+"&pdfname="+pdfnames+"&subname="+subnames+"&p1="+a1);
}
</script>
Conclusion
A production-safe PDF generation workflow in Oracle APEX using JasperReports ensures that every generated report is reliable, secure, and scalable. By assigning a unique file name to each PDF, the solution eliminates the risk of reports being overwritten, even when multiple users generate reports simultaneously. The generated PDFs are streamed directly to the user’s browser for immediate download, providing a seamless user experience without requiring temporary file management.

