I'm downloading a file without an extension when I go to a servlet
This is code of doGet method (these are just test lines, don't take them seriously):
try {
PrintWriter pw = response.getWriter();
pw.write("test");
pw.println(request.getParameter("a"));
DAOFactory m = DAOFactory.getDAOFactory(1);
Connection conForTests = MySQLDAOFactory.getConnection();
UserDao s = m.getUserDao();
boolean check = s.validateUser("test1","test1",conForTests);
pw.write(String.valueOf(check));
User user = s.findUser("test1",conForTests);
int id = user.getUserId();
pw.write(11);
} catch (SQLException|IOException sqlException) {
System.out.println("asdsad");
sqlException.printStackTrace();
}
System.out.println("asdsad");
}
And I checked all the lines removing them line by line and I have found out that at this line:
pw.write(11);
And that's 11 was a user id so to not retrieve that id each time, I have just written 11. The servlet starts not showing a page, but downloading a file without an extension.
I checked that 11 number is staying for a Vertical Tab in ASCII table. Why is 11 code in ASCII table makes browser to not displaying but downloading file?
And that is content of this file:
Why am I downloading a file with no extension using servlet?
Because you just opened a response stream and started writing into it. In lay terms, you are just sending some bytes back to the browser, but the browser doesn't know what does bytes are. Is it html? Is it plain text? Is it an image? Some other thing?
So before starting to write the response, you need to say what that response is by setting a content type. Replace this code of yours:
try {
PrintWriter pw = response.getWriter();
....
with:
try {
response.setContentType("text/html")
PrintWriter pw = response.getWriter();
....
or whatever content type you prefer (a text/plain can also work for what you are doing).
See also:
what is the use of "response.setContentType("text/html")" in servlet
Java - Default contentType for Servlet
Related
How to download all files in the file directory when clicking the export or download at the same time?
At present, all the files in the file directory have been obtained, then all the files are placed in the list, and then the stream is written after traversing all the files. However, when importing the second file, it will report cannot reset buffer after response has been committed
The source of the problem is in this code: // response.reset();
Code:
String filePath = "/code/data/";
// Get all file addresses of the directory
List<String> filePathList = getFilePath(filePath);
//Create thread pool
for (String str : filePathList){
download(request, response, str);
}
private void download(HttpServletRequest request,
HttpServletResponse response,String filePath) {
File file = new File(filePath);
//Gets the file name.
String fileName = file.getName();
InputStream fis = null;
try {
fis = new FileInputStream(file);
request.setCharacterEncoding("UTF-8");
String agent = request.getHeader("User-Agent").toUpperCase();
if ((agent.indexOf("MSIE") > 0) || ((agent.indexOf("RV") != - 1) &&
(agent.indexOf("FIREFOX") == -1))) {
fileName = URLEncoder.encode(fileName, "UTF-8");
} else {
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
}
// response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/force-download");
// Set forced download not to open
response.addHeader("Content-Disposition",
"attachment; filename=" + fileName);
response.setHeader("Content-Length", String.valueOf(file.length()));
byte[] b = new byte[1024];
int len;
while ((len = fis.read(b)) != - 1) {
response.getOutputStream().write(b, 0, len);
}
response.flushBuffer();
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
What are the good solutions Thanks
I have not read your code in detail because the bad formatting makes my head hurt.
However, from a superficial reading, it looks like this server-side code is trying to deliver multiple files in response to a single HTTP request.
AFAIK, that is not possible. The HTTP request / response model does not support this. It certainly does not allow a servlet to:
change response headers after the response output stream has been opened
do anything after the response output stream has been closed.
(Your code appears to be trying to do both of those things!)
So, you have to do it differently. Here are some possibilities:
On the server side, assemble all of the files to be downloaded into (say) a temporary ZIP file and then send that. Leave it to the user to unpack the ZIP file ... or not ... as they want.
This is often the best approach. Imagine how annoyed you would be if a few thousand separate files unexpectedly landed in your web browser's Downloads folder.
As 1. and also do something on the client side to transparently unpack the files from the ZIP and put them in the right place in the client's file system.
The "something" could be custom javascript embedded in the web page, or a custom client implemented in Java ... or any other language. (But in the former case, there may be a security issue in allowing sandboxed javascript to write files in arbitrary places without the user confirming each file ... tedious.)
You might be able to send a "multipart" document as the response. However from what I have read, most browsers don't support multipart for downloads; e.g. some browsers will discard all but the last part. (Note: multipart is not designed for this purpose ...)
Change things so that an HTTP request only downloads one file at a time from the directory, and add some client-side stuff to 1) fetch a list of files from the server and iterate the list, fetching each file.
See also: Download multiple files with a single action
I am using JasperReport to export a report to a PDF. The code runs fine with no exception messages showing up in the console/log. However, the report does not export to the browser. In other words, the report is being created, I just cannot download or gain access to it.
Here is the export code:
public void generatePDFReport(Map<String, Object> parameters, JRDataSource jrDataSource, String resource, String filename)
{
OutputStream os = null;
try{
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
os = response.getOutputStream();
InputStream reportTemplate = this.getClass().getClassLoader().getResourceAsStream(resource);
byte[] pdf = null;
try {
JasperDesign masterDesign = JRXmlLoader.load(reportTemplate);
masterReport = JasperCompileManager.compileReport(masterDesign);
masterReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
JasperPrint masterPrint = JasperFillManager.fillReport(masterReport, parameters, jrDataSource);
pdf = JasperExportManager.exportReportToPdf(masterPrint);
} catch (JRException e) {
log.error(e);
}
response.setContentType("application/pdf");
response.setContentLength(pdf.length);
response.setHeader("Content-disposition", "attachment; filename=\""+filename+"\"");
context.responseComplete();
os.write(pdf);
pdf = null;
}catch(Exception e){
log.error(e);
}finally{
try{
os.flush();
os.close();
}catch(IOException e){
log.error(e);
}
}
}
I am almost 100% certain that there is nothing wrong with the code as it works fine for different reports (I run the same export code for several other reports and it works as expected for all of them except for this one).
Knowing this, I figured it must have something to do with the report itself. The report is a jrxml JasperReport file. The report was created using iReport. However, I modified the above code to simply save it to the downloads folder and the report is being created perfectly fine.
So, the problem is that the report is successfully being created in the backend but it is not being sent to the front-end (browser) as expected.
I am open to any suggestions as to why this report would not be working.
Running the code inside a bean is problematic because:
only one call to getOutputStream is allowed per HTTP request
the web framework (J2EE/JSF) has likely already written HTTP headers
the JSF page has likely already been written as HTML inside a temporary buffer (flushed upon calling responseComplete()).
the headers could be reset, but that won't help with the getOutputStream issue
calling responseComplete() flushes any HTML along with PDF content to the browser
Use a servlet. The send method of the servlet needn't be any more complex than:
protected void send(final byte[] content) throws IOException {
setContentLength(content.length);
try (final OutputStream out = getOutputStream()) {
out.write(content);
}
}
Also consider setting the cache so that stale reports are not possible:
protected void disableCache() {
// https://tools.ietf.org/html/rfc7234#section-7.1.3
setHeader(CACHE_CONTROL, "private, no-store, no-cache, must-revalidate");
// https://tools.ietf.org/html/rfc7234#section-5.3
setHeader(EXPIRES, "Thu, 01 Dec 1994 16:00:00 GMT");
// https://tools.ietf.org/html/rfc7234#section-5.4
setHeader(PRAGMA, "no-cache");
// https://tools.ietf.org/html/rfc7232#section-2.2
setHeader(LAST_MODIFIED, getServerTimestamp());
}
private String getServerTimestamp() {
final SimpleDateFormat rfc1123 = new SimpleDateFormat(DATE_RFC_1123, getDefault());
rfc1123.setTimeZone(getTimeZone("GMT"));
final Calendar calendar = Calendar.getInstance();
return rfc1123.format(calendar.getTime());
}
This implies, for example:
#WebServlet(
name = "ReportServlet",
urlPatterns = {PATH_SERVLET + "ReportServlet"}
)
public class ReportServlet extends AbstractServlet {
}
And then use a regular anchor link:
<h:outputLink value="/app/path/servlet/Reportservlet">Run Report</h:outputLink>
In summary, don't send binary report data by intercepting a request to a JSF page; use a servlet, instead.
Communications between servlets and JSF pages can be made via:
Session variables (HTTPSession on the servlet side)
URL parameters
Servlets have the advantage that the JSF overhead is completely avoided, which will make the report run faster from the user's perspective. Also, don't compile the report -- use the .jasper file directly, which will also have performance improvements. (I did not mean to imply using the .jrxml file was the problem, merely that it isn't a necessary step.)
I figured out a solution to my problem. Ultimately, I found that there was nothing wrong with the report generation code or the reports, but there was an ajax issue that was preventing the outputstream from exporting the report to the browser.
I have a database where the user doesn't has access to.
Still I can go to the database and "read" the documents with for example
var db:NotesDatabase = sessionAsSigner.getDatabase("","somedir/some.nsf");
In this database there's a pdf file I would like to open or download. I have the filename and the unid . If the user had acces to the database I could do it with
http(s)://[yourserver]/[application.nsf] /xsp/.ibmmodres/domino/OpenAttachment/ [application.nsf]/[UNID|/$File/[AttachmentName]?Open
How can I do it with sessionAsSigner without putting a $PublicAccess=1 field on the form ?
edit:
the pdf file is stored as attachment in a richtextfield
second edit
I'm trying to use the XSnippet from Naveen and made some changes
The error message I get is : 'OutStream' not found
The code I tried is :
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=" + zipFileName);
var embeddedObj:NotesEmbeddedObject = null;
var bufferInStream:java.io.BufferedInputStream = null;
var outStream:java.io.OutputStream = response.getOutputStream();
embeddedObj = downloadDocument.getAttachment(fileName);
if (embeddedObj != null) {
bufferInStream = new java.io.BufferedInputStream(embeddedObj.getInputStream());
var bufferLength = bufferInStream.available();
var data = new byte[bufferLength];
bufferInStream.read(data, 0, bufferLength); // Read the attachment data
ON THE NEXT LINE IS THE PROBLEM
OutStream.write(data); // Write attachment into pdf
bufferInStream.close();
embeddedObj.recycle();
}
downloadDocument.recycle();
outStream.flush();
outStream.close();
facesContext.responseComplete();
Create an XAgent (= XPage without rendering) which takes datebase + documentid + filename as URL parameters and delivers the file as response OutputStream.
The URL would be
http(s)://[yourserver]/download.nsf/download.xsp?db=[application.nsf]&unid=[UNID]&attname=[AttachmentName]
for an XAgent download.xsp in a database download.nsf.
The code behind the XAgent runs as sessionAsSigner and is able to read the file even the user itself has no right to access file's database.
Use Eric's blog (+ Java code) as a starting point. Replace "application/json" with "application/pdf" and stream pdf file instead of json data.
As an alternative you can adapt this XSnippet code from Thomas Adrian. Use download() together with grabFile() to write your pdf-File to OutputStream.
Instead of extracting attachment file to path and reading it from there you can stream the attachment right from document to response's OutputStream. Here is an XSnippet from Naveen Maurya as a good example.
If you can get the PDF file as a stream, you should be able to use the OutputStream of the external context's response.
Stephan Wissel has a blog posting about writing out an ODF file so you should be able to cut that up as a starting point.
http://www.wissel.net/blog/d6plinks/SHWL-8248MT
You already have the db so, you will just need to know the UNID of the document.
var doc = db.getDocumentByUNID(unid) 'unid is a supplied param
var itm:RichTextItem = doc.getFirstItem("Body") 'assuming file is in body field
Once you have the itm, you can loop round all of the embeddedObjects and get the pdf file. At this point, I don't know if you can stream it directly or if you have to detach it, but assuming you detach it, you will then use something like this.
File file = new File("path to file");
FileInputStream fileIn = new FileInputStream(file);
Don't forget to clean up the temporarily detached file
I have been working on creating a series of buttons that uploads, downloads, and deletes files in Spring MVC, with JSP pages, and Java this past few days. I have the Upload and Delete working perfectly, and just got the download almost working. I stress almost because the download comes with a very odd condition.
If I upload say an exe or a jar file, and then go back and try and download it. A box will show up asking me if I want to open it or save it. If I want to do either it's not corrupted or anything, it's just fine.
If, however, the file is text based, as in a PDF, TXT, .doc, even XML, a browser tab will open, and it will show up in there.
So can anyone point me in the direction on how I might fix this?
The first block of code is my controller method, the second is the line in my jsp that triggers the button.
#RequestMapping("/FileDownload")
public ModelAndView FileDownload(
#RequestParam(value = "FileID", required = false) int fileID,
#RequestParam(value = "theFile", required = false) MultipartFile thefile,
#ModelAttribute("fileAttachment") #Valid fileAttachment, BindingResult result, HttpServletResponse response){
ModelAndView mav = new ModelAndView();
fileAttachment doc = attachmentService.getFileAttachment(fileID);
try {
response.setHeader("Content- Disposition", "inline;filename=\""
+ doc.getFileName() + "\"");
OutputStream out = response.getOutputStream();
response.setContentType(doc.getFileType());
FileCopyUtils.copy(doc.getFileContent(), response.getOutputStream());
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
Here is the line that configures the button in the jsp
<button name="FileDownloadd" type="button" value="Download" onClick="location.href=FileDownload.html?FileID=${fileattach.FileID}'">Download</button> </td>
Marc's comment above was the answer. Since it was a comment, and I want to close this. I will post it in quotes.
you're telling the browser to display it inline. That means if the browser >knows how to render the file's contents, it will. text/pdf/xml can be rendered >directly by a browser (or at least via a plugin). If you want to force a >download, then use attachment as your disposition, and/or force a mime-type >like application/octet-stream, which the browser WON'T try to render.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
how to display a pdf file in jsp using servlet
I retrieve a pdf file from my database and put it in a file like this
String str="select * from files where name='Security.pdf';";
Statement stmt2= conn.createStatement
(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs = stmt2.executeQuery(str);
while(rs.next())
{
InputStream input = rs.getBinaryStream("content");
//to create file
File f=new File("c:/pdfile.pdf");
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=input.read(buf))>0)
out.write(buf,0,len);
out.close();
input.close();
System.out.println("\nFile is created..");
}
Now this is at server end. In my client side, Whenever user clicks a link say
a href=pdf(pdf is my servlet name) in my jsp page, I should display the file retrieved from database on client's Browser.
What should I do?
Set your content-type of the response to pdf
response.setContentType("application/pdf");
Then write the pdf contents into the response object
Don't save the PDF to a file on the server, just send it back to the browser as the servlet's response. Basically, instead of that FileOutputStream, use the OutputStream that you get from calling getOutputStream() on your ServletResponse object. You'll also need to set a Content-Type header so that the browser knows it's a PDF file.
Having a servlet write to a hard-coded path like that is dangerous because several instances of the servlet can run at the same time, in different threads. (Think about what happens if two people enter your servlet's URL in their browsers at the same time.) If they're both writing to the same file at the same time, they'll end up corrupting it.