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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:09:03