How to detect when Vaadin FileDownloader succeeds

2019-02-14 19:22发布

问题:

I have Vaadin 7 code to give the user an option to download a file:

    Button btnDownloadResults = new Button("Download Results", FontAwesome.CLOUD_DOWNLOAD);
    resource = new StreamResource(new MyStreamResource(), suggestedSaveAsFilename);
    new FileDownloader(resource).extend(btnDownloadResults);

I would like to trigger code when the download has succeeded, or even if the download manages to start. Uses for this include closing a window, starting a progress spinner, or incrementing a download count.

Unlike the Vaadin Upload component, the FileDownloader does not have any listeners for finding out when a file download fails, succeeds, or starts.

Here is a simplified version of my StreamResouce subclass:

public class MyStreamResource implements StreamSource {
@Override
public InputStream getStream() {
    String filename = /* code to determine the filename */;

    try {
        final File results = new File(FilenameUtils.normalize(filename));
        return new FileInputStream(results);
    } catch (FileNotFoundException fnfe) {
        String errorMsg = "Cannot download results. Try again later, or contact your sysadmin.";
        Utilities.showError(errorMsg);

        return null;
    } catch (Exception e) {
        Utilities.logAndShowException(e);
        return null;
    }
}
}

Note that the getStream method returns before the user has even been prompted where to save the file (which they can choose to cancel.) So I can't trigger anything from inside that method.

One suggestion I got was to subclass the FileDownloader as follows:

FileDownloader fileDownloader = new FileDownloader(fileInputStream) {
    private static final long serialVersionUID = -4584979099145066535L;
    @Override
    public boolean handleConnectorRequest(VaadinRequest request, VaadinResponse response, String path) throws IOException {
        boolean result = super.handleConnectorRequest(request, response, path);
        if (result) {
            /* YOUR LOGIC GOES HERE */
        }
        return result;
    }
} ;

Again, this fires too soon (and the boolean result is always true, even if my StreamSource returns null.)

Any suggestions?

回答1:

After more research I believe the answer is that there is no simple way to get this information from the FileDownloader.

The difficulty appears to be a consequence of the way the FileDownloader is designed. From the FileDownloader docs: "Download should be started directly when the user clicks e.g. a Button without going through a server-side click listener to avoid triggering security warnings in some browsers."

Because there is no round-trip back to the web server, there is no place to respond when the download fails, starts, or succeeds.

Some vague (and possibly bad) ideas for a workaround:

  • Have JS post some kind of asynchronous notification to the web server, letting it know what happened. (Using JMS or Ajax?)
  • If there was some kind active process on the backend involved with transferring the file, it would know when the transfer happened.

But the short answer seems to be there is no built-in way in Vaadin to do it.



标签: vaadin