Displaying Pdf Document by Servlet - java

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();

Related

Download file in ADF works for the first time only

I have an ADF Table in JSF page that is bounded to View Object which holds user's uploaded files. This View Object contains all the information needed to download a file like blob domain , file type and file name. For each row there is a download button that enables the user to download the selected file.
Every things works perfectly for the first time. Problem is when the user press the download button for some file he/she already download it, the file get corrupted. The file appears in the download section for browser, but when I tried to open it tells that the file can not be open because the file format or file extension is not supported.
here is the button in the JSF page:
<af:column id="c31">
<af:commandButton text="Download" id="cb12" partialSubmit="true">
<af:fileDownloadActionListener method="#{ITDetalisBean.downloadSelectedFile}"
filename="#{row.FileName}" contentType="#{row.FileType}"/>
</af:commandButton>
</af:column>
As you can see the button is placed in <af:column> tag. So for each file row there is corresponding download button.
Here is the Bean method:
public void downloadSelectedFile(FacesContext facesContext, OutputStream outputStream)
{
// get the view object from the application module
AppModuleImpl appM = (AppModuleImpl)(JSFUtils.getApplicationModule("AppModuleDataControl"));
ViewObject fileUploadedVO = appM.findViewObject("UplodedFilesViewTransient1");
// get the file content as blob domain from the current row
BlobDomain blobDomain=(BlobDomain)fileUploadedVO.getCurrentRow().getAttribute("FileContn");
// download the file using output stream
try {
HttpServletResponse response =
(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
InputStream in = blobDomain.getBinaryStream();
outputStream = response.getOutputStream();
byte[] buf = new byte[1024];
int count;
while ((count = in.read(buf)) >= 0) {
outputStream.write(buf, 0, count);
}
in.close();
outputStream.flush();
outputStream.close();
facesContext.responseComplete();
} catch (IOException ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
Problem solved by adding the following:
blobDomain.closeInputStream();
blobDomain.closeOutputStream();
at the end of try block before the last statement facesContext.responseComplete();
Minor Change:
I was getting the outputstream by this line: outputStream = response.getOutputStream();
Instead I should use the outputstream that's come with method as an argument:
public void downloadSelectedFile(FacesContext facesContext, OutputStream outputStream)

Display PDF in browser with a servlet

I want to display a PDF file in browser. I have the path to the pdf in JS and I am making a call to grab the PDF as a servlet from java. Here's what I have so far:
JavaScript:
RequestManager.getJSON(Config.server + "getPDF.json?pdfPath=" + this.pathToPdfFile, (function(data){
$("#" + this.divId).append('<object id="' + this.pdfObjectId + '" data="' + data + '" type="application/pdf" width="600" height="800"></object>');
ResizeManager.addResizeHandler(this.pdfObjectId, this.divId, -10, -10);
}).bind(this));
Java:
#RequestMapping("/getPDF")
public void pdfPathToServlet(Model model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String pdfPath = request.getParameter("pdfPath");
if (pdfPath == null || pdfPath.equals(""))
throw new ServletException("Invalid or non-existent file parameter in UrlServlet servlet.");
if (pdfPath.indexOf(".pdf") == -1)
pdfPath += ".pdf";
File pdf = new File(pdfPath);
String pdfName = pdfPath.substring(pdfPath.lastIndexOf("/") + 1, pdfPath.length());
logger.debug(pdfName);
ServletOutputStream stream = null;
BufferedInputStream buf = null;
try
{
stream = response.getOutputStream();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename='" + pdfName + "'");
FileInputStream input = new FileInputStream(pdf);
response.setContentLength((int) pdf.length());
buf = new BufferedInputStream(input);
int readBytes = 0;
while ((readBytes = buf.read()) != -1)
stream.write(readBytes);
}
catch (IOException ioe)
{
throw new ServletException(ioe.getMessage());
}
finally
{
if (stream != null)
stream.close();
if (buf != null)
buf.close();
}
}
My problem is that this is showing the binary output in my browser as text.
I'm not sure what I am doing incorrectly. I have tried changing the header to be attachment instead of inline, but that showed the same thing. I believe I want inline though, as I wish to show it in browser and not download it.
Your JavaScript part makes no sense. You're obtaining a PDF file as ajax response and then attempting to set it as data attribute of the <object> element. The data attribute must point to a real URL, not to the file content. Fix your JS accordingly:
$("#" + this.divId).append('<object id="' + this.pdfObjectId + '" data="' + Config.server + "getPDF.json?pdfPath=" + this.pathToPdfFile + '" type="application/pdf" width="600" height="800"></object>');
The webbrowser will take care about sending the appropriate HTTP request on the given URL and initializing/rendering the <object> element using the Adobe Acrobat Reader plugin — if any available, I'd rather enclose a PDF inside the <object> so that there's at least a graceful degradation to a download link.
Unrelated to the concrete question, that Java code is not part of a servlet at all, but a Spring MVC action. I recommend to get your terms straight and read in our Servlets wiki page to learn what they really are.
response.setHeader("Content-Disposition", "attachment;filename=" + pdfName);
response.setHeader("Content-Disposition", "inline; filename='" + pdfName + "'");
You cannot display a PDF inline. It needs to be alone on its own page (or Iframe).

How do I return a zip file to the browser via the response OutputStream?

In this situation, I have created a zip file containing search result files, and am trying to send it to the user. Here is the chunk of code I am currently trying to use.
File[] zippable = new File[files.size()];
File resultFile = ZipCreator.zip(files.toArray(zippable), results);
InputStream result = new FileInputStream(resultFile);
IOUtils.copy(result, response.getOutputStream());
However, this currently doesn't work quite right. Instead of returning the zip file that I have created, it returns an html file. If I manually change the file extension afterwards, I can see that the contents of the file are still the search results that I need. So the problem just lies in returning the proper extension to the response.
Does anyone have any advice for this situation?
You need to set the Content-Type response header to the value application/zip (or application/octet-stream, depending on the target browser). Additionally, you may want to send additional response headers indicating attachment status and filename.
You need to set the content type header to application/octet-stream prior to streaming the results. Depends on what implementation of response you are using on how you actually do this.
Here is some working code, just in case anyone needs it:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
// The zip file you want to download
File zipFile = new File(zipsResourcesPath + zipFileName);
response.setContentType("application/zip");
response.addHeader("Content-Disposition", "attachment; filename=" + zipFileName);
response.setContentLength((int) zipFile.length());
try {
FileInputStream fileInputStream = new FileInputStream(zipFile);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while ((bytes = fileInputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
} catch (IOException e) {
logger.error("Exception: " + e);
}
}
And the HTML:
<a class="btn" href="/path_to_servlet" target="_blank">Download zip</a>
Hope this helps!
So I found a hack for this : ) Just add ".zip" in your filename and set your content type as application/zip. Works like a charm.
response.setContentType("application/zip");
String licenseFileName = eId;
response.setHeader("Content-disposition", "attachment; filename=\"" + licenseFileName +".zip");

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.

Streaming a pdf through a servlet to a browser

I have yer typical servlet that streams a pdf to a browser. The pdfs are stored on an internal server from which my servlet fetches. If I hit the servlet directly from the browser, the pdf is displayed. If I try the same URL in an <IMG> tag in a web page, ... broken pipe.
Any insight on why this should be?
As an experiment, I can stream gifs without issue.
Here's the code which I pretty much scavenged from the innerwebs:
public class PdfServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(PdfServlet.class.getName());
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) {
String url = (String) req.getParameter("url");
log.info("The URL is " + url);
String format = "application/pdf";
// String format = "image/gif";
streamBinaryData(url, format, res);
}
/*
* This Method Handles streaming Binary data
* <p>
* #param String urlstr ex: http;//localhost/test.pdf etc.
* #param String format ex: pdf or audio_wav or msdocuments etc.
* #param ServletOutputStream outstr
* #param HttpServletResponse resp
*/
private void streamBinaryData(
String urlstr,
String format,
HttpServletResponse resp) {
ServletOutputStream outstr = null;
String ErrorStr = null;
try {
outstr = resp.getOutputStream();
//find the right MIME type and set it as contenttype
resp.setContentType(format);
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
URL url = new URL(urlstr);
URLConnection urlc = url.openConnection();
int length = urlc.getContentLength();
resp.setContentLength(length);
// resp.setHeader("Content-Length", String.valueOf(+length));
// resp.setHeader("Content-Disposition", "inline");
// Use Buffered Stream for reading/writing.
InputStream in = urlc.getInputStream();
bis = new BufferedInputStream(in);
bos = new BufferedOutputStream(outstr);
byte[] buff = new byte[length];
int bytesRead;
// Simple read/write loop.
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
log.info("Got a chunk of " + bytesRead);
bos.write(buff, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
ErrorStr = "Error Streaming the Data";
outstr.print(ErrorStr);
} finally {
log.info("finally!!!");
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
if (outstr != null) {
outstr.flush();
outstr.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
...and the HTML file. The pdf fails with a broken pipe and the gif image is displayed even though the content type is being returned as 'application/pdf'.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Cheesy Servlet Experiment</title>
</head>
<body>
<h1>Cheesy Servlet Experiment</h1>
<P>
<img src="http://10.0.0.9/ServletExperiment/pdf?url=http%3a%2f%2fwww.samplepdf.com%2fsample.pdf" alt="yah mon">
<P>
<img src="http://10.0.0.9/ServletExperiment/pdf?url=http%3a%2f%2fbbs.homeshopmachinist.net%2fimages%2fstatusicon%2fforum_new.gif" alt="yah mon">
</body>
</html>
Edit - the following works in FF. I don't know how standard it is.
<object data="http://www.samplepdf.com/sample.pdf" type="application/pdf" width="600" height="600">
alt : test.pdf
</object>
Interesting info here. Looks reasonably well supported.
Can your browser even display PDF files in img elements? That's really unlikely. I think the browser ends the connection when it finds out that it's actually not an image.
Some browsers don't complain about content-types. They check the image file and figure out which format the image is in by itself. That can explain why your GIF image is displayed.
The problem is that you are trying to display a PDF document with the img Tag. img can handle only simple image formats like JPEG, GIF or PNG.
Usually the plain browser is not able to display PDF content on its own. If there is no PDF viewer plugin installed then the browser will only show a save dialog to download the PDF file.
So the safest way would be that your HTML page only contains a link to your PDF file. Maybe with a target="_blank" to open a new browser window.
you should use an anchor tag (if you have to use an img, have an A wrap the IMG with the IMG's src pointing to a real image). The href of the anchor will be your servelt that displays PDFs. make suer you set the right content-type in the servlet.
First thing: you are trying to read length at once.
this is not a good practice as it doent assure you of the task
try reading smaller chunks by
byte [] read_buffer = new byte[1024 * 10]
This way u read 10kb at once.
And write those 10kb on bos.
Keep this loop until you get -1 by the read function.
And yes. You shoud not use img tag for pdf

Categories

Resources