Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用SpringMVC视图中的嵌套对象持久化新对象 上下文_Java_Spring_Hibernate_Spring Mvc_Jsp - Fatal编程技术网

Java 使用SpringMVC视图中的嵌套对象持久化新对象 上下文

Java 使用SpringMVC视图中的嵌套对象持久化新对象 上下文,java,spring,hibernate,spring-mvc,jsp,Java,Spring,Hibernate,Spring Mvc,Jsp,有一个应用程序使用SpringMVC和SpringDataJPA。JPA提供者是Hibernate,视图层由JSP页面表示 有一个用于创建新用户的页面。通过此页面创建新用户时,用户被分配到用户组(从列表中选择)。用户是新用户,但此时已存在所选的组。用户@实体中有一组组对象。用户s和组s之间的双向关联是@manytomy,一个表(组成员)链接这些实体 当视图层将用户对象传递给控制器时,将对用户调用设置组(设置组)方法。然后通过userDetailsService.add(User)持久化该User

有一个应用程序使用SpringMVC和SpringDataJPA。JPA提供者是Hibernate,视图层由JSP页面表示

有一个用于创建新用户的页面。通过此页面创建新用户时,用户被分配到用户组(从列表中选择)。
用户
是新用户,但此时已存在所选的
用户
@实体
中有一组
对象。
用户
s和
s之间的双向关联是
@manytomy
,一个表(
组成员
)链接这些实体

当视图层将
用户
对象传递给控制器时,将对
用户
调用
设置组(设置组)
方法。然后通过
userDetailsService.add(User)
持久化该
User
对象,该对象是
@事务性的


问题 当呈现页面时,
被加载到视图中,然后它们与持久化单元分离。 在持久化
用户
时,关联的
被分离,并且
端与
用户
不同步。
User
实体定义了同步事务双方的实用方法(
addGroup(Group-Group)
removeGroup(Group-Group)
),但我找不到使用它们的方法,因为这种方法只能在服务层中创建的事务之外调用它们

问题: 在此场景中,保持所有实体始终处于有效状态的最佳方法是什么?用户和组都应该传递到服务层吗


代码 为了简洁起见,省略了一些部分

createuser.jsp

<body>
<sf:form id="details" method="post" action="${pageContext.request.contextPath}/docreate" modelAttribute="user">

<h2>Sing up</h2>
<table class="formtable">
  <tr>
    <td class="label">Userame: </td> <td><sf:input path="username" name="username" type="text" /> <div class="error"> <sf:errors path="username"></sf:errors> </div></td>
  </tr>
    <tr>
    <td class="label">Password: </td> <td><sf:input id="password" path="password" name="password" type="password" /> <div class="error"><sf:errors path="password"></sf:errors> </div></td>
  </tr>
    <tr>
    <td class="label">Confirm password: </td> <td><input id="confirmpass" name="confirmpass" type="password" /> <div id="matchpass"></div></td>
  </tr>
  <tr>
   <td class="label" align="right">Group</td><td><sf:select id="groups" path="groups" items="${groups}" itemValue="id" 
            itemLabel="groupName"/></td>
  </tr>
    <tr>
    <td> </td> <td class="button"><input value="Create user" type="submit" /> </td>
  </tr>
</table>

</sf:form>
</body>
UserDetailsServiceImpl.java

@Transactional
public void add(User user) {
    if (!contains(user.getUsername())) {
        userRepository.save(user);
    }       
}
User.java

@Entity
@Table(name="users",schema="sec")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String username;    
    private String password;
    private boolean enabled;    

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name="group_members", schema="sec", joinColumns= { @JoinColumn(name="user_id") }, inverseJoinColumns = { @JoinColumn(name="group_id") } )
    private Set<Group> groups = new HashSet<>();
    
    // ...
    
    public void addGroup(Group group) {
        this.groups.add(group);
        group.getUsers().add(this);
    }

    public void removeGroup(Group group) {
        this.groups.remove(group);
        group.getUsers().remove(this);
    }
    
    public void setGroups(Set<Group> groups) {
        for (Group group : groups) {
            this.groups.add(group);
        }
    }
}
@实体
@表(name=“users”,schema=“sec”)
公共类用户{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
私有字符串用户名;
私有字符串密码;
启用私有布尔值;
@ManyToMany(fetch=FetchType.LAZY)
@JoinTable(name=“group_members”,schema=“sec”,joinColumns={@JoinColumn(name=“user_id”)},inverseJoinColumns={@JoinColumn(name=“group_id”)})
私有集组=新HashSet();
// ...
公共无效添加组(组){
this.groups.add(组);
group.getUsers().add(此);
}
public void removeGroup(组){
此.groups.remove(组);
group.getUsers().remove(此);
}
公共void集合组(集合组){
用于(组:组){
this.groups.add(组);
}
}
}
Group.java

@Entity
@Table(name="groups",schema="sec")
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String groupName;   
    // ...
    
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
    private Set<User> users = new HashSet<>();
    
    // Method to synchronize bidirectional association
    public void addUser(User user) {
        this.users.add(user);
        user.getGroups().add(this);
    }
    
    public void removeUser(User user) {
        this.users.remove(user);
        user.getGroups().remove(this);
    }
    // ...

    public Set<User> getUsers() {
        return users != null ? users : new HashSet<>();
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }
    // ...
}
@实体
@表(name=“groups”,schema=“sec”)
公共课组{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
私有字符串组名;
// ...
@ManyToMany(fetch=FetchType.LAZY,mappedBy=“groups”)
private Set users=new HashSet();
//同步双向关联的方法
public void addUser(用户){
this.users.add(用户);
user.getGroups().add(此);
}
public void removeUser(用户用户){
this.users.remove(用户);
user.getGroups().remove(此);
}
// ...
公共集getUsers(){
返回用户!=null?用户:new HashSet();
}
公共void集合用户(集合用户){
this.users=用户;
}
// ...
}

由于事务是在服务层启动的,所以实现此同步的唯一可能选择是

  • 服务层或
  • 道层
  • 服务层定义了一个
    add(user)
    方法和一个
    set(user)
    方法,这两个方法都调用
    save(user)
    方法,因此在包含该方法的DAO层中同步关联是合乎逻辑的。 此外,在DAO层中引用
    EntityManager
    似乎更合适

    @Autowired
    private GroupRepository groupRepository;
    
    @PersistenceContext
    EntityManager em;
    
    // ...
    
    public User save (User user) {
        // If the group already exists, then attach it to the persistence context by  getting a reference to it else attach it by saving
        Set<Group> groups = user.getGroups();
        if (!groups.isEmpty()) {
            Set<Group> managedGroups = groups.stream()
                                                .map(group -> group.getId() == 0L ? groupRepository.save(group) : em.getReference(Group.class, group.getId()))
                                                .collect(Collectors.toSet());
            // Synchronize the bidirectional association
            for (Group group : managedGroups) {
                user.addGroup(group);
            }
        }
        else {
            // Default group
            Optional<Group> result = groupRepository.findByGroupName("USERS");
            if (result.isPresent())
                user.addGroup(result.get());
        }
        // ...
    }
    
    @Autowired
    私有组存储库组存储库;
    @持久上下文
    实体管理器;
    // ...
    公共用户保存(用户){
    //如果组已经存在,则通过获取对该组的引用将其附加到持久性上下文,否则通过保存将其附加
    Set groups=user.getGroups();
    如果(!groups.isEmpty()){
    Set managedGroups=groups.stream()
    .map(组->组.getId()==0L?组存储库.save(组):em.getReference(组.class,组.getId())
    .collect(收集器.toSet());
    //同步双向关联
    对于(组:managedGroups){
    user.addGroup(组);
    }
    }
    否则{
    //默认组
    可选结果=groupRepository.findByGroupName(“用户”);
    if(result.isPresent())
    user.addGroup(result.get());
    }
    // ...
    }
    
    @Autowired
    private GroupRepository groupRepository;
    
    @PersistenceContext
    EntityManager em;
    
    // ...
    
    public User save (User user) {
        // If the group already exists, then attach it to the persistence context by  getting a reference to it else attach it by saving
        Set<Group> groups = user.getGroups();
        if (!groups.isEmpty()) {
            Set<Group> managedGroups = groups.stream()
                                                .map(group -> group.getId() == 0L ? groupRepository.save(group) : em.getReference(Group.class, group.getId()))
                                                .collect(Collectors.toSet());
            // Synchronize the bidirectional association
            for (Group group : managedGroups) {
                user.addGroup(group);
            }
        }
        else {
            // Default group
            Optional<Group> result = groupRepository.findByGroupName("USERS");
            if (result.isPresent())
                user.addGroup(result.get());
        }
        // ...
    }