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

Spring Boot+MongoDB:如何在Expense中自动关联当前登录用户ID

Expense Tracker 关联问题解决方案

1. 实体类关联调整

双向关联方案(推荐)

在Expense类中添加对User的引用,配合User类的@DBRef列表,实现双向关联:

修改Expense类:

@Document(collection = "expenses")
public class Expense {
    @Id
    private String id;

    @NotBlank(message = "item field required")
    private String item;

    @NotBlank(message = "shop field required")
    private String shop;

    @Min(value = 1L, message = "Minimum is £1")
    private int price;

    @NotBlank(message = "Category field required")
    private String category;

    @NotNull(message = "Date field required")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
    private LocalDate date;

    @NotNull(message = "Time field required")
    private LocalTime time;

    // 添加用户关联
    @DBRef
    private User user;

    // Getter & Setter
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    // 原有Getter & Setter保留
}

单向关联方案(简化版)

若无需从User反向查询支出,可直接在Expense中存储用户ID字符串,无需@DBRef:

修改Expense类:

@Document(collection = "expenses")
public class Expense {
    // 原有字段不变...

    @NotBlank(message = "User ID is required")
    private String userId;

    // Getter & Setter
    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }
}

2. 控制器关联逻辑实现

双向关联场景下的控制器修改

@PostMapping()
public ResponseEntity<Expense> addExpense(@RequestBody @Valid Expense expense) {
    // 处理时间截断
    LocalTime truncatedTime = expense.getTime().truncatedTo(ChronoUnit.SECONDS);
    expense.setTime(truncatedTime);
         
    // 获取当前登录用户
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    User currentUser = (User) authentication.getPrincipal();

    // 关联用户到支出
    expense.setUser(currentUser);
    // 更新用户的支出列表并保存
    if (currentUser.getExpenses() == null) {
        currentUser.setExpenses(new ArrayList<>());
    }
    currentUser.getExpenses().add(expense);
    userService.saveUser(currentUser); // 确保UserService提供save方法

    Expense savedExpense = expenseService.saveExpense(expense);
    return new ResponseEntity<>(savedExpense, HttpStatus.CREATED);
}

单向关联场景下的控制器修改

@PostMapping()
public ResponseEntity<Expense> addExpense(@RequestBody @Valid Expense expense) {
    // 处理时间截断
    LocalTime truncatedTime = expense.getTime().truncatedTo(ChronoUnit.SECONDS);
    expense.setTime(truncatedTime);
         
    // 获取当前登录用户ID
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    User currentUser = (User) authentication.getPrincipal();

    // 设置支出的用户ID
    expense.setUserId(currentUser.getId());

    Expense savedExpense = expenseService.saveExpense(expense);
    return new ResponseEntity<>(savedExpense, HttpStatus.CREATED);
}

3. 个人支出查询实现

双向关联查询

在ExpenseRepository中添加方法:

public interface ExpenseRepository extends MongoRepository<Expense, String> {
    List<Expense> findByUser(User user);
}

对应Service方法:

public List<Expense> getUserExpenses(User user) {
    return expenseRepository.findByUser(user);
}

单向关联查询

在ExpenseRepository中添加方法:

public interface ExpenseRepository extends MongoRepository<Expense, String> {
    List<Expense> findByUserId(String userId);
}

对应Service方法:

public List<Expense> getUserExpenses(String userId) {
    return expenseRepository.findByUserId(userId);
}

关键注意点

  • Expense类必须添加@Document(collection = "expenses")注解,否则MongoDB无法识别为文档实体。
  • 使用@DBRef时,关联的User必须已持久化(当前登录用户满足此条件)。
  • 双向关联场景下,更新用户支出列表后需保存User实体,否则关联关系不会同步到数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 23:36:06