为什么Spring boot"懒得初始化一个角色集合"使用Eager fetch类型解决?

时间:2017-04-20 08:02:02

标签: java spring

我正在编写一个简单的Spring启动应用程序。

对于身份验证部分,我实现了自定义UserDetails。当我向登录端点发出请求时,我得到了这个例外:

Authentication Failed: failed to lazily initialize a collection of role: com.boot.cut_costs.config.security.CustomUserDetails.roles, could not initialize proxy - no Session

CustomUserDetails.java

@Entity
@Table(name="ACCOUNT_USER")
public class CustomUserDetails implements UserDetails {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "USER_ID")
    private long id;

    @NotBlank
    @Column(name = "USERNAME")
    private String username;

    @NotBlank
    @Column(name = "PASSWORD")
    private String password;

    @Column(name = "LOCKED")
    private boolean locked;

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "USER_ROLE", 
                joinColumns = @JoinColumn(name = "USER_ID"), 
                inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
    private Set<CustomRole> roles;

    public CustomUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) { // jpa only
        this.setUsername(username);
        this.setPassword(password);
        this.roles = new HashSet<CustomRole>();
        for (GrantedAuthority authority: authorities) {
            roles.add(new CustomRole(authority.getAuthority()));
        }
    }

    public CustomUserDetails() { // jpa only
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Set<CustomRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<CustomRole> roles) {
        this.roles = roles;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        ArrayList<String> authoritiesList = new ArrayList<String>();
        for (CustomRole role: roles) {
            authoritiesList.add(role.getRole());
        }
        return AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", authoritiesList));
    }
    //Some more getters and setters ...

}

CustomRole.java

@Entity
@Table(name="ACCOUNT_ROLE")
public class CustomRole {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="ROLE_ID")
    private long id;

    @Column(name="ROLE")
    private String role;

    public long getId() {
        return id;
    }

    //delete if not necessary
    public void setId(long id) {
        this.id = id;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public CustomRole() {} //for jpa

    public CustomRole(String role) {
        this.role = role;
    }
}

当我在Eager注释中创建获取类型ManyToMany时,它可以正常工作。

我读到这是不好的做法。首先,我想知道为什么?第二,我想知道什么是好的做法?我在这里混合服务层和DAO吗?

1 个答案:

答案 0 :(得分:2)

当您使用 Lazy 时,您加载的用户没有角色,角色只会在您使用时收费

这里你使用了 spring security ,当你调用CustomUserDetails时,你应该把 Eager 加载所有角色, 在一般情况下使用Eager并不是一个好习惯,因为您加载了许多不需要它们的细节