Thymeleaf表单下拉框数据无法插入MySQL,手动操作正常求排查方案
问题描述
页面表单包含金额、备注、日期输入框及从数据库加载的下拉框,下拉框显示正常。用户选择下拉项提交后,Transaction表的category字段为NULL,其他字段保存正常,但可在MySQL中手动为该字段赋值。曾出现"Cannot add or update a child row a foreign key constraint fails"错误,现已解决但无报错信息,仅category字段未保存。
相关代码
Thymeleaf表单代码
<form action="#" th:action="@{/api/transaction/saveTransaction/{walletId} (walletId=${id})}" th:object="${transaction}" method="POST"> <input type="text" th:field="*{amount}" placeholder="Enter amount" class="form-control mb-4 col-4"> <input type="text" th:field="*{note}" placeholder="Enter note" class="form-control mb-4 col-4"> <input type="date" th:field="*{date}" class="form-control mb-4 col-4"> <select class="form-control" id="dropOperator"> <option value="0">Select category</option> <option th:each="categories : ${categories}" th:value="${categories.name}" th:text="${categories.name}"></option> </select> <button type="submit" class="btn btn-info col-2"> Save Wallet</button> </form>
保存表单的Controller代码
@PostMapping("/saveTransaction/{walletId}") public String saveTransaction(@PathVariable(value = "walletId") long walletId, @ModelAttribute("transaction") Transaction transaction) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal(); long userId = user.getId(); Wallet wallet = walletService.getWalletById(walletId); transaction.setWallet(wallet); transactionService.saveTransaction(transaction); return "redirect:/api/wallet/userWallet/balance/" + userId; }
显示表单的Controller代码
@GetMapping("/showNewTransactionForm/{id}") public String showNewTransactionForm(@PathVariable(value = "id") long id, Transaction transaction, Model model) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal(); long userId = user.getId(); model.addAttribute("userId", userId); model.addAttribute("transaction", transaction); List<Category> categories = categoryService.getAllCategories(); model.addAttribute("categories", categories); return "new_transaction"; }
Category实体类
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "category_id") private Long id; @Column(name = "category_name") private String name; @OneToMany(cascade = CascadeType.ALL, mappedBy = "category") private List<Transaction> transactions;
Transaction实体类
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "transaction_id") private Long id; private double amount; private String note; @DateTimeFormat(pattern = "yyyy-MM-dd") @Column(name = "date") private Date date; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "category_name", referencedColumnName = "category_name") private Category category; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="wallet_id", nullable=false) private Wallet wallet;
排查解决建议
修复下拉框与实体的绑定:当前下拉框未通过
th:field绑定到Transaction的category属性,导致提交时category参数无法被Spring MVC封装到实体中。修改下拉框代码:<select class="form-control" id="dropOperator" th:field="*{category}"> <option value="">Select category</option> <option th:each="cat : ${categories}" th:value="${cat.name}" th:text="${cat.name}"></option> </select>同时需确保CategoryService实现了
findByName(String name)方法,让Spring能通过提交的名称查询到对应的Category实体。手动处理category参数转换:如果Spring无法自动将字符串类型的分类名称转为Category实体,可手动处理:
- 修改下拉框的name属性:
<select class="form-control" id="dropOperator" name="categoryName"> <option value="">Select category</option> <option th:each="cat : ${categories}" th:value="${cat.name}" th:text="${cat.name}"></option> </select> - 在Controller中接收参数并关联实体:
@PostMapping("/saveTransaction/{walletId}") public String saveTransaction(@PathVariable(value = "walletId") long walletId, @ModelAttribute("transaction") Transaction transaction, @RequestParam("categoryName") String categoryName) { // 原有逻辑... if (!categoryName.isEmpty()) { Category category = categoryService.getCategoryByName(categoryName); transaction.setCategory(category); } transactionService.saveTransaction(transaction); return "redirect:/api/wallet/userWallet/balance/" + userId; }
- 修改下拉框的name属性:
优化实体关联配置:当前用分类名称作为外键关联,建议改为用主键category_id关联,更稳定且避免名称重复问题:
- 修改Transaction实体的关联配置:
@ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "category_id", referencedColumnName = "category_id") private Category category; - 下拉框使用分类ID作为value:
<select class="form-control" id="dropOperator" th:field="*{category}"> <option value="">Select category</option> <option th:each="cat : ${categories}" th:value="${cat.id}" th:text="${cat.name}"></option> </select>
- 修改Transaction实体的关联配置:
检查Service层保存逻辑:确认transactionService.saveTransaction方法中没有无意中将category字段设为null,确保repository的save方法正确执行。
内容的提问来源于stack exchange,提问作者asu
相关产品推荐
相关产品推荐

