The following method sets up a DownloadHandler
with a byte array and a filename, and programmatically triggers the download using JavaScript
private static void downloadFile(byte[] fileContent, String fileName) {
DownloadHandler handler = (DownloadEvent event) -> {
event.setFileName(fileName);
event.getResponse().setHeader("Content-Type",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
event.getResponse().setHeader("Cache-Control", "public, max-age=3600");
try (OutputStream out = event.getOutputStream()) {
out.write(fileContent);
}
};
Anchor downloadAnchor = new Anchor(handler, "Download Excel");
UI.getCurrent().access(() -> {
UI.getCurrent().add(downloadAnchor);
downloadAnchor.getElement().executeJs("this.click(); $0.remove()", downloadAnchor.getElement());
});
}
This works reliably when called from within a normal view.
However, when called from within a dialog, it behaves inconsistently(works sometimes and sometimes does not) :
In firefox
http://localhost:8080/VAADIN/dynamic/resource/0/f87e9251-f7e3-40db-98a5-327a73268ec1/ might have a temporary problem or it could have moved.
Error code: 403 Forbidden
In brave
it tries to save a download.json file
Am I doing something wrong here or is it a Vaadin Issue?
Reproducible example:
@Route("")
public class MainView extends VerticalLayout {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(MainView.class);
public MainView() {
List<Person> people1 = Arrays.asList(new Person("Alice", 30), new Person("Bob", 25));
List<Person> people2 = List.of(new Person("Charlie", 35));
add(new H3("Grid 1 (Main View)"), createGrid(people1), createDownloadButton(people1, "grid1_main.xlsx"));
add(new H3("Grid 2 (Main View)"), createGrid(people2), createDownloadButton(people2, "grid2_main.xlsx"));
Dialog dialog = new Dialog();
VerticalLayout dialogLayout = new VerticalLayout();
dialogLayout.setWidth(600, Unit.PIXELS);
dialogLayout.add(new H3("Grid 1 (Dialog)"), createGrid(people1),
createDownloadButton(people1, "grid1_dialog.xlsx"));
dialogLayout.add(new H3("Grid 2 (Dialog)"), createGrid(people2),
createDownloadButton(people2, "grid2_dialog.xlsx"));
dialog.add(dialogLayout);
Button openDialogButton = new Button("Open Dialog", e -> dialog.open());
add(openDialogButton);
}
private Grid<Person> createGrid(List<Person> people) {
Grid<Person> grid = new Grid<>(Person.class, false);
grid.setHeight(150, Unit.PIXELS);
grid.addColumn(Person::getName).setHeader("Name");
grid.addColumn(Person::getAge).setHeader("Age");
grid.setItems(people);
return grid;
}
private Button createDownloadButton(List<Person> data, String fileName) {
return new Button("Download Excel", e -> {
byte[] excel = createExcel(data);
downloadFile(excel, fileName);
});
}
private static byte[] createExcel(List<Person> data) {
try (Workbook workbook = new XSSFWorkbook()) {
Sheet sheet = workbook.createSheet("Data");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("Name");
header.createCell(1).setCellValue("Age");
for (int i = 0; i < data.size(); i++) {
Person person = data.get(i);
Row row = sheet.createRow(i + 1);
row.createCell(0).setCellValue(person.getName());
row.createCell(1).setCellValue(person.getAge());
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
workbook.write(out);
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException("Failed to create Excel file", e);
}
}
private static void downloadFile(byte[] fileContent, String fileName) {
DownloadHandler handler = (DownloadEvent event) -> {
event.setFileName(fileName);
event.getResponse().setHeader("Content-Type",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
event.getResponse().setHeader("Cache-Control", "public, max-age=3600");
try (OutputStream out = event.getOutputStream()) {
out.write(fileContent);
}
};
Anchor downloadAnchor = new Anchor(handler, "Download Excel");
UI.getCurrent().access(() -> {
UI.getCurrent().add(downloadAnchor);
downloadAnchor.getElement().executeJs("this.click(); $0.remove()", downloadAnchor.getElement());
});
}
public static class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}