Java Spring MVC新手:如何将Flying-saucer生成的PDF保存至/resources或指定目录
Hey there! As someone new to Java and Spring MVC, I totally get wanting to control where your generated PDFs end up instead of the default temp folder. Let’s walk through how to adjust your code to save to your desired directory, with some important notes along the way.
First: A Critical Note About the /resources Directory
Before diving in, it’s key to know: When your project is packaged (like into a JAR/WAR for deployment), the /resources folder becomes part of the classpath and is read-only. Writing to it at runtime will cause errors in production. For development, you might get it working, but it’s not a recommended practice. Instead, use a dedicated output folder (either inside your project root or a server-side directory) for generated files.
Step 1: Define Your Target Directory
Option 1: Project Root-Based Directory (Great for Development)
Use System.getProperty("user.dir") to get your project’s root path, then build out your target folder:
// Get the project root directory String projectRoot = System.getProperty("user.dir"); // Define your desired output folder (e.g., project-root/pdf-output) String targetDir = projectRoot + "/pdf-output"; // Ensure the directory exists (create it if not) File outputDirectory = new File(targetDir); if (!outputDirectory.exists()) { outputDirectory.mkdirs(); // Recursively creates parent folders too }
Option 2: Web App Root Directory (For Spring MVC Web Apps)
If you’re working with a web application, you can use the ServletContext to get the web app’s root path:
@Autowired private ServletContext servletContext; public void setupPdfDirectory() { // Get the web app's root path String webAppRoot = servletContext.getRealPath("/"); // Define a folder inside WEB-INF (safe from direct web access) String targetDir = webAppRoot + "/WEB-INF/pdf-output"; File outputDirectory = new File(targetDir); if (!outputDirectory.exists()) { outputDirectory.mkdirs(); } }
Option 3: Hardcoded Custom Directory (For Production Servers)
For production, you might want to use a fixed server directory (e.g., /opt/apps/my-app/pdf-output):
String targetDir = "/opt/apps/my-app/pdf-output"; File outputDirectory = new File(targetDir); if (!outputDirectory.exists()) { outputDirectory.mkdirs(); }
Just make sure your application has write permissions for this directory!
Step 2: Modify Your PDF Generation Code to Write to the Target File
Now that you have your target directory, update your Flying-Saucer code to write the PDF there instead of the temp folder. Use a FileOutputStream with your custom path, and always use try-with-resources to auto-close streams safely:
// Assume you already have your ITextRenderer instance set up with Thymeleaf content ITextRenderer renderer = new ITextRenderer(); // ... (your existing code to set the Thymeleaf template content to the renderer) // Create a unique filename to avoid overwriting existing PDFs String uniqueFileName = "report-" + java.util.UUID.randomUUID() + ".pdf"; String pdfFilePath = targetDir + "/" + uniqueFileName; // Write the PDF to the target file try (FileOutputStream outputStream = new FileOutputStream(pdfFilePath)) { renderer.createPDF(outputStream); System.out.println("PDF saved successfully to: " + pdfFilePath); } catch (IOException | DocumentException e) { // Handle exceptions (log them, show error message, etc.) e.printStackTrace(); }
Bonus Tips
- Avoid Overwriting Files: Using
UUID.randomUUID()or timestamps in filenames ensures each generated PDF has a unique name. - Permission Checks: In production, double-check that your application user has write access to the target directory. If you’re on Linux, you might need to set chmod permissions or adjust the directory owner.
- Development vs Production: Use Spring profiles to switch between directories (e.g., project root for dev, server directory for prod) to avoid hardcoding paths that don’t work across environments.
内容的提问来源于stack exchange,提问作者Julien Knepper

