JSF application: Open file, not download it - java

Current situation: I'm trying to create a JSF app (portlet) which should contains links to excel files (xls, xlt) stored on public network drive G: mapped for all users in our company. The main goal is to unify access to these files and save work to users in search of the reports somewhere on G drive. I hope it's clear..?
I'm using following servlet to open a file. Problem is, that it's not just opened, but downloaded by browser and after that, opened:
#WebServlet(name="fileHandler", urlPatterns={"/fileHandler/*"})
public class FileServlet extends HttpServlet
{
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
private String filePath;
public void init() throws ServletException {
this.filePath = "c:\\Export";
System.out.println("fileServlet initialized: " + this.filePath);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
{
String requestedFile = request.getPathInfo();
File file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
String contentType = getServletContext().getMimeType(file.getName());
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
close(output);
close(input);
}
}
private static void close(Closeable resource) {
if (resource != null) resource.close();
}
}
How to just start appropriate application (e.g. Excel, Word, etc.) clicking on link (with absolute file path) and open the file in its original location?
UPDATE: I'm trying to use <a> tag:
File // various "/" "\" "\\" combinations
File
But it doesn't work:
type Status report
message /G:/file.xls
description The requested resource is not available.

File URLs are considered as a security risk by most browsers, because they cause files to be opened on a client's machine by a web page, without the end user being aware of it. If you really want to do that, you'll have to configure the browser to allow it.
See the wikipedia article for solutions.

Related

Load image Dynamically via Java servlet

I am trying to load images from server to my JSP
My files are:
image.jsp
<img src='servlet1' height='300px'/>
DisplayImage.java
public class DisplayImage extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
FileInputStream fin = new FileInputStream("path/to/my/img.jpg");
BufferedInputStream bin = new BufferedInputStream(fin);
BufferedOutputStream bout = new BufferedOutputStream(out);
int ch =0;
while((ch=bin.read())!=-1){
bout.write(ch);
}
bin.close();
fin.close();
bout.close();
out.close();
}
}
Application I'm supposed to build is a Vehicle Directory where I can upload images, and these images are stored in a folder /home/upload/ outside CATALINA
(NB: I didn't use a folder inside project directory coz I am deploying the project via *.war file, which removes every files inside when a new version needs to be deployed.)
I want to display the details and image based on search parameters.
( Edit: I have the file name stored in database when I upload them, so can get the list of image names from DB for a particular vehicle, Since it is stored in folder /home/upload/ , full path will be like /home/upload/fileName.jpg which I need to pass to servlet to load)
Problem I face is that:
image src attribute is specified as servlet1 and the servlet by default serves the image from path defined in DisplayImage.java file
Is there any way that I can pass /another/file/Path.jpg or fileName.jpg to the servlet so that I can display other image files too,
Yeah, In JSP, you can pass your search parameters in request.
Like
<input id="imageSerach" name="imageSerach"/>
<div id="ImageContent"/>
and make ajax call to servlet with imageSearch param.
$.ajax({
url: servleturl,
data: {
imageSerach : $('#imageSerach').val()
},
success: function(responseData){
$('#ImageContent').html('<img src="data:image/png;base64,' + responseData + '" />');
}
});
Servlet :-
public class DisplayImage extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{
String fileName = req.getParameter("imageSerach");
response.setContentType("image/jpeg");
ServletOutputStream out;
File f = new File("path/of/file/"+fileName);
if (f.exists())
out = response.getOutputStream();
FileInputStream fin = new FileInputStream("path/of/file/"+fileName);
BufferedInputStream bin = new BufferedInputStream(fin);
BufferedOutputStream bout = new BufferedOutputStream(out);
int ch =0;
while((ch=bin.read())!=-1){
bout.write(ch);
}
bin.close();
fin.close();
bout.close();
out.close();
else
// no file exit
}
}

Download the file from database without saving it on server

I want to retrieve the pdf (Stored as BLOB) from Database using jersey api
I am using mybatis as data base framework .
I am able to download the pdf but the problem is i get the input stream as database to which i save it as file and then pass that it in Response but i don't want to save that file in server , i want file directly to be downloaded to user .
Current Process :
DATABASE-------> input stream-----> File -----------> add to response ----->user downloads it
retrieving making file passing file user downloads
What i want :
DATABASE---------->input stream------------> add to response -------> user downloads it
retrieving passing file user downloads
I want remove File making in server as data is confidential
Resource interface
#GET
#Path("v1/download/{id}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(#PathParam("id") int id) throws IOException, SQLException;
Resource Impl
#Override
public Response downloadFile(int id) throws IOException, SQLException {
// TODO Auto-generated method stub
File file = fileUploadService.downloadFile(id);
ResponseBuilder response = Response.ok(file);
response.header("Content-Disposition", "attachment;filename=aman.pdf");
return response.build();
}
Service method
#Override
public File downloadFile(int id) throws IOException {
// TODO Auto-generated method stub
File fil=new File("src/main/resources/Sample.pdf");
FileUploadModel fm =mapper.downloadFile(id);
InputStream inputStream = fm.getDaFile();
outputStream = new FileOutputStream(fil);
int read = 0;
byte[] bytes = new byte[102400000];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
return fil;
}
This code is working but i want to remove making of file on server side i.e i want to remove File fil=new File("src/main/resources/Sample.pdf"), this operation which is in service method .
Thanks in advance.
Instead of using File, use ByteArrayOutputStream and write to it. Then return the result as a byte[] which you can pass to your Response.ok(content).
Didn't test this, but something like this:
public byte[] downloadFile(int id) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
FileUploadModel fm =mapper.downloadFile(id);
InputStream inputStream = fm.getDaFile();
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
return out.toByteArray();
}
Also, that's a lot of bytes to allocate to an array. You can experiment with what works for you, but something like 1024 would likely be totally sufficient.
You'll probably also want to add another header to your response for Content-Type.

Tomcat not loading new images from context path after server is already started

Inside server.xml of my tomcat folder, i have a virtual folder under <Host> tag:
<Context docBase="C:\app_files\" path="/app_files"/>
So i can access files from inside this folder through the url: http://localhost:8080/app_files/some_file.jpg
But this only works if the image or file was already there BEFORE the server was started. If i go to a URL pointing to an image created after the server was started, it gives the 404 error. After restarting the server, the image loads correctly.
How to sove this problem?
If you use Tomcat application manager you can undeploy/deploy your single application without restarting the whole server (and without impact on other webapps) or, more brutally, you can replace the desired war from the webapps dir (again undeploy/deploy will ensue). If you have to guarantee uptime for your application even in this case you have to go with parallel deployment (here a guide for tomcat 8)
try to add the attribute autoDeploy="true" to your context configuration, this will tell catalina to monitor your docbase location for changes
I actually managed to do what i wanted without using the Context on the server.xml.
It's based on the BalusC's solution to serve static files through servlets
Here's how:
First, i created an environment variable in my system (can be done in every os, just google for "how to create environment variable on windows, linux, etc"), called MANAGEMENT_FILES, the variable value in my case was c:/management_files/
Then, on the method that creates the image that should be shown to the user, i save the image on this folder (which is the value of the environment variable from the previous step):
public String imageUrl;
public void createAndShowImage() {
try {
String imageName = "/nice_images_folder/cool_image.jpg";
File imageFile = new File(System.getenv("MANAGEMENT_FILES") + imageName);
//Here goes your logic to create the file
createImage(imageFile);
//Here i use a fixed URL, you can do it as you see fit
this.imageUrl = "http://localhost:8080/MyCoolApp/" + CoolFileServlet.BASE_URL + imageName + "?delete=true";
} catch (Exception e) {
e.printStackTrace();
}
}
And this is the servlet you have to create, this servlet returns the image or any other file that you put inside the folder:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet(name="CoolFileServlet", urlPatterns={CoolFileServlet.BASE_URL + "*"})
public class CoolFileServlet extends HttpServlet {
public static final String BASE_URL = "/shiny_happy_files/";
private static final int DEFAULT_BUFFER_SIZE = 10240;
private String filePath;
public void init() throws ServletException {
this.filePath = System.getenv("MANAGEMENT_FILES");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String requestedFile = request.getPathInfo();
if (requestedFile == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
File file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
String contentType = getServletContext().getMimeType(file.getName());
if (contentType == null) {
contentType = "application/octet-stream";
}
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
close(output);
close(input);
try {
if ("true".equals(request.getParameter("delete"))) {
if (!file.delete()) {
throw new RuntimeException("File could not be deleted");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Notice that you can pass the parameter delete=true in the url when it is accessed, to delete it right after it is recovered (in cases when it will not be needed anymore).
In my case i needed to show the image on the page after the user performed some action, so all i had to do was show the image url:
<h:graphicImage url="#{myManagedBean.imageUrl}"/>
That's it, you can serve any type of file with this servlet, and it will return the file you want, instantly, and the file will remain active between server restart/redeploy (if it was not deleted through delete=true.
If you care for a different approach, you can also do this by mapping a function in a controller that returns a IOUtils object while specifying the media type, then calling the function's URL in your img's src.
#ResponseBody
#RequestMapping(value="/load_photo", params = {"myPhoto"}, method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public byte[] loadPhoto(#RequestParam(value = "myPhoto") String myPhoto) throws IOException {
File file = new File(servletContext.getRealPath("")+Constants.PATH_TO_FILE+myPhoto);
FileInputStream fis = new FileInputStream(file);
return IOUtils.toByteArray(fis);
}
Then you call your img in your JSP:
<img class="photo" src="/app/controller/load_photo?myPhoto=${myPhoto}">
With this, you can serve dynamically generated images.

File download returns corrupted file (I think) in Play framework 2.2.2

I'm struggling with getting file upload/download to work properly in Play framework 2.2.2. I have a Student class with a field called "cv". It's annotated with #Lob, like this:
#Lob
public byte[] cv;
Here are the upload and download methods:
public static Result upload() {
MultipartFormData body = request().body().asMultipartFormData();
FilePart cv = body.getFile("cv");
if (cv != null) {
filenameCV = cv.getFilename();
String contentType = cv.getContentType();
File file = cv.getFile();
Http.Session session = Http.Context.current().session();
String studentNr = session.get("user");
Student student = Student.find.where().eq("studentNumber", studentNr).findUnique();
InputStream is;
try {
is = new FileInputStream(file);
student.cv = IOUtils.toByteArray(is);
} catch (IOException e) {
Logger.debug("Error converting file");
}
student.save();
flash("ok", "Vellykket! Filen " + filenameCV + " ble lastet opp til din profil");
return redirect(routes.Profile.profile());
} else {
flash("error", "Mangler fil");
return redirect(routes.Profile.profile());
}
}
public static Result download() {
Http.Session session = Http.Context.current().session();
Student student = Student.find.where().eq("studentNumber", session.get("user")).findUnique();
File f = new File("/tmp/" +filenameCV);
FileOutputStream fos;
try {
fos = new FileOutputStream(f);
fos.write(student.cv);
fos.flush();
fos.close();
} catch(IOException e) {
}
return ok(f);
}
The file seems to be correctly saved to the database (the cv field is populated with data, but it's obviously cryptic to me so I don't know for sure that the content is what it's supposed to be)
When I go to my website and click the "Download CV" link (which runs the download action), the file gets downloaded but can't be opened - saying the PDF viewer can't recognize the file etc. (Files uploaded have to be PDF)
Any ideas on what might be wrong?
Don't keep your files in DB, filesystem is much better for that! Save uploaded file on the disk with some unique name, then in your database keep only path to the file as a String!
It's cheaper in longer run (as said many times)
It's easier to handle downloads, i.e. in Play all you need to serve PDF is:
public static Result download() {
File file = new File("/full/path/to/your.pdf");
return ok(file);
}
it will set proper headers, like Content-Disposition, Content-Length and Content-Type not only for PDFs

how to display image which is outside server directory in strtus

This question is continuation to my previous question Accessing External Files Into Our Web Application, actually I am uploading file using struts tag <html:file property="file" />
But now I wanted to show the uploaded images from that location but I am getting src location as http://localhost:9443/D:/resources/images/img1.jpg which is not a valid path for that image.
How to access that image which is outside my server directory.
This is how I am sending Ajax response with Absolute path of images
public ActionForward getAjaxUploadedFiles(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
{
String imagePath = "D:/resources/images/";
ArrayList<String> path = new ArrayList<String>();
File imageFile = new File(imagePath);
File imageFiles[] = imageFile.listFiles();
for (int i = 0; i < imageFiles.length; i++) {
path.add(imageFiles[i].getAbsolutePath());
}
PrintWriter out = response.getWriter();
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.setStatus(HttpServletResponse.SC_OK);
StringBuffer strXMl = new StringBuffer();
strXMl.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
strXMl.append("<start>");
for (String imagePth : path) {
strXMl.append("<imagePath>");
strXMl.append(imagePth);
strXMl.append("</imagePath>");
}
strXMl.append("</start>");
if(strXMl != null){
String Xml = strXMl.toString();
out.write(Xml);
System.err.println("XMl Reponse is: " + Xml);
}
else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
out.flush();
return mapping.findForward(null);
}
This is how I am rendering images at JSP
$(response).find("imagePath").each(function() {
row = tblReportList.insertRow(0);
row.className="TableBordergray";
row.style.width="100%";
var imagePath = $(this).text();
cell = row.insertCell(0);
cell.innerHTML="<img src='" + imagePath + "' alt='" + imagePath + "' height='42' width='42'>";
});
but at img tag I am getting image path as http://localhost:9443/D:/resources/images/img1.jpg
Hi Below is the answer to my question, I have created ImageServlet for displaying image, steps to perform:
1. you need to add mapping in web.xml file:
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/ImageServlet/*</url-pattern>
2. create ImageServlet:
public class ImageServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//Setting image path
ImageLocationService locationService = new ImageLocationService();
try {
String imageCategory = request.getParameter("imageCategory");
if (imageCategory != null) {
this.imagePath = locationService.getImageLocation(imageCategory);
}else{
this.imagePath = ConfigConstants.imageLocation;
}
} catch (Exception e) {
e.printStackTrace();
}
// Get requested image by path info.
String requestedImage = request.getPathInfo();
// Check if file name is actually supplied to the request URI.
if (requestedImage == null) {
// Do your thing if the image is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Decode the file name (might contain spaces and on) and prepare file object.
File image = new File(imagePath, URLDecoder.decode(requestedImage, "UTF-8"));
// Check if file actually exists in filesystem.
if (!image.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Get content type by filename.
String contentType = getServletContext().getMimeType(image.getName());
// Check if file is actually an image (avoid download of other files by hackers!).
// For all content types, see: http://www.w3schools.com/media/media_mimeref.asp
if (contentType == null || !contentType.startsWith("image")) {
// Do your thing if the file appears not being a real image.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open streams.
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
e.printStackTrace();
}
}
}
}
3. At jsp side you need to add the mapping in step 1 in your img tag i.e. input type='image':
<input type="image" alt='No image found' src='../ImageServlet/append image name that you want to display' />
You can even create Action class and use execute method for doing the same.
You can't render images in such way. Web server treated your image path as relative and add qualifying url location on the server. You should create an action to serve images, for example
<action path="/image" ... scope="request" validate="false"/>
Then render HTML like
cell.innerHTML="<img src='" + '/image?path=' + imagePath + "' alt='" + imagePath + "' height='42' width='42'>";
Now, create the action that write the binary image data to the response output stream. Take a parameter path in the action that let you find a file for binary output. After the flushing output return null so struts should not forward the action further. You could also add headers to turn off a Cache-Control to make sure the images are retrieved from the server.

Categories