首页 > 解决方案 > Thymeleaf - 基于表单数据构建 URL

问题描述

我目前正在编写一个电子商务 Web 应用程序,并且正在开发添加到购物车功能。

当您添加到购物车时,它会创建一个发布请求,将数据提交到用户的购物车。我想知道是否有更好的编写方法(如何将表单数据放入 URL)。

当有人点击添加到购物车时,它应该根据当前登录的用户(w/spring security)在这种类型的 url 中发送一个发布请求: /cart/{productId}/{quantity} - 然后它将被添加到用户的购物车。

百里香代码:

    <div th:each="product : ${popularProducts}">
<form action="#" th:action="@{/cart/} + ${product.getId() + @{/} + ${quantity}" th:object="${product}" method="POST">
  <div class="card">
    <img class="card-img" th:src="${product.getPictureUrl()}">
      <a href="#" class="card-link text-danger like">
        <i class="fas fa-heart"></i>
      </a>
    </div>
    <div class="card-body">
      <h4 class="card-title"  th:text="${product.getName()}"></h4>
      <h6 class="card-subtitle mb-2 text-muted"  th:text="${product.getCategory()}"></h6>
      <p class="card-text" th:text="${product.getDescription()}">
      <div class="buy d-flex justify-content-between align-items-center">
        <div class="price text-success"><h5 class="mt-4" th:text="'$' + ${product.getPrice()}"></h5></div>
        <div class="form-group blu-margin">
         <div class="form-label-group">
              <input th:field="*{quantity}" type="text" id="quantity" name="quantity" class="form-control" placeholder="1" required="required">
           </div>
        </div>
         <a href="#" class="btn btn-danger mt-3"><i class="fas fa-shopping-cart"></i> Add to Cart</a>
      </div>
    </div>
    </form>

购物车控制器:

@PostMapping("/cart/{productId}/{quantity}")
public void addProduct(@PathVariable String productId, @PathVariable String quantity, Model model) {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    User user = ((User) principal);

    if (productService.findById(Long.parseLong(productId)) != null) {
        Optional<Product> product = productService.findById(Long.parseLong(productId));
        int quantityAmount = Integer.parseInt(quantity);
        user.getCart().getCartItems().add(new CartItems(product.get(), quantityAmount,
                product.get().getPrice() * quantityAmount, user.getCart()));
    }

    List<CartItems> itemsInCart = user.getCart().getCartItems();
    int numItems = itemsInCart.size() + 1;

    model.addAttribute("amountOfItems", numItems);

}

产品类别:

@Table(name = "products")
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id")
private Long id;

@Column(name = "name")
private String name;

@Column(name = "category")
private String category;

@Column(name = "description")
private String description;

@Column(name = "price")
private Double price;

@Column(name = "stock")
private int stock;

@Column(name = "picture_url")
private String pictureUrl;

public Product() {

}

public Product(String name, String category, String description, Double price, int stock, String pictureUrl) {
    this.name = name;
    this.category = category;
    this.description = description;
    this.price = price;
    this.stock = stock;
    this.pictureUrl = pictureUrl;
}
// and getters/setters...

CartItems 类:

@Table(name = "cartitems")
public class CartItems implements Serializable {

private static final long serialVersionUID = -3426230490106082532L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

@Column(name = "quantity")
private int quantity;

@Column(name = "price")
private double price;

@OneToOne
@JoinColumn(name = "product_id")
private Product product;

@ManyToOne
@JoinColumn(name = "cart_id")
private Cart cart;

public CartItems() {

}

public CartItems(Product product, int quantity, double price, Cart cart) {
    this.quantity = quantity;
    this.price = price;
    this.product = product;
    this.cart = cart;
}
// all getters and setters..

标签: spring-bootspring-mvcspring-securitythymeleaf

解决方案


使用表单数据的 Thymeleaf URL

如何将表单数据放在 URL 中?

您不能使用用户在 Web 表单中输入的数据来构建 Thymeleaf URL。Thymeleaf 是一个服务器端的 HTML 预处理器。它使用服务器上已有的数据来“填补”Thymeleaf 模板中的空白。然后将生成的 HTML 从服务器发送到浏览器。那时,浏览器中没有 Thymeleaf。

使用 POST 数据

您对表单数据使用 http POST 操作是正确的。这意味着所有用户提供的数据都将在请求正文中发送到服务器,我相信您已经知道了。

通常,尝试将此类数据添加到 URL 不是一个好主意。您可以使用客户端 JavaScript 执行此操作 - 但由于各种原因,这是一个坏主意 - 尤其是这样:可以为 URL 添加书签、保存和轻松重新播放。表单数据通常代表一个事务。您不想以这种方式重新提交大多数交易(重复订单等)。一些背景阅读是here

因此,使用更通用的 URL,然后从请求正文中提取表单数据。无论如何,正文中的数据基本上与您尝试添加到 URL 的数据相同。

Thymeleaf URL - 一般

最后一点:仅供将来参考,与此特定 URL 没有直接关系,原因上面已经提到...

而不是使用这个:

"@{/cart/} + ${product.getId() + @{/} + ${quantity}"

...链接应该这样创建:

"@{/cart/{id}/{qty}(id=${product.id},qty=${quantity})}"

在此示例中,{id}是一个占位符(您可以随意调用它),它从括号中的参数接收其值()

id=${product.id}

同样的观点也适用于{qty}

此外,您不需要直接使用吸气剂getId()。使用字段名称id。Thymeleaf 将处理调用相关的 getter(假设它定义正确)。

请参阅 Thymeleaf链接 url的文档。


推荐阅读