13 Replies Latest reply on Dec 7, 2007 5:35 PM by nathan dennis

    File upload to application folder

    Edem Morny Novice

      Hi,

      I have an s:fileUpload control that i use to upload an image file to a directory in my application under the name "img".

      However when i try to save the uploaded file to that folder i get a FileNotFoundException. I know this is not Seam specific, but i still get the same error even if i use the FacesContext i.e. i use it to get access to the ExternalContext and subsequently to the request path of the folder i want to write to. I even tried to use the org.jboss.seam.util.Resources getResource method, which gets me a URL, but i still am not able to write to that URL.

      Can anybody whip up some code on how exactly i can write the byte data i upload to the folder. I'll be very grateful.

        • 1. Re: File upload to application folder
          Shane Bryzak Master

          Can't you just create a FileOutputStream and write the data to that?

          • 2. Re: File upload to application folder
            Stuart Robertson Novice

            The seam component lets you bind to a stream. You can then do just what Shane suggests. Here's how I use it:

            private InputStream uploadFileInputStream;
            


            and

            <s:fileUpload id="catalog" data="#{catalogUpdate.uploadFileInputStream}"
             fileName="#{catalogUpdate.uploadFileName}" />
            


            In your bean, the stream is set to the file contents.

            • 3. Re: File upload to application folder
              Glenn Marcus Newbie

              Seam 1.2.1GA
              Jboss 4.0.5

              I think the challenge here is not receiving the file, but then being able to write the file to a specified location.

              Specifically, I wish to allow a user to upload a .jpg or .png and have it saved off my webroot so that the image can be displayed using an image tag. I do not want to save these images into the database as seamspace and ui does. I want to put them into the filesystem.

              I currently have s:fileupload configured and working. The filecontents are available to my SFSB as

              private byte[] picture
              


              Even if it was an InputStream, I still need to be able to write it out to a new file off of webroot.
              Here is what I have so far:

              profile.xhtml
               <s:fragment rendered="#{user.picture ne null}">
               <s:div id="memberPicture">
               <h:outputLabel for="picture">Member photo:</h:outputLabel>
               <h:outputText value="#{user.picture.originalFilename}" />
               <h:graphicImage value="/content/#{user.picture.filename}"/>
               </s:div>
               </s:fragment>
               <s:fragment rendered="#{identity.loggedIn and (loggedInUser.id==user.id)}">
               <s:fragment rendered="#{user.picture==null}">
               <h:form enctype="multipart/form-data">
               <s:validateAll>
               <div class="formRow">
               <h:outputLabel for="picture">Member photo</h:outputLabel>
               <s:fileUpload id="picture" data="#{profile.picture}" accept="images/png,images/jpg" contentType="#{profile.pictureContentType}" fileName="#{profile.pictureOriginalFilename}"/>
               <div class="validationError"><h:message for="picture"/></div>
               </div>
               </s:validateAll>
               <div class="buttons">
               <h:commandButton value="Upload" action="#{profile.addPicture}" />
               </div>
               </h:form>
               </s:fragment>
               <s:fragment rendered="#{user.picture ne null}">
               <h:form enctype="multipart/form-data">
               <div class="buttons">
               <h:commandButton value="Delete" action="#{profile.deletePicture}" />
               </div>
               </h:form>
               </s:fragment>
               </s:fragment>
              


              ProfileAction.java (the SFSB)
              @Stateful
              @Name("profile")
              public class ProfileAction implements Profile
              {
               @In(required = false, create = false)
               @Out(required = false, scope=SESSION)
               private User loggedInUser;
              
               private String pictureOriginalFilename;
               private String pictureContentType;
               private byte[] picture;
              ...
              
               public String addPicture()
               {
               log.info("addPicture() called");
               log.info("addPicture() - picture size in bytes:#0", picture==null?"0":picture.length);
               log.info("addPicture() - original filename:#0", pictureOriginalFilename);
               log.info("addPicture() - contentType:#0", pictureContentType);
              
               User userToUpdate = em.find(User.class, loggedInUser.getId());
               if (picture != null && picture.length > 0)
               {
               log.info("addPicture() - about to save MemberImage");
              
               // need to save byte[] picture to a unique filename
               try
               {
               OutputStream pictureFileStream = new FileOutputStream(pictureOriginalFilename);
               pictureFileStream.write(picture);
               pictureFileStream.close();
               } catch (Exception e)
               {
               log.info("addPicture() - Problem saving picture: #0", e);
               }
               MemberImage img = new MemberImage();
               img.setMember(userToUpdate);
               img.setContentType(pictureContentType);
               img.setOriginalFilename(pictureOriginalFilename);
               img.setFilename(pictureOriginalFilename);
               em.persist(img);
               log.info("addPicture() - saved MemberImage:#0", img);
              
               userToUpdate.setPicture(img);
               em.persist(userToUpdate);
              
               loggedInUser = userToUpdate;
               }
              
               return "success";
               }
              
              ...
              
              }
              


              How do I write the file out to my webroot? Specifically, I want to write them into /content and be able to use s:graphicImage to display it. Any code examples would be very much appreciated.

              Glenn

              • 4. Re: File upload to application folder
                Shane Bryzak Master

                Your code looks ok to me, is it throwing an exception? Serving it back with s:graphicImage should be a snap, as it supports loading the image from a file directly. Here's what the docs say:

                Attributes

                * value ? image to display. Can be a path String (loaded from the classpath), a byte[], a java.io.File, a java.io.InputStream or a java.net.URL.
                Currently supported image formats are image/png, image/jpeg and image/gif.
                * fileName ? if not specified the served image will have a generated file name. If you want to name your file, you should specify it here.
                This name should be unique


                • 5. Re: File upload to application folder
                  Glenn Marcus Newbie

                  No exceptions were being thrown but the file was not being served. Then I did a search on my hard drive and found that the files were being saved into $JBOSS_HOME\bin.

                  I added the following path to point to the deployed webroot:

                  OutputStream pictureFileStream = new FileOutputStream("../server/default/deploy/fresh.ear/fresh.war/content/" + pictureOriginalFilename);
                  


                  Now files are getting saved in my webroot and displaying correctly on the page.

                  How do I programaticaly get the absolute system filepath of the webroot? Is it somewhere in facesContext?


                  • 6. Re: File upload to application folder
                    Pete Muir Master

                    I doubt you really want to do this. What happens if the app is deployed collapsed?

                    • 7. Re: File upload to application folder
                      Glenn Marcus Newbie

                      Well, I don't want to store the image files in the database due to their size
                      (multiple MB), and you are suggesting keeping them out of the web-root due
                      to packaging issues.

                      What strategy do you recommend? Should I put them into a well known
                      directory outside of the app and write a custom servlet to serve the files from
                      that location?

                      • 8. Re: File upload to application folder
                        Pete Muir Master

                        Yes, this is what I would do.

                        • 9. Re: File upload to application folder
                          Shane Bryzak Master

                          +1 on what Pete said, that's what I'd do too.

                          • 10. Re: File upload to application folder
                            Melanie Ntolo Newbie

                            Hello,
                            I hope you have already found a solution with the FileNotFoundException. Anyway I'm going to tell you how I solved this.

                            I had the same problem: Upload an image through s:fileupload and save it in anoter location.
                            Like you I got the FileNotFoundException.

                            1- You can't use only the fileName property of s:fileupload because this fileName doesn't have the directory structure. It just have something like this: bild.jpg
                            2- You have to locate the directory inside your application (where you want to save your file) with such a code for example:

                            Properties props = System.getProperties();
                            String jbossServerHomeUrl = props.getProperty( "jboss.server.home.url");
                            


                            Psst: with your debugger, you can browse the properties inside props, and see what you have inside...

                            3- When you have your URL Please create an URI with it. And then create a file based on you URI
                            URI bckGUri = new URI( jbossServerHomeUrl );
                            File ilogBackgroundsFile = new File( bckGUri );
                            ilogBackgroundsFile.mkdirs();
                            


                            Psst: If you forget the mkdirs(), you will have the FileNotFoudException again!!

                            4- Then write in your file
                            String imageFileDir = props.getProperty("jboss.server.home.dir") + File.separator + "bild.jpg";
                            FileOutputStream fos = new FileOutputStream( imageFileDir );
                            fos.write( byteArray );
                            


                            Please be aware that I told of URL in part 3 but of Directories in part 4
                            Hope this will help!

                            Hope


                            • 11. Re: File upload to application folder
                              Edem Morny Novice

                              Thanx man!!!! It works beautifully now

                              • 12. Re: File upload to application folder
                                Eric H Novice

                                I set it up so that I use an XMBean to store (persist) configuration data, external to the application. I was facing exactly this problem. It's a bit complicated but all the code for it is here:

                                http://chiralsoftware.com/master-sauce/

                                Storing files in an exploded ear... not a good idea. The EAR file should be thought of as an immutable application file.

                                • 13. Re: File upload to application folder
                                  nathan dennis Expert

                                  pete, you said that a custom servlet is the best way to do this. i am working toward a high traffic environment and i need large amounts of space to store pictures. i was thinking of letting my upload function query my database for a suitable foreign server to store the picture on,,, and writing it down to the remote host.
                                  here is my question. what is the problem with just letting apache deploy that content on the foreign host? wouldnt that be much quicker than executing more code?

                                  these really arent images im worried about securing. i was thinking some really basic cookie authentication as more of a deterrent than a actually securing the data.

                                  what do you think?? terabytes of pictures coming my way,,, how do i handle it and still be cost and performance effective?