Сссылка для перехода на страницу товара
Хочу сделать переход на страницу товара
Вот код контроллера
@GetMapping(value = "/case")
public String shopPage(Model model, @RequestParam("id") Long id, Principal principal) {
try {
String username = principal.getName();
if (username != null) {
User user = userService.findByLogin(username);
if (!user.isFieldsNotNull()) {
return "redirect:/" + username;
}
model.addAttribute("sign", "выйти");
}
} catch (Exception e) {
model.addAttribute("sign", "войти");
}
ShopCaseDto shop = shopMapper.toShopCaseDto(shopService.findById(id));
List<ShopCaseItemDto> shopItems = shop.getItems();
ShopCaseItemDto ratingItem = shopService.getTheMostRatingItem(shop.getItems());
List<ImageDto> images = ratingItem.getImages();
ImageDto logo = shop.getLogo();
model.addAttribute("shop", shop);
model.addAttribute("images", shopService
.convertListImages(images));
model.addAttribute("shopItems", shopItems);
model.addAttribute("logo", shopService.convertImage(logo));
model.addAttribute("ratingItem", ratingItem);
return "shop_page";
}
@GetMapping(value = "/item")
public String itemPage(Model model, @RequestParam("shop") Long shopId, @RequestParam("item") Long itemId, Principal principal) {
try {
String username = principal.getName();
if (username != null) {
User user = userService.findByLogin(username);
if (!user.isFieldsNotNull()) {
return "redirect:/" + username;
}
model.addAttribute("sign", "выйти");
}
} catch (Exception e) {
model.addAttribute("sign", "войти");
}
Item item = shopService.getItemById(shopService.findById(shopId).getItems(), itemId);
List<ImageDto> images = imageMapper.toListImageDto(item.getImages());
model.addAttribute("item", itemMapper.itemToItemDTO(item));
model.addAttribute("image", shopService.convertListImages(images));
return "shop_item_page";
}
Вот код карточки, где я хочу сделать кнопку с переходом на страницу
<div class="row" th:fragment="list" xmlns:th="http://www.thymeleaf.org">
<div th:each="shop_item,stat: ${shopItems}" class="col-sm-4">
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title" th:text="${shop_item.name}">Product Name</h5>
<p class="card-text" th:text="${shop_item.description}">Material</p>
<p class="card-text" th:text="${shop_item.rating}">Price</p>
<a th:href="@{/shop/{id}/item/{itemid} (id=${shop.id} ,itemid=${shop_item.id})}" class="btn btn-primary">Открыть</a>
</div>
</div>
</div>
В итоге я открываю эту ссылку
http://localhost:8888/shop/2/item/3
Высвечивает такую ошибку
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Nov 22 20:58:24 MSK 2021
There was an unexpected error (type=Not Found, status=404).
No message available
Объясните пожалуйста, что я делаю неправильно
Ответы (1 шт):
Spring выдает ошибку, т.к. вы ссылаетесь и пытаете открыть страницу, которая не обрабатывается ни одним из методов, которые вы привели в данном вопросе.
Почему так случилось и что с этим делать разберемся ниже.
@RequestParam
@RequestParam - это аннотация, которая перехватывает параметр запроса.
Именно ПАРАМЕТР ЗАПРОСА и ничто иное.
Это то, что передается после вопросительного знака в строке запроса.
http://localhost:8888/home?param1=test¶m2=value
В данном случае мы бы могли перехватить эти данные с помощью следующих аннотаций и параметров
@RequestParam("param1") String firstParameter, @RequestParam("param2") String secondParameter
И это значит, что это не то что нам нужно, потому что с помощью данных аннотаций мы не можем извлечь данные из пути... (того что указано до знака вопроса)
Для таких вещей используются переменные пути и мы о них поговорим чуть позже.
@GetMapping
Аннотация @GetMapping позволяет связать запросы, соответствующие указанному шаблону, с методом, который будет их обрабатывать.
В данном случае аннотация @GetMapping(value = "/item") позволяет нам обрабатывать запросы вида http://localhost:8888/item или в лучшем случае http://localhost:8888/shop/item (при условии, что вы еще указали mapping над самим контроллером)
И это опять не то, что нам нужно.
Исходя из всех исходных, запрос, который обрабатывает метод itemPage() вашего контроллера должен был бы выглядеть вот так:
http://localhost:8888/item?shop=123&item=456
или
http://localhost:8888/shop/item?shop=123&item=456
(при условии проставленной аннотации с путем над контроллером)
Вы же ожидаете:
http://localhost:8888/shop/123/item/456
Теперь давайте разберемся как этого достигнуть
@PathVariable
Как я уже упоминал, Вам нужно было использовать переменные пути.
Аннотация @PathVariable позволяет связать параметр метода контроллера с частью шаблона, которому должен удовлетворять запрос.
Для этого в шаблоне пути используются плейсхолдеры, ограниченные справа и слева фигурными скобками
Например:
@GetMapping(value="/schools/{school}/courses/{course}/materials")
В аннотации указаны два плейсхолдера {school} и {course}, которые мы впоследствии можем перехватить с помощью аннотаций, следующим образом:
@PathVariable("school") Long schoolId, @PathVariable("course") Long courseId,
В вашем случае эта пара будет выглядеть следующим образом:
Шаблон:
@GetMapping(value = "/shop/{shop}/item/{item}")
или
@GetMapping(value = "/{shop}/item/{item}")
если над контроллером указан шаблон ("/shop")
и параметры:
@PathVariable("shop") Long shopId, @PathVariable("item") Long itemId,
Итог:
// метод shopPage() в данном листинге не указываю, т.к. он без изменений
// далее
@GetMapping(value = "/shop/{shop}/item/{item}")
public String itemPage(Model model, @PathVariable("shop") Long shopId, @PathVariable("item") Long itemId, Principal principal) {
try {
String username = principal.getName();
if (username != null) {
User user = userService.findByLogin(username);
if (!user.isFieldsNotNull()) {
return "redirect:/" + username;
}
model.addAttribute("sign", "выйти");
}
} catch (Exception e) {
model.addAttribute("sign", "войти");
}
Item item = shopService.getItemById(shopService.findById(shopId).getItems(), itemId);
List<ImageDto> images = imageMapper.toListImageDto(item.getImages());
model.addAttribute("item", itemMapper.itemToItemDTO(item));
model.addAttribute("image", shopService.convertListImages(images));
return "shop_item_page";
}