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
相关产品推荐
相关产品推荐

