You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

解决方向

  1. 请求路径不匹配:
    控制器中获取所有账户的映射是@GetMapping("/"),但外层有@RequestMapping("/accounts"),实际访问路径应为localhost:8080/accounts。而创建账户后重定向到redirect:/,该路径无对应控制器方法,导致直接返回空数据的index.html。
    修复方案:将创建账户后的重定向改为redirect:/accounts,或添加根路径跳转方法:

    @GetMapping("/")
    public String redirectToAccounts() {
        return "redirect:/accounts";
    }
    
  2. 数据渲染依赖验证:

    • 检查控制台的调试输出Number of accounts retrieved: X,若为0说明Service层未正确获取数据;若大于0则数据已传入模型,需排查前端问题。
    • 确认AccountDto类的id、accountHolderName、balance字段有对应的getter方法(Thymeleaf需通过getter访问属性)。
    • 核对前端Thymeleaf变量名${accounts}与控制器添加的模型变量名是否一致。
  3. 删除逻辑错误:
    当前删除方法先删除账户再跳转到确认页面,此时账户已不存在,会导致getAccountById(id)报错。需调整流程:先跳转到确认页面,确认后再执行删除操作。

内容的提问来源于stack exchange,提问作者Phileoreal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:14:56