Part III – WebUI with Vaadin Flow for the URL Shortener

1. Introduction and objectives

The first two parts of this series established the theoretical and practical foundations of a URL shortener in pure Java. We discussed the semantic classification of short URLs, the architecture of a robust mapping system, and the implementation of a REST-based service based on the JDK HTTP server. These efforts resulted in a functional, modularly extensible backend that creates, manages, and efficiently resolves short links. However, a crucial component was missing-a visual interface for direct user interaction with the system. This interface is essential for tasks such as manual link creation, viewing existing mappings, and analysing individual redirects.

This is precisely where the third part of this series comes in. The focus is on the development of a graphical user interface based on Vaadin Flow. The goal is to provide a web interface developed entirely in Java that eliminates the need for client-side frameworks and integrates seamlessly into the application’s existing WAR structure. The decision to use Vaadin Flow follows a pragmatic principle: Anyone who already writes Java should also be able to define interfaces in Java, with a type-safe layout, a declarative component model, and a clear separation between the UI and domain layers.

UI integration in our project serves not only to enhance functionality but also to achieve a didactic objective. In security-critical applications like URL shorteners, human interaction is key. A well-designed UI not only facilitates convenient operation but also prevents common errors and misuse through appropriate validation, clear feedback, and restrictive permissions concepts. This makes the user interface itself a security-relevant part of the architecture.

In the remainder of this article, we will examine the structure, design, and concrete implementation of the Vaadin interface in detail. This ranges from the module architecture to navigation and view components, including advanced features such as QR code generation and expiration time display. The goal remains to implement all functionality exclusively using Java’s built-in tools—in the spirit of a transparent, maintainable, and extensible system design.

The UI is not just an add-on, but a central component of a comprehensive shortener solution. It caters to both productive use and teaching and exploration, providing a sense of security and reliability.

2. UI strategy and technology choice

Choosing the right technology for the user interface of a technical service is far more than a matter of taste – it touches on key aspects such as maintainability, security model, development efficiency, and deployment strategy. In the context of our URL shortener, which deliberately avoids external frameworks and was implemented entirely in Java 24, it made sense to choose a solution for the UI that fits seamlessly into this philosophy. The decision was therefore made to use Vaadin Flow, a server-side UI framework powered and developed entirely in Java.

2.1 Why Vaadin Flow for a server-side interface?

Vaadin Flow enables the development of component-based web applications in Java, without the need for JavaScript, front-end build processes, or manual maintenance of HTML, CSS, or TypeScript artefacts. All UI components, from simple input fields to complex tables, are described declaratively in Java, allowing the UI to seamlessly integrate into the existing modular structure. For a purely Java-based backend logic like our URL shortener, this results in a coherent overall architecture that eliminates the need for language or context switching, instilling confidence in its efficiency.

The logic is executed entirely server-side: User interactions trigger events that are processed on the server, with the presentation in the browser synchronised via the Vaadin client. This architecture not only simplifies state management but also reduces potential attack surfaces, as no server-side business logic migrates to the frontend.

2.2 UI paradigms for administration systems

When designing an admin interface, it’s not about aesthetic brilliance, but rather functional clarity, robust interactions, and data accountability. Users of a URL shortener—whether self-hosted, in educational institutions, or within an organisation—need an easy way to manually shorten new URLs, browse existing mappings, check expiration times, and delete potentially critical entries. These functions must be visible, traceable, and cancelable at any time.

Vaadin Flow offers a variety of ready-made components, such as Grid, FormLayout, Dialogue, Notification or Binder that enable efficient implementation of such use cases – including validation, event control, and dynamic data binding. This not only saves development time but also enables a consistent user experience that scales elegantly with increasing complexity.

2.3 Differentiation from client-side frameworks

Unlike single-page application frameworks such as Angular, React or Vue, Vaadin Flow requires no separate frontend build pipeline, no TypeScript toolchains, and no JSON serialisation of server communication. The entire application, including the UI, can be deployed as a classic WAR Package and run in a servlet container such as Jetty or Tomcat. This not only reduces DevOps effort but also the risk of version conflicts, CDN outages, or cross-origin issues.

This server-side approach is particularly suitable for applications where Data sovereignty, security and long-term maintainability are in the foreground – for example, with internal tools, admin consoles, or security-critical services. The integration of session-based security mechanisms, IP filters, or role-based access is also much more controlled in a Vaadin servlet than with headless backends with an external JavaScript frontend.

The choice of Vaadin Flow is therefore not just a technological decision, but an expression of an architectural style: stable, server-centric, Java-enabled– ideal for secure, maintainable and explainable systems.

3. User interface architecture

The user interface is not an isolated component, but an integral part of the system. It must fit seamlessly into the existing module architecture without enforcing domain-specific dependencies or abandoning the loose coupling between core logic and application layers. In a purely Java-based environment without frameworks such as Spring or Jakarta EE, this separation is particularly important because it allows the UI to be viewed as a separate layer, both technically and semantically.

3.1 Integration into the existing WAR structure

The application is already organised as a multi-tiered Maven project, which is consolidated into a central WAR module. This WAR module knows the servlet context, initialises the HTTP server (for REST) and the VaadinServlet (for the UI), and thus takes on the role of Integration and delivery unit. The previous modules shortener-core(domain) and shortener-api (HTTP routing) remain unaffected.

The new UI module –shortener-ui-required– is implemented as an additional Maven module, which is used exclusively by shortener-core. It contains all Vaadin-specific logic, UI components, and views. In the WAR module, this module is then connected via a servlet registration – typically via a Servlet, which is defined in the deployment descriptor (web.xml) or via ServletContainerInitializer- and is integrated.

The structure follows the principle: Only the WAR module knows the specific deployment topology. All other modules remain generic and independent.

3.2 Separation of routing, views and services

Within the UI module, responsibilities are divided:

  • Routing and Navigation are centrally controlled via a MainLayout class and with @Route-annotated views. These define the paths within the UI (e.g./, /create, /admin) and automatically take over session and history management from Vaadin.
  • Views (approximately CreateView, OverviewView, StatsView) form the interactive interfaces. They integrate Vaadin components such as TextField, Grid, Button, Dialog and provide user interaction. Each view is stateless and delegates to services.
  • Services encapsulate the interaction with the business logic. These are not typical Spring beans, but regular Java classes that can be implemented either directly or via the Singleton pattern (ServiceRegistry, StaticFactory), and are instantiated. They call methods shortener-core and take care of conversion, validation and error handling.

This structure allows for a clear separation between presentation, application logic, and business logic. It is explicitly based on classic UI architectural patterns such as Model-View-Service (MVS), without the overhead or magic of full-fledged frameworks.

3.3 Communication with the core module (DI without frameworks)

Since dependency injection containers are not used, the views are deployed with service instances manually or via a central deployment class. A typical approach is to implement a UiServiceLocator, which contains all the required components (e.g.UrlMappingStore, ShortCodeGenerator), is created once and then made available as a singleton.

For example, the constructor of a view can look like this:

This form of explicit dependency creation has the advantage that the origin of all components remains traceable, no hidden initialisation takes place, and the entire application context remains transparently controllable – a property that is particularly important in safety-critical systems.

4. User guidance and UX design

An administration interface is not a classic front end for end users, but a specialised tool – comparable to a precision instrument. Its user interface must be efficient, robust, and explainable. In contrast to dynamic consumer UIs, which boast animations, branding, or complex interactions, clarity, predictability, and freedom from redundancy are paramount here. The design of a Vaadin interface for a URL shortener, therefore, follows a minimalist, function-centric UX strategy.

4.1 Navigation concept: Dashboard, Create, Overview

From the user’s perspective, the application is divided into three central task areas:

  • Creating new short links: A simple input form with target URL validation and an optional custom alias. Speed and clarity are paramount.
  • Overview of existing mappings: A tabular display of all generated shortlinks, supplemented with sorting and filtering options. This allows for targeted searches by alias, target address, or expiration date.
  • Administrative Dashboard: An area for viewing metrics (e.g. number of mappings, frequently used short links) as well as for targeted deletion or extension of entries.

Navigation is done via a Vaadin layout with a main menu (e.g. AppLayout or DrawerToggle) and named routes. All routes are directly accessible via URL, with bookmarks and refreshes always leading to a consistent state—an inherent advantage of Vaadin Flow due to server-side session management and declarative routing.

4.2 Input validation and feedback

A key UX criterion is the correctness of the inputs. When creating a new mapping, it must be ensured that

  • The input field for the URL is not empty,
  • The URL is syntactically valid (including http/https),
  • optional aliases are not already assigned or reserved.

These validations are performed immediately upon input (client-side via Binder) and again server-side in the service layer, whereby the view displays corresponding error messages as Notification, ErrorMessage or directly in the field context. A deliberate UX detail: In the event of errors, the focus remains on the field, the previous input is not deleted, and a visual highlight appears, instead of a general error dialogue.

Successful processes (e.g., successfully created a short link) lead to clear success messages, including immediate copying options, e.g., via a button with an icon (“copy to clipboard”) to support cross-media use.

4.3 Readability, design system and accessibility

The UI is functional, not decorative. Accordingly, attention is paid to a clear visual grid: sufficient white space, consistent labels, understandable icons, and no unnecessary animations. Colours serve solely for semantic marking (e.g., red for deletion actions, green for success messages), not for stylistic individualisation.

Vaadin Flow comes with a solid standard design that extends @Theme, or custom CSS classes can be extended, but only where functionally necessary. The entire application remains fully keyboard-operated, screen reader-compatible, and high-contrast enough for low-barrier use. This is especially important in contexts where administrators work in security-critical areas with increased accessibility requirements.

5. Implementation of the UI components with Vaadin Flow (including source code)

5.1 MainLayout: Navigation frame and routing

The MainLayout forms the common structure of all views. It is based on the AppLayout and defines a vertical navigation menu with links to the central views:

This structure separates navigation logic from application logic. New views only need to be @Route(…, layout = MainLayout.class) and connected.

5.2 CreateView: Input form with validation

The view for creating new short links consists of a TextField for the target URL, an optional alias field, and a button for generating the mapping. Simple validation logic is provided via the binder:

This view encapsulates the entire user interaction for creating new short links. Incorrect entries result in immediate feedback, while valid entries are persisted and output directly as feedback.

5.3 OverviewView: Grid-based management view

The OverviewView displays all existing mappings in the grid. Optionally, additional columns such as creation time or expiration date can be displayed. Each row allows deletion via a confirmation dialogue:

The grid is updated automatically after deletions. Additional filter or export functions can be easily added based on this structure.

5.4 Consistent behaviour for dialogues and notifications (with code)

In an administration interface for a security-critical service such as a URL shortener, the way the system handles user interactions is crucial. The response to inputs—be they correct, incorrect, or critical—must be predictable, explainable and context-appropriate. Particularly important are:

  • immediate, non-blocking success messages for valid actions,
  • precise, field-oriented fault indications in case of incorrect entries,
  • intention-confirming dialogues for potentially destructive operations such as deleting mappings.

These three feedback types can be implemented entirely using Vaadin Flow’s built-in tools – specifically: notification, dialogue, and component binding via Binder.

Success stories via Notification

After successful actions (e.g., creating a short link or deleting an entry), a discreet, automatically disappearing notification is displayed. This is non-blocking, clearly informs users of the success, and allows them to continue working seamlessly.

Notification.show(“Short link created successfully.”, 3000, Notification.Position.TOP_CENTER);

For targeted feedback with content (e.g. the generated short code), an inline component or a copyable text block can be displayed alternatively:

Error messages through field-based validation withBinder

Failed inputs—such as invalid URLs or duplicate aliases—do not need to be displayed in general dialogues, but rather directly in the affected field. To do this, Vaadin uses the Binder<T> mechanism, which binds validation rules directly to UI components:

The method isValidHttpUrl checks, for example, with a simple Regex or URI.create(…) Logic for syntactical validity. Errors are automatically displayed as error messages directly below the field, visually highlighted and focused:

If an error occurs at the application level (e.g. alias already assigned), this can also be communicated via a global notification:

Destructive actions only after explicit confirmation

When deleting a short link, resetting a counter, or performing similar irreversible actions, the operation must never be performed without confirmation. Vaadin’s dialogue component, combined with descriptive text and two explicit buttons, is ideal for this.

Example from the OverviewView:

Features of this implementation:

  • An explicit button triggers the action.
  • Confirmation is dialogue-based with a cancel option.
  • The change will be reflected immediately upon completion.
  • Feedback is provided immediately via notification.

Interaction and reuse

A central UX pattern of this interface is to standardise the behaviour of all interactions. This avoids surprises for users. Consistent behaviour means:

actionReaction
URL successfully shortenedNotification, display of the short link
Incorrect inputField marking, inline error message
Alias already takencentral notification with incorrect colouring
Delete the short linkDialogue with two buttons
Confirmed deletionNotification: Grid is reloading

These patterns can be encapsulated component-based – for example, using utility methods for dialogue generation or notification factories, which can later also be adapted for logging or internationalisation.

7. Deploying the UI in the WAR context

The user interface is not delivered as a separate application, but integrated into a central WAR file that contains both the REST API and the Vaadin-based UI. This monolithic approach is deliberately chosen: It enables a consistent deployment model on servlet containers such as Jetty, Tomcat or Undertow without relying on complex build pipelines, containerization, or framework integration.

7.1 Servlet configuration for Vaadin inweb.xml

Vaadin Flow is traditionally registered via the servlet com.vaadin.flow.server.VaadinServlet. Since there is no automatic configuration (as with Spring Boot), the assignment is made explicitly in the deployment descriptor:

The entry /* as a URL pattern causes all paths not occupied by the REST API (e.g./shorten, /abc123) to be handled by the UI. The REST endpoints can still be accessed via explicit HttpServlet registrations with priority.

Alternatively, manual division via filters or explicit exclusion lists is possible, for example, /api/* should be strictly reserved for the REST branch.

7.2 Theme-Integration ohne Frontend-Toolchain

A big advantage of Vaadin Flow in server mode is that there is no Node.js, npm or Webpack. All components and resources are handled at the JVM level and delivered as servlet resources at runtime. Themes can be defined directly in the classpath:

In the directory frontend/themes/shortener-theme/, then lies:

  • styles.css– own adjustments
  • theme.json– Metadata and component binding

The Maven plugin vaadin-maven-plugin automatically generates the corresponding frontend bundle during package or install, fully integrated into the WAR build, without the need for external tools.

A typical Maven excerpt inshortener-war/pom.xml:

The use of build-frontend. This is only required during initial deployment or when making theme changes. During operation, everything is loaded from the WAR.

7.3 Operation in Tomcat or Jetty

The resulting WAR file can be used in any Servlet 4.0+ compatible container for deployment. Recommended are:

  • Jetty 12 for embedded deployments or local tests
  • Apache Tomcat 10.1+ for production-related scenarios
  • Eclipse Servlet Container (e.g. Open Liberty) for modular applications

Deployment is incredibly simple:

cp target/shortener.war $CATALINA_BASE/webapps/

After starting the container, the application can be accessed via the usual path:

http://localhost:8080/shortener/

REST endpoints (e.g., POST /shorten) and UI routes (/overview, /create) coexist. This results in a robust, clearly controlled deployment model:

  • No framework magic
  • No container lock-in
    No build complexity

8. Conclusion and outlook

With the integration of a Vaadin Flow-based interface, our URL shortener not only receives an interactive user interface, but also a complete, maintainable and production-ready management layer – realised exclusively with funds from the JDK. The graphical UI serves not as a decorative accessory, but as an integral part of the system architecture. It enables the secure creation, analysis, and maintenance of short links – typically via the same infrastructure used for REST endpoints or background processes.

The decision, exclusively Core Java and Vaadin Flow, has proven to be viable: The separation of module boundaries remains clear, deployment takes place as a classic WAR file, and all interactions – from validations and feedback logic to permission models – can be implemented in a comprehensible and transparent manner. Instead of framework magic, convention-over-configuration, or annotation-based autowiring, the focus here is once again on understandable system design down to the details.

Particularly noteworthy is the efficiency with which Vaadin Flow maps UI logic directly in the Java context. Developers retain control over state, access protection, and lifecycles – without relying on build toolchains, client routing, or third-party libraries. The associated simplification of the maintenance and security model is a significant advantage in the context of safety-critical infrastructure.

The system can also be further developed in the future without any architectural disruption. Possible next steps include:

  • Modularisation of the UI into reading and writing segments
  • Asynchronous Event-Analysis via server push or WebSockets
  • Connection to external security systems such as OAuth2 or LDAP
  • Deployment on embedded Jetty for minimalist distributions
  • Migration to native builds via GraalVM to reduce runtime overhead

This makes the URL shortener suitable not only as a learning object or internal tool, but also as a blueprint for lean, robust and self-determined Java web applications – without vendor lock-in, without complex tooling dependencies and with the focus on Readability, transparency and control.

Happy Coding

Sven


Discover more from Sven Ruppert

Subscribe to get the latest posts sent to your email.