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

按日期分组展示用户交易余额的循环逻辑问题排查

解决按日期分组展示每日收支余额的循环问题

你的问题核心是控制器未正确传递所有日期的分组数据,或Thymeleaf循环逻辑错误导致仅展示最后一组数据。以下是两种可行的解决方法:


方案一:直接在Thymeleaf中遍历分组后的Map

控制器代码(确保传递完整的分组数据)

@GetMapping("/wallet")
public String walletPage(Model model) {
    // 获取全部交易记录
    List<Transaction> allTransactions = transactionService.listAll();
    // 按交易日期分组
    Map<LocalDate, List<Transaction>> transactionsByDate = allTransactions.stream()
            .collect(Collectors.groupingBy(Transaction::getTransactionDate));
    // 将分组数据传入页面
    model.addAttribute("transactionsByDate", transactionsByDate);
    return "wallet";
}

Thymeleaf页面代码(遍历所有日期分组)

<div class="daily-transactions">
    <h2>每日收支明细</h2>
    <!-- 遍历日期-交易列表的键值对 -->
    <div th:each="dateEntry : ${transactionsByDate}">
        <div class="day-group">
            <h3 th:text="${dateEntry.key}">2024-05-20</h3>
            <!-- 计算当日总收入 -->
            <p>当日收入:<span th:text="${#numbers.formatDecimal(dateEntry.value.stream().filter(t -> t.type == 'INCOME').mapToDouble(t -> t.amount).sum(), 2, 2)}">0.00</span></p>
            <!-- 计算当日总支出 -->
            <p>当日支出:<span th:text="${#numbers.formatDecimal(dateEntry.value.stream().filter(t -> t.type == 'EXPENSE').mapToDouble(t -> t.amount).sum(), 2, 2)}">0.00</span></p>
            <!-- 计算当日余额 -->
            <p class="balance">
                当日余额:<span th:text="${#numbers.formatDecimal(
                    dateEntry.value.stream().filter(t -> t.type == 'INCOME').mapToDouble(t -> t.amount).sum() - 
                    dateEntry.value.stream().filter(t -> t.type == 'EXPENSE').mapToDouble(t -> t.amount).sum(), 
                2, 2)}">0.00</span>
            </p>
        </div>
    </div>
</div>

方案二:提前在控制器封装每日余额DTO(推荐)

把计算逻辑移到后端,页面更简洁易维护。

1. 创建每日余额DTO

public class DailyBalance {
    private LocalDate date;
    private double totalIncome;
    private double totalExpense;
    private double dailyBalance;

    // 构造器
    public DailyBalance(LocalDate date, double totalIncome, double totalExpense) {
        this.date = date;
        this.totalIncome = totalIncome;
        this.totalExpense = totalExpense;
        this.dailyBalance = totalIncome - totalExpense;
    }

    // Getter方法(无需Setter,只读数据)
    public LocalDate getDate() { return date; }
    public double getTotalIncome() { return totalIncome; }
    public double getTotalExpense() { return totalExpense; }
    public double getDailyBalance() { return dailyBalance; }
}

2. 控制器代码(生成每日余额列表)

@GetMapping("/wallet")
public String walletPage(Model model) {
    List<Transaction> allTransactions = transactionService.listAll();
    
    // 分组并转换为DailyBalance列表,支持按日期排序
    List<DailyBalance> dailyBalances = allTransactions.stream()
            .collect(Collectors.groupingBy(Transaction::getTransactionDate))
            .entrySet().stream()
            .map(entry -> {
                LocalDate date = entry.getKey();
                double income = entry.getValue().stream()
                        .filter(t -> "INCOME".equals(t.getType()))
                        .mapToDouble(Transaction::getAmount)
                        .sum();
                double expense = entry.getValue().stream()
                        .filter(t -> "EXPENSE".equals(t.getType()))
                        .mapToDouble(Transaction::getAmount)
                        .sum();
                return new DailyBalance(date, income, expense);
            })
            .sorted(Comparator.comparing(DailyBalance::getDate).reversed()) // 按日期倒序展示
            .collect(Collectors.toList());
    
    model.addAttribute("dailyBalances", dailyBalances);
    return "wallet";
}

3. Thymeleaf页面代码(直接遍历余额列表)

<div class="daily-balances">
    <h2>每日收支余额</h2>
    <div th:each="balance : ${dailyBalances}">
        <div class="day-item">
            <h3 th:text="${balance.date}">2024-05-20</h3>
            <p>收入:<span th:text="${#numbers.formatDecimal(balance.totalIncome, 2, 2)}">0.00</span> 元</p>
            <p>支出:<span th:text="${#numbers.formatDecimal(balance.totalExpense, 2, 2)}">0.00</span> 元</p>
            <p class="balance" th:classappend="${balance.dailyBalance >= 0 ? 'positive' : 'negative'}">
                当日余额:<span th:text="${#numbers.formatDecimal(balance.dailyBalance, 2, 2)}">0.00</span> 元
            </p>
        </div>
    </div>
</div>

关键注意事项

  • 避免在控制器循环分组时,用同一个Model属性反复覆盖数据(这是导致仅展示最后一组的常见原因),必须传递完整的集合/Map。
  • Thymeleaf遍历Map时,要遍历entrySet(即th:each="entry : ${map}"),通过entry.key和entry.value分别获取日期和当日交易列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:08:18