From 9d258aa50581584c515ce9253dabfc1f409d28c3 Mon Sep 17 00:00:00 2001 From: Marcus Hellberg Date: Mon, 1 Apr 2024 15:36:34 -0700 Subject: [PATCH] Update the crud example --- .../src/main/java/com/baeldung/IndexView.java | 4 +- .../main/java/com/baeldung/data/Employee.java | 9 +- .../java/com/baeldung/spring/CrudView.java | 69 ----------- .../com/baeldung/spring/EmployeeEditor.java | 117 ++++++++---------- .../com/baeldung/spring/EmployeesView.java | 95 ++++++++++++++ 5 files changed, 160 insertions(+), 134 deletions(-) delete mode 100644 vaadin/src/main/java/com/baeldung/spring/CrudView.java create mode 100644 vaadin/src/main/java/com/baeldung/spring/EmployeesView.java diff --git a/vaadin/src/main/java/com/baeldung/IndexView.java b/vaadin/src/main/java/com/baeldung/IndexView.java index c69b160895..45ab534ef6 100644 --- a/vaadin/src/main/java/com/baeldung/IndexView.java +++ b/vaadin/src/main/java/com/baeldung/IndexView.java @@ -4,7 +4,7 @@ import com.baeldung.introduction.PushView; import com.baeldung.introduction.basics.VaadinFlowBasics; import com.baeldung.introduction.FormView; import com.baeldung.introduction.GridView; -import com.baeldung.spring.CrudView; +import com.baeldung.spring.EmployeesView; import com.vaadin.flow.component.html.H1; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; @@ -20,6 +20,6 @@ public class IndexView extends VerticalLayout { add(new RouterLink("Grid", GridView.class)); add(new RouterLink("Form", FormView.class)); add(new RouterLink("Push", PushView.class)); - add(new RouterLink("CRUD", CrudView.class)); + add(new RouterLink("CRUD", EmployeesView.class)); } } diff --git a/vaadin/src/main/java/com/baeldung/data/Employee.java b/vaadin/src/main/java/com/baeldung/data/Employee.java index 2685e38286..cdaa426eeb 100644 --- a/vaadin/src/main/java/com/baeldung/data/Employee.java +++ b/vaadin/src/main/java/com/baeldung/data/Employee.java @@ -4,6 +4,7 @@ package com.baeldung.data; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.validation.constraints.Size; @Entity public class Employee { @@ -12,11 +13,13 @@ public class Employee { @GeneratedValue private Long id; + @Size(min = 2, message = "First name must have at least 2 characters") private String firstName; + @Size(min = 2, message = "Last name must have at least 2 characters") private String lastName; - protected Employee() { + public Employee() { } public Employee(String firstName, String lastName) { @@ -28,6 +31,10 @@ public class Employee { return id; } + public void setId(Long id) { + this.id = id; + } + public String getFirstName() { return firstName; } diff --git a/vaadin/src/main/java/com/baeldung/spring/CrudView.java b/vaadin/src/main/java/com/baeldung/spring/CrudView.java deleted file mode 100644 index a77e32e965..0000000000 --- a/vaadin/src/main/java/com/baeldung/spring/CrudView.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.baeldung.spring; - -import com.baeldung.data.Employee; -import com.baeldung.data.EmployeeRepository; -import org.springframework.util.StringUtils; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.grid.Grid; -import com.vaadin.flow.component.icon.VaadinIcon; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.TextField; -import com.vaadin.flow.data.value.ValueChangeMode; -import com.vaadin.flow.router.Route; - -@Route("crud") -public class CrudView extends VerticalLayout { - - private final EmployeeRepository employeeRepository; - - private final EmployeeEditor editor; - - final Grid grid; - - final TextField filter; - - private final Button addNewBtn; - - public CrudView(EmployeeRepository repo, EmployeeEditor editor) { - this.employeeRepository = repo; - this.editor = editor; - this.grid = new Grid<>(Employee.class); - this.filter = new TextField(); - this.addNewBtn = new Button("New employee", VaadinIcon.PLUS.create()); - - HorizontalLayout actions = new HorizontalLayout(filter, addNewBtn); - add(actions, grid, editor); - - grid.setHeight("200px"); - grid.setColumns("id", "firstName", "lastName"); - grid.getColumnByKey("id").setWidth("50px").setFlexGrow(0); - - filter.setPlaceholder("Filter by last name"); - - filter.setValueChangeMode(ValueChangeMode.EAGER); - filter.addValueChangeListener(e -> listEmployees(e.getValue())); - - grid.asSingleSelect().addValueChangeListener(e -> { - editor.editEmployee(e.getValue()); - }); - - addNewBtn.addClickListener(e -> editor.editEmployee(new Employee("", ""))); - - editor.setChangeHandler(() -> { - editor.setVisible(false); - listEmployees(filter.getValue()); - }); - - listEmployees(null); - } - - void listEmployees(String filterText) { - if (StringUtils.isEmpty(filterText)) { - grid.setItems(employeeRepository.findAll()); - } else { - grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText)); - } - } -} diff --git a/vaadin/src/main/java/com/baeldung/spring/EmployeeEditor.java b/vaadin/src/main/java/com/baeldung/spring/EmployeeEditor.java index 25e447102c..0bc2c61e20 100644 --- a/vaadin/src/main/java/com/baeldung/spring/EmployeeEditor.java +++ b/vaadin/src/main/java/com/baeldung/spring/EmployeeEditor.java @@ -1,92 +1,85 @@ package com.baeldung.spring; import com.baeldung.data.Employee; -import com.baeldung.data.EmployeeRepository; +import com.vaadin.flow.component.Composite; import com.vaadin.flow.component.Key; -import com.vaadin.flow.component.KeyNotifier; import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.data.binder.Binder; -import com.vaadin.flow.spring.annotation.SpringComponent; -import com.vaadin.flow.spring.annotation.UIScope; -import org.springframework.beans.factory.annotation.Autowired; -@SpringComponent -@UIScope -public class EmployeeEditor extends VerticalLayout implements KeyNotifier { +public class EmployeeEditor extends Composite { - private final EmployeeRepository repository; + public interface SaveListener { + void onSave(Employee employee); + } + + public interface DeleteListener { + void onDelete(Employee employee); + } + + public interface CancelListener { + void onCancel(); + } private Employee employee; - TextField firstName = new TextField("First name"); - TextField lastName = new TextField("Last name"); + private SaveListener saveListener; + private DeleteListener deleteListener; + private CancelListener cancelListener; - Button save = new Button("Save", VaadinIcon.CHECK.create()); - Button cancel = new Button("Cancel"); - Button delete = new Button("Delete", VaadinIcon.TRASH.create()); - HorizontalLayout actions = new HorizontalLayout(save, cancel, delete); + private final Binder binder = new Binder<>(Employee.class); - Binder binder = new Binder<>(Employee.class); - private ChangeHandler changeHandler; +public EmployeeEditor() { + var firstName = new TextField("First name"); + var lastName = new TextField("Last name"); - @Autowired - public EmployeeEditor(EmployeeRepository repository) { - this.repository = repository; + var save = new Button("Save", VaadinIcon.CHECK.create()); + var cancel = new Button("Cancel"); + var delete = new Button("Delete", VaadinIcon.TRASH.create()); - add(firstName, lastName, actions); + binder.forField(firstName).bind(Employee::getFirstName, Employee::setFirstName); + binder.forField(lastName).bind(Employee::getLastName, Employee::setLastName); - binder.bindInstanceFields(this); + save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + save.addClickListener(e -> save()); + save.addClickShortcut(Key.ENTER); - setSpacing(true); + delete.addThemeVariants(ButtonVariant.LUMO_ERROR); + delete.addClickListener(e -> deleteListener.onDelete(employee)); - save.getElement().getThemeList().add("primary"); - delete.getElement().getThemeList().add("error"); + cancel.addClickListener(e -> cancelListener.onCancel()); - addKeyPressListener(Key.ENTER, e -> save()); + getContent().add(firstName, lastName, new HorizontalLayout(save, cancel, delete)); +} - save.addClickListener(e -> save()); - delete.addClickListener(e -> delete()); - cancel.addClickListener(e -> editEmployee(employee)); - setVisible(false); - } + private void save() { + // Save the form into a new instance of Employee + var updated = new Employee(); + updated.setId(employee.getId()); - void delete() { - repository.delete(employee); - changeHandler.onChange(); - } - - void save() { - repository.save(employee); - changeHandler.onChange(); - } - - public interface ChangeHandler { - void onChange(); - } - - public final void editEmployee(Employee c) { - if (c == null) { - setVisible(false); - return; + if (binder.writeBeanIfValid(updated)) { + saveListener.onSave(updated); } - final boolean persisted = c.getId() != null; - if (persisted) { - employee = repository.findById(c.getId()).get(); - } else { - employee = c; - } - - cancel.setVisible(persisted); - binder.setBean(employee); - setVisible(true); - firstName.focus(); } - public void setChangeHandler(ChangeHandler h) { - changeHandler = h; + public void setEmployee(Employee employee) { + this.employee = employee; + binder.readBean(employee); + } + + public void setSaveListener(SaveListener saveListener) { + this.saveListener = saveListener; + } + + public void setDeleteListener(DeleteListener deleteListener) { + this.deleteListener = deleteListener; + } + + public void setCancelListener(CancelListener cancelListener) { + this.cancelListener = cancelListener; } } diff --git a/vaadin/src/main/java/com/baeldung/spring/EmployeesView.java b/vaadin/src/main/java/com/baeldung/spring/EmployeesView.java new file mode 100644 index 0000000000..8b78b1b1c5 --- /dev/null +++ b/vaadin/src/main/java/com/baeldung/spring/EmployeesView.java @@ -0,0 +1,95 @@ +package com.baeldung.spring; + +import com.baeldung.data.Employee; +import com.baeldung.data.EmployeeRepository; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.value.ValueChangeMode; +import com.vaadin.flow.router.Route; + +@Route("employees") +public class EmployeesView extends VerticalLayout { + + private final EmployeeRepository employeeRepository; + + private final TextField filter; + private final Grid grid; + private final EmployeeEditor editor; + + + public EmployeesView(EmployeeRepository repo) { + employeeRepository = repo; + + // Create components + var addButton = new Button("New employee", VaadinIcon.PLUS.create()); + filter = new TextField(); + grid = new Grid<>(Employee.class); + editor = new EmployeeEditor(); + + // Configure components + configureEditor(); + + addButton.addClickListener(e -> editEmployee(new Employee())); + + filter.setPlaceholder("Filter by last name"); + filter.setValueChangeMode(ValueChangeMode.EAGER); + filter.addValueChangeListener(e -> updateEmployees(e.getValue())); + + grid.setHeight("200px"); + grid.asSingleSelect().addValueChangeListener(e -> editEmployee(e.getValue())); + + // Compose layout + var actionsLayout = new HorizontalLayout(filter, addButton); + add(actionsLayout, grid, editor); + + // List customers + updateEmployees(""); + } + + private void configureEditor() { + editor.setVisible(false); + + editor.setSaveListener(employee -> { + var saved = employeeRepository.save(employee); + updateEmployees(filter.getValue()); + editor.setEmployee(null); + grid.asSingleSelect().setValue(saved); + }); + + editor.setDeleteListener(employee -> { + employeeRepository.delete(employee); + updateEmployees(filter.getValue()); + editEmployee(null); + }); + + editor.setCancelListener(() -> { + editEmployee(null); + }); + } + + private void editEmployee(Employee employee) { + editor.setEmployee(employee); + + if (employee != null) { + editor.setVisible(true); + } else { + // Deselect grid + grid.asSingleSelect().setValue(null); + editor.setVisible(false); + } + + } + + private void updateEmployees(String filterText) { + if (filterText.isEmpty()) { + grid.setItems(employeeRepository.findAll()); + } else { + grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText)); + } + } +}