Friday, March 5, 2010

File upload in JSF2 using base class

Surfing the net for JSF2 resources can be a tedious task. Actually for file upload I actually found a couple of blogs describing how to do it the firs I found actually only (FileUpload with JSF 2 and Servlet 3.0) made a taglib based on the second one. And it includes maven which I do not use.

I had to remake the example a bit since I got question to provide a sample application. When extracting the code I noticed it did not work anymore. The reason is probably the one mentioned at this blog: http://mcatr.blogspot.com/2010/01/multipart-requests-and-jsf.html.To make it work again, I did a solution that I am not happy with but it works. It takes the idea from this blog, joined with some from the other blogs mentioned. The former blog states that a multipart request to JSF 2 do not work, because it can not extract parameters from that kind of request.

The problem is that for what I actually wanted it was not right and one was a little bit overkill. So as usual I took another approach. I got some helf from Uploading files with JSF 2.0 and Servlet 3.0 but that solution includes making a custom component and renderer, and is dependant on classes found in Uploading files in Servlet 3.0. I actually copied all the code and tried it...but I got a failure when loading the page. So I wanted something with less code. and simpler to use, and I have a case when I am going to store vCards in a database so a solution to save the file on disk means I have to modify code anyway.

I took the following approach:

  • Use standard html <input type="file" />
  • Use @ManagedBean
  • I first had a base class to handle the file and extended the Managed bean with this one, but since this stopped working I had to add:
    • A Wrapper to wrap multipart requests
    • A Filter to catch multipart request and transform them to the Wrapper type.
  • I also have a FacesUtil class to simplify getting request and parameters
Here is the code:

In the view (vCardForm.xhtml)

Class to represent the uploaded file (UploadFile.java)

I created a class to store some information about the file being upload, I can later choose if I want to store to disk or in a database, for example sending this to an EJB and the EJB descides what to do.

The managed bean (VCardBean.java)

The interesting thing going on here is that i initialize the base class with the request for use of the request. Probably I could have done this in the constructor of the baseclass, but something you have to have to refactor.

MultipartRequestWrapper


MultipartRequestFilter



Session bean for handling the storage.

For the example this only stores it in the session.

Finally the class to inherit to make it all work

This is now obsolete, but I keep it in case JSF will handle the mutlipart form in the future. But even then it may not be needed.

The only thing needed in the Managed bean is to call findFile("vcardFile") on the multipart request to get the file that is being uploaded and take action on that.

A sample project (for netbeans) can be found here: http://sites.google.com/site/ironicprogrammer/home/jsf-file-upload-example

29 comments:

  1. it would be of great help if you could upload this sample application ..

    ReplyDelete
  2. Ok, Maybe I will. It is part of a bigger application. I rewrote the code on the blog a little, but when I have time I will make a stripped version and put it on the Google-site.

    ReplyDelete
  3. great .. thanks for uploading the sample app ..

    ReplyDelete
  4. Hope you saw I had to rewrite a bit. Anyway, the sample project should work.

    ReplyDelete
  5. Does it work with https as well ? Many file-upload components are not working over https if you are using a self-signed certificate ..

    ReplyDelete
  6. Have not tried, but can not see why not. Test and see what happen :)

    ReplyDelete
  7. Where does it save to? can i save the file to my desktop? what configuration have to be changed? Thks

    ReplyDelete
  8. It does not save it anywhere, or whereever you want it to be. I used EJB to save it to a database. But you can write any code you want in the business layer or the web project to save the file where you want it.

    ReplyDelete
  9. The sample application is great.

    I just have a problem with validation. First, as far as I know I cannot add standard JSF validators to tag and second, if the specified file does not exist, where would I throw ValidationException?

    Thanks

    ReplyDelete
  10. It doesn't works here, the wrapper rans down and no parts were in the request to loop through...

    ReplyDelete
  11. @n3whous3: Running on glassfish v3? How is it set up otherwise? This worked for me.

    ReplyDelete
  12. This solution works perfectly for file uploads. However, I have a strange problem. When using enctype="multipart/form-data" the code in this example gets executed. The fields in forms are correctly transformed, however in one form I have a selectManyListbox and this list box always returns only one option when used in conjunction with the file upload solution. Do you have an idea why this could happen?

    ReplyDelete
  13. Have not used JSF for long, but probably the requestwrapper does something that makes that listbox behaving differently. Put som debugging on that to see what happens.

    ReplyDelete
  14. This tutorial's great but how do i upload a file to folder?it would be great if you could help me how to upload it to folder.Thank you

    ReplyDelete
  15. Hi "minhltnt", have a look here > http://www.mkyong.com/struts/struts-file-upload-example/ to get inspiration how to save it to the file system.

    ReplyDelete
  16. Hi,thanks your support and i have a questions again: i use EJB3+JSF+Primcefaces,i have method handle upload image in folder and it work well but it just work when server deploy first,when i upload image to server(folder:/WEB-INF/item/) have image but i re-start server i can't find image which was uploaded.How do i solve this problem?Hope your support again.Thanks!

    ReplyDelete
  17. This tutorial is great, works perfectly for me.
    You literally saved my ass. Thanks !

    ReplyDelete
  18. Your project does not mention the list of jar used

    ReplyDelete
  19. Well, I do not solve everything for everyone. If you use Netbeans you would probably figure it out or get all the help you need to use it.

    Anyway, I also imply that you have some basic knowledge, and I also post stuff to document things I have done and maybe will need again. For me it is not interesting to list jar-files

    ReplyDelete
  20. Man, I still have an issue: never had problems with the stuff written by you, on the contrary, the issue I have is the following:

    with the JSF implementation I use - Mojarra 2.* - when I put the enctype to multipart stuff, the controller methods in the managed bean (the stuff you put at action="" in h:commandButton) DOES NOT GET CALLED. Now that is a 100 points question, what shall I do about that...

    ReplyDelete
  21. Well, I do not know Mojarra 2. Probably some issues with framworks and the order stuff gets called. Does Mojarra use som call stack like struts that for some reason overrides/removes stuff on the way?

    ReplyDelete
  22. does not work on jboss - tomcat: https://issues.apache.org/bugzilla/show_bug.cgi?id=49711

    ReplyDelete
  23. I see you did not post my second comment :) - the second one, very curious if you found anything offensive as I merely pointed out an issue. The discussion was getting interesting.

    ReplyDelete
  24. I have posted all comments I have seen. Not offensive, but I am not really interested in discussions with anonymous on things I did 2 years ago. But I really do not know wich comment you mean should have been offensive? Was it the jboss-tomcat issue?

    ReplyDelete
  25. WTF ... it is COMPLICATED!!!!! to upload a simple f***** file !

    ReplyDelete
  26. Hi dear author,
    tell us please there we can get your FacesUtil.class ?

    ReplyDelete
  27. You cant. I do not work at the same place as I wrote this code.
    You need to do the work yourself. What it does is to wrap code like:
    HttpServletRequest req = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
    To avoid having that much code everytime it just do that in
    FacesUtil.getRequest()

    ReplyDelete
  28. It has some bugs and these are the solutions:

    Bug1: "WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception"
    http://www.imixs.org/roller/ralphsjavablog/entry/using_multipartconfig_in_a_servlet
    This worked! Now it can upload files and download.
    Bug2: "java.io.FileNotFoundException: d:\tmp\upload_633d607a_143cc20a63e__7ffb_00000011.tmp (The device is not ready)", caused by my disk name.
    Bug3: "javax.faces.FacesException: PWC3991: getOutputStream() has already been called for this response"
    This doesn't matter too much since the function works just fine now.
    This bug I'm trying to solve by using my knowledge – UploadFile.java implements Serializable and close all stream. Solution: Add this "FacesContext.getCurrentInstance().responseComplete();" from http://stackoverflow.com/questions/5662455/jsf-2-0-convert-xhtml-page-to-pdf-using-flying-saucer-java-lang-illegalstateexc or https://community.oracle.com/thread/1726938?start=0&tstart=0

    Changes:
    1)add the following to web.xml

    f:\tmp
    20848820
    418018841
    1048576

    2)In VCardBean, findVCard method add "
    output.flush();
    FacesContext.getCurrentInstance().responseComplete();"
    3)create folder f:\tmp

    ReplyDelete
  29. Bugs? Yes maybe depending how the environment is set up. Considder also that I wrote this post 4 years ago, so the App-server you are running on, and versions of Servlet API etc, may differ now.

    ReplyDelete