Glassfish - uploading images - doing it right

2019-04-10 12:47发布

问题:

I am on latest glassfish (3.1.2) - so no need for apache FileItem and no bugs with getPart(). I read that the best practice on uploading images is saving them on the file system (see here for instance). I am editing already existing code - smelly at that - so I had the idea to do :

Part p1 = request.getPart("file");
System.out.println("!!!!!P1 : " + p1);

Prints :

!!!!!P1 : File name=DSC03660.JPG, 
StoreLocation=C:\_\glassfish3\glassfish\domains\domain1\generated\jsp\elkethe\upload_7cb06306_138b413999a__7ffa_00000000.tmp, 
size=2589152bytes, isFormField=false, FieldName=file

newlines mine. In the code people are doing :

if (request.getParameter("crop") != null) {
    // get path on the server
    String outputpath = this.getServletContext().getRealPath(
            "images/temp/" + session.getId() + ".jpg");
    // store photo
    InputStream is = p1.getInputStream();
    createPhoto(is, outputpath);
    session.setAttribute("photo_path", "images/temp/" + session.getId()
            + ".jpg");
    response.sendRedirect("cropping");
    return;
}

Where

private void createPhoto(InputStream is, String outputpath) {
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(outputpath);
        // write bytes taken from uploaded file to target file
        int ch = is.read();
        while (ch != -1) {
            os.write(ch);
            ch = is.read();
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        Helpers.close(os);
    }
}

Now what happens is that the file is uploaded in the StoreLocation (???) on submitting the form so apparently all this p1.getInputStream() is for naught.

My questions are :

  • what is StoreLocation ? How tmp are those glassfish uploads ? Where are all those parameters set ? I did read BalusC' tutorial - but there is no mention of StoreLocation (google is not very helpful either).
  • What would be a more professional way of handling the situation - including keeping the photos outside the webroot - but using facilities glassfish provides (if it does provide) ?
  • Even p1 printing so nice escapes me (it does not seem to Override toString())

Interested in tips even in how should one rename the photos etc (is this sessionID thing Right ? - check also the time trick) :

if (request.getParameter("save") != null) {
    long time = System.currentTimeMillis();
    String path = "images/upload/" + session.getId() + time + ".jpg";
    String outputpath = this.getServletContext().getRealPath(path);
    // store photo
    InputStream is = p1.getInputStream();
    createPhoto(is, outputpath);
    // etc
}

回答1:

Good practice is to pick a path on the filesystem where photos will be uploaded. Often this path is programmed to be configurable via java system property (eg: by passing -Dcom.mycompany.uploadPath=/path/to/photos/dir system property on JVM arguments).

You can also use java system propeties to find environment specific path: user.dir, user.home etc. See System Properties on Java SE Tutorial. Or to use glassfish-relative path, see glassfish system properties.

Once you have reference to Part, it's just about doing file IO to copy the uploaded file into this upload path, eg:

Part part = // obtain part somehow..
String photoFileName = // build a file name somehow..
InputStream photoInputStream = part.getInputStream();
FileOutputStream photoOutputStream = new FileOutputStream(System.getProperty("com.mycompany.uploadPath") + File.separator + photoFileName);
IOUtils.copy(photoInputStream, photoOutputStream);
// close streams here...

Code above uses apache IOUtils for convenience but feel free to write your own copy method. You should also add exception handling method



回答2:

What is StoreLocation ? How tmp are those glassfish uploads ? Where are all those parameters set ?

StoreLocation is just the the java.io.File object for the FileItem's data's temporary location on the disk. Resides in javax.servlet.context.tempdir which defaults to %GLASSFISH_HOME%\domains\domain1\generated\jsp\webApp. Those uploads are as tmp as anything (The lifetime of the file is tied to the lifetime of the FileItem instance; the file will be deleted when the instance is garbage collected - from here). Haven't yet managed to change the value of javax.servlet.context.tempdir programmatically (comment please) - it is the tempdir property of the sun-web-app element of the sun-web.xml.

What would be a more professional way of handling the situation - including keeping the photos outside the webroot - but using facilities glassfish provides (if it does provide) ?

Well a more professional way is to Use Part.write() to move the file to the desired location. Due to glassfish implementation though you can't supply an absolute path to write - a chore. I asked here.

As to where to save the file : https://stackoverflow.com/a/18664715/281545

That is for saving the file - to serve it from a location outside the app you need to define "alternatedocroot" properties in the sun-web.xml (or glassfish-web.xml).

Even p1 printing so nice escapes me (it does not seem to Override toString())

Oh yes it does

Interested in tips even in how should one rename the photos etc (is this sessionID thing Right ? - check also the time trick)

No it is not - I tend towards File#createTempFile() - anyway this is a different question asked here