File Downloads To Browser - java

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.

Related

Java Springboot- Display live Inline file peview while editing

I am working on project to create a live inline file (e.g DOCX, PDF, txt, JSON etc.. ) preview in browser , while editing any file using java springboot web application.
I have tried below code which opens e.g: pdf file in a new tab in browser.
But what I am trying to do is to preview the file live along side while editing it.
#GetMapping
public ResponseEntity<InputStreamResource> previewLive() {
String filePath = "/path/";
String fileName = "fileName.pdf";
File file = new File(filePath+fileName);
HttpHeaders headers = new HttpHeaders();
headers.add("content-disposition", "inline;filename=" +fileName);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.parseMediaType("application/pdf"))
.body(resource);
}
One way I could think of is converting the file to image and display page wise on browser in the same place side by side where i am editing my file using an existing online editor.
Any way or a point to direction I can look for would be really helpful.
Deducted from this post it's not possible to edit and render pdf at the same time in browser using js/spring.
However if you edit the pdf in the corresponding software(Acrobat etc.) f.ex. LiveReload could be the tool you're looking for.

Why am I downloading a file with no extension using servlet?

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

JasperReport with OutputStream not exporting to PDF

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.

Save facebook connect profile picture to own server

I am working in an application which uses facebook connect to fetch a user’s profile picture. But after the connection is made I still have to be able to crop and resize the “large” image. Therefor I want to download the profile picture from the facebook server to my own server.
As of now I am not able to download the picture to my server. Here is what I am doing:
The facebook profile picture get sync in our application from facebook with the following path http://graph.facebook.com/uid/picture?type=large
Now we need the image to be get saved locally from the URL mentioned above
Crop it and display it, but we are unable to save the image from the provided URL
Question
• So how we can save the facebook profile picture in our server using this path http://graph.facebook.com/uid/picture?type=large?
• Or what is the other solution to save facebook profile? Picture to be save in our server first before displaying it?
• How do we still keep it in sync with facebook if we use the saved picture?
Then I have another question:
How do you delete the cookies for a once established facebook connect connections if a user does not want to use facebook connect no more?
If have tried to do this with the following code but no results:
var api_key = "135xxxxxxxxxxx";
var channel_path = ""+2;
FB.init(api_key , cookie:false, channel_path, { "ifUserConnected": update_user_box });
Function update_user_box(){
Var fbId=FB.Connect.get_loggedInUser();
The code given above to delete the false cookie is not working. What do I have to do to resolve this issue?
Instead of saving all the profile photos you could display the photo in a div that is too small for the entire image. Basically let the html do the cropping.
<body>
<div style="background-image: url(http://scm-l3.technorati.com/11/01/14/25023/facebook-logo.jpg); width: 380px; height: 300px;">
</div>
</body>
OR, per my comments below, you could wrap an image and resize the div. Both options work. One avoids using a CSS url() which might not follow redirects in come rare cases.
<body>
<div style="width: 380px; height: 300px; overflow: hidden;">
<img src="http://scm-l3.technorati.com/11/01/14/25023/facebook-logo.jpg" alt="Facebook" />
</div>
</body>
Like OffBySome said above, the key is knowing that it will redirect you. So, we turn off following the redirect automatically and retrieve the actual URL of the picture from the header of the profile URL. Here's a snippet I've used to download the actual image file. Available as a gist here: https://gist.github.com/1092990
private static final String PROFILE_PICTURE_URL = "https://graph.facebook.com/%s/picture?type=large&access_token=%s";
private String downloadFacebookProfilePicture(String uid, String accessToken, String username) throws MalformedURLException, IOException {
//Get the picture url
HttpURLConnection.setFollowRedirects(false);
String profilePictureUrlString = new URL(String.format(PROFILE_PICTURE_URL, uid, accessToken)).openConnection().getHeaderField(
"location");
//Set up temp location for picture
String fileExtension = StringUtils.substring(profilePictureUrlString,
StringUtils.lastIndexOf(profilePictureUrlString, ".") + 1);
String tempFilePath = (new StringBuilder(String.valueOf(System
.getProperty("java.io.tmpdir"))))
.append(StringUtils.replace(username, ".", "_")).append(".")
.append(fileExtension).toString();
String exportUrl = profilePictureUrlString;
//Download file to temp location
downloadFile(exportUrl, tempFilePath);
return tempFilePath;
}
private void downloadFile(String exportUrl, String filepath)
throws IOException, MalformedURLException {
InputStream inStream = new URL(exportUrl).openStream();
FileOutputStream outStream = new FileOutputStream(filepath);
copyStreams(inStream, outStream);
}
private void copyStreams(InputStream inStream, OutputStream outStream)
throws IOException {
try {
int c;
while ((c = inStream.read()) != -1) {
outStream.write(c);
}
} finally {
if (inStream != null) {
inStream.close();
}
if (outStream != null) {
outStream.flush();
outStream.close();
}
}
}
You should probably split your questions into separate questions but as others have pointed out, https://graph.facebook.com/me/picture will return a 302 redirect to the image URL that you can save to your server so you'll need to make sure you're either following the redirect or reading the Location header (more on how to do that here) to get the URI of the actual image.
As for your question on how to make sure you are always using the most up to date picture, you should subscribe to the "/picture" connection of the "User" object using Real-time Updates and we will ping your callback whenever any user of your app updates their picture so you can go pull the latest one. This way you won't have to keep polling to see if the user has changed their picture.
If you're able to achieve what you're going for with just CSS (without caching the pic on your own server), check out squinlan's solution.
When you try to download the image, make sure whatever you are download the image with can follow 302 redirects because the graph Facebook link only returns a redirect to the image, not the actual image itself. But cropping the image with CSS would make a lot more sense.

Issue opening Excel documents with Internet Explorer

I have run into an issue in which IE does not open up the Save As/Open dialog box for an Excel document like Firefox does.
So I have created a servlet filter that is using '*.xls' as the url pattern. The issue that I now face (since this is the first filter I have created) is how to get the name of the file that the user wants so that the dialog box gets populated correctly. Currently the filter is invoked when the user selects a link on a given page.
Here is what I came up with:
The above is what I have doFilter().
String fileName = "fileName.xls";
HttpServletRequest httpRequest = (HttpServletRequest) pRequest;
String requestURI = httpRequest.getRequestURI();
if(StringUtils.isNotBlank(requestURI))
{
String uri[] = StringUtils.split(requestURI, '/');
fileName = uri[uri.length - 1];
}
HttpServletResponse httpResponse = (HttpServletResponse) pResponse;
httpResponse.setContentType("application/vnd.ms-excel");
httpResponse.setHeader("Content-disposition", "attachment; filename=\"" + fileName +"\"");
web.xml:
<filter>
<filter-name>ExcelFilter</filter-name>
<filter-class>vsg.rp.common.ExcelFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ExcelFilter</filter-name>
<url-pattern>*.xls</url-pattern>
</filter-mapping>
This all is working on my development box: Windows XP, JBoss, Eclipse, Oracle. But when it runs on the test server—Linux, Apache/JBoss, Oracle—it does not work. It appears that the filter is not even being called, no errors thrown, etc. Any idea as to why this would happen?
You want the content type set appropriately as well as the content disposition header, thus:
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename +
"\"");
Use the Content-Disposition HTTP header and set it to something like:
attachment; filename=myworkbook.xls
The is a Microsoft Knowledge Base Article all about this problem. And here is an example of setting Content-Disposition in Java code.
In addition to setting the headers for the content type, you'll also want to ensure that the server DOES NOT tell the browser to NOT CACHE the file.
In IE land, if you tell IE not to cache the file, it happily downloads the file... then tries to open the file from the directory it saved the file to... However since the headers said "don't cache" it takes this literally, and doesn't save the file, thus Excel throws an error saying, "There is no file!".
Long story short, tell IE to CACHE the file.

Categories

Resources