Spring Boot+Thymeleaf实现全站URL显示Gallery动态子菜单
Hey there! Let's break down how to implement this global gallery submenu that shows up on every page, pulling data straight from MySQL. Since you already have your page fragments split (header, footer), we'll focus on integrating the dynamic data seamlessly across all your pages.
1. Create the Gallery Entity
First, map your MySQL gallery table to a Java entity. Make sure the fields match your actual table structure:
import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @Entity public class Gallery { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // Stores "Gallery1", "Gallery2", "Gallery3" etc. private String url; // Optional: links each submenu to a specific page // Getters & Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
2. Build a Repository Interface
Use Spring Data JPA to handle database interactions with minimal code:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface GalleryRepository extends JpaRepository<Gallery, Long> { // We'll use the default findAll() method to fetch all gallery entries }
3. Add a Service Layer (Recommended)
Separate business logic from controllers with a service class:
import org.springframework.stereotype.Service; import java.util.List; @Service public class GalleryService { private final GalleryRepository galleryRepository; // Constructor injection (preferred over @Autowired) public GalleryService(GalleryRepository galleryRepository) { this.galleryRepository = galleryRepository; } public List<Gallery> getAllGalleries() { return galleryRepository.findAll(); } }
4. Make Gallery Data Available Globally
This is the critical step! To ensure every page can access the gallery submenu data, use @ControllerAdvice with @ModelAttribute. This adds the gallery list to the model for every incoming request:
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ModelAttribute; import java.util.List; @ControllerAdvice public class GlobalControllerAdvice { private final GalleryService galleryService; public GlobalControllerAdvice(GalleryService galleryService) { this.galleryService = galleryService; } @ModelAttribute("galleries") public List<Gallery> getGalleries() { return galleryService.getAllGalleries(); } }
5. Update Your Header Fragment
Modify your Thymeleaf header fragment to render the dynamic submenus. Here's a sample implementation:
Example Header Fragment with Dynamic Gallery Submenu:
<header> <nav> <ul class="main-menu"> <li><a th:href="@{/home}">Home</a></li> <li class="dropdown"> <a href="#">Gallery</a> <ul class="submenu"> <!-- Iterate over the global galleries model attribute --> <th:block th:each="gallery : ${galleries}"> <li><a th:href="@{${gallery.url}}" th:text="${gallery.name}"></a></li> </th:block> </ul> </li> <li><a th:href="@{/about}">About</a></li> <!-- Other menu items --> </ul> </nav> </header>
Here's how your header appears with the populated submenus:
6. Verify Across All Pages
Thanks to @ControllerAdvice, you don't need to manually add gallery data to any controller's model. For example, a simple Home controller works perfectly without extra code:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HomeController { @GetMapping("/home") public String home() { // Galleries are already added to the model globally! return "home"; } }
Just include your header fragment in any template (like home.html) as you normally would:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Home Page</title> </head> <body> <div th:replace="fragments/header :: header"></div> <!-- Rest of your home page content --> </body> </html>
Quick Pro Tips
- To sort gallery entries alphabetically, update the service method:
return galleryRepository.findAll(Sort.by(Sort.Direction.ASC, "name")); - Add caching to reduce database hits: Annotate
getAllGalleries()with@Cacheable("galleries")and enable caching with@EnableCachingin your main Spring Boot application class.
内容的提问来源于stack exchange,提问作者Nobita

