Search code examples
spring-bootthymeleaf

Using Spring Boot, Thymeleaf and Oracle: How to dynamically populate the submenus in a web site menu defined in a fragment?


I have a web site that consists of approximately 30 html thymeleaf templates. I have a home_navigation.html fragment that gets included in all templates as the header. This header defines a main navigational menu with popup submenus. The popup submenus under one of my main menus needs to be generated from my oracle database table.

Normally when passing data from a database into a Thymeleaf template I would put the code in the controller to call the java DAO and return a list of Link objects and then add that list in the controller to the model using .setAttribute. Then in the Thymeleaf template I would iterate through the "${List}" in a "th:each" outputting the "<a href..." for each Link object in the list. That is all fine and dandy.

I also can pass parameters into the fragment. So that isn't the problem BUT...

Since the main navigational menu is added as a header fragment into the beginning of every template then I would have to go into every defined controller and add code that would pull the list of Links and pass it into the template and then pass the list into the fragment from every page. that would be approximately 30 times!!!

How...using Spring Boot and Thymeleaf, does someone feed data into a fragment to populate a menu dynamically from a database that is then added as a header fragment into every page/template on the site?

Is there a way to create a controller for the fragment and somehow have every page call the controller for the fragment before the fragment contents are put into every page?

Thank you.


Solution

  • There are a number of ways to solve this problem depending on whether your menu can change while the user is logged in. If it can change then you can create a base controller class that has a method annotated with @ModelAttribute. All of your controllers would inherit from this base class. This method would obtain the menu items and add them to the model each time a page is requested. A simplistic example of such a class is:

      @Component
      public abstract class BaseController {
          @Autowired
          private AlphabetService alphabetService;
    
          @ModelAttribute(name = "alphabet")
          public List<String> getAlphabet() {
              return alphabetService.getCharacters();
          }
      }
    

    Your page would access them as normal

    th:each="character : ${alphabet}"
    

    You could also access the service directly in the page by doing something like

    th:each="character: ${@alphabetService.getCharacters()}"
    

    If the menu items do not change while the user is logged in then you could add @SessionAttributes("alphabet") at the class level to the above example and the service method would be called only once when the first page is displayed and cached in the session for future access.