SpringBoot/SpringSecurity登录用户无法更新信息,无报错但数据库未变更
Spring用户更新信息无法持久化(无报错)
问题根源
你的Controller里存在致命逻辑错误:前端提交的表单数据已经绑定到user参数,但你直接用数据库查询的原始用户覆盖了这个参数,导致Service接收的是未修改的原始用户,自然不会有任何更新写入数据库。
看这段错误代码:
// 前端提交的user已包含修改后的firstName/lastName,但此处直接被原始用户覆盖 user = repo.findByEmail(principal.getName());
修复方案
保留前端提交的user对象中的修改字段,仅通过数据库查询获取原始用户的完整数据,再将修改字段同步到原始用户后执行保存。同时注意处理密码字段:如果前端留空,不要覆盖原始密码。
修正后的代码
Controller类
@PostMapping("/myAccount/update") public String updateAccount(User userForm, RedirectAttributes redirectAttributes, Principal principal){ System.out.println("Updating user details..."); // 从数据库获取原始用户数据 User userInDB = repo.findByEmail(principal.getName()); // 将前端修改的字段同步到原始用户 userInDB.setFirstName(userForm.getFirstName()); userInDB.setLastName(userForm.getLastName()); // 密码字段处理:仅当前端输入新密码时才更新 if (userForm.getPassword() != null && !userForm.getPassword().isEmpty()) { // 注意:生产环境必须加密密码,禁止明文存储 userInDB.setPassword(userForm.getPassword()); } User updatedUser = service.updateAccount(userInDB); if (updatedUser == null) { System.out.println("Error updating user details."); } else { redirectAttributes.addFlashAttribute("message", "Details Updated!"); return "redirect:/myAccount"; } return "redirect:/myAccount"; }
优化后的Service类(简化逻辑)
在@Transactional注解下,修改从数据库获取的持久化状态对象后,事务提交时Hibernate会自动同步到数据库,手动调用repo.save()并非必须(但调用也不影响):
@Transactional public User updateAccount(User userToUpdate){ System.out.println("Fetching user with id: " + userToUpdate.getId()); Optional<User> optionalUser = repo.findById(userToUpdate.getId()); if(!optionalUser.isPresent()){ System.out.println("User not found."); return null; } User userInDB = optionalUser.get(); System.out.println("User fetched: " + userInDB); // 同步修改字段 userInDB.setFirstName(userToUpdate.getFirstName()); userInDB.setLastName(userToUpdate.getLastName()); // 密码字段补充处理 if (userToUpdate.getPassword() != null && !userToUpdate.getPassword().isEmpty()) { userInDB.setPassword(userToUpdate.getPassword()); } System.out.println("Updated user ready to persist: " + userInDB); // 事务提交时自动同步数据库,save方法可省略 User savedUser = repo.save(userInDB); System.out.println("User saved: " + savedUser); return savedUser; }
补充说明
- 控制台输出看似正常是因为打印的是同一个对象的内存地址,但对象字段值实际为原始数据,并未被前端修改。
- 生产环境务必使用加密工具(如
BCryptPasswordEncoder)处理密码,禁止明文存储。 - 可使用
ModelMapper等工具类简化字段拷贝操作,避免手动编写大量set方法。
内容的提问来源于stack exchange,提问作者James Coding
相关产品推荐
相关产品推荐

