Lab 5: Lazy Loading
In this lab, we simulate a slow system and we want to improve the user experience by giving them faster feedback.
Simulate a large payload and slow system
We start by creating a lot of users in the initializeUsers
method in the Lab5Application
class with the datafaker.net library.
@SpringBootApplication
public class Lab5Application {
public static void main(String[] args) {
SpringApplication.run(Lab5Application.class, args);
}
@Bean
public ApplicationRunner initializeUsers(UserService userService, GroupService groupService) {
return (args) -> {
EasyUser thomas = userService.createUser(
"Thomas",
"This is a password"
);
userService.createUser(
"Cassandra",
"Test1234"
);
groupService.createGroup("USER_GROUP");
groupService.createGroup("ADMIN_GROUP");
groupService.addUserToGroup("USER_GROUP", thomas.uuid);
Faker faker = new Faker();
for (int i = 0; i < 10000; i++) {
userService.createUser(
faker.internet().username(),
faker.internet().password()
);
}
};
}
}
We also introduce a delay in the UserService.findAll
method by adding a Thread.sleep
to simulate a slow external system.
public List<EasyUser> findAll() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return easyUserList;
}
Problem
Now start the Lab5Application
and navigate to http://localhost:8080.
You will see that the request will take 3 seconds suggesting an unresponsive system to the user.
To improve the user experience we want to lazy load the slow user table after the initial page load with htmx.
Lazy Loading the user table
We create a constant GET_USER_TABLE
and then add an HTTP GET endpoint in the UserController
where we render the userTableComponent
.
public static final String GET_USER_TABLE = "/user-table";
@HxRequest // (1)
@GetMapping(GET_USER_TABLE)
public ViewContext userTable() {
return userTableComponent.render();
}
(1): We use the @HxRequest
annotation of the htmx-spring-boot library.
The endpoint will only accept a request when it's made from htmx.
Now restart the Lab5Application
and try to navigate to http://localhost:8080/user-table.
You should not be able to access it.

To render the user table we need to change the UserMangement back to a ViewComponent.
@ViewComponent
@Order(1)
public class UserManagementComponent implements Page {
public ViewContext render() {
return new UserManagementContext();
}
public record UserManagementContext() implements ViewContext {}
@Override
public NavigationItem navigationItem() {
return new NavigationItem("User Management", UserController.USER_MANAGEMENT_PATH);
}
}
Now create a UserManagementComponent.jte
file in the same package as the UserManagementComponent
@import static de.tschuehly.easy.spring.auth.user.UserController.GET_USER_TABLE
<div hx-get="${GET_USER_TABLE}" <%-- (1) --%>
hx-trigger="load"> <%-- (2) --%>
<img src="/spinner.svg"
class="htmx-indicator" <%-- (3) --%>
alt="Result loading..." width="50" >
</div>
(1): The hx-get
attribute creates a GET
request to the GET_USER_TABLE
endpoint.
(2): The hx-trigger="load"
attribute triggers the request when the page loads.
We can show a loading spinner with an <img>
element.
(3): By adding the htmx-indicator
CSS class the element is shown while the HTTP request of the parent htmx element is in flight.
Rendering the UserMangement
Now back in the UserController
we autowire the userMangementComponent
by injecting it into the constructor.
Then we replace the userTableComponent.render()
method with userManagementComponent.render() in
public static final String USER_MANAGEMENT_PATH = "/";
@GetMapping(USER_MANAGEMENT_PATH)
public ViewContext userManagementComponent() {
return layoutComponent.render(
userManagementComponent.render()
);
}
Restart the Lab5Application
and navigate to http://localhost:8080.
You can see that the page loads instantly and only the user table rendering is delayed.
Lab-5 Checkpoint 1
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-5-checkpoint-1 -b lab-5-c1
Last updated