角色管理模块:
新增角色:重点在于zTree这部分,这个功能等会做详细介绍
编辑角色:难点在于zTree默认选中用户已拥有的权限,这个功能只介绍数据的回显
删除角色:因为这个功能比较简单,所以直接省略,不过要注意以下两点
1:删除角色时,需要删除role_permission中对应的数据:
2:删除角色时,要考虑到如果有用户绑定了这个角色,那么需要根据自己系统的业务需求来做相应的处理
这篇博客难点就是zTree,不熟悉的朋友可以学习一下zTree案例
地址:https://blog.csdn.net/qq_37936542/article/details/78429675
角色新增:
新增页面展示:因为前端技术有限,我们只着重介绍zTree和后端逻辑
一:封装pojo
角色:
import java.util.List;
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
/**
* 因为做这个功能时,前端需要封装权限id的list集合上传,但是我直接用List<Integer> permissions这个属性接收一直报错,
* 无奈之下,只能在前端将权限id的list集合json化,然后用perms属性接收再反序列化成list保存。
* 如果大家直接实现了List<Integer> permissions属性接收,请赐教
*/
private String perms;
private List<Integer> permissions;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
public List<Integer> getPermissions() {
return permissions;
}
public void setPermissions(List<Integer> permissions) {
this.permissions = permissions;
}
public String getPerms() {
return perms;
}
public void setPerms(String perms) {
this.perms = perms;
}
@Override
public String toString() {
return "Role [id=" + id + ", roleName=" + roleName + ", roleDesc="
+ roleDesc + ", permissions=" + permissions + ", perms="
+ perms + "]";
}
}
zTree节点:
public class Node {
// 节点id
private Integer id;
// 父节点id
private Integer pId;
// 节点名称
private String name;
// 需要自定义图片时,使用该属性
private String iconSkin;
// 通过该属性,设置图片
private Integer level;
// 当需要设置某个节点被选中的时候,通过该属性定义
private Boolean checked;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getpId() {
return pId;
}
public void setpId(Integer pId) {
this.pId = pId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIconSkin() {//根据level的值来返回节点图片
String icon;
switch(this.level){
case 0:
icon = "icon0";
break;
case 1:
icon = "icon1";
break;
case 2:
icon = "icon2";
break;
default:
icon = "icon3";
break;
}
return icon;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
public Boolean getChecked() {
return checked;
}
public void setChecked(Boolean checked) {
this.checked = checked;
}
@Override
public String toString() {
return "Node [id=" + id + ", pId=" + pId + ", name=" + name
+ ", iconSkin=" + iconSkin + ", level=" + level + ", checked="
+ checked + "]";
}
}
二:页面引入zTree相关js、css
<link rel="stylesheet" href="js/ztree_v3/css/zTreeStyle/zTreeStyle.css"
type="text/css">
<script src="js/jquery.min.js"></script>
<script src="js/jquery.ztree.core-3.5.min.js"></script>
<script src="js/jquery.ztree.excheck-3.5.min.js"></script>
<script src="js/jquery.ztree.exedit-3.5.min.js"></script>
三:准备zTree容器
<!-- 这里需要注意class需要设置为ztree,否则可能会导致树的css样式不起作用 -->
<div>
<ul id="ztree" class="ztree"></ul>
</div>
四:页面js
$(function() {
//zTree相关代码=======================
var zTreeObj;
initTree();//加载zTree
function initTree() {//zTree初始化函数
$.get("role/tree.do", function(data) {
zTreeObj = $.fn.zTree.init($("#ztree"), setting, data);
// zTreeObj.expandAll(true); //直接展开树结构
});
}
var setting = {
check : {// 定义是否显示单选和复选框
enable : true,
chkStyle : "checkbox",
chkboxType : {// 勾选 checkbox 对于父子节点的关联关系
"Y" : "s",
"N" : "s"
}
},
data : {// 节点数据系列的属性配置
simpleData : {
enable : true,
idKey : "id",// 节点数据中保存唯一标识的属性名称 默认值:"id"
pIdKey : "pId"// 节点数据中保存其父节点唯一标识的属性名称 默认值:"pId"
}
},
};
//zTree相关代码结束 ============================
$("#addBtn").on("click", function() {//添加按钮点击事件
//获取选中权限节点id的集合
var nodes = zTreeObj.getCheckedNodes(true);
if(nodes.length == 0){
layer.alert("权限不可为空")
return;
}
var _list = [];
for (var i = 0; i < nodes.length; i++) {
_list.push(nodes[i].id)
}
//字段非空验证
if (validate())
return;
$.ajax({
url : basePath + "/role.do",
data : {
"roleName" : $("#roleName").val(),
"roleDesc" : $("#roleDesc").val(),
"perms" : JSON.stringify(_list),
},
type : "POST",
success : function(data) {
layer.alert("操作成功")
},
error : function(data) {
layer.alert("操作失败")
}
});
})
//字段的非空验证
function validate() {
if ($("#roleName").val() == '') {
$("#validateName").html("角色名称不可为空");
$("#validateDesc").html("");
return true;
}
if ($("#roleDesc").val() == '') {
$("#validateName").html("");
$("#validateDesc").html("角色描述不可为空");
return true;
}
return false;
}
});
五:后台请求
1:zTree初始化请求
<!-- Controller代码 -->
@GetMapping("/tree")
@ResponseBody
public ResponseEntity<List<Node>> tree() {
try {
List<Node> nodes = roleService.getNodes();
return new ResponseEntity<List<Node>>(nodes, HttpStatus.OK);
} catch (Exception e) {
log.error("获取权限节点失败", e);
return new ResponseEntity<List<Node>>(
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
<!-- sql语句 -->
<select id="getNodes" resultType="com.mote.pojo.Node">
SELECT p.id id, p.parent_id
p_id, p.perm_desc name, p.`level` `level` FROM
permission p
</select>
2:新增按钮点击请求
<!-- jackson工具依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.3</version>
</dependency>
<!-- Controller代码 -->
@PostMapping()
@ResponseBody
public ResponseEntity<Integer> addRole(Role role) {
try {
roleService.addRole(role);
return new ResponseEntity<Integer>(Common.common_success,
HttpStatus.OK);
} catch (Exception e) {
log.error("添加角色失败", e);
return new ResponseEntity<Integer>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
<!-- Service代码,这个方法需要加事务控制 -->
public int addRole(Role role) throws Exception {
//jackson
ObjectMapper mapper = new ObjectMapper();
// 添加角色返回主键
roleDao.addRole(role);
// 将string转成list
JavaType jt = mapper.getTypeFactory().constructParametricType(
ArrayList.class, Integer.class);
List<Integer> list = mapper.readValue(role.getPerms(), jt);
role.setPermissions(list);
// 添加角色-权限
return roleDao.addRolePrem(role);
}
<!-- sql语句 -->
<insert id="addRole" useGeneratedKeys="true" keyProperty="id">
INSERT
INTO role (role_name, role_desc) VALUES (#{roleName},#{roleDesc});
</insert>
<insert id="addRolePrem">
INSERT INTO role_permission (role_id, perm_id) VALUES
<foreach collection="permissions" item="perm" separator=",">
(#{id}, #{perm})
</foreach>
</insert>
六:页面css(实现zTree的自定义图片)
<style>
<!-- icon0_ico_open:level为0的节点打开时显示的图片,img/house.png:图片路径 -->
.ztree li span.button.icon0_ico_open {
margin-right: 2px;
background: url(img/house.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
<!-- icon0_ico_close:level为0的节点关闭时显示的图片,img/house.png:图片路径 -->
.ztree li span.button.icon0_ico_close {
margin-right: 2px;
background: url(img/house.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.icon1_ico_open {
margin-right: 2px;
background: url(img/doc.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.icon1_ico_close {
margin-right: 2px;
background: url(img/doc.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.icon2_ico_open {
margin-right: 2px;
background: url(img/permission.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.icon2_ico_close {
margin-right: 2px;
background: url(img/permission.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
<!-- icon3_ico_docu:level为3的子节点显示的图片 -->
.ztree li span.button.icon3_ico_docu {
margin-right: 2px;
background: url(img/permission.png) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle
}
</style>
角色编辑:
效果展示:回显的时候,zTree默认选中用户的权限节点(Node的checked属性为true即为选中)
数据回显的实现逻辑:
点击更新按钮,进入后台,查询出role相关属性,再跳转到角色更新界面,到了界面以后,zTree通过ajax请求去后台查询权限节点数据进行显示。
1:跳转更新界面请求
<!-- Controller代码 -->
@GetMapping("/toUpdRole/{id}")
public ModelAndView toUpdRole(@PathVariable("id") Integer id) {
ModelAndView mv = new ModelAndView();
try {
Role role = roleService.getRole(id);
mv.addObject("role", role);
} catch (Exception e) {
log.error("跳转更新角色页面失败", e);
mv.setViewName("404");
return mv;
}
mv.setViewName("role/editrole");
return mv;
}
<!-- sql语句 -->
<select id="getRole" resultType="com.mote.pojo.Role">
SELECT * FROM role WHERE id = #{id}
</select>
2,zTree初始化请求
<!-- Controller代码 -->
@GetMapping("/permTree")
@ResponseBody
public ResponseEntity<List<Node>> permTree(@RequestParam("id")Integer id) {
try {
List<Node> nodes = roleService.getPermNodes(id);
return new ResponseEntity<List<Node>>(nodes, HttpStatus.OK);
} catch (Exception e) {
log.error("获取权限节点失败", e);
return new ResponseEntity<List<Node>>(
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
<!-- sql语句 -->
<select id="getPermNodes" resultType="com.mote.pojo.Node">
SELECT p.id,p.parent_id pid,p.perm_desc NAME,p.`level`,
IF (p.id IN (
SELECT perm_id FROM role_permission WHERE role_id = #{id}
), TRUE,FALSE) checked
FROM permission p
</select>
用户管理模块
用户添加、用户编辑、用户删除,相比较角色模块,这三个功能实现起来比较简单。就简单展示一下页面结构。
用户管理主页:
1,新增用户(页面需要的数据:所有的角色)
注意:数据库保存用户密码时,使用shiro自带的MD5撒盐加密
@PostMapping()
@ResponseBody
public ResponseEntity<Integer> addUser(User user) {
try{
User flag = userService.getUserByName(user.getUserName());//验证用户名
if(flag != null)
return new ResponseEntity<Integer>(Common.common_fail, HttpStatus.OK);
Md5Hash pwd = new Md5Hash(user.getPassword(), user.getUserName());//将密码进行MD5盐值加密,盐为用户名
user.setPassword(pwd.toString());
userService.addUser(user);//添加用户
}catch(Exception e){
log.error("添加用户失败",e);
return new ResponseEntity<Integer>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<Integer>(Common.common_success,HttpStatus.OK);
}
2,编辑用户(页面需要的数据:个人信息和所有的角色)
3,删除用户(省略...)
上一节:数据库表格设计
下一节:spring整合shiro
tip:有错误或疑问,请评论留言,谢谢