У меня есть приложение Spring Boot 3 с Thymeleaf в интерфейсе. Страница выглядит так:
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org" xmlns = "http://www.w3.org/1999/html" th:lang = "en" lang = "en">
<!-- Head-->
<head th:replace = "~{fragments/head :: head}"></head>
<body>
<div th:if = "${profileSection == 'Profile info'}">
<div th:replace = "~{fragments/user/profile-info :: profileInfo}"></div>
</div>
<div th:if = "${profileSection == 'Downloads'}">
<div th:replace = "~{fragments/user/downloads :: downloads}"></div>
</div>
</body>
</html>
Когда пользователь нажимает на ссылку профиля, вышеуказанная страница будет отображаться с profileSection == 'Profile info', так что fragments/user/profile-info :: profileInfo будет отображаться первым, а данные пользователя, такие как имя, адрес электронной почты, номер телефона и т. д., будут отображаться. Есть боковая панель с, скажем, 2 ссылками. Profile info и Downloads.
Я хочу вот что: когда пользователь нажимает ссылку Download на боковой панели, fragments/user/downloads :: downloads должен отображаться в середине страницы без получения загрузок из бэкэнда, вместо этого он должен использовать текущий объект user, например: user.getDownloads() для рендеринга загрузки список. Таким образом, мне не нужно делать дополнительный раунд в БД, чтобы снова получить пользователя. Пользователь имеет отношения @ManyToMany с объектом загрузки.
Как я могу это сделать? Или это вообще возможно?
Если загрузки пользователя содержат много данных, они могут излишне потреблять много памяти, поскольку пользователь может вообще не получить доступ к разделу загрузок. Есть лучший подход к этой проблеме.
Для начала убедитесь, что отношение @ManyToMany имеет FetchType.LAZY (это значение по умолчанию, так что все будет в порядке, если вы не указали FetchType.EAGER явно). Таким образом, память не будет заполнена, если пользователь специально не запрашивает загрузки.
Когда пользователь нажимает ссылку Downloads на боковой панели, в HTML-файле должен быть такой код:
<a th:href = "@{/user/downloads}">Downloads</a>
В классе Controller вы можете иметь что-то вроде:
@GetMapping("/user/downloads")
public String getDownloads(@AuthenticationPrincipal(expression = "user") User user, Model model) {
user.getDownloads().size(); // Now you have access to downloads
model.addAttribute("profileSection", "Downloads");
model.addAttribute("user", user);
return "user/profile-page";
}
Обязательно импортируйте аннотацию AuthenticationPrincipal:
org.springframework.security.core.annotation.AuthenticationPrincipal
Не используйте этот, он устарел:
org.springframework.security.web.bind.annotation.AuthenticationPrincipal
Spring Boot предоставляет вошедшего в систему пользователя в вашем методе Controller, поэтому просто добавьте объект пользователя в модель, и внутри фрагмента fragments/user/downloads :: downloads вы можете сделать что-то вроде приведенного ниже фрагмента, чтобы просмотреть список загрузки пользователя:
<div th:each = "download : ${user.downloads}">
...
</div>
Примечание. Будьте осторожны, если вы используете Lombok. Аннотации @Data/@Getter могут привести к загрузке ленивых элементов без явного вызова.