Lab 6: Full Text Search
We now have a lot of users in our system. We want to enable our users to search through the list of users.
Search Users
In this lab, we will stream through the list of users and filter it using the Java streams API. Create a new method searchUser
in the UserService
.
public List<EasyUser> searchUser(String searchString) {
return easyUserList.stream().filter(
it -> it.uuid.toString().contains(searchString)
|| it.username.contains(searchString)
|| it.password.contains(
searchString)
).toList();
}
ListComponent
Create a new package de.tschuehly.easy.spring.auth.web.list
and then create a ListComponent.java
ViewComponent.
package de.tschuehly.easy.spring.auth.web.list;
import de.tschuehly.spring.viewcomponent.core.component.ViewComponent;
import de.tschuehly.spring.viewcomponent.jte.ViewContext;
import java.util.List;
@ViewComponent
public class ListComponent {
public ViewContext render(List<ViewContext> viewContextList){ // (1)
return new ListContext(viewContextList);
}
public record ListContext(List<ViewContext> viewContextList)
implements ViewContext {}
}
(1): The render method has a List<ViewContext>
parameter and pass it to the ListContext
We then create a ListComponent.jte
template and loop through the ViewContext List with the @for
syntax and then render each ViewContext.
@import de.tschuehly.easy.spring.auth.web.list.ListComponent.ListContext
@param ListContext listContext
@for(var context: listContext.viewContextList())
${context}
@endfor
Next, we will autowire the listComponent
we just created in the UserTableComponent
and create a renderSearch
method.
public ViewContext renderSearch(String searchQuery) {
List<ViewContext> userRowList = userService.searchUser(searchQuery) // (1)
.stream().map(userRowComponent::render) // (2)
.toList();
return listComponent.render(userRowList); // (3)
}
(1): We will pass the searchQuery
parameter to the userService.searchUser
method
(2): We stream through the list of users and then render each user with the userRowComponent::render
method.
(3): We then pass the userRowList
to the listComponent.render
method and return the result.
UserController
In the UserController
we first need to autowire the UserTableComponent
.
Then we create a GET_SEARCH_USER
and SEARCH_PARAM
constant and a search user endpoint:
public static final String GET_SEARCH_USER = "/search-user";
public static final String SEARCH_PARAM = "searchQuery";
@HxRequest
@GetMapping(GET_SEARCH_USER)
public ViewContext searchUser(
@RequestParam(SEARCH_PARAM) String searchQuery // (1)
) {
return userTableComponent.renderSearch(searchQuery); // (2)
}
(1): The endpoint has a @RequestParam
that has SEARCH_PARAM
as value
(2): In the method we call the userTableComponent.renderSearch
method and return the result.
In the UserTableComponent.jte
template we first need to add two imports:
@import static de.tschuehly.easy.spring.auth.user.UserController.*
@import de.tschuehly.easy.spring.auth.htmx.HtmxUtil
Then we will create a new <tr>
element as the first child of the <thead>
:
<tr>
<th colspan="4">
<label>
Search Users
<input type="text"
name="${SEARCH_PARAM}" <%-- (1) --%>
hx-get="${GET_SEARCH_USER}" <%-- (2) --%>
hx-trigger="input changed delay:500ms, search" <%-- (3) --%>
hx-target="${HtmxUtil.idSelector(USER_TABLE_BODY_ID)}"> <%-- (4) --%>
</label>
</th>
</tr>
(1): The <input>
field has the SEARCH_PARAM
constant as name
attribute, this will map to the @RequestParam
we defined in the UserController.searchUser
method.
(2): We then add a hx-get
attribute and set it to GET_SEARCH_USER
.
(3): We tell htmx to trigger the request when an input
event is detected and the value has changed
. Htmx then starts a delay
timer of 500ms
. If the event is seen again in the 500ms it will reset the delay.
(4): We target the body of the table with the USER_TABLE_BODY_ID
and swap the innerHTML of it.
Success!
If we restart the application and navigate to http://localhost:8080 we can see that the search is working:

Lab-6 Checkpoint 1
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-6-checkpoint-1 -b lab-6-c1
Last updated