Java file upload: build a web UI with the webforJ Upload

For a Java file upload web UI, use the webforJ Upload component. Create an Upload, add filters and limits, listen for onUpload, and move each UploadedFile out of the temporary folder into your own storage. The component gives you the picker, the drop zone, the file list and progress reporting, and all of your handling code stays in Java.
The Upload component is available since webforJ 26.01. This post builds a complete upload page: one or many files, accepted types and size limits, drag and drop, progress, a Spring service that saves the files, a Table that lists them, and file download.
How do you add an upload field?
Create the component, add it to a layout, and give it at least one filter. A filter is a description plus glob patterns separated by semicolons:
Upload upload = new Upload();
upload.addFilter("Documents", "*.pdf;*.docx");
upload.addFilter("Images", "*.png;*.jpg");
layout.add(upload);
By default the component shows a select button, a drop area, the list of picked files, and an upload button. The user picks files, clicks Upload, and the files travel to the server. You don't write markup, a servlet, or a multipart parser.
Upload renders inline in the page. If you need a modal that blocks the app until the user finishes, the FileUploadDialog returns the same UploadedFile type from a single call, OptionDialog.showFileUploadDialog("Upload a file"). Use the inline component when picking files is part of a larger form, which covers most cases.
How do you upload multiple files?
Selection mode decides how many files the user can pick. MULTIPLE is the default, and SINGLE suits a field that holds one value, such as a profile photo:
upload.setSelectionMode(Upload.SelectionMode.SINGLE);
Folders work too. setPicker(Upload.Picker.DIRECTORY) uploads the top-level files of a folder, and DIRECTORY_RECURSIVE walks the whole tree.
How do you limit file types and size?
Filters narrow what the picker offers. setMaxFileSize caps the bytes per file and setMaxFiles caps the batch. Both run in the browser before any bytes move, so a file that's too large never consumes bandwidth. When a picked or dropped file breaks a limit, the component fires UploadRejectEvent:
upload.setMaxFiles(5d);
upload.setMaxFileSize(10d * 1024 * 1024); // 10 MB
upload.onReject(e -> Toast.show(e.getMessage()));
Treat these limits as guidance for the user. A browser can be bypassed, so the server has to enforce its own. Set webforj.fileUpload.maxSize in your configuration as a hard ceiling in bytes, and webforj.fileUpload.accept to restrict allowed types. With Spring, both go in application.properties. Then re-check the name or type of every file in your own code before you store it, as the service below does.
How does drag and drop work?
Drag and drop is on by default. Files dropped on the component are handled like picked files, and the drop label changes while a file hovers over it. Turn it off with setDrop(false) when files should only come from the picker.
Auto upload removes the need to click Upload. ON_SELECT starts the transfer when files are picked, ON_DROP when they're dropped, and ALWAYS covers both:
upload.setAutoUpload(Upload.AutoUpload.ON_SELECT);
upload.setVisible(false, Upload.Part.UPLOAD_BUTTON);
Presets reshape the component for common layouts. INLINE fits a form field, BUTTON_ONLY shows just the picker button, and DROPZONE shows only the drop label and the list. With HEADLESS, every built-in part is hidden and the children you add() become the visible surface of the drop area. Call setPreset() before setVisible() when you use both. On phones, setCapture(Upload.Capture.ENVIRONMENT) opens the rear camera, and a matching image filter makes it open in still mode.
How do you show upload progress?
The component reports progress per file and for the whole batch. onProgress fires repeatedly during one file's transfer. onListProgress fires alongside it with batch totals, which is what a single progress bar needs:
ProgressBar progress = new ProgressBar();
upload.onListProgress(e -> progress.setValue((int) e.getListProgress()));
The other events cover the rest of the life cycle:
| Event | Fires |
|---|---|
UploadChangeEvent | The list of picked files changes |
UploadEvent | The files have reached the server |
UploadRejectEvent | A file breaks a client-side limit, before any bytes move |
UploadErrorEvent | A transfer fails after it started |
UploadCompleteEvent | Every queued file finished, with getUploadedFiles() and getFailedFiles() |
UploadCancelEvent | The user clicks Cancel |
UploadEvent is the place to save files. UploadCompleteEvent is the place to update the screen when the batch is done. All listeners run on the UI thread, so they can update components directly.
