Spring如何存储两实体间关联关系:代码片段与用户实体权限场景实现
实现方案
你当前的实体已经包含了核心业务字段,只需要补充JPA关联注解绑定实体关系,再配套对应的业务校验逻辑即可满足需求,具体实现如下:
1. 实体关系修正
你需要明确两类核心关联,补充JPA注解完成数据库映射:
- 作者和代码片段:
一对多关系,一个用户可以上传多个代码片段,一个代码片段仅对应一个作者 - 可访问用户和代码片段:
多对多关系,一个代码片段可以授权给多个用户,一个用户可以被授权访问多个代码片段,需要额外中间表存储关联关系
修正后完整Code实体代码
@Entity @Table(name = "snippets") @NoArgsConstructor @Getter @Setter public class Code { private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); @Id @GeneratedValue private Long id; private String code; private String date; // 关联作者:多对一,外键存储在snippets表的author_id字段 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "author_id", nullable = false) private User author; // 关联可访问用户:多对多,中间表存储关联关系 @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "snippet_allowed_users", joinColumns = @JoinColumn(name = "snippet_id"), inverseJoinColumns = @JoinColumn(name = "user_id") ) private List<User> allowedUsers; public Code(CodeDto code, User currentLoginUser) { this.code = code.getCode(); this.date = LocalDateTime.now().format(formatter); this.author = currentLoginUser; // 初始化时默认作者自己有访问权限 this.allowedUsers = Collections.singletonList(currentLoginUser); } }
修正后完整User实体代码
@Entity @Table(name = "users") @Getter @Setter @EqualsAndHashCode(of = "id") @NoArgsConstructor public class User implements UserDetails { @Id @GeneratedValue private Long id; private String username; private String password; @Enumerated(EnumType.STRING) private UserRole userRole; @Transient private boolean locked; private boolean enabled = true; // 关联用户自己上传的代码片段:双向一对多,由Code实体的author字段维护关系 @OneToMany(mappedBy = "author", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY) private List<Code> codeList; // 可选字段:关联用户被授权访问的代码片段,不需要查询用户所有可访问片段可以删除 @ManyToMany(mappedBy = "allowedUsers", fetch = FetchType.LAZY) private List<Code> accessibleSnippets; public User(String username, String password, UserRole userRole) { this.username = username; this.password = password; this.userRole = userRole; } // UserDetails接口默认实现,按需调整即可 @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority(userRole.name())); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return !locked; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } }
注意:关联字段默认使用LAZY加载策略,避免不必要的关联查询损耗性能,如果业务需要即时加载关联数据可以改为EAGER,或者查询时用JOIN FETCH指定加载。
2. 核心业务逻辑实现
- 上传代码片段:校验用户登录状态,将当前登录用户作为作者创建Code实体,存入数据库即可
- 授权逻辑:只有代码片段的作者有权限调用授权接口,接口收到待授权用户ID列表后,校验当前操作人是否为片段作者,校验通过后更新allowedUsers列表即可
- 访问校验:用户请求查看代码片段时,判断当前登录用户是片段作者、或者在allowedUsers列表中,符合条件才返回代码内容,否则返回403无权限
内容的提问来源于stack exchange,提问作者Tomek Nowak
相关产品推荐
相关产品推荐

