Я использую пружинный ботинок + тимелеф + neo4j. Все работает нормально, за исключением того, что тимелеаф не может разрешить некоторые атрибуты переменной 'product', используемые в блоке th: each в шаблоне product_grid.html, который включает th: src = "$ {product.URL} ", th: text =" $ {Product.title} "и выражение th: action =" @ {/ product / ($ {Product.getId ()})} "в теге формы. Th: text = "$ {Product.Price}" работает. Когда я проверяю код, созданный в браузере, тег src пуст (src: ""), текстовый атрибут, содержащий тег заголовка, не отображается в браузере. Действие th: работает нормально, но когда я нажимаю кнопку, определенную внутри формы, URL-адрес меняется на http: // localhost: 8080 / product /? btn = Просмотр + Продукт вместо следующего кода, который отображается в консоли браузера http: // локальный: 8080 / продукт /? 1
Примечание: я пытаюсь получить URL-адрес изображения из поля, которое хранится в базе данных neo4j. Каталог проекта: образ каталога проекта
Шаблон: product_grid.html
<html xmlns:th = "http://www.thymeleaf.org" >
<head>
<meta charset = "utf-8" />
<meta http-equiv = "X-UA-Compatible" content = "IE=edge">
<title>Products</title>
<meta name = "viewport" content = "width=device-width, initial-scale=1">
<script src = "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.bundle.min.js" integrity = "sha384-feJI7QwhOS+hwpX2zkaeJQjeiwlhOP+SdQDqhgvvo1DsjtiSQByFdThsxO669S2D"
crossorigin = "anonymous"></script>
<script src = "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity = "sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin = "anonymous"></script>
<link href = "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel = "stylesheet" integrity = "sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin = "anonymous">
</head>
<body>
<nav class = "navbar navbar-expand-lg navbar-dark bg-dark">
<a class = "navbar-brand" href = "#">Grada</a>
<button class = "navbar-toggler" type = "button" data-toggle = "collapse" data-target = "#navbarSupportedContent" aria-controls = "navbarSupportedContent"
aria-expanded = "false" aria-label = "Toggle navigation">
<span class = "navbar-toggler-icon"></span>
</button>
<div class = "collapse navbar-collapse" id = "navbarSupportedContent">
<ul class = "navbar-nav mr-auto">
<li class = "nav-item ">
<a class = "nav-link" href = "#">Home
<span class = "sr-only">(current)</span>
</a>
</li>
<li class = "nav-item">
<a class = "nav-link">My Best Products</a>
</li>
<li class = "nav-item">
<a class = "nav-link" th:href = "@{/login}">Login</a>
</li>
</ul>
<form class = "form-inline my-2 my-lg-0">
<input class = "form-control mr-sm-2" type = "search" placeholder = "Search" aria-label = "Search">
<a class = "btn btn-outline-success my-2 my-sm-0" href = "file:///home/madhav/SPM/Grada/public_html/product.html">Search</a>
</form>
</div>
</nav>
<div class = "container text-center">
<div class = "row">
<div th:each = "Product:${products}" class = "col-lg-3 col-sm-12 col-md-6 my-2 p-auto">
<div class = "card">
<div class = "card-body">
<img src = "http://via.placeholder.com/150x150/888/111" th:src = "${Product.URL}" alt = "img" class = "card-img-top img-thumbnail img-fluid">
<div class = "card-title lead" th:text = "${Product.title}">Some product name</div>
<div class = "card-text">Price: ₹<span th:text = "${Product.Price}">400</span></div>
</div>
<form method = "GET" action = "/" th:action = "@{/product/(${Product.getId()})}">
<input type = "submit" name = "btn" class = "form-control btn btn-primary" value = "View Product">
<input type = "submit" name = "btn" class = "form-control btn btn-primary" value = "Add to Cart">
</form>
</div>
</div>
</div>
</div>
</body>
</html>`Модель продукта: Product.html
package com.grada.ecommerce.Models;
import com.grada.ecommerce.Models.Seller;
import org.neo4j.ogm.annotation.*;
import java.util.HashSet;
import java.util.Set;
@NodeEntity(label = "Product")
public class Product
{
public Product()
{
}
public Product(String title, Double price, int quantity, float rating, String description, String url, String company)
{
this.title = title;
this.Rating = rating;
this.Description = description;
this.Price = price;
this.Quantity = quantity;
this.URL = url;
this.Company = company;
}
@Id
@GeneratedValue
private Long id;
@Property(name = "title")
public String title;
@Property(name = "Rating")
public float Rating;
@Property(name = "Description")
public String Description;
@Property(name = "Price")
public Double Price;
@Property(name = "Quantity")
public int Quantity;
@Property(name = "Company")
public String Company;
@Property(name = "URL")
public String URL;
@Override
public String toString()
{
return this.title;
}
public Long getId() {
return id;
}
public String getTitle()
{
return title;
}
@Relationship(type = "Sells", direction = Relationship.INCOMING)
public Seller Seller;
}package com.grada.ecommerce.Controllers;
import com.grada.ecommerce.Models.Product;
import com.grada.ecommerce.Models.Seller;
import com.grada.ecommerce.Services.ProductService;
import com.grada.ecommerce.Services.SellerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class ProductController
{
final ProductService productService;
final SellerService sellerService;
@Autowired
public ProductController(ProductService productService, SellerService sellerService)
{
this.productService = productService;
this.sellerService = sellerService;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String Index(Model model)
{
Iterable<Product> products = productService.products();
model.addAttribute("products", products);
return "product_grid";
}
@RequestMapping(value = "/product", method = RequestMethod.GET)
public String ShowProduct(@RequestParam(value = "id") Long id, Model model)
{
Product product = productService.findProductByID(id);
if (product == null)
return "redirect:/";
model.addAttribute("product", product);
return "productid";
}
@RequestMapping(value = "/add")
public String AddProduct(Model model)
{
model.addAttribute("product", new Product());
return "add";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String AddProduct(@ModelAttribute Product product)
{
productService.addProduct(product);
return "redirect:/";
}
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public String DeleteProduct(Model model)
{
model.addAttribute("product", new Product());
return "delete";
}
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public String DeleteProduct(@ModelAttribute Product product)
{
productService.deleteProduct(product);
return "redirect:/";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String LoginPage(Model model)
{
return "login";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String Authenticate(Model model, String username, String password)
{
if (username.equalsIgnoreCase("[email protected]") && password.equals("fakeseller"))
{
Iterable<Product> products = productService.products();
model.addAttribute("products", products);
return "loggedin";
}
else
return "redirect:/login";
}
@RequestMapping(value = "/policy", method = RequestMethod.GET)
public String PolicyPage()
{
return "policies";
}
}Кроме того, по какой причине вы используете method = "GET" вместо POST?
Кроме того, ваш пользовательский интерфейс будет выглядеть странно - вы будете создавать новый столбец для каждого продукта, если внимательно присмотритесь.
Хорошо, я изменю его на нижний регистр. Нет особой причины для использования GET, но должно ли это иметь значение? Что касается UI, я просто пытался распечатать информацию о каждом продукте, который есть в БД, на странице.
Да, использование GET vs POST имеет значение. Если вы отправляете данные, вы захотите использовать POST: stackoverflow.com/questions/504947/…
Вы также можете использовать сокращенные обозначения @GetMapping и @PostMapping в вашем контроллере. И распечатайте значение productService.products();, чтобы убедиться, что вы добавляете товары нормально.
Есть ли в вашем классе Product установщики для значений, которые вам не хватает? Если это проблема, я отправлю ответ
Добро пожаловать в SO.
Включите методы setX для ваших переменных в класс Product. Тимелисту они нужны для связывания.
ИМО, отличный способ сделать это - использовать Project Lombok и просто аннотировать свой класс с помощью @Data. Тогда вам даже не нужно будет указывать геттеры или сеттеры (или ваш toString()) вообще.
Используйте строчные буквы для своих переменных, поскольку по соглашению переменные с заглавной первой буквой относятся к классу, а не к переменной экземпляра.
Как уже упоминалось, используйте в форме POST вместо GET, поскольку вы отправляете данные.
Используйте сокращения @GetMapping и @PostMapping, чтобы облегчить чтение.
Когда я изменил метод с GET на POST, он сработал! Спасибо! Но согласно предоставленной вами ссылке GET используется для извлечения данных, т.е. запрос, не так ли? POST будет использоваться, когда я захочу изменить некоторые данные. Здесь я просто отправляю товар и получаю подробную информацию о нем. Итак, почему использование GET создает конкретную проблему, которую я получаю?
Было бы слишком долго обсуждать это в комментарии, но в вашем случае ваш View Product можно было бы заменить простым тегом привязки. Состояние системы не меняется, и я не вижу смысла даже создавать из нее форму. Если вы добавляете в корзину, за кулисами обычно происходит много вещей, вы хотите, чтобы это было безопасно, и т. д. У вас тоже много других проблем, поэтому не стоит их изучать. пока вы не разберетесь с ними. Основная причина заключается в том, какой метод вы на самом деле вызываете, в зависимости от GET или POST.
Вы пробовали изменить регистр на строчные? Или еще лучше, вместо
Productназовите ееoneProductилиitem, чтобы переменная была уникальной и более удобной для чтения.