How to Upload and Store an Image with Google App Engine (Java)

How to upload and store an image with google app engine (java)

The link your provided "How do I handle file uploads to my app?" explains how you can upload the image.

To host the images, you need to use the Datastore service to store and serve image along with your other data.

Here is a sample code. It is meant as a sketch, for how you can have your own entity (i.g. business, user, etc) have a field for an image. I ignored all error handling and recovery to simplify the code.

Declaring your entity with the image. You can imagine having other fields, e.g. tags, location, etc

@Entity
public class MyImage {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;

@Persistent
private String name;

@Persistent
Blob image;

public MyImage() { }
public MyImage(String name, Blob image) {
this.name = name;
this.image = image;
}

// JPA getters and setters and empty contructor
// ...
public Blob getImage() { return image; }
public void setImage(Blob image) { this.image = image; }
}

Then when you start accepting images (watch out for cases where an image with the same name has already been uploaded in addition to the typical file upload failures). ServletFileUpload and IOUtils are classes that are part of the Apache Commons library.

// Your upload handle would look like
public void doPost(HttpServletRequest req, HttpServletResponse res) {
// Get the image representation
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(req);
FileItemStream imageItem = iter.next();
InputStream imgStream = imageItem.openStream();

// construct our entity objects
Blob imageBlob = new Blob(IOUtils.toByteArray(imgStream));
MyImage myImage = new MyImage(imageItem.getName(), imageBlob);

// persist image
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.makePersistent(myImage);
pm.close();

// respond to query
res.setContentType("text/plain");
res.getOutputStream().write("OK!".getBytes());
}

And finally when you want to serve an image given its name:

Blob imageFor(String name, HttpServletResponse res) {
// find desired image
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("select from MyImage " +
"where name = nameParam " +
"parameters String nameParam");
List<MyImage> results = (List<MyImage>)query.execute(name);
Blob image = results.iterator().next().getImage();

// serve the first image
res.setContentType("image/jpeg");
res.getOutputStream().write(image.getBytes());
}

Storing uploaded images on Google App Engine with Java

Now it is possible on GAE. Simply you have to store your files in Blobstore. You can upload your files like this:

<body>
<form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="submit" value="Submit">
</form>

And then to serve file from servlet:

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
blobstoreService.serve(blobKey, res);

Upload an image to google app engine blobstore with java programmatically

You can simply write binary data to blobstore:

byte[] yourBinaryData = // get your data from request
writeChannel.write(ByteBuffer.wrap(yourBinaryData));

Upload image to Google Cloud Storage (Java)

You can public your file, and then the media link of the blob can access anywhere.

https://cloud.google.com/storage/docs/access-control/making-data-public

This is my solution.

try {
FileInputStream serviceAccount =
new FileInputStream("firebaseKey/serviceAccountKey.json");

FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://xxxxx.firebaseio.com")
.build();
FirebaseApp fireApp = FirebaseApp.initializeApp(options);

StorageClient storageClient = StorageClient.getInstance(fireApp);
InputStream testFile = new FileInputStream(file.getPath());
String blobString = "NEW_FOLDER/" + "FILE_NAME.jpg";
Blob blob = storageClient.bucket("xxxxxx.appspot.com")
.create(blobString, testFile , Bucket.BlobWriteOption.userProject("xxxxxxx"));
blob.getStorage().createAcl(blob.getBlobId(), Acl.of(Acl.User.ofAllUsers(), Acl.Role.READER));
System.out.println(blob.getMediaLink());
} catch (Exception e){
e.printStackTrace();
}

How to properly upload (image) file to Google Cloud Storage using Java App Engine?

As far as I can tell, there is no problem with Google Cloud Storage or the APIs; the problem is earlier, in the reading of the content from HttpServletRequest.

The lines containing ------266cb0e18eba are actually part of the MIME encoding and marks the beginning and end of a part.

You can resolve the issue in one of two ways.

Option A: Keep the code the same, but change the way you upload data

Replace:

$ curl -F file=@"picture.jpg" http://myAppEngineProj.appspot.com/myServlet

With:

$ curl -X POST -d @"picture.jpg" http://myAppEngineProj.appspot.com/myServlet

Option B: Fix the Java code and continue using curl as you are using it

Replace:

java.io.InputStream is = request.getInputStream();

With:

javax.servlet.http.Part filePart = request.getPart("file");
java.io.InputStream is = filePart.getInputStream()

Which opens an input stream on the correct part in the multipart MIME message which curl constructed.

This is documented here:

http://docs.oracle.com/javaee/6/tutorial/doc/gmhba.html

Option B is probably the better option because it will work with forms and form uploads.

How to upload images to Google Cloud Storage using Google App Engine?

I ended up using https://cloud.google.com/appengine/docs/python/googlecloudstorageclient/app-engine-cloud-storage-sample (The GCS client @ChrisC73 pointed out.

Also, referred to @vocausa's signed_url project: https://github.com/voscausa/appengine-gcs-signed-url

Upload File to Google Cloud Storage via appengine

Finally I am able to uploading a file from client end to Google Cloud Storage via appengine.

I assume that before executing these steps you have following things ready

  • JSON file from your service account.
  • Created a default bucket.

Step 1: Make a Servlet like this

package XXXXXXXXX;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.Arrays;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.api.client.http.InputStreamContent;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.model.ObjectAccessControl;
import com.google.api.services.storage.model.StorageObject;

import XXXXXXXXXXXXX.StorageFactory;

//@author Umesh Chauhan

/**
* Save File to GCS
*
* @param fileName File Name with format
* @header Content-Type "*/*"
* @return file path
* @throws Exception Any Error during upload
*/
public class UploadFile extends HttpServlet
{

private static final long serialVersionUID = 1L;
private final String BUCKET = "YOUR BUCKET NAME";
private int maxFileSize = 6 * 1024 * 1024;

@Override
protected void doOptions ( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
{
// pre-flight request processing
resp.setHeader ( "Access-Control-Allow-Origin", "*" );
resp.setHeader ( "Access-Control-Allow-Methods", "*" );
resp.setHeader ( "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept" );
}

@Override
public void doPost ( HttpServletRequest request, HttpServletResponse response )
throws ServletException, java.io.IOException
{

try
{
String path = uploadFile ( request.getParameter ( "fileName" ), request.getContentType (),
request.getInputStream (), BUCKET, request.getInputStream ().available () );
// Sending Response
response.setStatus ( HttpServletResponse.SC_OK );
response.getWriter ().write ( path );
response.getWriter ().flush ();
response.getWriter ().close ();

}
catch ( GeneralSecurityException e )
{
e.printStackTrace ();
}
}

public String uploadFile ( String name, String contentType, InputStream input, String bucketName,
int contentLength ) throws IOException, GeneralSecurityException
{

InputStreamContent contentStream = new InputStreamContent ( contentType, input );

if ( contentLength < maxFileSize )
{

// It is done Automatically.
/*
* // Setting the length improves upload performance
* contentStream.setLength ( contentLength );
*/

StorageObject objectMetadata = new StorageObject ()
// Set the destination object name
.setName ( name )
// Set the access control list to publicly read-only
.setAcl ( Arrays.asList (
new ObjectAccessControl ().setEntity ( "allUsers" ).setRole ( "READER" ) ) );

// Do the insert
Storage client = StorageFactory.getService ();

Storage.Objects.Insert insertRequest = client.objects ()
.insert ( bucketName, objectMetadata, contentStream );

insertRequest.execute ();

return "https://storage.cloud.google.com/" + BUCKET + "/" + name;
}
else
{
throw new GeneralSecurityException ( "File size canot be more then 6 MB !" );
}
}

public void doGet ( HttpServletRequest request, HttpServletResponse response )
throws ServletException, java.io.IOException
{
throw new ServletException ( "GET method used with " + getClass ().getName () + ": POST method required." );
}

}

Step 2: Your Storage Factory

package XXXXXXXXXXXX;

import java.io.IOException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Collection;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.StorageScopes;

//@author Umesh Chauhan

public class StorageFactory
{

private static Storage instance = null;

public static synchronized Storage getService () throws IOException, GeneralSecurityException
{
if ( instance == null )
{
instance = buildService ();
}
return instance;
}

private static Storage buildService () throws IOException, GeneralSecurityException
{

HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport ();
JsonFactory jsonFactory = new JacksonFactory ();

GoogleCredential credential = GoogleCredential.fromStream (
new URL ( "HERE GOES THE URL FOR YOUR SERVICE ACCOUNT JSON - I USED GOOGLE DRIVE DIRECT DOWNLOAD LINK TO MY JSON FILE" )
.openStream () );

// Depending on the environment that provides the default credentials
// (for
// example: Compute Engine, App Engine), the credentials may require us
// to
// specify the scopes we need explicitly. Check for this case, and
// inject
// the Cloud Storage scope if required.
if ( credential.createScopedRequired () )
{
Collection<String> scopes = StorageScopes.all ();
credential = credential.createScoped ( scopes );
}

return new Storage.Builder ( transport, jsonFactory, credential ).setApplicationName ( "YOUR PROJECT NAME" ).build ();
}
}

Step 3: Update you web.xml

    <servlet>
<servlet-name>UploadFile</servlet-name>
<servlet-class>PACKAGE.UploadFile</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>UploadFile</servlet-name>
<url-pattern>/uploadManager/UploadFile</url-pattern> //Based on your original URL
</servlet-mapping>


Related Topics



Leave a reply



Submit