Route Templates Flow
- Specifying Multiple Route Parameters
- Accessing Route Parameter Values
- Optional Route Parameters
- Wildcard Route Parameters
- Constraining Route Parameter Values with Regular Expressions
- Try It
In this guide, you’ll learn how to create a view that accepts multiple route parameters using route templates. You’ll also learn how to use modifiers and regular expressions to tweak the behavior of the route parameters. Finally, a mini-tutorial will help you apply these concepts in a real Vaadin application.
Tip
|
Using a single route parameter is easier than using a route template. If you can get the job done using the HasUrlParameter<T> interface, use that instead.
|
Specifying Multiple Route Parameters
To specify multiple route parameters, you use a route template instead of a static path when declaring a @Route
. In a route template, one or more of the URL segments is a route parameter. Route parameters must follow the following syntax:
:parameter_name[modifier][(regex)]
The following sections explain this syntax in detail.
The following example demonstrates a view with two route parameters: customerId
and action
:
@Route("customer/:customerId/:action")
public class CustomerView extends Main {
...
}
Now, if you navigate to /customer/cu12345/edit
, the router renders the CustomerView
with the following route parameter values:
-
customerId
→"cu12345"
-
action
→"edit"
Accessing Route Parameter Values
To access the route parameter values, your view must implement the BeforeEnterObserver
interface. This interface defines the beforeEnter()
method, which is called by the router before navigating to the view. Inside the method, you can access the route parameters:
@Route("customer/:customerId/:action")
public class CustomerView extends Main implements BeforeEnterObserver {
private static final String PARAM_CUSTOMER_ID = "customerId"; 1
private static final String PARAM_ACTION = "action";
@Override
public void beforeEnter(BeforeEnterEvent event) {
var customerId = event.getRouteParameters().get(PARAM_CUSTOMER_ID).get();
var action = event.getRouteParameters().get(PARAM_ACTION).get();
// Process the parameters
}
...
}
-
Tip: To improve readability and maintainability, declare route parameter names as constants near the
@Route
annotation.
The RouteParameters
class defines methods for accessing route parameter values as String
, Integer
, or Long
. They all return an Optional<T>
.
In the example above, both customerId
and tab
are required, so you can assume that those route parameter values are never empty. If you try to navigate to /customer
or /customer/cu12345
, the router returns a 404 Not Found
error.
Optional Route Parameters
By default, all route parameters are required. To make a route parameter optional, use the ?
modifier:
@Route("customer/:customerId/:action?") 1
public class CustomerView extends Main implements BeforeEnterObserver {
private static final String PARAM_CUSTOMER_ID = "customerId";
private static final String PARAM_ACTION = "action";
@Override
public void beforeEnter(BeforeEnterEvent event) {
var customerId = event.getRouteParameters().get(PARAM_CUSTOMER_ID).get();
var action = event.getRouteParameters().get(PARAM_ACTION).orElse(null); 2
// Process the parameters
}
...
}
-
The
action
route parameter is now optional. -
The route parameter value can now be empty.
Now, if you navigate to /customer/cu12345
, the action
route parameter is empty. You can handle empty parameters by providing a default value, redirecting users, or displaying an error message.
When using multiple optional route parameters, values are assigned from left to right. If a parameter is missing, the next available value shifts left to fill its place. For instance, consider an application with the route customer/:customerId?/:action?
:
-
/customer
→ Calls thecustomer
route with no route parameters at all. -
/customer/cu12345
→ Calls thecustomer
route with"cu12345"
as the value ofcustomerId
. -
/customer/cu12345/edit
→ Calls thecustomer
route with"cu12345"
as the value ofcustomerId
, and"edit"
as the value ofaction
.
Wildcard Route Parameters
By default, a route parameter captures only a single URL segment. However, the last segment in the route template can be declared a wildcard route parameter. This means that the route parameter captures all the segments in its place. A wildcard route parameter is always optional.
To denote a route parameter a wildcard, use the *
modifier:
@Route("api/:path*")
public class ApiViewer extends Main implements BeforeEnterObserver {
@Override
public void beforeEnter(BeforeEnterEvent event) {
var path = event.getRouteParameters().get("path").orElse("");
// Process the path
}
}
Now, if you navigate to api/com/vaadin/flow/
, the path
route parameter has the value "com/vaadin/flow"
.
You can also access the URL segments captured by a wildcard route parameter individually:
@Route("api/:path*")
public class ApiViewer extends Main implements BeforeEnterObserver {
@Override
public void beforeEnter(BeforeEnterEvent event) {
List<String> segments = event.getRouteParameters().getWildcard("path");
// Process the segments
}
}
Now, if you navigate to the same URL, the segments
variable contains the list ["com", "vaadin", "flow"]
.
Note
|
If a route parameter is missing, getWildcard() returns an empty list.
|
Constraining Route Parameter Values with Regular Expressions
In all the examples discussed, the route parameters accept any value. However, a specific value is often expected for a route parameter and the view should be shown only when that specific value is present in the URL. You can do this by defining a regular expression for the route parameter. This reduces the need for validation and sanitation of route parameter values in the beforeEnter()
method.
Note
| The syntax of the regular expressions is checked at application startup. If there is an error, the application fails to start. |
In the following example, the customerId
route parameter is constrained to an integer between 1 and 9 digits, and the action
route parameter can be either "view"
, "edit"
, or empty:
@Route("customer/:customerId([0-9]{1,9})/:action?(view|edit)")
public class CustomerView extends Main {
...
}
If you navigate to a URL that doesn’t meet these constraints, you’ll receive a 404 Not Found
error.
When you specify constraints on wildcard route parameters, the regular expression is applied to every segment that would be captured by the route parameter. If any of the segments fails to match the expression, the whole route template fails to match the URL, and you’ll get a 404 Not Found
error.
Try It
In this mini-tutorial, you’ll create a view that uses a route template. You’ll then change the route template and see how the view behaves.
Set Up the Project
First, generate a walking skeleton with a Flow UI, open it in your IDE, and run it with hotswap enabled.
Create the View
Create a new package [application package].tutorial.ui.view
. Then, in this package, create a new class called TemplateView
:
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Route;
@Route("template")
public class TemplateView extends Main implements BeforeEnterObserver {
private static final String PARAM1 = "param1";
private static final String PARAM2 = "param2";
private static final String PARAM3 = "param3";
@Override
public void beforeEnter(BeforeEnterEvent event) {
var param1 = event.getRouteParameters().get(PARAM1).orElse("N/A");
var param2 = event.getRouteParameters().get(PARAM2).orElse("N/A");
var param3 = event.getRouteParameters().get(PARAM3).orElse("N/A");
setText("param1: \"" + param1 + "\", param2: \"" + param2
+ "\", param3: \"" + param3 + "\"");
}
}
Open your browser and go to: http://localhost:8080/template
You should see:
param1: "N/A", param2: "N/A", param3: "N/A"
Define Required Route Parameters
Next, introduce the three route parameters, like this:
@Route("template/:param1/:param2/:param3")
public class TemplateView extends Main implements BeforeEnterObserver {
...
}
Now, go back to your browser. Because the route parameters are required and you haven’t provided any values, you should see a Could not navigate to 'template'
error message.
To give values for the route parameters, navigate to this URL:
You should see:
param1: "say", param2: "hello", param3: "vaadin"
Make Route Parameters Optional
You’re now going to make the first two route parameters optional. Add the ?
modifier to them:
@Route("template/:param1?/:param2?/:param3")
public class TemplateView extends Main implements BeforeEnterObserver {
...
}
Go back to your browser. You should still see all three route parameter values. However, watch what happens if you go to:
Since the first two parameters are optional, the last parameter takes the first available value. You should see:
param1: "N/A", param2: "N/A", param3: "say"
Now add a second route parameter value by navigating to:
You should see:
param1: "say", param2: "N/A", param3: "hello"
Mark a Route Parameter as Wildcard
You’re now going to make the last route parameter a wildcard. Add the *
modifier to it:
@Route("template/:param1?/:param2?/:param3*")
public class TemplateView extends Main implements BeforeEnterObserver {
...
}
Go back to the browser. If you reload the page, you should now see the following:
param1: "say", param2: "hello", param3: "N/A"
The "hello"
string has moved from param3
to param2
. The reason for this is that wildcard route parameters are also optional. Next, navigate to the following URL:
The last route parameter now holds two segments instead of one. You should see:
param1: "say", param2: "hello", param3: "to/vaadin"
Add Regular Expressions
You’re now going to add some regular expressions to constrain the route parameters. You’ll force param1
to consist of digits only, and all the segments of param3
to be one of hello
, to
, and vaadin
:
@Route("template/:param1?([0-9]*)/:param2?/:param3*(hello|to|vaadin)")
public class TemplateView extends Main implements BeforeEnterObserver {
...
}
Go back to the browser. You should now see a Could not navigate to 'template/say/hello/to/vaadin
. This is because the first route parameter value is not a number. To fix this, navigate to:
You should see:
param1: "123", param2: "say", param3: "hello/to/vaadin"
Final Thoughts
You’ve now successfully implemented route templates in Flow. You learned how to:
-
Specify multiple route parameters in a view.
-
Make route parameters optional.
-
Use a wildcard route parameter to capture multiple URL segments.
-
Use regular expressions to constrain the values of route parameters.
You’re now ready to use route parameters in real Vaadin applications. Try specifying your own route template, and make a custom API for navigating to it! Include at least one numeric route parameter, and use RouteParameters.getInteger()
to retrieve it.