如何避免同一用户创建同名Wallet?校验逻辑失效求助
同一用户创建同名钱包校验失效问题
我有两张表User和Wallet,User包含字段id,Wallet包含字段userId、walletName。想要实现禁止同一用户创建同名钱包,最初的全局校验逻辑不符合需求,修改为按userId+walletName校验后仍失效,用户依然能创建同名钱包。
最初的校验代码
if (walletRepository.existsByWalletName(walletRequest.getWalletName())) { return ResponseEntity.badRequest().body(new MessageResponse("You already have wallet with that name, choose another!")); }
修改后的接口代码
@PostMapping("/user/{user_id}/wallets") public ResponseEntity<?> createWallet(@PathVariable(value = "user_id") Long user_id, @RequestBody Wallet walletRequest, User user) { if (walletRepository.existsByUserIdAndWalletName(user.getId(), walletRequest.getWalletName())) { return ResponseEntity.badRequest() .body(new MessageResponse("You already have wallet with that name, choose another!")); }
相关实体类及仓库代码
User 实体类
@Entity @Table(name = "users", uniqueConstraints = { @UniqueConstraint(columnNames = "username"), @UniqueConstraint(columnNames = "email") }) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotEmpty @Size(min = 3, max = 20) private String username; @NotEmpty @Size(max = 50) @Email private String email; @NotEmpty @Size(min = 6) private String password; @NotEmpty(message = "Please, insert a first name") private String firstName; @NotEmpty(message = "Please, insert a last name") private String lastName; @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) private Set<Role> roles = new HashSet<>(); public User() { } public User(String username, String email, String password, String firstName, String lastName) { this.username = username; this.email = email; this.password = password; this.firstName = firstName; this.lastName = lastName; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
Wallet 实体类
@Entity @Table(name = "wallet") public class Wallet { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotEmpty(message = "Please, insert a wallet name") private String walletName; private double initialBalance; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore private User user; public Wallet() { } public Wallet(String walletName, double initialBalance) { this.walletName = walletName; this.initialBalance = initialBalance; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getWalletName() { return walletName; } public void setWalletName(String walletName) { this.walletName = walletName; } public double getInitialBalance() { return initialBalance; } public void setInitialBalance(double initialBalance) { this.initialBalance = initialBalance; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
Wallet Repository
boolean existsByUserIdAndWalletName(Long userId, String walletName);
问题排查与修复方案
1. 修复接口参数绑定问题
当前接口直接注入User user,Spring无法自动将路径中的user_id绑定到User对象,导致user.getId()可能为空或不是当前请求的用户ID。需通过user_id从数据库查询对应用户:
@PostMapping("/user/{user_id}/wallets") public ResponseEntity<?> createWallet(@PathVariable(value = "user_id") Long user_id, @RequestBody Wallet walletRequest, @Autowired UserRepository userRepository) { // 查询当前用户 User user = userRepository.findById(user_id) .orElseThrow(() -> new RuntimeException("用户不存在")); if (walletRepository.existsByUserIdAndWalletName(user.getId(), walletRequest.getWalletName())) { return ResponseEntity.badRequest() .body(new MessageResponse("该名称的钱包已存在,请更换其他名称!")); } // 后续创建钱包逻辑 Wallet wallet = new Wallet(walletRequest.getWalletName(), walletRequest.getInitialBalance()); wallet.setUser(user); walletRepository.save(wallet); return ResponseEntity.ok(new MessageResponse("钱包创建成功")); }
2. 添加数据库联合唯一约束
仅靠代码校验存在并发风险,需在Wallet表的user_id和walletName字段添加联合唯一约束,从数据库层面拦截重复数据:
@Entity @Table(name = "wallet", uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "walletName"})) public class Wallet { // 原有代码不变 }
3. 确保Repository方法正确性
可自定义查询语句,避免Spring Data JPA自动生成SQL出错:
@Repository public interface WalletRepository extends JpaRepository<Wallet, Long> { @Query("SELECT COUNT(w) > 0 FROM Wallet w WHERE w.user.id = :userId AND w.walletName = :walletName") boolean existsByUserIdAndWalletName(@Param("userId") Long userId, @Param("walletName") String walletName); }
内容的提问来源于stack exchange,提问作者Stefan Jankovic
相关产品推荐
相关产品推荐

