mirah / dubious

A Web Framework Written in Mirah for running on AppEngine
Apache License 2.0
121 stars 13 forks source link

File upload support #8

Open hakunin opened 13 years ago

hakunin commented 13 years ago

I had the need for file uploads support.

My solution uses appache commons jar (that is not included in Dubious) and it seesms Dubious itself doesn't have support for file uploads (other than blobstore which is a paid feature of appengine if I'm correct)

I would like my solution to be included in dubious or other solution for file uploads.

hakunin commented 13 years ago

Here is the article I used to implement my file uploads http://shogi-software.blogspot.com/2009/04/google-app-engine-and-file-upload.html

hakunin commented 13 years ago

Here is my awesome solution for this problem:

Don't forget to add apache commons to jars. package dubious; import java.util.Map; import java.util.HashMap; import java.util.Iterator; import javax.servlet.http.HttpServletRequest;

// for reading form data when posted with multipart/form-data
import java.io.*;
import javax.servlet.ServletException; 
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.google.appengine.api.datastore.Blob; 

// Fetch the attributes for a given model using rails conventions.
// We need to do this in Java because getParameterMap uses generics.
// We currently only support one lever: foo[bar] but not foo[bar][baz].
// We currently only pull the first value, so no support for checkboxes
public class ScopedParameterMap {
    public static Map params(HttpServletRequest req, String model) 
      throws ServletException, IOException {        

      Map<String, Object> scoped = new HashMap<String, Object>();      

      if (req.getHeader("Content-Type").startsWith("multipart/form-data")) {
        try { 
          ServletFileUpload upload = new ServletFileUpload();
          FileItemIterator iterator = upload.getItemIterator(req);

          while (iterator.hasNext()) {
            FileItemStream item = iterator.next(); 
            InputStream stream = item.openStream(); 

            String attr = item.getFieldName();

            if (attr.startsWith(model + "[") && attr.endsWith("]")) {
              int len = 0;
              int offset = 0;
              byte[] buffer = new byte[8192];
              ByteArrayOutputStream file = new ByteArrayOutputStream();

              while ((len = stream.read(buffer, 0, buffer.length)) != -1) {
                offset += len;
                file.write(buffer, 0, len);
              }

              String key = attr.split("\\[|\\]")[1];

              if (item.isFormField()) {
                scoped.put(key, file.toString());
              } else {
                scoped.put(key, file.toByteArray());
              }
            }
          }
        } catch (Exception ex) { 
          throw new ServletException(ex); 
        }
      } else {
        Map params = req.getParameterMap();
        Iterator i = params.keySet().iterator();
        while (i.hasNext()) {
            String attr = (String) i.next();
            if (attr.startsWith(model + "[") && attr.endsWith("]")) {
                String key = attr.split("\\[|\\]")[1];
                String val = ((String[]) params.get(attr))[0];
                scoped.put(key, val);
                // TODO: when multiple values, set a List instead
            }
        }
      }

      return scoped;
    }
}
hakunin commented 13 years ago

Add this so that blobs don't get overriden when not sending any file.

            if (file.size() > 0) {
              scoped.put(key, file.toByteArray());
            }