Using Cloud Storage with Java for the App Engine standard environment

This part of the Bookshelf tutorial for Java shows how to store images in Cloud Storage.

This page is part of a multipage tutorial. To start from the beginning and read the setup instructions, go to Java Bookshelf app.

Creating a Cloud Storage bucket

The following instructions detail how to create a Cloud Storage bucket. Buckets are the basic containers that hold your data in Cloud Storage.

  1. In your terminal window, create a Cloud Storage bucket, where YOUR_BUCKET_NAME represents the name of your bucket:

    gsutil mb gs://YOUR_BUCKET_NAME
  2. To view uploaded images in the Bookshelf app, set the bucket's default access control list (ACL) to public-read:

    gsutil defacl set public-read gs://YOUR_BUCKET_NAME

Running the app on your local machine

To run the app locally:

  1. In the getting-started-java/bookshelf-standard/3-binary-data directory, enter the following command to start a local web server:

    mvn package appengine:run -Dbookshelf.bucket=[YOUR-BUCKET]
    Replace [YOUR-BUCKET] with your bucket name.
  2. In your web browser, go to http://localhost:8080.

Now you can browse the app's web pages, add books with cover images, edit books, and delete books.

Deploying the app to the App Engine standard environment

To deploy to the App Engine standard environment:

  1. To create a Datastore index that is uploaded to the Bookshelf app, create at least one book, and then click My Books. Note, building the app using the clean command deletes that local index so do this on the build of the app that you are going to deploy.
  2. In the getting-started-java/bookshelf-standard/3-binary-data directory, enter this command to deploy the app:
  3. mvn appengine:deploy -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION] -Dbookshelf.bucket=[YOUR-BUCKET]
    Replace [YOUR-PROJECT-ID] with your project ID and [YOUR-VERSION] with your version, for example, 1, or 2, or some other string value you want to use.
  4. In your web browser, enter the following URL:

    Replace the following:

After you update your app, you can redeploy the updated version by entering the same command as when you first deployed the app as well as specifying the same project ID and version. This overwrites the currently deployed app. If you specify a different version string in the updated command line, the new deployment creates a new version of your app and promotes it to be the currently serving version.

You can reduce costs by deleting the non-serving versions of your app.

To delete an app version:

  1. In the Cloud Console, go to the Versions page for App Engine.

    Go to the Versions page

  2. Select the checkbox for the non-default app version you want to delete.
  3. Click Delete to delete the app version.

For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

App structure

Binary data sample structure

The app uses Cloud Storage to store binary data, such as pictures in this case. The app continues to use Datastore for book information.

Understanding the code

This section walks you through the app's code and explains how it works.

Handle user uploads

It is simple to use the Cloud Storage API for Java. In most cases, a single line is all you need to authenticate locally.

static {
  storage = StorageOptions.getDefaultInstance().getService();

Upload blobs to Cloud Storage

Verify the file matches your requirements before uploading it.

 * Checks that the file extension is supported.
private void checkFileExtension(String fileName) throws ServletException {
  if (fileName != null && !fileName.isEmpty() && fileName.contains(".")) {
    String[] allowedExt = {".jpg", ".jpeg", ".png", ".gif"};
    for (String ext : allowedExt) {
      if (fileName.endsWith(ext)) {
    throw new ServletException("file must be an image");

Make the filename unique by appending a timestamp to it. Using storage.create, pass a BlobInfo created with bucketName and fileName, and set the access control list so that all users can read and pass the file's InputStream. The result is the public URL for the object.

 * Uploads a file to Google Cloud Storage to the bucket specified in the BUCKET_NAME
 * environment variable, appending a timestamp to end of the uploaded filename.
public String uploadFile(FileItemStream fileStream, final String bucketName)
    throws IOException, ServletException {

  DateTimeFormatter dtf = DateTimeFormat.forPattern("-YYYY-MM-dd-HHmmssSSS");
  DateTime dt =;
  String dtString = dt.toString(dtf);
  final String fileName = fileStream.getName() + dtString;

  // the inputstream is closed by default, so we don't need to close it here
  BlobInfo blobInfo =
              .newBuilder(bucketName, fileName)
              // Modify access list to allow all users with link to read file
              .setAcl(new ArrayList<>(Arrays.asList(Acl.of(User.ofAllUsers(), Role.READER))))
  // return the public download link
  return blobInfo.getMediaLink();