如何从谷歌应用引擎上运行的servlet发送保存字节数组图像的帖子请求到谷歌云存储

时间:2013-10-09 14:35:07

标签: google-app-engine google-cloud-storage

我在google app引擎上运行servlet,以byte []格式接收图像。我想使用POST请求将此图像保存在Google云存储中。

要想到这里的想法是一些代码不能正常工作但是方向正确:

public void postReq( byte[] image) {
    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(getUploadUrl());
    FileBody uploadFilePart = new FileBody(?????, "image/jpg");
    MultipartEntity reqEntity = new MultipartEntity();
    reqEntity.addPart("upload-file", uploadFilePart);
    httpPost.setEntity(reqEntity);
    HttpResponse response = httpclient.execute(httpPost);
}

public String getUploadUrl() {
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    UploadOptions uploadOptions = null;
    String bucket = Constants.BUCKET_NAME;
    uploadOptions = UploadOptions.Builder.withGoogleStorageBucketName(bucket);
    return blobstoreService.createUploadUrl("/upload", uploadOptions);
}

org.apache.http.impl.client.DefaultHttpClient;已被弃用,所以显然不是正确的方法。 我在互联网上找到的一些东西,但我无法运行它们: http://knowledge-serve.blogspot.com/2012/09/upload-file-on-google-cloud-storage.html 正在上传文件 - Using java.net.URLConnection to fire and handle HTTP requests

Google提供了一些非常好的教程,但是用于从html页面上传图片: https://developers.google.com/cloud/samples/photofeed/servephotos

目标是让POST请求将多部分/数据发送到谷歌,然后谷歌将请求返回到我的GAE Servlet,在这种情况下为“/ upload”。所以我应该这样做,但在servlet和byte [] image:

<form action="<%=serviceManager.getUploadUrl()%>" method="post" enctype="multipart/form-data">
    <input id="input-file" class="inactive file btn" type="file" name="photo" onchange="onFileSelected()">
    <textarea name="title" placeholder="Write a description"></textarea>
    <input id="btn-post" class="active btn" type="submit" value="Post">
    <a class="cancel" onclick="togglePhotoPost(false)">Cancel</a>
</form>

2 个答案:

答案 0 :(得分:2)

 1. Send the image via json from android device to the server. 
 2. register your two servlets. One for seving the image to Blob store and one for downloading the image:


<servlet>
    <servlet-name>UploadHandlerServlet</servlet-name>
    <servlet-class>.servlet.UploadHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UploadHandlerServlet</servlet-name>
    <url-pattern>/upload</url-pattern>
</servlet-mapping>
    <servlet>
    <servlet-name>ImagesDownloadServlet</servlet-name>
    <servlet-class>.servlet.ImagesDownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ImagesDownloadServlet</servlet-name>
    <url-pattern>/download</url-pattern>
</servlet-mapping>

and one more servlet that receives the post request with the image. Lets call it "PhoneServlet"
 3. From PhoneServlet we are making post request this way:



    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.io.StringReader;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    private void sendMultipartDataPostReq(byte[] imageByteArray, long boundary, String type) throws MalformedURLException, IOException {        
        log.warning("sendMultipartDataPostReq( ) START");
        String charset = "UTF-8";
        String CRLF = "\r\n"; // Line separator required by multipart/form-data.
        HttpURLConnection  connection = (HttpURLConnection)new URL(getUploadUrl()).openConnection();
        connection.setInstanceFollowRedirects(true);
        connection.setDoOutput(true);// fires POST request
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        PrintWriter writer = null;
        try {
            OutputStream output = connection.getOutputStream();
            writer = new PrintWriter(new OutputStreamWriter(output, charset), true);// true = autoFlush, important! 
            // Send normal param issueId
            writer.append("--" + boundary).append(CRLF);
            writer.append("Content-Disposition: form-data; name=\""+Constants.PARAMETER_TYPE_ISSUEID+"\"").append(CRLF);
            writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
            writer.append(CRLF);
            writer.append(Integer.toString(image.getIssueId())).append(CRLF).flush();
            // Send normal param boundary
            writer.append("--" + boundary).append(CRLF);
            writer.append("Content-Disposition: form-data; name=\""+Constants.PARAMETER_TYPE_BOUNDARY+"\"").append(CRLF);
            writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
            writer.append(CRLF);
            writer.append(Long.toString(boundary)).append(CRLF).flush();
            // Send normal param type
            writer.append("--" + boundary).append(CRLF);
            writer.append("Content-Disposition: form-data; name=\""+Constants.PARAMETER_TYPE_TYPE+"\"").append(CRLF);
            writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
            writer.append(CRLF);
            writer.append(type).append(CRLF).flush();
            // Send binary file.
            writer.append("--" + boundary).append(CRLF);
            writer.append("Content-Disposition: form-data; name=\""+Constants.PARAMETER_TYPE_PHOTO+"\"; filename=\""+ boundary+".jpg" + "\"").append(CRLF);
            writer.append("Content-Type: image/jpg").append(CRLF);
            writer.append("Content-Transfer-Encoding: binary").append(CRLF);
            writer.append(CRLF).flush();
            output.write(imageByteArray);
            output.flush();// Important! Output cannot be closed. Close of writer will close output as well. 
            writer.append(CRLF).flush(); // CRLF is important! It indicates end of binary boundary.
            writer.append("--" + boundary + "--").append(CRLF);// End of multipart/form-data.
            writer.close();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                log.warning("COnection HTTP_OK");
            } else {
                log.warning("Server returned HTTP error code");
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, e.toString(), e);
        }
        log.warning("sendMultipartDataPostReq( ) END");
    }

 4. This invokes UploadServlet 

        public class UploadHandlerServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
        private static Logger log = Logger.getLogger(UploadHandlerServlet.class.getName());

        @Override
        public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
            log.warning("UploadHandlerServlet doPost START");
            BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
            Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req);
            List<BlobKey> keys = blobs.get(Constants.PARAMETER_TYPE_PHOTO);
            String issueId = req.getParameter(Constants.PARAMETER_TYPE_ISSUEID);
            String type = req.getParameter(Constants.PARAMETER_TYPE_TYPE);
            String boundary = req.getParameter(Constants.PARAMETER_TYPE_BOUNDARY);

            EntityManager em = EMF.get().createEntityManager();
            if (type!=null && type.equals(Constants.IMAGE_TYPE_IMAGE)) {
                log.warning("UploadHandlerServlet doPost: IMAGE_TYPE_IMAGE");
                Issue issue = em.find(Issue.class, Integer.parseInt(issueId));
                //we expect only one image so we get only the first key
                Image image = new Image(issue,keys.get(0).getKeyString(),true, Long.parseLong(boundary));
                em.getTransaction().begin();
                em.persist(image);
                em.getTransaction().commit();
                log.warning("UploadHandlerServlet doPost new Image key is saved");
            }
            else if (type!=null && type.equals(Constants.IMAGE_TYPE_THUMBNAIL)) {
                log.warning("UploadHandlerServlet doPost: IMAGE_TYPE_THUMBNAIL");
                Image image = ImageDAO.getImageByTimeCreated(Long.parseLong(boundary));
                if (image !=null) {
                    image.setBlobKeyThumbnail(keys.get(0).getKeyString());
                    em.getTransaction().begin();
                    em.merge(image);
                    em.getTransaction().commit();
                }
                log.warning("UploadHandlerServlet doPost new Thumbnail key is saved");
            }
            log.warning("UploadHandlerServlet doPost END");
        }
    }

and after UploadHandlerServlet our pictures are in the database as blob keys and in the google BlobStore. 
5. We can download them using the ImagesDownloadServlet:

        public class ImagesDownloadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        @Override
        public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
            String blobkeyString = req.getParameter("blobkey");
            if (blobkeyString != null) {
                BlobKey blobKey = new BlobKey(blobkeyString);
                BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
                blobstoreService.serve(blobKey, res);
            }
            else {
                res.sendError(400, "One or more parameters are not set");
            }
        }
    }

6. The important thing for making the POST request is to use java.net library and nothing else from apache for example to make POST request. All these servlets are on our server. 

答案 1 :(得分:0)

我使用spring MVC servlet上传文件。以下是png文件的示例:

@RequestMapping(value="/gcs/{bucket}/{id}", method = RequestMethod.PUT)
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws    IOException {
  GcsService gcsService =
               GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance());
//  GcsFileOptions go = new GcsFileOptions(Builder.);
  GcsFileOptions options = new    GcsFileOptions.Builder().mimeType("image/png").build();
GcsOutputChannel outputChannel =
    gcsService.createOrReplace(getFileName(req), options);
//outputChannel.write(ByteBuffer.wrap(content));
copy(req.getInputStream(), Channels.newOutputStream(outputChannel));
}

private GcsFilename getFileName(HttpServletRequest req) {
String[] splits = req.getRequestURI().split("/", 4);
if (!splits[0].equals("") || !splits[1].equals("gcs")) {
  throw new IllegalArgumentException("The URL is not formed as expected. " +
      "Expecting /gcs/<bucket>/<object>");
}
return new GcsFilename(splits[2], splits[3]);
} 

然后你可以发送一个PUT请求(而不是POST)到url / gcs / {your_bucket} / {your_file}