微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

休眠JPA循环

如何解决休眠JPA循环

我创建了一个实体类

@Entity
@Table(name="users")
@Getter @Setter
public class usermodel implements Serializable {

    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private static final long serialVersionUID = -5608230793232883579L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(nullable = false,unique = true)
    private String userId;

    @Column(nullable = false,length = 50)
    private String firstName;

    @Column(nullable = false,length = 50)
    private String lastName;

    @Email
    @Column(nullable = false,length = 120,unique = true)
    private String email;

    @Column(nullable = false)
    private String encryptedPassword;

    private Boolean emailVerificationStatus = false;

    private String emailVerificationToken;

    @ManyToMany(cascade= { CascadeType.PERSIST },fetch = FetchType.EAGER )
    @JoinTable(
            name = "user_role",joinColumns = @JoinColumn(name = "user_id",referencedColumnName = "id"),inverseJoinColumns=@JoinColumn(name = "role_id",referencedColumnName = "id"))
    private List<RoleModel> roles;

    @JsonManagedReference
    @OnetoMany(mappedBy = "user")
    private List<ProjectModel> projects;
}

对于项目列表,我还有一个实体类

@Entity
@Table(name= "projects")
@Getter @Setter
public class ProjectModel implements Serializable {
    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    public static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(nullable = false,unique = true)
    private String projectId;
    
    // ... 

    @Column
    @JsonManagedReference
    @OnetoMany(mappedBy = "project")
    private List<ObjectiveModel> objectives;

    // ...

    @JsonBackReference
    @ManyToOne(
            cascade = { CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH },fetch = FetchType.LAZY
    )
    private usermodel user;

}

我还使用DTO层与数据库通信:

@Getter @Setter
public class UserDto implements Serializable {

    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private static final long serialVersionUID = -5352357837541477260L;

    // contains more information than models used for rest
    private long id;
    private String userId;
    private String firstName;
    private String lastName;
    private String email;
    private String password;
    private String encryptedPassword;
    private String emailVerificationToken;
    private Boolean emailVerificationStatus = false;

    private List<String> roles;
    private List<ProjectDto> projects;
}

每个实体都有自己的Dto等效项。我可以创建一个用户。我的问题是尝试登录。我的userServiceImpl实现了Spring Security UserService。这是我的实现:

@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    usermodel usermodel = userRepository.findByEmail(email);
    if(usermodel == null)
        throw new UsernameNotFoundException("User with email "  + email + " not found");

    return new UserPrincipalManager(usermodel);
}

我的UserPrincipalManager:

public class UserPrincipalManager implements UserDetails {

    private static final long serialVersionUID = 7464059818443209139L;

    private usermodel usermodel;
    private ProjectModel projectModel;

    @Getter @Setter
    private String userId;

    @Autowired
    public UserPrincipalManager(usermodel usermodel) {
        this.usermodel = usermodel;
        this.userId = usermodel.getUserId();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new HashSet<>();
        Collection<AuthorityModel> authorityModelEntities = new HashSet<>();
        // get user roles
        Collection<RoleModel> roleModels = usermodel.getRoles();
        if (roleModels == null) {
            return authorities; // null
        }
        // get user roles
        roleModels.forEach((role) ->{
            authorities.add(new SimpleGrantedAuthority(role.getName()));
            authorityModelEntities.addAll(role.getAuthorities());
        });
        // get user authorities
        authorityModelEntities.forEach(authorityModel -> {
            authorities.add(new SimpleGrantedAuthority(authorityModel.getName()));
        });

        return authorities;
    }

    @Override
    public String getpassword() {
        return this.usermodel.getEncryptedPassword();
    }

    @Override
    public String getUsername() {
        return this.usermodel.getEmail();
    }

    // we do not store this information in DB
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // we do not store this information in DB (yet)
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // we do not store this information in DB (yet)
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // isEnabled depending if account is activated => email verification status value
    @Override
    public boolean isEnabled() {
        return this.usermodel.getEmailVerificationStatus();
    }

}

尝试登录User sql请求时正在循环。

at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
    at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
    at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
    at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
    at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
    at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
    at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
    at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
    at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
    at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)

最后,应用程序崩溃并返回403错误

2020-10-05 12:07:22.215 DEBUG 4564 --- [nio-8080-exec-8] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.Vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.3.3.RELEASE.jar:5.3.3.RELEASE]

如果用户没有关联的项目,则登录功能有效。

解决方法

我对模型映射器一无所知,但我想为您提供替代解决方案,因为我认为这是Blaze-Persistence Entity Views的完美用例。

我创建了该库,以允许在JPA模型与自定义接口或抽象类定义的模型之间轻松进行映射,例如类固醇上的Spring Data Projections。这个想法是,您可以按自己喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(获取器)映射到实体模型。

针对您的用例的DTO模型可能与Blaze-Persistence Entity-Views相似,如下所示:

@EntityView(UserModel.class)
public interface UserDto extends Serializable {
    @IdMapping
    Long getId();
    String getUserId();
    String getFirstName();
    String getLastName();
    String getEmail();
    String getPassword();
    String getEncryptedPassword();
    String getEmailVerificationToken();
    Boolean getEmailVerificationStatus();
    Set<String> getRoles();
    Set<ProjectDto> getProjects();

    @EntityView(ProjectModel.class)
    interface ProjectDto {
        @IdMapping
        Long getId();
        String getProjectId();
        // Other mappings...
    }
}

查询是将实体视图应用于查询的问题,最简单的方法就是按ID查询。

UserDto a = entityViewManager.find(entityManager,UserDto.class,id);

Spring Data集成使您可以像使用Spring Data Projections一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

这里最大的好处是,它只会获取实际需要的列,并且会在启动时根据您的JPA模型验证DTO模型,因此不会再有运行时意外!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。