Upgrade to Pro — share decks privately, control downloads, hide ads and more …

You may not need JavaScript

You may not need JavaScript

Single page applications (SPA) have become the standard for web application development. Angular, React and Vue.js are the best-known. But does this client architecture fit every application? Or are there alternatives that may fit better and are less complex to develop?

In the first part of the talk, the differences between SPAs and classic, server-side approaches are explained and the advantages and disadvantages are discussed.

The second part reports on a current customer project in which the front end of a large ERP system had to be replaced by a modern web front end. The chosen framework is Vaadin Flow, a server-side web framework that makes development of web applications entirely in Java possible.

First, the new architecture of Vaadin Flow, which is no longer based on GWT but on web components, is explained. Then it will be shown how configurable, form-based and data-centric web applications can be implemented very efficiently by using jOOQ as a database access layer.

#Vaadin #jOOQ

Simon Martinelli

May 28, 2022

More Decks by Simon Martinelli

Other Decks in Programming


  1. You may not need JavaScript Single Page Applications for Java

    Developers Simon Martinelli @simas_ch martinelli.ch
  2. Existing System • Existing ERP System based on Oracle Forms

    • Customizable by the customer → Goal: Build a modern web frontend ~800 Forms ~2000 Tables und Views ~5000 Procedures und Functions ~100 User Defined Types
  3. Runtime Generated UI UI Data Generate UI User accesses module

    Based on user rights and data UI ready
  4. UI Models • Server-Side Rendering • JSF • Spring MVC

    with Thymeleaf • Single Page Application • React, Angular, Vue etc. • Vaadin https://msdn.microsoft.com/en-us/magazine/dn463786.aspx
  5. History HTML AJAX GWT Web Components .1 3 4 5

    6 7 8 10 TypeScript Lit .2 LTS 14 15 Vaadin Components & Flow 23 … Hilla
  6. Why Vaadin? • Type-safe Java API • A rich component

    model • Grids with paging, sorting, and filtering • Forms with validation and conversion • Bi-directional Data Binding • No REST API • Direct access from UI code to services or repositories → A great fit for data-centric business applications
  7. Example Code Vaadin Flow @Route public class HelloView extends VerticalLayout

    { public HelloView() { TextField textField = new TextField("Your Name"); Label label = new Label(); Button button = new Button("Greet", e -> label.setText("Hello, " + textField.getValue())); add(textField, label, button); } }
  8. Routing @Route(value = "S450", layout = MainLayout.class) public class S450

    implements HasUrlParameter<String> { @Override public void setParameter(BeforeEvent event, @OptionalParameter String parameter) { Location location = event.getLocation(); QueryParameters queryParameters = location.getQueryParameters(); Map<String, List<String>> parameterMap = queryParameters.getParameters(); ... } }
  9. Grid • Paging with lazy loading • Sortable, filterable and

    editable Grid grid = new Grid<>(CustomerRecord.class); grid.setColumns("id", "firstName", "lastName", "email"); Grid.Column<CustomerRecord> editColumn = grid.addColumn( new ComponentRenderer<>(customer -> new RouterLink("Edit", CustomerView.class, customer.getId()))); editColumn.setFrozen(true); grid.setColumnReorderingAllowed(true);
  10. Data Provider // In-Memory grid.setItems(List.of("Barcelona, "Berne"); // Lazy grid.setItems( query

    -> repository.findAll(createFilter(query), createOrderBy(query), query.getOffset(), query.getLimit()), query -> repository.count(createFilter(query)) );
  11. Forms • mit und binder.forField(id) .withNullRepresentation("") .withConverter(new StringToIntegerConverter(0, "Integers only"))

    .withValidator((value, context) -> value > 0 ? ValidationResult.ok() : ValidationResult.error("Id must be greater than 0")) .bind(EmployeeRecord::getId, EmployeeRecord::setId);
  12. Push • Activated with @Push • Uses Atmosphere button.addClickListener(event ->

    taskExecutor.execute(() -> { // do something that takes a while button.getUI().ifPresent(ui -> ui.access(() -> Notification.show("Done!"))); }));
  13. Testbench • Uses Selenium and WebDrivers @Test public void say_hello()

    { $(TextFieldElement.class).id("name").setValue("World"); $(ButtonElement.class).id("say-hello").click(); LabelElement text = $(LabelElement.class).id("text"); assertEquals("Hello World", text.getText()); }
  14. Karibu Testing • Unit Testing library for Vaadin • Open

    Source https://github.com/mvysny/karibu-testing @Test void say_hello() { _get(TextField.class, spec -> spec.withId("name")).setValue("World"); _get(Button.class, spec -> spec.withId("say-hello")).click(); Label label = _get(Label.class, spec -> spec.withId("text")); assertThat(label.getText()).isEqualTo("Hello World"); }
  15. Spa, PWA et cetera • A Vaadin application is a

    SPA • PWA Support • Web App Manifest • Information about an application, e.g., name, theme, icon and description. These details are required to create an installable version of the web application • Service Worker • Runs separately from the browser thread • Intercepts network requests • Cached and retrieves resources from the cache • Delivers push notifications
  16. jOOQ Generator <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <configuration> <generator> <database> <name>org.jooq.meta.extensions.ddl.DDLDatabase</name> <properties>

    <property> <key>scripts</key> <value>src/main/resources/db/migration/*.sql</value> </property> </properties> </database> <target> <packageName>ch.martinelli.vaadin.demo.db</packageName> <directory>target/generated-sources/jooq</directory> </target> </generator> </configuration> </plugin>
  17. Metamodel public class Employee extends TableImpl<EmployeeRecord> { public final TableField<EmployeeRecord,

    Integer> ID = createField(DSL.name("ID"), SQLDataType.INTEGER.nullable(false) .defaultValue(DSL.field("NEXT VALUE FOR \"PUBLIC\".\"SECURITY_GROUP_SEQ\"", SQLDataType.INTEGER)), this, ""); public final TableField<EmployeeRecord, String> NAME = createField("NAME", SQLDataType.VARCHAR(255).nullable(false), this, ""); public final TableField<EmployeeRecord, Integer> DEPARTMENT_ID = createField("DEPARTMENT_ID", SQLDataType.INTEGER.nullable(false), this, ""); @Override public UniqueKey<EmployeeRecord> getPrimaryKey() { return Keys.CONSTRAINT_7; } ... }
  18. jOOQ DSL Result<EmployeeRecord> records = dslContext .selectFrom(EMPLOYEE) .fetch(); dslContext .insertInto(DEPARTMENT)

    .columns(DEPARTMENT.NAME) .values("IT") .execute(); Result<Record1<String>> records = dslContext .select(EMPLOYEE.NAME) .from(EMPLOYEE) .join(DEPARTMENT).on(DEPARTMENT.ID.eq(EMPLOYEE.DEPARTMENT_ID)) .where(DEPARTMENT.NAME.eq("IT")) .fetch();
  19. CRUD with jOOQ • jOOQ generates for each table with

    a unique key an implementation of UpdateableRecord // Store (insert or update) a record to the database. int store() throws DataAccessException; // Delete a record from the database int delete() throws DataAccessException; // Refresh a record from the database. void refresh() throws DataAccessException;
  20. Conclusion • Creating the entire UI with Java makes the

    life (for Java developers) easier • jOOQ enables type-safe SQL in Java • Vaadin and jOOQ are a great combination when developing data centric business apps