【问题标题】:Thymeleaf. Right way to send object using form to controller百里香叶。使用表单将对象发送到控制器的正确方法
【发布时间】:2021-03-17 12:38:27
【问题描述】:

我对 thymeleaf 形式的帖子有疑问。它发生在我试图将我的 ShoppingCart 对象发送到控制器时。 项目详情:/products 端点,用户可以在其中将所需的产品添加到他的 ShoppingCart(session)。 在购物车中,添加的产品将转换为具有字段产品和数量的新实体 OrderedProduct。 当用户准备好时,他会去 /cart 端点确认交易并发送订单。

所以,然后我将发布请求发送到 /orders 端点。但是在控制器中,我得到了一个带有空字段(orderedProducts,total)的空购物车。 据我了解,这是百里香的预期行为。为了从我的购物车中传递参数,我应该明确地将它们定义为表单中的隐藏字段。 所以我添加了这个:

<input type="hidden" name="total" th:field="*{total}"/>
<input type="hidden" name="orderedProducts" th:field="*{orderedProducts}"/>

然后我得到这样的异常:

Field error in object 'shoppingCart' on field 'orderedProducts': rejected value [null,null];
codes [typeMismatch.shoppingCart.orderedProducts,typeMismatch.orderedProducts,typeMismatch.java.util.List,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [shoppingCart.orderedProducts,orderedProducts];arguments [];
default message [orderedProducts]];default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'orderedProducts';
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'null,null';
nested exception is java.lang.NumberFormatException: For input string: "null,null"]]

据我了解这是转换问题,我们应该为 OrderedProduct 定义特殊转换器(如本主题中:https://stackoverflow.com/a/60066445/14308420)。 考虑到 OrderedProduct 存储在 session 中,但没有 id,如何制作转换器?

checkout.html

<form th:action="@{/orders}" th:object="${cart}" method="post">
  <input type="hidden" name="total" th:field="*{total}"/>
  <input type="hidden" name="orderedProducts" th:field="*{orderedProducts}"/>
  <label for="phoneNumber">Phone number: </label>
  <input type="number" required="required" name="phoneNumber"
                   class="form-control" id="phoneNumber">
  <button type="submit" class="btn-lg btn-primary">Order</button>
</form>

OrderUIController

@PostMapping
  public String create(@ModelAttribute ShoppingCart cart,
      @RequestParam("phoneNumber") Long phoneNumber) {
    Order order = new Order();
    order.setOrderedProducts(cart.getOrderedProducts());
    order.setPhoneNumber(phoneNumber);
    order.setTotal(cart.getTotal());
    service.create(order);
    return "redirect:/profile";
  }   

购物车

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart implements Serializable {
    private List<OrderedProduct> orderedProducts = new ArrayList<>();

    private Long total;
}

OrderedProduct

public class OrderedProduct extends AbstractBaseEntity {
    private Integer quantity;

    private Product product;
}

【问题讨论】:

  • 与您的问题没有直接关系,但您不应从隐藏字段中的值中获取total。如果有人打开 devtools 并更改那里的价值,他们将能够非常便宜地购物。
  • @WimDeblauwe 感谢您的重要评论。我们如何才能确保字段总数?考虑到用户可以在 checkout.html 中更改购物车中产品的数量,并且字段总计将相应更改。 我想警告:在您的个人资料中“驯服 Thymeleaf”和“使用 Spring Boot 构建 API 后端的实用指南”指向相同的链接。
  • 感谢关于我的个人资料的提示,现已修复。关于总数:您应该让服务器根据购物车中的产品再次计算总数。您可以从Order 中删除setTotal,并让该类根据订单上设置的产品计算它。

标签: html spring spring-mvc thymeleaf


【解决方案1】:

要使用表单将自定义对象传递给控制器​​,我们应该制作一个转换器。 如果您的对象有一个 id,那么您可以像本主题中那样(https://stackoverflow.com/a/60066445/14308420)。 但是,如果您的数据库中不存在对象,那么您可以遵循本指南 (https://www.baeldung.com/spring-type-conversions)。 下面的代码中有一个示例。 就我而言,我通过在 OrderController 中自动装配 ShoppingCart 解决了这个问题,而没有将订购产品列表作为表单中的字段传递。

例子:

public class Employee {

    private long id;
    private double salary;

    // standard constructors, getters, setters
}


public class StringToEmployeeConverter
  implements Converter<String, Employee> {

    @Override
    public Employee convert(String from) {
        String[] data = from.split(",");
        return new Employee(
          Long.parseLong(data[0]), 
          Double.parseDouble(data[1]));
    }
}


@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToEmployeeConverter());
    }
}

【讨论】:

    猜你喜欢
    • 2021-02-27
    • 2020-02-19
    • 1970-01-01
    • 2015-05-18
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 2019-07-10
    相关资源
    最近更新 更多