如何将类作为Model属性传递?页面展示关联属性报错求助
订单列表展示报错问题处理
问题描述
我定义了Order类,通过model.addAttribute将其列表传递至HTML页面,期望展示order.customer.address、order.orderDetailList.product.name、order.orderDetailList.quantity属性,但运行时出现报错。
相关代码
Controller代码
@GetMapping("/orders") public String orders(Model model, Principal principal){ if(principal == null){ return "redirect:/login"; } List<Order> orders = orderService.getAllOrders(); model.addAttribute("orders", orders); }
Order实体类
public class Order { private Long id; // 省略其他属性 private String orderStatus; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "customer_id", referencedColumnName = "customer_id") private Customer customer; @OneToMany(cascade = CascadeType.ALL, mappedBy = "order") private List<OrderDetail> orderDetailList; }
OrderDetail实体类
public class OrderDetail { private Long id; private int quantity; private double totalPrice; private double unitPrice; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "order_id", referencedColumnName = "order_id") private Order order; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", referencedColumnName = "product_id") private Product product; }
Thymeleaf页面代码
<table class="table table-bordered" th:if="${size > 0}"> <thead> <tr> <th scope="col">Order Index</th> <th scope="col">Order Date</th> <th scope="col">Order Items</th> <th scope="col">Delivery address</th> <th scope="col">Order Status</th> </tr> </thead> <tbody> <tr th:each="order : ${orders}"> <th scope="row" th:text="${order.id}"></th> <td th:text="${order.orderDate}"></td> <td th:text="${order.orderDetailList}"></td> <td th:text="${order.customer.address}"></td> <td th:text="${order.orderStatus}"></td> </tr> </tbody> </table>
报错原因分析
- 懒加载初始化异常:OrderDetail中的Product采用
FetchType.LAZY懒加载,Thymeleaf页面渲染时Hibernate会话已关闭,无法初始化懒加载对象,会抛出LazyInitializationException。 - 订单详情展示方式错误:直接用
th:text="${order.orderDetailList}"会输出List对象的toString内容,无法展示单个商品的名称和数量。 - 空指针风险:若订单未关联Customer,访问
order.customer.address会触发NullPointerException。 - 属性名称不匹配:你期望的属性是
order.orderDetails,但实体类中实际定义的是orderDetailList,属性名不匹配会导致取值失败。
解决方案
解决懒加载问题
- 方式一:修改OrderDetail中Product的加载策略为
FetchType.EAGER:@OneToOne(fetch = FetchType.EAGER) @JoinColumn(name = "product_id", referencedColumnName = "product_id") private Product product; - 方式二:在Service层使用关联查询提前加载数据,避免会话关闭后无法初始化:
// 在OrderService的getAllOrders方法中使用JPQL public List<Order> getAllOrders() { return entityManager.createQuery( "SELECT o FROM Order o " + "JOIN FETCH o.customer " + "JOIN FETCH o.orderDetailList od " + "JOIN FETCH od.product", Order.class ).getResultList(); }
- 方式一:修改OrderDetail中Product的加载策略为
正确展示订单详情
修改页面中订单详情的渲染逻辑,遍历orderDetailList展示商品名称和数量:<td> <ul> <li th:each="detail : ${order.orderDetailList}"> <span th:text="${detail.product.name}"></span> - <span th:text="${detail.quantity}"></span> 件 </li> </ul> </td>处理空值避免空指针
使用Thymeleaf的Elvis运算符处理可能为空的属性:<td th:text="${order.customer?.address ?: '无收货地址'}"></td>核对属性名称
确保页面中使用的属性名与实体类完全一致,实体类中订单详情列表是orderDetailList,不要写成orderDetails。
内容的提问来源于stack exchange,提问作者alnvalnnn
相关产品推荐
相关产品推荐

