Spring 3+Thymeleaf银行应用:数据库数据无法在前端显示求助
问题:Spring + Thymeleaf银行应用前端无法展示数据库数据
我使用Spring 3和Thymeleaf开发基础银行应用,通过Postman操作本地数据库完全正常,账户能成功创建并写入数据库,但Thymeleaf构建的前端页面(index.html)无法展示数据库中的账户数据。访问localhost:8080时,页面仅显示表头和“Create New Account”按钮,无任何账户信息。
控制器代码(AccountController.java)
import com.bankapp.banking.dto.AccountDto; import com.bankapp.banking.service.AccountService; import com.bankapp.banking.service.impl.InsufficientFundsException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import java.util.List; @Controller @RequestMapping("/accounts") public class AccountController { @Autowired private AccountService accountService; public AccountController(AccountService accountService) { this.accountService = accountService; } // Add Account Page @GetMapping("/add") public String addAccountForm(Model model) { AccountDto accountDto = new AccountDto(); model.addAttribute("accountDto", accountDto); return "add-account"; } // Add Account Form Submission @PostMapping("/add") public String addAccount(@ModelAttribute AccountDto accountDto) { accountService.createAccount(accountDto); return "redirect:/"; } @GetMapping("/") public ModelAndView getAllAccounts() { List<AccountDto> accounts = accountService.getAllAccounts(); // 调试用:打印获取到的账户数量 System.out.println("Number of accounts retrieved: " + accounts.size()); ModelAndView modelAndView = new ModelAndView("index"); modelAndView.addObject("accounts", accounts); return modelAndView; } @GetMapping("/{id}") public String getAccountById(@PathVariable Long id, Model model) { AccountDto accountDto = accountService.getAccountById(id); model.addAttribute("accountDto", accountDto); return "account-details"; } // Deposit Page @GetMapping("/{id}/deposit") public String depositForm(@PathVariable Long id, Model model) { AccountDto accountDto = accountService.getAccountById(id); model.addAttribute("accountDto", accountDto); return "deposit"; } @PostMapping("/{id}/deposit") public String deposit(@PathVariable Long id, @RequestParam("amount") Double amount) { try { accountService.deposit(id, amount); return "redirect:/accounts/" + id; } catch (IllegalArgumentException e) { return "redirect:/accounts/" + id + "?error=" + e.getMessage(); } } // Withdraw Page @GetMapping("/{id}/withdraw") public String withdrawForm(@PathVariable Long id, Model model) { AccountDto accountDto = accountService.getAccountById(id); model.addAttribute("accountDto", accountDto); return "withdraw"; } @PostMapping("/{id}/withdraw") public String withdraw(@PathVariable Long id, @RequestParam("amount") Double amount) { try { accountService.withdraw(id, amount); return "redirect:/accounts/" + id; } catch (IllegalArgumentException | InsufficientFundsException e) { return "redirect:/accounts/" + id + "?error=" + e.getMessage(); } } @PostMapping("/{id}/delete") public String deleteAccount(@PathVariable Long id) { accountService.deleteAccount(id); return "redirect:/accounts/" + id + "/confirm-delete"; } @PostMapping("/{id}/confirmDelete") public String confirmDelete(@PathVariable Long id, Model model) { AccountDto accountDto = accountService.getAccountById(id); model.addAttribute("accountDto", accountDto); return "confirm-delete"; } }
前端页面(index.html)
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Banking App - Home</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> </head> <body> <div class="container my-2"> <h1>Accounts</h1> <a th:href="@{/accounts/add}" class="btn btn-primary btn-sm mb-3">Create New Account</a> <table class="table table-striped table-responsive-md"> <thead> <tr> <th>ID</th> <th>Account Holder Name</th> <th>Balance</th> <th>Action</th> </tr> </thead> <tbody> <tr th:each="accountDto : ${accounts}"> <td th:text="${accountDto.id}"></td> <td th:text="${accountDto.accountHolderName}"></td> <td th:text="${accountDto.balance}"></td> <td> <a th:href="@{'/accounts/' + ${accountDto.id} + '/deposit'}" class="btn btn-success btn-sm">Deposit</a> <a th:href="@{'/accounts/' + ${accountDto.id} + '/withdraw'}" class="btn btn-warning btn-sm">Withdraw</a> <form th:action="@{'/accounts/' + ${accountDto.id} + '/delete'}" method="post"> <input type="hidden" name="_method" value="DELETE"/> <button type="submit" class="btn btn-danger btn-sm">Delete</button> </form> </td> </tr> </tbody> </table> <th:block th:if="${param.error}"> <div class="alert alert-danger" role="alert"> <span th:text="${param.error}"></span> </div> </th:block> </div> </body> </html>
解决方向
请求路径不匹配:
控制器中获取所有账户的映射是@GetMapping("/"),但外层有@RequestMapping("/accounts"),实际访问路径应为localhost:8080/accounts。而创建账户后重定向到redirect:/,该路径无对应控制器方法,导致直接返回空数据的index.html。
修复方案:将创建账户后的重定向改为redirect:/accounts,或添加根路径跳转方法:@GetMapping("/") public String redirectToAccounts() { return "redirect:/accounts"; }数据渲染依赖验证:
- 检查控制台的调试输出
Number of accounts retrieved: X,若为0说明Service层未正确获取数据;若大于0则数据已传入模型,需排查前端问题。 - 确认
AccountDto类的id、accountHolderName、balance字段有对应的getter方法(Thymeleaf需通过getter访问属性)。 - 核对前端Thymeleaf变量名
${accounts}与控制器添加的模型变量名是否一致。
- 检查控制台的调试输出
删除逻辑错误:
当前删除方法先删除账户再跳转到确认页面,此时账户已不存在,会导致getAccountById(id)报错。需调整流程:先跳转到确认页面,确认后再执行删除操作。
内容的提问来源于stack exchange,提问作者Phileoreal
相关产品推荐
相关产品推荐

