Why doesn'n create pdf-documents in java servlet? [duplicate] - java

This question already has answers here:
How can I serve a PDF to a browser without storing a file on the server side?
(4 answers)
Closed 6 years ago.
I use iText/Pdfbox to create a PDF document. Everything works when I create the PDF using a standalone Java class like this:
public static void main(String[] args){
...
...
...
}
The document is created correctly.
But I need create a PDF document from a Servlet. I paste the code into the get or post method, run that servlet on the server, but the PDF document isn't created!
This code works as a standalone application:
This code doesn't work:

Please read the documentation. For instance the answer to the question How can I serve a PDF to a browser without storing a file on the server side?
You are currently creating a file on your file system. You aren't using the response object, meaning you aren't sending any bytes to the browser. This explains why nothing happens in the browser.
This is a simple example:
public class Hello extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/pdf");
try {
// step 1
Document document = new Document();
// step 2
PdfWriter.getInstance(document, response.getOutputStream());
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello World"));
document.add(new Paragraph(new Date().toString()));
// step 5
document.close();
} catch (DocumentException de) {
throw new IOException(de.getMessage());
}
}
}
However, some browsers experience problems when you send bytes directly like this. It's safer to create the file in memory using a ByteArrayOutputStream and to tell the browser how many bytes it can expect in the content header:
public class PdfServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// Get the text that will be added to the PDF
String text = request.getParameter("text");
if (text == null || text.trim().length() == 0) {
text = "You didn't enter any text.";
}
// step 1
Document document = new Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos);
// step 3
document.open();
// step 4
document.add(new Paragraph(String.format(
"You have submitted the following text using the %s method:",
request.getMethod())));
document.add(new Paragraph(text));
// step 5
document.close();
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
}
catch(DocumentException e) {
throw new IOException(e.getMessage());
}
}
}
For the full source code, see PdfServlet. You can try the code here: http://demo.itextsupport.com/book/
You wrote in a comment
This demo writes the PDF file into the browser. I want to save the PDF on my hard drive.
This question could be interpreted in two different ways:
You want to write the file to a specific directory on the user's disk drive without any user interaction. This is forbidden! It would be a serious security hazard if a server could force a file to be written anywhere on a user's disk drive.
You want to show a dialog box so that the user can save the PDF on his disk drive in a directory of his choice instead of just showing the PDF in the browser. In this case, please take a closer look at the documentation. You'll see this line: response.setHeader("Content-disposition","attachment;filename="+ "testPDF.pdf"); You can set the Content-disposition to inline if you want the PDF to open in the browser, but in the question, the Content-disposition is set to attachment which triggers a dialog box to open.
See also How to show a Save As dialog for a iText generated PDF?

Related

Write over a pdf file (template) with a servlet

so i just heard about the API called iText and i'm not really familiar with its use.
So my problem now is i want to write over an existing pdf file (a template) the informations provided in a jsp form.
I tried some code found on the internet it works fine but not on servlets.
Thanks.
EDIT Here is the code i found and tried to put into a servlet.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Document document = new Document(PageSize.A4);
try {
PdfWriter.getInstance(document, new FileOutputStream(new File(
"test.pdf")));
document.open();
String content = request.getParameter("aa");
Paragraph paragraph = new Paragraph(content);
document.add(paragraph);
} catch (DocumentException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
document.close();
}
}
I look at your servlet and I see:
new FileOutputStream(new File("test.pdf"))
This means that you are writing a file to the file system on your server. I don't see you sending any bytes to the response object, so nothing shows up in the browser.
You claim that iText "doesn't work in a servlet", but that's not correct: if no exception is thrown, a file named "test.pdf" is creating in your working directory on the server side. That's not very smart, because the more people use your servlet, the more PDFs will be saved on the server. You probably don't want that. You probably want to create the PDF in memory, and serve the PDF bytes to the browser.
The short answer to your question, is that you should write the PDF to the OutputStream of the response object instead of to a FileOutputStream:
public class Hello extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/pdf");
try {
// step 1
Document document = new Document();
// step 2
PdfWriter.getInstance(document, response.getOutputStream());
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello World"));
document.add(new Paragraph(new Date().toString()));
// step 5
document.close();
} catch (DocumentException de) {
throw new IOException(de.getMessage());
}
}
}
However, to avoid known issues with this approach, you should also read the official documentation. Search for the keyword "servlet" and you'll find these FAQ entries:
How can I serve a PDF to a browser without storing a file on the server side? (iText 5)
How can I serve a PDF to a browser without storing a file on the server side? (iText 7)
Since you are new at iText, it is surprising that you chose to use iText 5 instead of the newer iText 7. iText 7 isn't compatible with iText 5; it is a complete rewrite of the library. I recommend that you use iText 7, because we have stopped active development on iText 5.
Update:
The error known as "The document has no pages." indicates that you are trying to create a document that doesn't have any content.
Replace:
String content = request.getParameter("aa");
Paragraph paragraph = new Paragraph(content);
document.add(paragraph);
With:
document.add(new Paragraph("Hello"));
My guess is that something went wrong while fetch the parameter "aa", causing no content to be added to the document.

How to generate and download an Excel report using jsp servlet [duplicate]

This question already has answers here:
Implementing a simple file download servlet [duplicate]
(5 answers)
Closed 7 years ago.
I have generated the Excel report using Apache POI. What I want now, I want to send this to the browser for download. My JSP is as follows.
<html>
<head><title> Excel Generator</title>
</head>
<body>
generate report
</body>
</html>
Here is my servlet code
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String report_path=request.getSession().getServletContext().getInitParameter("REPORT_PATH");
HouseHoldReportGenerator report = new HouseHoldReportGenerator("HOUSE_HOLD",attrStr_,dbParam);
report.Write_Report___(report_path, dbParam);
System.out.println("path-->"+report_path+report.getFileName_());}
I have my report generation java class as HouseHoldReportGenerator. It generates the report. But What I want from one click on the link in jsp page I want it to be generated and downloaded. I can get the report destination also.
you should add the following in your servlet method..
try{
//This is for downloading
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=nameOfExcel");
File file = new File("path_to_the_file/excelfile.xls"); //<- the name of excel that you have already created.
FileInputStream fileIn = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
byte[] outputByte = new byte[4096];
//copy binary contect to output stream
while(fileIn.read(outputByte, 0, 4096) != -1)
{
out.write(outputByte, 0, 4096);
}
fileIn.close();
out.flush();
out.close();
}
catch(IOException e){
e.printStackTrace();
}
Look at that answer: https://stackoverflow.com/a/14281064/5594550
Basically you need to set a correct HTTP header and then stream the file to the client through response.getOutputStream()

Create and download CSV file in a Java servlet

I am working on Java ExtJS application in which I need to create and download a CSV file.
On clicking a button I want a CSV file to be downloaded to a client's
machine.
On buttons listener I am calling a servlet using AJAX. There I am
creating a CSV file.
I don't want the CSV file to be saved in the server. I want the file should be created dynamically with a download option. I want the contents of a file to be created as a string and then I will serve the content as file in which it will open as download mode in browser (this I have achieved in other language, but not sure how to achieve it in Java).
Here is my code only to create a CSV file, but I really don't want to create or save CSV file if I can only download the file as CSV.
public String createCSV() {
try {
String filename = "c:\\test.csv";
FileWriter fw = new FileWriter(filename);
fw.append("XXXX");
fw.append(',');
fw.append("YYYY");
fw.append(',');
fw.append("ZZZZ");
fw.append(',');
fw.append("AAAA");
fw.append(',');
fw.append("BBBB");
fw.append('\n');
CSVResult.close();
return "Csv file Successfully created";
} catch(Exception e) {
return e.toString();
}
}
Can any one help me on this.
Thanks
I got the solution and I am posting it below.
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=\"userDirectory.csv\"");
try
{
OutputStream outputStream = response.getOutputStream();
String outputResult = "xxxx, yyyy, zzzz, aaaa, bbbb, ccccc, dddd, eeee, ffff, gggg\n";
outputStream.write(outputResult.getBytes());
outputStream.flush();
outputStream.close();
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
Here we don't need to save / store the file in the server.
Thanks
First of all you need to get the HttpServletResponse object so that you can stream a file into it.
Note : This example is something I Wrote for one of my projects and it works.Works on Java 7.
Assuming you got the HttpServletResponse you can do something like this to stream a file. This way the file will be saved into clients' machine.
public void downloadFile(HttpServletResponse response){
String sourceFile = "c:\\source.csv";
try {
FileInputStream inputStream = new FileInputStream(sourceFile);
String disposition = "attachment; fileName=outputfile.csv";
response.setContentType("text/csv");
response.setHeader("Content-Disposition", disposition);
response.setHeader("content-Length", String.valueOf(stream(inputStream, response.getOutputStream())));
} catch (IOException e) {
logger.error("Error occurred while downloading file {}",e);
}
}
And the stream method should be like this.
private long stream(InputStream input, OutputStream output) throws IOException {
try (ReadableByteChannel inputChannel = Channels.newChannel(input); WritableByteChannel outputChannel = Channels.newChannel(output)) {
ByteBuffer buffer = ByteBuffer.allocate(10240);
long size = 0;
while (inputChannel.read(buffer) != -1) {
buffer.flip();
size += outputChannel.write(buffer);
buffer.clear();
}
return size;
}
}
What this does is, get an inputstream from your source file and write that stream into the outputstream of the HttpServletResponse. This should work since it works perfectly for me. Hope this helps. Sorry for my bad English.
I would like add something to the answer by gaurav. I recently had to implment this functionality in a project of mine and using javascript was out of the question becuase we had to support IE 9. What is the problem with IE 9?
(Export to CSV using jQuery and html), see the second answer in the link.
I needed an easy way to convert a ResultSet of a database query to a string which represent the the same data in CSV format. For that I used http://opencsv.sourceforge.net/ which provided an easy way to get a String ot of the ResultSet, and the rest is as above answer did it.
THe examples in the project soruce folder give good examples.

Displaying Pdf Document by Servlet

I am trying to show pdf document in a iframe. I have set the source of the iframe to a servlet and passing some parameter to the servlet.
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String docName = request.getParameter("docName");
String id = request.getParameter("id");
if (StringUtils.isNotBlank(id) && StringUtils.isNotBlank(docName)) {
DocumentService service = DamServiceProvider.PROVIDER.getDocumentService();
FileInBean fileInBean = new FileInBean();
fileInBean.setDocName(docName);
fileInBean.setId(Integer.valueOf(id));
FileDataBean fileDataBean = service.getFileDataBean(fileInBean);
if (fileDataBean.getStatusCode() == 0) {
Map<String, String> headerFieldMap = fileDataBean.getHeaderFieldMap();
String contentType = headerFieldMap.get("Content-type");
String contentLength = headerFieldMap.get("Content-Length");
String contentDisposition = headerFieldMap.get("Content-Disposition");
byte[] stream = fileDataBean.getStream();
ByteArrayInputStream inputStream = new ByteArrayInputStream(stream);
OutputStream outputStream = response.getOutputStream();
response.reset();
response.setBufferSize(4096);
response.setContentLength(Integer.valueOf(contentLength));
response.setContentType(contentType);
response.setHeader("Content-Disposition", contentDisposition);
System.out.println(contentDisposition);
IOUtils.copy(inputStream, outputStream);
outputStream.close();
inputStream.close();
}
}
} catch (Exception ex) {
Log.error(this, ex.getMessage());
}
}
Now in my page I have a master–detail interface. The master part contains a carousel of series of pdf file items. On clicking the item I am refreshing the detail view which contains the iframe.
I can see the servlet get called. Most of the times the iframe is displaying the pdf document. But sometimes it is showing weird xml structure which contains xml tags and some unreadable output. Please see the attach image:
This is not happening for a particular file. If a file shows this output, sometime later if click the item it shows the valid pdf and if an item shows a valid pdf sometime later it shows this kind of output if I click on it. When the iframe shows this type of output my browser displays an information that this pdf document might be corrupted.
I have checked the repository where the files are and I have found no issues there. All of them are valid pdf and I can download and open them by pdf reader.
I am unable to find the cause of this issue. Any pointer would be very helpful.
Update - 1
I have checked the output. It ends with %%EOF and has %PDF in the beginning.
Update - 2
I have checked in Chrome's Network Console the GET is returning mainly three types of content-type: application/pdf, text/plain, application/octet-stream.
application/pdf: it is showing the pdf.
text/plain it is showing the content that I mentioned above.
application/octet-stream didn't arise in Firefox but in Chrome and in that case it is opening the download file window.
I have placed a log in the servlet to see the content-type that returned from service. For all the cases it is application/pdf.
I think it maybe a problem with the content-Type, you can confirm if this is the espected in your browser with the developer tools (in the network console for Chrome).
try something like this.
File pdfFile = new File(this.pdfStoreLocation + pdfFileName);
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=" + pdfFileName);
response.setContentLength((int) pdfFile.length());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFile));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
// byte array declared
byte[] buf = new byte[2048];
boolean eof = false;
while (!eof) {
int length = bis.read(buf);
if (length == -1) {
eof = true;
}else {
bos.write(buf, 0, length);
}
}
try {
bis.close();
}catch (IOException ex) {
LOGGER.error("Exception in closing buffered input stream on pdf file->" + this.pdfStoreLocation + pdfFileName);
}
try {
bos.flush();
}catch (IOException ex) {
LOGGER.error("Exception in fliushing buffered output stream on pdf file->"
+ this.pdfStoreLocation + pdfFileName);
}
bos.close();

iText generated PDF not shown correctly in Chrome

I am using the iText library in Java to generate a pdf file. The idea is that a user fills in some information and that when the user clicks on the generate button the pdf is shown in a new tab in the browser. Now I have stumbled upon some problems doing this, which are :
- the URL does not change, so instead of /application/user.pdf I get /application/dashboard.xhtml
- I can save the pdf file in all browsers except for Chrome.
Please note that I don't want to save it on disc but simply show the pdf in the browser so the user can choose if he wants to save it.
Here is the code that I use to generate my pdf :
public static void createPdf(User user, byte languageNumber, HttpServletResponse response) {
Document document = new Document();
try {
/* PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("c://" + user.getUsername() + "_" + languageCode + ".pdf"));*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos);
document.addTitle("Your CV");
document.addSubject("This is your CV");
document.addKeywords("CV");
document.addAuthor(user.getUsername());
document.open();
document.add(
new Paragraph(user.getPersonalInformation().getFirstname() + " " + user.getPersonalInformation().getLastname()));
document.close();
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
response.setContentLength(baos.size());
//ServletOutputStream out = response.getOutputStream();
OutputStream out = response.getOutputStream();
baos.writeTo(out);
out.flush();
out.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
*This method is behind a button on my JSF page *
public String exportPdf() {
user = userService.retrieveLoginUser();
FacesContext context = FacesContext.getCurrentInstance();
try {
Object response = context.getExternalContext().getResponse();
if (response instanceof HttpServletResponse) {
HttpServletResponse hsr = (HttpServletResponse) response;
PdfCreator.createPdf(user, selectLanguage, hsr);
//Tell JSF to skip the remaining phases of the lifecycle
context.responseComplete();
}
return "../" + user.getUsername() + ".pdf";
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Used technologies :
- JSF 2.0
- Facelets
- iText
Thanks in advance :D
The way that I have achieved this in the past is by creating a seperate Servlet to serve PDF documents directly. In the web.xml file you would specify the servlet mapping to *.pdf.
What you can do then is rather than override the FacesServlet response bytes to server the PDF file you just redirect the response to filename.pdf, passing needed parameters in the URL.
Your PDF servlet can actually do the work of building the necessary PDF, it will open in a seperate tab and the URL will match the response redirect.
Does chrome open the PDF and then not render it correctly? In that case, please open an issue at http://new.crbug.com and attach an example PDF file that shows the problem. Reply with the issue number here.

Categories

Resources