Java file upload using Oreilly Multipartrequest - java

I'm doing a java web application that manage online auctions. At a certain point in the application the user can sell a product, so I have built a page where there is a form; in this form I have to handle the file upload using Oreilly Multipartrequest library. When I click the submit button a servlet should handle all the parameters, add the product on the database, and then redirect to the users page, but instead of doing it, the application hangs in a blank page. I'm using netbeans so I have checked the logs, but I can't find any errors; I have also checked on the logs inside the tomcat folder, but again I can't any errors. I don't know what to do neither where to search the solution.
Here is the part of the code that handle the upload:
try {
MultipartRequest multi =
new MultipartRequest(request, getServletContext().getRealPath("/img"), 10*1024*1024,
"ISO-8859-1", new DefaultFileRenamePolicy());
Enumeration files = multi.getFileNames();
while (files.hasMoreElements()) {
name = (String)files.nextElement();
filename = multi.getFilesystemName(name);
// String originalFilename = multi.getOriginalFileName(name);
// String type = multi.getContentType(name);
File f = multi.getFile(name);
if (f != null) {
session.setAttribute("success", "file written correctly");
}
}
} catch (IOException IEx) {
this.getServletContext().log("Error reading saving file");
}
Am I doing something wrong, or my idea is correct?
P.S. If the user decide not to upload any picture, I have to put on the database a default picture.

Related

How to get my page to update an image when overwritten

I am attempting to overwrite and update an image on a page whenever my end user would like. They would simply upload a new image, and it will replace the old with the same file name and then the src path in the web page does not need to change. However, it kind of works. The file overwrites. but when I refresh the page the image does not change to the new. The odd kicker is, When I go into my IDE (Eclipse) and double-click the new image file, THEN I can refresh the web page and it shows the new replaced one. This is my first job project, and I have not found the answer elsewhere.I will provide the code;
<img th:src="#{/img/uploadedFile.jpg}" alt="image"></img>
#RequestMapping(method=RequestMethod.POST, value="image")
public String processImageForm(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
return "redirect:image";
}
String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
Path path = Paths.get(UPLOADED_FOLDER + fileName + extension);
try {
Files.deleteIfExists(path);
} catch (IOException | SecurityException e) {
System.err.println(e);
}
try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Files.write(path, bytes);
redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'");
} catch (IOException e) {
e.printStackTrace();
}
return "redirect:image";
}
}
My guess would be that you are not copying that file to the correct location.
You know that in a web app the the war file is created and then deployed on a server. So in order to change something you need to change it on the server (even when running from Eclipse it creates a server context from you). I guess that's where your problem comes from - you copy the file to the wrong place.
And when you are running from Eclipse the file is properly replaced on your local file system but this doesn't change the deployed war application. When you double click it in Eclipse it notices the change and automatically redeploys it for you basically changing the file on the server.

Spring MVC upload a file and then provide a link for downloading

I have Spring MVC web app running on Tomcat.
I upload a file and save it in the /tmp folder on the file system.
Then I need to show a link to that file in the view (Thymeleaf), so that the user can download the file by clicking on the link. How to do that?
I've heard about configuring Tomcat to allow a specific context to link to a folder on the FS, but not sure how to do that or if that is the only solution. Please help.
The way I approach this is slightly different. Basically I use two controller actions for handling file uploads, one for uploading, and for downloading (viewing) files.
So upload action would save files to some preconfigured directory on the file system, I assume you already have that part working.
Then declare download action similar to this
#Controller
public class FileController {
#RequestMapping("/get-file/{filename}")
public void getFileAction(#RequestParam filename, HttpServletResponse response) {
// Here check if file with given name exists in preconfigured upload folder
// If it does, write it to response's output stream and set correct response headers
// If it doesn't return 404 status code
}
}
If you want to make impossible to download file just by knowing the name, after uploading file, save some meta info to the database (or any other storage) and assign some hash (random id) to it. Then, in getFileAction, use this hash to look for file, not the original filename.
Finally, I would discourage using /tmp for file uploads. It depends on the system/application used, but generally temp directory are meant, as name suggest, for temporary data. Usually it is guaranteed data in the temp directory will stay for "reasonable time", but applications must take into account that content of temp directory can be deleted anytime.
This is the precisely setup that worked for me (Tomcat 8, SpringMVC, boot):
server.xml:
<Context docBase="C:\tmp\" path="/images" />
In the controller:
public String createNewsSource(#ModelAttribute("newsSource") NewsSource source, BindingResult result, Model model,
#RequestParam("attachment") final MultipartFile attachment) {
new NewsSourceValidator().validate(source, result);
if (result.hasErrors()) {
return "source/addNewSource";
}
if (!attachment.isEmpty()) {
try {
byte[] bytes = attachment.getBytes();
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File("/tmp/" + attachment.getOriginalFilename())));
stream.write(bytes);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
source.setLogo("images/" + attachment.getOriginalFilename());
newsSourceService.createNewsSourceIfNotExist(source);
return "redirect:/sources/list";
}
As you can see I am saving the file to /tmp, but in the DB (source.setLogo()), I am pointing to images as mapped in server.xml
Here's where I found about Tomcat config:
If the images are all located outside the webapp and you want to have
Tomcat's DefaultServlet to handle them, then all you basically need to
do in Tomcat is to add the following Context element to
/conf/server.xml inside tag:
This way they'll be accessible through http://example.com/images/....
SO answer to a similar question

how to monitor progress of uploading file in servlet 3.1

i want to monitor the progress of the file which is getting uploaded
i m using servlet 3.1
i know that by the specs of servlet 3.1 , i don't need apache common fileUpload
i can do that only by the Part class
i did this
InputStream inputStream = null;
double s;
String size=null;
String contentType=null;
String submittedName=null;
String tim=null;
String actualLocation=null;
System.out.println("getting it also here");
Part filePart = request.getPart("file");
System.out.println("getting it here");
if(description.equals(""))
{
System.out.println("please provide some description about file");
}
else{
if (filePart != null )
{
s=(double)filePart.getSize();
double MB=(s/1048576);
if(MB != 0)
{
size=String.valueOf((float)MB);
contentType=filePart.getContentType();
submittedName=getFormatted(filePart.getSubmittedFileName());
tim=String.valueOf(System.currentTimeMillis());
actualLocation=name+"-"+commun+"-"+tim+"-"+submittedName;
System.out.println("getting it there");
inputStream = filePart.getInputStream();
System.out.println("getting it here & there");
try
{
File file=new File(x,actualLocation);
Files.copy(inputStream, file.toPath());
}
i know i can use a listener to monitor the progress , but the main question is that where should i set progress listener
i thought it should be set with Part filePart.before System.out.println("getting it here")
this is a screenshot of my project
u can see that chrome is displaying the progress of uploading (in the bottom)(but i want a much more impressive progress bar)
when i ran my project i thought that in the console i'll see "getting it also here " while uploading but i found that control is not coming to that part unless uploading is completed.
i'm a bit confuse at which segment the uploading is happening and where should i set progress listener
You don't need to do anything in server side for upload progress bar. You can do that just using javascript, html and css.
If you are using jQuery take a look at this pugin http://malsup.com/jquery/form/. Here is a file upload progress bar demo link http://malsup.com/jquery/form/progress.html. There are two more demos and plenty more examples in the website.
And you can take a look at this tutorial http://codular.com/javascript-ajax-file-upload-with-progress for doing this with html5 and javascript. Just ignore the PHP part.
You should not have to change anything in your java code, cause the servlet method will be hit after the file upload has been completed.

Webapplication: Delete files during runtime

I am developing a webapp (for mobile phones). There is one xhtml page, where I want to show a picture, which is stored locally on my hard drive (for example: D:\pictures\test.jpg).
Since browsers block images when they are located on a local harddrive, I wrote a method in my javabean, where the picture, stored on the localHD, is copied to the webApp directory, when the user enters the xhtml page. After the user leaves the page, the copied file inside the webapp should be deleted.
So when I'm running my app, copying works perfectly and the pictures are displayed correctly. However, when the files should get deleted, I get this errormessage:
java.nio.file.FileSystemException: D:\WebAppPath\src\main\webapp\resources\pics\test.jpg:
The process cannot be accessed because the file is being used by another process.
Strangely enough, after stopping and restarting the application I can delete the same image if it is still in the webApp directory. (But Only once; after re-copying it, I get the error message again.)
Also if I want to delete the file manually, by using Windows explorer, I get the error message that the file can't be deleted because it is used by Java(TM) Platform SE Binary.
So to delete the file (manually or via the bean) I have to wait for a restart of the application, which of course is not an acceptable solution for the end user.
I'm using JSF2.0 with Primefaces and Primefaces Mobile components. My IDE is Netbeans and I use Spring Webflow framework to navigate and trigger actions/methods between the xhtml pages.
Here's the code for the copying method in my JavaBean:
public void copyFotoToLocalhost() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
String originalFile = "D:\\localFilepath\\" + tempItemName;
String tempFileName = "D:\\WebAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName;
File existTest = new File(tempFileName);
if (existTest.exists() == false) {
try {
File orFile = new File(originalFile);
File tempFile = new File(tempFileName);
InputStream in = new FileInputStream(orFile);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
tempFile.setWritable(true);
System.out.println("File copied.");
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage() + " in the specified directory.");
System.exit(0);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
Here's the code for the delete method:
public void deleteFotos() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
Path tempLocation = Paths.get("D:\\webAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName);
fotoList.remove(i);
i--;
try {
Files.deleteIfExists(tempLocation);
System.out.println("sucessfully deleted" + tempPic.getItemName());
} catch (IOException ex) {
Logger.getLogger(WundDokuBean.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Fail # " + tempPic.getItemName());
}
}
fotoList.clear();
}
Do you have an idea, how to fix this?
I hope you understand my problem, if not please tell me which information you need, I'll try to provide it.
There is one xhtml page, where I want to show a picture, which is stored locally on my hard drive (for example: D:\pictures\test.jpg). Since browsers block images when they are located on a local harddrive (...)
I want to clear out a conceptual misunderstanding first: You seem to expect that it would work fine when the browser wouldn't have blocked it. This is completely untrue. You seem to expect that images are inlined in the HTML output. No, they are downloaded individually and independently from the HTML page. If you had continued to use local disk file system paths, then it would have worked only and only if your webpage visitor has also exactly the same file at exactly the same location at their disk file system. In reality, this is obviously not the case. It would only work if both the webbrowser and webserver runs at physically the same machine.
Coming back to your concrete problem of being unable to delete the file, it's is caused because the servletcontainer usually locks the files in expanded WAR folder. I can't tell the exact reason, but that's not relevant here as this whole approach is wrong anyway. This approach would fail when the deployed WAR file is not expanded on disk file system, but instead in server's memory. Also, hardcoding environment-specific disk file system paths is a bad idea. You'd need to edit, rewrite, recompile, rebuild the whole WAR everytime you change the environment. In other words, your webapp is not portable.
You need to keep the files there where they originally are and make them publicly available by a real URL. This can be achieved in 2 general ways:
Add a virtual host to the server config, pointing to D:\localFilepath\. How to achieve that depends on the server used. You didn't tell anything about the server make/version used, but using Spring suggests that you're not being able to use full Java EE stack and are likely using a barebones JSP/Servlet container such as Tomcat. In that case, it's a matter of adding the following line to its /conf/server.xml:
<Context docBase="D:\localFilepath" path="/fotos" />
This way they are available by http://localhost:8080/fotos/*.
Create a servlet which reads files from D:\localFilepath and writes to HTTP response. With Servlet 3.0 and Java 7 it's really a breeze. Here's a kickoff example (nullchecks/file-exist-checks/doHead()/caching/resuming omitted for brevity):
#WebServlet("/fotos/*")
public class FotosServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletExcpetion, IOException {
File file = new File("D:/localFilepath", request.getPathInfo().substring(1));
response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", String.valueOf(file.length()));
Files.copy(file.toPath(), response.getOutputStream());
}
}
That's basically it. This way they're available on http://localhost:8080/contextname/fotos/*.

Locating a file in a network disk in a Servlet

I create ImageServlet to refer to videos out of my web application scope.
The location of all of my videos are on a intranet location that could be reached from any computer in the intranet:
String path = "\\myip\storage\ogg\VX-276.ogg"
In my application, when I write it as URL - it can't display it!
If I try to open it with chrome it automatically changes it to file://myip/storage/ogg/VX-276.ogg and the file is being displayed.
I tried to do so: file:////odelyay_test64/storage/ogg/
as well but Java converts the string to: file:\myip\storage\ogg\VX-276.ogg which does not exist!
What is the correct way to refer to it?
EDITED
I create a small test:
String path = "file://myip/storage/ogg/VX-276.ogg";
File file = new File(path);
if (file.exists())
System.out.println("exists");
else {
System.out.println("missing" + file.getPath());
}
and I get:
missing file:\myip\storage\ogg\VX-276.ogg
As you can see the slashes are being switched
As per your previous question, you're referencing the resource in a HTML <video> tag. All URLs in the HTML source code must be http:// URLs (or at least be relative to a http:// URL). Most browsers namely refuse to load resources from file:// URLs when the HTML page is itself been requested by http://. You just need to let the URL point to the servlet. If the servlet's doGet() method get hit, then the URL is fine and you should not change it.
Your concrete problem is in the way how you open and read the desired file in the servlet. You need to ensure that the path in File file = new File(path) points to a valid location before you open a FileInputStream on it.
String path = "file://myip/storage/ogg/VX-276.ogg";
File file = new File(path);
// ...
If the servlet code is well written that it doesn't suppress/swallow exceptions and you have read the server logs, then you should have seen an IOException such as FileNotFoundException along with a self-explaining message in the server logs whenever reading the file fails. Go read the server logs.
Update as per the comments, it turns out that you're using Windows and thus file:// on a network disk isn't going to work for Java without mapping it on a drive letter. You need to map //myip on a drive letter first, for example X:.
String path = "X:/storage/ogg/VX-276.ogg";
File file = new File(path);
// ...
in the end I used VFS library of apache and my code looks like this:
public static void main(String[] args) {
FileSystemManager fsManager = null;
String path = "\\\\myip\\storage\\ogg\\VX-276.ogg";
try {
fsManager = VFS.getManager();
FileObject basePath;
basePath = fsManager.resolveFile("file:" + path);
if (basePath.exists())
System.out.println("exists");
else {
System.out.println("missing" + basePath.getURL());
}
} catch (FileSystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
In this way, I don't need to create a driver for each user of the system and it allows me not to depend on operation system!

Categories