I managed to implement downloading with https://vaadin.com/forum/thread/17010389
Now I need to use dynamically defined filename instead of fixed one.
Is it possible ?
Yes. You need to create a new StreamResource and set it as the href
of the Anchor. Here’s a brief example:
public class MainView extends VerticalLayout {
public MainView() {
TextField filenameTextField = new TextField("input file name here");
filenameTextField.setValue("default.txt");
Anchor anchor = new Anchor(getStreamResource("default.txt", "default content"), "click me to download");
anchor.getElement().setAttribute("download",true);
filenameTextField.addValueChangeListener(e -> {
anchor.setHref(getStreamResource(filenameTextField.getValue(), filenameTextField.getValue() + " contains some text"));
});
add(filenameTextField, anchor);
}
public StreamResource getStreamResource(String filename, String content) {
return new StreamResource(filename,
() -> new ByteArrayInputStream(content.getBytes()));
}
}
Thank you !
I have created a class DownloadLink.
Perhaps it makes it a little bit easier
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.server.StreamResource;
public class DownloadLink extends Anchor {
private static final long serialVersionUID = 1L;
public DownloadLink(File file) {
Anchor anchor = new Anchor(getStreamResource(file.getName(), file), file.getName());
anchor.getElement().setAttribute("download", true);
anchor.setHref(getStreamResource(file.getName(), file));
add(anchor);
}
public StreamResource getStreamResource(String filename, File content) {
return new StreamResource(filename, () -> {
try {
return new ByteArrayInputStream(FileUtils.readFileToByteArray(content));
} catch (IOException e) {
e.printStackTrace();
}
return null;
});
}
}
When you create this Class you must give the full path to the file to the constructor
File in = new File("C:\\dev\\wcontent\\mail\\attachments\\575\\Demo.txt");
DownloadLink downloadLink = new DownloadButton(in);
add(downloadLink);
Instead of the line:
return new ByteArrayInputStream(FileUtils.readFileToByteArray(content));
it’s better to use:
return new BufferedInputStream(new FileInputStream(content));
Otherwise, large files require a lot of memory.
Related to this, how would one do lazy loading of the data?
I have a problem handling exception scenario reading stream.
public StreamResource getResource(String docId, String filename) {
return new StreamResource(filename, () -> {
try {
URL url = new URL("http://something.com?id=" + docId);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn.getResponseCode() == 200) {
return new BufferedInputStream(conn.getInputStream());
}
} catch (Exception e) {
e.printStackTrace();
}
** return null;**
});
When null is returned, NPE triggers error handling in
VaadinSession.getCurrent().setErrorHandler((ErrorHandler) errorEvent -> {
ErrorNotification.show("Sistem error: ", errorEvent.getThrowable().getLocalizedMessage());
});
but in this phase UI.getCurrent() is null and throws
throw new IllegalStateException("UI instance is not available. It means that you are calling this method out of a normal workflow where it's always implicitely set. That may happen if you call the method from the custom thread without 'UI::access' or from tests without proper initialization.");
What is the best way to return in UI phase if stream is null?
Using anchor.href I sometimes get “No file” or “File missing” error
Button button = ComponentHelper.getPrimaryButton("XLS Report", false);
Anchor anchor = new Anchor(new StreamResource("Report.xlsx", () -> new ByteArrayInputStream(null)), "");
anchor.add(button);
anchor.getElement().setAttribute("download",true);
button.addClickListener(event -> {
anchor.setHref(getStreamResource4ExportExcel());
});
return anchor;
It seems that the latest Vaadin 14 (14.4.2 for me) broke something. After the download with the solutions above the client-side UI is unresponsive and requires a page refresh to come back (F5 on the browser).
The solution I have that worked was to open the download URI as a new window with:
UI.getCurrent().getPage().executeJs("window.open('"+registration.getResourceUri()+"', \"_blank\", \"\");");
The drawback of this is that the browser might complain about the page opening a link and block it but users should be used to this behaviour.
Filipe Leahy-Dios:
It seems that the latest Vaadin 14 (14.4.2 for me) broke something. After the download with the solutions above the client-side UI is unresponsive and requires a page refresh to come back (F5 on the browser).The solution I have that worked was to open the download URI as a new window with:
UI.getCurrent().getPage().executeJs("window.open('"+registration.getResourceUri()+"', \"_blank\", \"\");");
The drawback of this is that the browser might complain about the page opening a link and block it but users should be used to this behaviour.
I wasn’t able to reproduce the issue with a simple 14.4.2 project. If you can provide some sample code to reproduce the breaking behavior, you should report an issue at https://github.com/vaadin/flow