将弹簧形式复选框选择添加到集合并保留它

时间:2014-11-27 15:32:10

标签: java jsp spring-mvc spring-security spring-form

我目前正在开发一个简单的SpringMVC应用程序。我最近开始使用Spring-security。用户及其各自的角色保存在数据库中。我目前的任务是实现一个注册用户"形成。我使用简单的.jsp和spring形式。用户可以有两个角色:ROLE_USER和ROLE_ADMIN,默认情况下会检查ROLE_USER。

以下是我的AppUser和AppUserRoles模型。

AppUser.java:

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;

@Entity
@Table(name="appusers")
public class AppUser {

    @Id
    @Column(name="USERNAME", unique = true, nullable = false, length = 45)
    @NotEmpty(message="Username field cannot be empty")
    private String username;

    @Column(name="PASSWORD", nullable = false, length = 60)
    @NotEmpty(message="Password field cannot be empty")
    @Size(min=6,max=10,message="Password must be between 6 and 10 letters")
    private String password;

    @NotEmpty(message="The user must have at least one defined role")
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "appUser")
    private Set<AppUserRole> userRole = new HashSet<AppUserRole>(0);

    public AppUser() {
        super();
    }


    public AppUser(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }


    public AppUser(String username, String password, Set<AppUserRole> userRole) {
        super();
        this.username = username;
        this.password = password;
        this.userRole = userRole;
    }

    public String getUsername() {
        return username;
    }


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


    public String getPassword() {
        return password;
    }


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


    public Set<AppUserRole> getUserRole() {
        return userRole;
    }


    public void setUserRole(Set<AppUserRole> userRole) {
        this.userRole = userRole;
    }

}

AppUserRole.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


@Entity
@Table(name="appuser_roles")
public class AppUserRole {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "USER_ROLE_ID", unique = true, nullable = false)
    private Integer userRoleId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "username", nullable = false)
    private AppUser appUser;

    @Column(name = "ROLE", nullable = false, length = 45)
    private String role;

    public AppUserRole() {
        super();
    }

    public AppUserRole(AppUser appuser, String role) {
        super();
        this.appUser = appuser;
        this.role = role;
    }

    public Integer getUserRoleId() {
        return userRoleId;
    }
    public void setUserRoleId(Integer userRoleId) {
        this.userRoleId = userRoleId;
    }
    public AppUser getAppuser() {
        return appUser;
    }
    public void setAppuser(AppUser appuser) {
        this.appUser = appuser;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }

}

包含registerUser()方法的AppUserDAOImpl.java片段:

@Override
public void registerUser(AppUser appUser) {

    sessionFactory.getCurrentSession().persist(appUser);
    logger.info(appUser.getUsername() + " persisted");
}

与注册表单相关的UserController.java片段:

@RequestMapping(value="/register")
public String goRegister(Model model) {
    model.addAttribute("AppUser", new AppUser());
    return "register";
}

@RequestMapping(value= "/registeruser_action", method = RequestMethod.POST)
public String addUser(@ModelAttribute("AppUser") @Valid AppUser appUser, BindingResult result){

    if(result.hasErrors()){
        return "register";
    }

    appUserDetailsService.registerUser(appUser);
    return "redirect:/menu";    
}

register.jsp片段与实际形式:

    <sf:form commandName="AppUser" action="registeruser_action" method="POST" >

        <div>
            Username:<br>
            <sf:input type="text" path="username"/>
            <sf:errors path="username" cssClass="errors"/>
        </div>
        <div>
            Password<br>
            <sf:input type="text" path="password"/>
            <sf:errors path="password" cssClass="errors"/>
        </div>
        <div>
            User role:<br>
            <sf:checkbox path="userRole" value="ROLE_USER" 
                disabled="true" checked="true" /> User <br>
            <sf:checkbox path="userRole" value="ROLE_ADMIN"/> Admin <br>
            <sf:errors path="userRole" cssClass="errors"/>
        </div>
        <br>

        <input type="submit" value="Submit">

    </sf:form>

具体来说,我想做什么,似乎无法在网上找出或找到: 我希望将复选框选择添加到我的AppUser.java模型中设置的userRole,然后保留它们。问题是,我在项目之前已将表单输入映射到对象字段,但从未收集过。我的乐观主义者非常希望我能够通过将复选框映射到弹簧形式的userRole路径来实现它,也许java和spring会自动地#34;明白它应该将它们添加到该集合中。我的现实主义者知道它并非那么简单。老实说,我知道它非常简单,但我似乎无法找到解决方案。希望在这里找到解决方案。

PS:我只发布了我认为对这个问题很重要的内容。例如,服务层似乎是额外的。将根据需要发布额外的信息/代码。

修改 好的,我按照akshay的建议在构造函数中添加了ROLE_USER。在尝试注册新用户时产生的异常让我意识到我完全错了。我试图将一个String分配给一个Set对象。 userRole的类型为Set,ROLE_USER是一个字符串。该集包含AppUserRole对象,其中应包含用户名和相应的角色字符串。基本上,现在的问题是:如何直接从spring形式添加包含用户名和相应角色的新对象到userRole集?

1 个答案:

答案 0 :(得分:0)

好的,你需要做一些事情。

假设您要显示所有可用角色的列表:用户检查他想要分配给当前用户的那些角色。

当前Role是一个简单的String,因此没有任何内容可以将复选框绑定到。然后,您可以在视图层上创建一个包装器:

public class RoleWrapper{

private String roleName;
private boolean selected;

}

在您的控制器上,您要添加将加载所有可用角色的ModelAttribute。请注意,您无法绑定到原始集合,因此需要包装此列表。因此,创建另一个类来包装您的列表:

public class RoleList{

private List<RoleWrapper> roles;

}

在控制器中构造一个实例并设置为模型属性:

@ModelAttribute("availableRoles")
public RoleList getAvailableRoles(){
//load from db and construct list

}

在JSP中,创建一个由此列表支持的表单,并将复选框绑定到布尔字段:

<form:form modelAttribute="roleList" method="post">
    <table>
        <thead>
            <tr>
                <th style="width: 80%;">Role</th>
                <th>Select</th>
            </tr>
        </thead>
        <tbody>
            <c:forEach items="${roleList.roles}"
                var="role" varStatus="status">
                <tr>
                    <td>role.name</td>
                    <td><form:checkbox
                            path="roles[${status.index}].selected" /></td>
                </tr>
            </c:forEach>
        </tbody>
    </table>
</form>

更新您的控制器以在提交时传递此列表。迭代并相应地设置用户角色:

@RequestMapping(value= "/registeruser_action", method = RequestMethod.POST)
public String addUser(@ModelAttribute("AppUser") @Valid AppUser appUser, @ModelAttribute("roleList") RoleList roleList, BindingResult result){

    if(result.hasErrors()){
        return "register";
    }

    for(RoleWrapper role : roleList.getRoles()){
        if(role.isSelected()){
            //add to user
        }
    }

    appUserDetailsService.registerUser(appUser);


    return "redirect:/menu";    
}

关于您坚持的问题,您需要执行以下操作。向关系添加级联选项,如果持久保留非拥有方(在本例中为AppUser),请确保关系的两侧都已设置。您应该封装添加/删除操作以确保域对象之间的关系是一致的。因此:

@Entity
@Table(name="appusers")
public class AppUser {

    @NotEmpty(message="The user must have at least one defined role")
    @OneToMany(fetch = FetchType.LAZY, cascade = cascadeType.ALL, mappedBy = "appUser")
    private Set<AppUserRole> userRoles = new HashSet<AppUserRole>(0);

    /**
    *   Force clients through add/remove. Plus, do not provide setter.
    */
    public Set<AppUserRole> getUserRoles() {
        return Collections.unmodifiableSet(userRoles);
    }

    public void addRole(AppUserRole userRole){
        userRole.setAppUser(this); //both sides set
        userRoles.add(userRole);
    }

    public void removeRole(AppUserRole userRole){
        userRoles.remove(userRole);
    }
}