Blog

Enable Users to Upload & Download Files

By  
Tarek Oraby
Tarek Oraby
·
On Sep 1, 2021 6:27:00 PM
·

This guide demonstrates how to create a web app that enables users to upload and download files to and from the server in Java.

Feature image for blog post

In this guide, we create a web app that enables users to upload and download files to and from the server. The UI allows users to select local files to be uploaded to the server. Once a file upload is completed, the UI offers a link allowing users to download the file back from the server. The web app is developed entirely in Java using Vaadin Flow (no HTML or JavaScript involved). You can explore the full source code on GitHub

What You Need

  • About 10 minutes
  • JDK 8 or later 

Import a starter project

  1. Download a starter project by clicking the following button
    DOWNLOAD A STARTER
  2. Unzip the starter and open the project in your favorite IDE.

Create Upload Area

Let’s start by creating the part of the UI that allows users to upload files to the server. The UploadArea class extends VerticalLayout, and it acts as a container holding two components: an Upload and a Span. The Upload component, uploadField, is one of Vaadin’s components that enable users to, well, upload files. The Span, errorField, is used to show users informative error messages in the event that something goes wrong during the upload process.

import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.upload.MultiFileReceiver;
import com.vaadin.flow.component.upload.Receiver;
import com.vaadin.flow.component.upload.Upload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class UploadArea extends VerticalLayout {

    private final Upload uploadField;
    private final Span errorField;

    public UploadArea(File uploadFolder) {
        uploadField = new Upload(createFileReceiver(uploadFolder));
        uploadField.setMaxFiles(100);
        // set max file size to 1 MB
        uploadField.setMaxFileSize(1 * 1024 * 1024);
        uploadField.setDropLabel(new Label("Drop file here (max 1MB)"));

        errorField = new Span();
        errorField.setVisible(false);
        errorField.getStyle().set("color", "red");

        uploadField.addFailedListener(e -> showErrorMessage(e.getReason().getMessage()));
        uploadField.addFileRejectedListener(e -> showErrorMessage(e.getErrorMessage()));

        add(uploadField, errorField);
    }

    public Upload getUploadField() {
        return uploadField;
    }

    public void hideErrorField() {
        errorField.setVisible(false);
    }

    private Receiver createFileReceiver(File uploadFolder) {
        return (MultiFileReceiver) (filename, mimeType) -> {
            File file = new File(uploadFolder, filename);
            try {
                return new FileOutputStream(file);
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
                return null;
            }
        };
    }

    private void showErrorMessage(String message) {
        errorField.setVisible(true);
        errorField.setText(message);
    }
}

Create Download-Links Area

Next, we create the part of the UI that lists the download links to the user. The DownloadLinksArea class also extends the VerticalLayout component, and it adds a link to the UI for each file that exists inside the upload folder.


import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.html.H4;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.server.StreamResource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

public class DownloadLinksArea extends VerticalLayout {

    private final File uploadFolder;

    public DownloadLinksArea(File uploadFolder) {
        this.uploadFolder = uploadFolder;
        refreshFileLinks();
        setMargin(true);
    }

    public void refreshFileLinks() {
        removeAll();
        add(new H4("Download Links:"));

        for (File file : uploadFolder.listFiles()) {
            addLinkToFile(file);
        }
    }

    private void addLinkToFile(File file) {
        StreamResource streamResource = new StreamResource(file.getName(), () -> getStream(file));
        Anchor link = new Anchor(streamResource, String.format("%s (%d KB)", file.getName(),
                (int) file.length() / 1024));
        link.getElement().setAttribute("download", true);

        add(link);
    }

    private InputStream getStream(File file) {
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        return stream;
    }
}

Create the Main View

Now we create the view that holds the upload and download-links area. This view is itself yet another VerticalLayout, and it is made accessible to the end user via the @Route annotation (in this case, it would be accessible via the empty  route).


import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import java.io.File;

@Route("")
public class UploadDownloadView extends VerticalLayout {

   public UploadDownloadView() {
      File uploadFolder = getUploadFolder();
      UploadArea uploadArea = new UploadArea(uploadFolder);
      DownloadLinksArea linksArea = new DownloadLinksArea(uploadFolder);

       uploadArea.getUploadField().addSucceededListener(e -> {
          uploadArea.hideErrorField();
          linksArea.refreshFileLinks();
      });

      add(uploadArea, linksArea);
  }

  private static File getUploadFolder() {
      File folder = new File("uploaded-files");
      if (!folder.exists()) {
          folder.mkdirs();
      }
      return folder;
  }
}

Run the Application

To run the project from the command line, type mvnw spring-boot:run (on Windows), or ./mvnw spring-boot:run (on macOS or Linux). 

Then, in your browser, open http://localhost:8080.

Summary

Congratulations! You have created a web app that enables users to upload and download files to and from the server in Java. And you did it in pure Java, without the need to use HTML or JavaScript, and without the need to expose REST services or think about HTTP requests, responses, and filter chains.

You can explore the full source code on GitHub.

See also

Tarek Oraby
Tarek Oraby
Tarek is a Product Manager at Vaadin. His daily work is a blend of talking to users, planning, and overseeing the evolution of Vaadin Flow and Hilla, ensuring they consistently delight our developer community.
Other posts by Tarek Oraby