11

I would like to upload an image and store it on the server, and later to show it with h:graphicImage? I would like to store it in "resources/images" of the app. I am using glassfish 4. Right now, the file goes to "domain1\generated\jsp\FileUpload". Thank you

My form

<h:form id="form" enctype="multipart/form-data">
        <h:messages/>
        <h:panelGrid columns="2">
            <h:outputText value="File:"/>
            <h:inputFile id="file" value="#{uploadPage.uploadedFile}"/>
        </h:panelGrid>
        <br/><br/>
        <h:commandButton value="Upload File" action="#{uploadPage.uploadFile}"/>
</h:form>

My bean

@Named
@ViewScoped
public class UploadPage {       
    private Part uploadedFile; 

    public void uploadFile(){
       File file = File.createTempFile("somefilename-", ".jpg", new File("C:\\var\\webapp\\images"));
    uploadedFile.write(file.getAbsolutePath());

    }
}
Pavel
  • 1,278
  • 2
  • 17
  • 34

2 Answers2

25

I would like to store it in "resources/images" of the app

No, please don't. The WAR deploy space isn't intented as permanent file storage location. All of those uploaded files would get lost whenever you redeploy the webapp for the very simple reason that they are not contained in the original WAR. See for an elaborate explanation also this answer on a very closely related question: Uploaded image only available after refreshing the page.


Right now, the file goes to "domain1\generated\jsp\FileUpload".

Because you specified a relative path in Part#write(). It becomes relative to the current working directory which you have no control over. See for an elaborate explanation also this related answer: getResourceAsStream() vs FileInputStream. You need to specify an absolute path, in other words, start the path with /.


Given that you're using Glassfish, the answer in Uploaded image only available after refreshing the page should also do it for you. In a nutshell:

  1. Create a /var/webapp/images folder. Note that this path is just examplary and fully free to your choice. Also note that when you're using Windows with a C:\ disk, then this path is equivalent to C:\var\webapp\images.

  2. Save the uploaded file in there.

    Path file = Files.createTempFile(Paths.get("/var/webapp/images"), "somefilename-", ".jpg", );
    
    try (InputStream input = uploadedFile.getInputStream()) {
        Files.copy(input, file, StandardCopyOption.REPLACE_EXISTING);
    }
    
    imageFileName = file.getFileName().toString();
    // ...
    

    (note: Files#createTempFile() is being used to autogenerate an unique filename, otherwise a previously uploaded file would get overwritten when the new uploaded file (by coincidence) has exactly the same filename)

  3. Tell GlassFish to register a virtual host on /var/webapp/images so that all files are available on http://example.com/images by adding the following entry to /WEB-INF/glassfish-web.xml of the webapp:

    <property name="alternatedocroot_1" value="from=/images/* dir=/var/webapp" />
    

    (note: alternatedocroot_1 must be exactly like that, keep it unmodified, if you have multiple, name it alternatedocroot_2, etc; also note that the /images part should indeed not be included in dir attribute, this is not a typo)

  4. Now you can display it as follows:

    <h:graphicImage value="/images/#{bean.imageFileName}" />
    

    (note: use value attribute, not name attribute)

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I get java.io.FileNotFoundException for No. 2. and SEVERE: enterprise.deployment.backend.invalidDescriptorFailure SEVERE: enterprise.deployment.backend.saxParserError SEVERE: Exception while deploying the app [FileUpload] SEVERE: Exception during lifecycle processing for No. 3 – Pavel Oct 02 '13 at 17:59
  • As to 2, make sure that the folders are already prepared. As to 4, I didn't said that it has to go in `web.xml`. It has to go in `glassfish-web.xml`. In Eclipse/Netbeans with official GlassFish plugin it should already be autocreated in the project when the project is associated with GlassFish as target runtime. Otherwise, create one yourself. – BalusC Oct 02 '13 at 18:05
  • the folders are created I get java.io.FileNotFoundException: C:\glassfish4\glassfish\domains\domain1\generated\jsp\FileUpload\c:\var\webapp\images\somefilename-8202982476788377654.jpg (The filename, directory name, or volume label syntax is incorrect) and there are files in the folder, but they are 0 bytes – Pavel Oct 02 '13 at 18:40
  • The path is indeed wrong. It should have been `c:\var\webapp\i‌​mages\somefilename-8202982476788377654.jpg` – BalusC Oct 02 '13 at 18:42
  • I just copied the file to the correct new folder and deleted the file in the default folder for uploading. Thanks – Pavel Oct 02 '13 at 21:12
  • This is a great answer, however, you may also want to consider saving the image in a DB as a BLOB. This will all you to easily incorporate the upload, saving and retrieval in a transactional context. – NBW Oct 03 '13 at 12:54
  • @NBW: indeed, but OP explicitly asked to save in disk, not in DB. – BalusC Oct 03 '13 at 12:59
  • WARNING: `File.createTempFile()` guarantees uniqueness of name only during the current invocation of the virtual machine. Therefore if you use this method for permanent storage of files (and not temp, as the method name suggests), then you need to ensure that the first argument of this method (generated filename prefix) remains unique beyond the lifespan of the VM (i.e., after restarting your server). – DTs Feb 21 '14 at 04:25
  • It seems Glassfish implementation does not support absolute paths, did you ever get this to save in the correct directory? It seems from your comments that you had to copy the file manually in the end? If you got it to work please provide update as I'm trying to achieve the same – DTs Feb 21 '14 at 04:27
  • @DTs No, I could not make it. – Pavel Jun 12 '14 at 12:00
  • @BalusC, Please how do one achieve this with Apache? – Ayodeji Dec 28 '15 at 01:40
  • 1
    @Ayodeji: Apache is the name of a software company. I gather you mean its Tomcat product? Nonetheless, the server-independent way is answered here: http://stackoverflow.com/q/18664579 – BalusC Dec 28 '15 at 12:21
2

Wasn't able to get it working with Path#write in glassfish, so I used Path#getInputStream as follows:

public void upload(){
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            String filename = getFilename(uploadedFile);
            File file = new File("/var/webapp/images/"+filename);
            bis = new BufferedInputStream(uploadedFile.getInputStream());
            FileOutputStream fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            int x;
            while((x = bis.read())!= -1){
                bos.write(x);
            }
        } catch (IOException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally{
            try {
                bos.flush();
                bos.close();
                bis.close();
            } catch (IOException ex) {
                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

private static String getFilename(Part part) {
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            }
        }
        return null;
    }
Dapope
  • 128
  • 1
  • 9