feat: export to CSV

This commit is contained in:
filippo-ferrari 2024-09-12 11:00:20 +02:00
parent 6df84a4b30
commit 2e2e7c3555
2 changed files with 57 additions and 1 deletions

11
pom.xml
View file

@ -52,6 +52,12 @@
<groupId>com.vaadin</groupId> <groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId> <artifactId>vaadin-spring-boot-starter</artifactId>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.11.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.vaadin.klaudeta</groupId> <groupId>org.vaadin.klaudeta</groupId>
<artifactId>grid-pagination</artifactId> <artifactId>grid-pagination</artifactId>
@ -101,6 +107,11 @@
<artifactId>vaadin-testbench-junit5</artifactId> <artifactId>vaadin-testbench-junit5</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.10.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -1,7 +1,7 @@
package com.application.munera.views.expenses; package com.application.munera.views.expenses;
import com.application.munera.security.SecurityUtils;
import com.application.munera.data.*; import com.application.munera.data.*;
import com.application.munera.security.SecurityUtils;
import com.application.munera.services.*; import com.application.munera.services.*;
import com.application.munera.views.MainLayout; import com.application.munera.views.MainLayout;
import com.vaadin.flow.component.UI; import com.vaadin.flow.component.UI;
@ -13,6 +13,7 @@ import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.dependency.Uses;
import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.GridVariant; import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.Notification;
@ -27,13 +28,22 @@ import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.data.converter.StringToBigDecimalConverter; import com.vaadin.flow.data.converter.StringToBigDecimalConverter;
import com.vaadin.flow.data.renderer.ComponentRenderer; import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.*; import com.vaadin.flow.router.*;
import com.vaadin.flow.server.StreamResource;
import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.PermitAll;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVFormat;
import org.vaadin.klaudeta.PaginatedGrid; import org.vaadin.klaudeta.PaginatedGrid;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@ -52,6 +62,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
private final Button cancel = new Button("Cancel"); private final Button cancel = new Button("Cancel");
private final Button save = new Button("Save"); private final Button save = new Button("Save");
private final Button delete = new Button("Delete"); private final Button delete = new Button("Delete");
private final Button exportToCSVButton = new Button("Export to CSV");
private final BeanValidationBinder<Expense> binder; private final BeanValidationBinder<Expense> binder;
private Expense expense; private Expense expense;
@ -109,6 +120,15 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
grid.setPageSize(22); // setting page size grid.setPageSize(22); // setting page size
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER); grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
// Export to CSV button
exportToCSVButton.addClickListener(event -> {
StreamResource resource = createCSVResource(expenseService.findAll());
Anchor downloadLink = new Anchor(resource, "Download CSV");
downloadLink.getElement().setAttribute("download", true);
add(downloadLink);
});
add(exportToCSVButton);
// when a row is selected or deselected, populate form // when a row is selected or deselected, populate form
grid.asSingleSelect().addValueChangeListener(event -> { grid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) UI.getCurrent().navigate(String.format(EXPENSE_EDIT_ROUTE_TEMPLATE, event.getValue().getId())); if (event.getValue() != null) UI.getCurrent().navigate(String.format(EXPENSE_EDIT_ROUTE_TEMPLATE, event.getValue().getId()));
@ -329,4 +349,29 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
} }
} }
} }
private StreamResource createCSVResource(List<Expense> expenses) {
return new StreamResource("expenses.csv", () -> {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader("Name", "Cost", "Category", "Period Interval", "Period Unit", "Date", "Status"))) {
for (Expense expense : expenses) {
csvPrinter.printRecord(
expense.getName(),
expense.getCost(),
expense.getCategory() != null ? expense.getCategory().getName() : "",
expense.getPeriodInterval(),
expense.getPeriodUnit(),
expense.getDate(),
expense.getIsPaid() ? "Paid" : "Unpaid"
);
}
} catch (Exception e) {
e.printStackTrace();
}
return new ByteArrayInputStream(stream.toByteArray());
});
}
} }