用户与角色之间的关系
我们在做用户模块的时候,漏掉了最后一个功能。在新增功能中是可以选择角色的。
这里写图片描述
用户与角色之间的关系也是多对多
- 一个用户对应多个角色
- 一个角色可以被多个用户使用。
这里写图片描述
现在呢,我们的用户表已经是写的了。我们最好就不要修改原有的用户表数据。那我们在不修改用户表代码的情况下,又怎么来实现多对多呢??
跟角色与权限是一样的。使用中间表来维护它们的关系就行了。
用户:user 用户id,名称... 1 用户1 2 用户2 用户角色:user_role 用户id,角色id 1 1 1 2 2 2 角色:role 角色Id,名称 1 管理员 2 一般用户
设计中间表
public class UserRole implements Serializable { private UserRoleId userRoleId; public UserRoleId getUserRoleId() { return userRoleId; } public void setUserRoleId(UserRoleId userRoleId) { this.userRoleId = userRoleId; } }
主键表
public class UserRoleId implements Serializable { private String user_id; //在使用的时候,Role相关的数据会用得特别多。为了方便使用了Role对象。而user就不需要使用User对象了。 private Role role; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserRoleId that = (UserRoleId) o; if (user_id != null ? !user_id.equals(that.user_id) : that.user_id != null) return false; return role != null ? role.equals(that.role) : that.role == null; } @Override public int hashCode() { int result = user_id != null ? user_id.hashCode() : 0; result = 31 * result + (role != null ? role.hashCode() : 0); return result; } public String getUser_id() { return user_id; } public void setUser_id(String user_id) { this.user_id = user_id; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } }
映射文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="zhongfucheng.user.entity.UserRole" table="user_role"> <composite-id name="userRoleId" class="zhongfucheng.user.entity.UserRoleId"> <!--manytoone可以生成外键字段。--> <key-many-to-one name="role" class="zhongfucheng.role.entity.Role" column="role_id" lazy="false"/> <key-property name="user_id" column="user_id" type="java.lang.String"/> </composite-id> </class> </hibernate-mapping>
增加模块
在跳转到JSP页面的前,把所有的角色找出来。放到request域对象中,让JSP页面显示出来。
public String addUI() { //把所有的角色查询出来,带过去给JSP页面显示 ActionContext.getContext().getContextMap().put("roleList", roleServiceImpl.findObjects()); return "addUI"; }
<%-- list是集合对象 name是要带给服务器端的字符串数组。 listkey 是集合元素对象的id listValue 是集合元素对象的名字 --%> <s:checkboxlist list="#roleList" name="userRoleIds" listKey="roleId" listValue="name"/>
这里写图片描述
编辑模块
编辑回显数据
在编辑模块中,需要将该用户所拥有的角色查询出来。然后把查询出来的id值放到数组中。
public String editUI() { //把所有的角色查询出来,带过去给JSP页面显示 ActionContext.getContext().getContextMap().put("roleList", roleServiceImpl.findObjects()); //外边已经传了id过来了,我们要找到id对应的User if (user != null &&user.getId() != null ) { //直接获取出来,后面JSP会根据User有getter就能读取对应的信息! user = userServiceImpl.findObjectById(user.getId()); //通过用户的id得到所拥有UserRole List<UserRole> roles = userServiceImpl.findRoleById(user.getId()); //把用户拥有角色的id填充到数组中,数组最后回显到JSP页面 int i=0; userRoleIds = new String[roles.size()]; for (UserRole role : roles) { userRoleIds[i++] = role.getUserRoleId().getRole().getRoleId(); } } return "editUI"; }
JSP通过checkboxlist进行回显,指定了name值就能够自动判定我们的用户拥有的角色是什么了。
<s:checkboxlist list="#roleList" name="userRoleIds" listKey="roleId" listValue="name"></s:checkboxlist>
这里写图片描述
处理编辑操作
在更新之前,首先删除用户与角色之间的关系【历史遗留问题】,如果不删除,那么用户所拥有的角色就一直保留着。无论你在JSP页面有没有勾选。
public String edit() throws IOException { //Struts2会自动把JSP带过来的数据封装到User对象上 if (user.getId() != null && user != null) { if (headImg != null) { //得到要把头像上传到服务器的路径 javax.servlet.ServletContext servletContext = ServletActionContext.getServletContext(); String realPath = servletContext.getRealPath("upload/user"); //由于用户上传的名字可能会相同,如果相同就被覆盖掉,因此我们要修改上传文件的名字【独一无二】 headImgFileName = UUID.randomUUID().toString() + headImgFileName.substring(headImgFileName.lastIndexOf(".")); FileUtils.copyFile(headImg, new File(realPath, headImgFileName)); //设置图片与用户的关系 user.setHeadImg(headImgFileName); } if (userRoleIds != null) { //删除用户与角色之间的关系【历史遗留问题】 userServiceImpl.deleteUserRoleById(userRoleIds); //保存用户与角色。 userServiceImpl.saveUserAndRole(user,userRoleIds); } } return "list"; }
调用保存用户与角色的关系。如果id不是为空的,那么就执行更新,如果id为空,就执行保存。
@Override public void saveUserAndRole(User user, String... userRoleIds) { //保存或更新用户 if (user.getId() != null) { userDaoImpl.update(user); } else { userDaoImpl.save(user); } //判断有没有把id带过来 if (userRoleIds != null) { for (String userRoleId : userRoleIds) { System.out.println(userRoleId); userDaoImpl.saveUserRole(new UserRole(new UserRoleId(user.getId(), new Role(userRoleId)))); } } }
总结
- 我们在本次的用户角色权限关系中,没有使用权限表来保存对应的权限。因为我们的权限都被我们固定了,没必要多使用一张数据库表了。
- 因此,我们使用了一个静态Map集合来保存我们的权限数据。之所以用Map是因为我们在页面上还需要通过名称来获取对应的权限。
- 在角色的集合中,如果我们有权限数据表,那我们的保存的是Privilege类型的数据。但是现在我们没有数据库表,因此保存的是Role_Privilege的关系。这样的话,我们就可以通过角色来获取对应的权限了。
- 而对于Role_privilege而言,仅仅只有两个外键。我们设置成复合主键的话要满足以下条件
- 将两个外键封装成一个JavaBean对象,该JavaBean对象要实现Seriliable接口
- 重写equals()和hashCode()方法
- 在设计Role_privilege的时候,我们考虑到了:当我们查看角色获取所有权限的时候,如果该集合保存的是roleId的话,那么我们仅仅只能获取角色的id。但如果我们存储的是Role对象的话,我们就可以直接获取角色的名称了。
- 在数据回显上也有个技巧。我们是使用静态Map集合来装载所有的权限的。而Web端传递过来的是代表权限的Code值。我们在显示的时候就可以把整个Map集合传过去。然后把代表权限的Code值也传过去。展现出有权限Code的那一部分数据。
- 修改角色权限的时候,Hibernate自动会把我们的本来用户的权限查询数据。然后追加那些我们勾选中的权限。在修改前,我们可以把原有的权限干掉,然后再把我们勾选后的权限修改起来。这样就达到我们的效果了。
- 由于我们的用户和角色也是多对多的关系的。我们不想破坏之前已经写好的JavaBean对象。我们也是可以使用中间表来保存我们关联数据的。
- checkboxlist是Struts2为我们提供的标签,能够遍历集合生成多选框。它会自动将我们的id值通过字符串数组的方式传入Controlller中
- 我们controller使用字符串数据得到勾选的id值。当我们要编辑页面的时候,通过用户的id得到用户的所有信息(包括用户所对应的角色)。我们将得到的角色集合遍历,把角色的id封装到我们的字符串数组中(主要为了通过checkboxList标签回显数据)。
- 如果我们不使用checkboxList的话,那我们得到用户的所有角色,就可以直接返回给页面来进行显示了。
- 我们在service层还可以通过判断用户的id的值是否为null,来执行保存或更新的操作。