java学习笔记——众筹项目练习——后台manager程序--权限管理的全部功能,模糊查询数据的分页显示,全选与单选的联动,模态框与zTree的联合使用,RBAC权限模型的简单使用

                                                    权限管理

在前面我练习了管理员的注册和登录,并成功的登录到了控制面板main.jsp页面,今天我们就来试着实现一下控制面板页面中的功能。在控制面板中,我们最先注意到的也是最重要的功能就是权限管理,并且在前面的文章中也介绍了RBAC权限模型的概念与数据库中表的实现。

好,我们一起一点一点的来完善控制面板页面的功能吧。

首先我们已经可以成功的跳转到了main.jsp页面,可是现在的控制面板页面还不具备任何功能,就连界面中显示的功能也都是原型页面中自带的假数据。所以我们要一点一点的改造。

那么我们从哪里开始呢?就从左边显示的功能菜单开始吧!!!

我的这个页面中左边的权限管理菜单应该是,单击就会显示子菜单的,但是我这里点击后没有效果完全点不开,与原型页面不符,可能是哪里出了问题。我们检测页面元素看看问题出在了哪里?发现是bootstrap加载出现了问题,路径有问题。

应该改成正确的加载路径。我们的bootstrap被放在了plugin文件夹下,所以需要修改路径。

好了,修改后就可以看见子菜单了。

虽然左边的菜单栏可以显示出来了,不过显示的都是原型页面中固定写死的假信息。我们需要将这个菜单栏改造成可以根据数据库表中的数据进行动态变化的菜单栏,因为我们菜单栏中有哪些菜单,不应该在页面中规定,而是在数据库中存储,数据库中有哪些菜单,页面的菜单栏中就应该显示哪些菜单,这样更加灵活,也更加贴合我们的需求,修改或者添加菜单时也更方便。

 

                                                菜单栏改造

我们可以看出左边的菜单栏其实是一个用于子父级关系的树形结构,并且每个父节点的后边还有一个标识这自己有一个子节点的数字标识。既然要将菜单栏存储在数据库表中,那么数据库中肯定是要有相应的菜单表喽,并且要实现树形结构就要根据子父级关系进行存储,我们数据库中的t_permission表正就是用来存储菜单的,我们先根据原型页面中的菜单在t_permission表中创建菜单数据(菜单名、图标、以及请求地址)。这里为了省事,值写了权限管理、用户维护、角色维护、许可维护的图标信息和请求信息(因为点击菜单操作需要跳转页面,所以会有请求信息,比如点击用户维护会跳转到用户列表页面)。

好,数据有了,现在我们来实现程序中的取得菜单数据。那我们应该在哪里获取菜单数据呢?因为登录后就回来到控制面板页面,并显示左侧的菜单栏。所以我们应该在登录成功的时候就获取到菜单数据,并保存到session域中为跳转到的控制面板页面使用。为了给页面减少计算的压力,我们应该在程序中就组装好菜单的子父级关系。可是如何给页面传递一个带有子父级关系的树形结构呢?我们需要对tPermission类稍加改造---添加一个List<tPermission> childs类型的成员变量来保存子菜单信息;这样我们就可以返还一个具有子父级关系的树形结构了,并且页面使用时也省了不少功夫。

好了,在程序中获取菜单信息并传达到控制面板页面代码完成。

先我们来修改页面,再页面中动态的显示这些菜单信息(我们默认菜单的树形结构只有两级)

原来的main.jsp页面

将显示左侧菜单栏的部分出取出来加以改造,因为左侧的菜单栏有好几个页面会使用,所以还是抽取成公共显示部分比较好。

然后再原来的控制面板页面中显示左侧菜单栏的位置引入我们公共的左侧菜单栏页面即可。

好了,页面也改造完毕,运行一下试试吧 。

当当当当,成功!!!!(因为图省事,只在数据库的t_permission表中填入了权限管理的图标和请求地址,所以别的菜单才光秃秃的,需要的时候会全部加上,嘻嘻)。

现在左侧的菜单还不能点击,因为点击菜单后会跳转页面,可是我们只在数据库中为用户权限中的几个菜单添加了url请求地址,并且请求地址中相应的界面也没有创建,所有点击菜单后不是现实找不到页面的错误就是返回首页。

让我们一点一点的实现接下来的功能吧!首先我们要保证点击左侧的菜单后可以成功的跳转页面,先来完成权限管理中用户维护、角色维护、许可维护这三个菜单的页面跳转吧。

 

                                             点击菜单权限管理跳转页面

想要成功的跳转页面,需要修改两个地方:一,跳转到的jsp页面存在。二,请求地址正确。

一,跳转到的jsp页面存在:我们现在还没有跳转后的页面,不过我们有原型页面,我们可以看看,点击相关的菜单后会跳转到哪个页面,这样我们把相关的原型页面转换为我们需要的jsp页面再加入到我们的项目中就可以了。前面的文章中我们知道了如何将html原型页面转换为jsp页面(先修改html文件的中的文件编码,再修改后缀为jsp就可以了)。

添加到eclipse后添加jsp文件头,然后修改文件后缀为.jsp。

同样的方式修改另外两个文件。

要跳转的jsp界面添加完毕。接下来我们修改点击菜单时发送跳转页面的请求,因为我们不同菜单的请求是房子数据库中存储的,菜单栏只是在数据库中取出而已,所以我们要修改数据库中 的数据。

为用户维护菜单添加请求后,还要有相应的处理controller来返回相关的页面,因为我们的用户维护页面在WEB-INF文件夹中,不能再浏览器中直接被访问。

并且修改页面中的依赖库路径,不然页面会乱掉的。

在控制面板点击左侧菜单栏跳转到user.jsp页面显示用户信息,这里需要注意的是,user页面与main页面都有左侧的菜单栏,但此时他们却不是同一个菜单栏,他们分别属于不同的页面。我们前面将左侧的菜单栏抽取成一个单独的jsp文件,就是为了可以让不同的页面在需要菜单栏时可以共用。

 

                                          user.jsp页面使用公共的菜单栏

引入公共的菜单栏文件。

再次访问user.jsp页面,发现菜单栏没有自动展开也没有变红。

既然我们点击了用户维护菜单,访问了user.jsp页面,那么左边的菜单栏中应该有相应的显示才对,权限管理自动展开并且用户维护菜单变色表示选中状态。这个需要实现起来也不难,并且html的原型页面也已经实现了,只需要改变相关菜单的样式就可以了。但是这里我们既然已经将左侧的菜单栏抽取成了一个公共的功能,那么我们就不能像之前在原型页面中那样设置相关菜单的样式了。我们需要封装一个公共的方法,用来设置不同菜单的选中样式,这样我们在菜单栏中访问所有页面时就都可以简单设置选中时应该显示的状态了。

 

                               添加公共的改变选中菜单栏中菜单状态方法

添加JavaScript方法实现父菜单展开,子菜单变红的方法,参数是菜单中请求的地址,因为菜单中的请求地址是唯一的,所以以此来区别点击了那个菜单。使用时在跳转到的相关页面传入本页面的请求地址就好了。

在user.jsp页面中只需要在pageContext域中保存跳转到本页面时的请求地址,然后加载上面的user_menu.jsp公共的菜单栏文件就可以了。

左侧菜单栏部分的功能差不多就调好了,我们继续。。。

接下来我们来实现user.jsp页面中右半部分的功能,右半部分的列表是用户列表,所有的用户都显示在这个列表中。我们的数据库中有一张t_user表,正是用来保存用户信息的,所有我们只需要将t_user表中的数据全部查出来并显示在user.jsp页面右半部分的用户列表中就可以了。

注意,这里的展示是有分页功能的,并不是所有数据全部都显示在每一页中。所以我们在显示用户列表的时候还要添加一个分页功能。

 

                                          添加获取用户列表功能并分页

我们现在t_user表中创建一些用户信息,毕竟用户信息太少的话也没有办法分页显示的嘛。

用户列表是在点击用户维护菜单后显示的,所以我们应该在处理用户维护请求/permission/user/list中获取用户信息,所以应该在controller中的users()方法中去获取用户信息。

添加获取用户信息的实现代码。这里分页数据中pn表示显示第几页,默认赋值1。ps表示每页显示几条数据,默认赋值5。还有就是页脚分页菜单处,一共可以显示3个连续页面。

修改界面,显示我们传过来的用户信息。

显示用户列表也很简单,for循环打印就可以了。

 

还有页脚处的分页按钮,都可以在我们传过来的PageInfo类型的user_info数据中找到相关的信息。要保证分页按钮与传输过来的用户数据的页数保持同步外,还要发送其他页用户数据的请求。每一个分页按钮都是一个用户数据页的请求。

显示用户数据和分页功能代码完成,我们去运行一下看看效果。。

点击用户维护,显示用户列表第一页,每页显示5条数据。

点击第二页、第三页,会重新发送用户信息分页数据的请求,改变用户数据显示,并且分页按钮也相应改变,但始终只显示3个页面的按钮(因为我们只设置了显示3个分页按钮)。

 

 

ok,用户列表展示,并分页功能完成。。

接下来,我们继续。在我们的user.jsp页面中还有一个查询的功能。用户列表可以根据查询的不同关键字来展示不同的信息。这个功能实现起来也不难,都是查询用户列表嘛,与之前的区别就是之前是查全部,而这个是根据条件查询。既然两个都是查询,那我们来优化一下,让他们合并为一个根据关键字查询的方法,如果关键字为空,我们就查全部。查询的方式应该使用模糊查询,并且我们这里只根据关键字去查询账号和用户名。就是说只要账号与用户名中存在关键字,我们就显示。

 

                                     查询优化:根据关键字查询用户列表

修改controller中的查询代码。添加根据条件查询,查询条件会作为参数传递过来,查询之后还要讲查询条件返回给页面用于回显。

修改user.jsp页面中条件查询form表单的参数,添加请求地址,将查询条件作为提交项,并可以从域中取得查询条件完成回显效果。

根据条件查询时当然不能忘了分页按钮啦!因为分页按钮也是会发送查询请求的,我们之前发送的是查询所有的分页请求,现在需要再添加上根据条件查询的分页请求,如何实现呢?我们可以写一个脚本,在点击分页按钮的时候为这个按钮的请求追加一个条件查询的参数(&sh=xxx)就行啦!

再运行试试看。。

输入模糊查询条件为s,点击查询

点击下一页。

ok,一切正常,呦呦呦完成了一个小功能。。。。

接下来我们来实现用户数据的删除功能。在做删除功能之前呢!有一个小功能需要实现,那就是用户数据的全选与单个数据选择的联动功能,在删除的时候很可能需要删除多项或者全部删除,全选与单选的联动功能可以方便我们的删除功能的使用。当然了这个联动的功能不光是删除需要,其他的功能也可以需要。总之,这个联动的功能虽小,但是很实用。

 

                                          全选与单个用户数据选择的联动功能

这个功能实现起来也很简单,直接使用JavaScript脚本就可以完成,由于这个功能可能会在很多的地方被使用,所以应该是一个公共的方法来让别人使用。首先检查单个用户数据选择框全中的个数如果等于全部,那么全选框也为选中状态,否则为不选中状态。再检查如果全选框的状态为选中状态,那么所有的单选框都变为选中状态,否则为不选中状态。

在user.jsp页面中引用这个common-js.jsp文件并调用这个公共的联动方法,传入全选框和单选框作为参数。

运行效果。点击全选按钮,下边所有的单选框也会跟着全部选中。

下边的单选框只要有一个没有选中,全选框就会取消选中。

ok。。。

有了这个全选的功能,那么接下来我们实现的这个批量删除功能就容易多了。

 

                                                         批量删除功能

这个功能该如何实现呢?因为我们的用户列表中的id都是数据库中存储的真实id,所以我们根据id去删除再好不过了。我们只需要在点击批量删除按钮时,去获取所有被选中的用户信息中的id,并以这些id作为删除请求的参数告诉程序删除即可。

先为批量删除按钮添加一个id=“delAllBtn”,用于为批量删除按钮绑定点击事件。再在每个用户的单选框元素中添加一个隐藏属性del_id=“${user.id}”,用于保存该用户的真实id,方便我们使用。

然后编写JavaScript脚本,为批量删除添加点击事件,获取所有选中的用户id并发送删除请求。

好,user.jsp页面修改好了,下面我们来实现删除数据库表中相关信息的代码。

根据页面请求地址与参数创建controller请求处理方法。

在UserServiceImpl的具体实现中为了严谨一点,我们当然要区分是删除单个id还是多个id啦!这样比较通用。

好了,批量删除功能的代码码完啦,运行一下试试看。。

先看看数据库总的用户数据,此时这一个用户信息还存在。

点击删除后,第4页消失了。

数据库中的数据也正确删除啦。

ok,批量删除这个功能我们也这么愉快的完成了。。。。

我们看批量删除按钮的旁边还有一个新建的按钮,这个按钮是用来新建用户的。新建用户这个功能实现起来很简单,基本与注册功能一样。只是多了一个页面跳转需要先跳转到adduser.jsp页面,然后基本与注册功能一模一样,这里就不是实现了。

接下来我们再往下看,看看还有什么功能。在用户列表中,每一条用户信息最后的操作列都有三个按钮。依次分别是角色分配、编辑、与删除三个按钮。

那我们就先来说说角色分配按钮吧!顾名思义,角色分配按钮就是用来为用户分配角色的。还记得我们之前讲过的权限管理RBAC模型吗?就是基于角色的权限管理模型。角色与权限是多对多的关系,每个角色可以有多个权限,同时一个权限也可以被多个角色同时拥有。那么用户与权限是怎么形成联系的呢?答案是用户不与权限有直接的联系,而是通过角色间接的与权限关联。那么用户与角色是什么关系呢?角色与用户当然也是多对多的关系啦,一个用户可以有多种身份,同时一个身份也可以被很多人拥有。就比如人民解放军这个身份被很多人拥有,但是他们每个人不光有解放军这一个身份,同时他们还可以是一个父亲、丈夫等等。

好了,扯得有点远了。这里的角色分配按钮就是让我们的用户,与左侧角色维护菜单中的某一个或某几个角色产生联系的功能按钮。接下来我们就来实现这个功能吧!

 

                                                             角色分配

我们回忆一下之前讲过的RBAC权限模型,大家就会想起用户与角色之间是多对多的关系。在数据库中想要为他们俩建立关联关系,就需要一张中间表。这张中间表不干别的,只需要记录用户与角色的对应关系即可。而角色分配这个功能正是用来操作这张表,已达到为用户分配角色的作用。

既然角色分配按钮具有角色分配功能,那么这个按钮肯定是可以跳转到角色分配页面啦!我们先来看看角色分配页面长什么样子吧!

页面比较简单,只有已分配角色和未分配角色两个列表,和两个分配与撤回的按钮。

我们先把角色分配页面添加到我们的项目中,让角色分配按钮可以跳转到角色分配页面之后再来实现别的功能吧!

在项目中添加原型页面很简单,这里就不多说了,前面的我们有过详细的讲解,只需要三步就可以了。一,将原型页面代码中所有关于编码的代码统统改成UTF-8,并将页面文件的编码格式也改成UTF-8。二,拷贝到项目中,并添加jsp文件头,保存、关闭文件。三,直接修改html文件后缀为jsp就可以了。

先为用户列表中每个用户的角色分配按钮添加一个保存本用户id的隐藏属性u_id="${user.id}",再为每个用户的角色分配按钮绑定点击事件。因为我们的用户可能会很多,那么用户的角色分配按钮同时也会很多,再为按钮绑定点击事件是根据id绑定肯定是不明智的,应该根据class绑定。因为class是可以充分出现的,而id不行,类型选择器可以找到所有相同class的元素为他们共同绑定事件。所以我们要为所有用户的角色分配按钮定义一个共同的class=“assignBtn”。

为所有角色分配按钮绑定点击事件,并添加请求,还要将原有的角色分配按钮点击事件删除,否则他会给我们捣乱的。

删除原有的角色分配按钮点击事件。

接下来我们去添加处理这个跳转到角色分配页面的请求controller,并可以正确跳转都角色分配页面。

添加好了,去试一下看看。。

ok,可以正常跳转了。但是界面是花的,这是因为我们把原型页面添加到项目中是,只转换了文件格式与后缀,并没有修改样式库的依赖路径,我们项目中的样式依赖路径与原型页面的路径不相同。找不到已添加的样式所以才会乱的。

修改依赖样式库的路径非常简单,根据我们项目的路径自行修改就可以了。

好,可以正确的来到角色分配页面啦。现在页面中显示的数据都是一些假数据。接下来我们要为页面添加真实的数据。真实的数据从哪来呢?当然是从数据库表中查询得到的啦!我们在处理角色分配按钮点击后发送的请求时,去数据库中查询某一个用户已经拥有的角色和未分配的角色信息,并添加到域对象中,这样跳转到角色分配界面后就可以使用某一用户的这些角色信息并且显示出来了。

还记得我们为每个用户的角色分配按钮都添加了一个隐藏的u_id=“${user.id}”吗?就是为了在点击角色分配按钮后发送请求的时候更方便的带上这个用户的id去查询用户的角色信息。既然用户id已经传递过来了,那么我们只要查询相关的角色信息并且添加到域对象中即可。

那么用户已经拥有的角色和未拥有的角色应该如何查询呢?已经拥有的可以访问用户和角色的中间表进行查询。那么未拥有的角色如何查询呢?我们可以把角色表中的所有角色全部取出来减去用户已拥有的角色不就得到了未拥有的角色嘛!

好,那我们就来先取得所有的角色信息与某一用户已拥有的角色信息。

取得所有的角色信息比较简单,只需要访问角色表,查询所有角色就可以了。

取得用户已拥有的角色信息要稍微麻烦一点,因为我们需要返回一个角色信息的list列表,而我们光去查询用户与角色的中间表的话,只能得到角色的id,这样的话我们还要根据角色id去角色表中查询角色然后才返回角色list。这样做比较麻烦!我干脆在角色表自动生成dao层的TRoleMapper中自定义添加一个多表联合查询方法好了,利用用户id查询拥有的角色id,再根据角色id返回角色list。

RoleServiceImpl.java中实现getAllRole()与getUserRole(Integer uid)两个功能。getAllRole()不必多说,只需要调用自动生成的dao层接口roleMapper查询所有角色返回list即可。

getUserRole(Integer uid)这个功能如何实现呢?自动生成的dao层接口roleMapper没有现成的接口供我们使用,我们又不想先去查用户与角色的关联表后取得角色id,在根据角色id去查角色表,获取角色list。这样比较麻烦!我们干脆在roleMapper中自定义一个可以多表联合查询的接口供我们使用。

光定义接口是没有用的,我们还要去实现具体的sql语句,实现如何查询。

好了,代码的取得未分配角色与有分配角色的实现我们写好了,并且添加到了域对象中,接下来我们修改角色分配页面assignRole.jsp来域对象中取得数据,并显示。

在修改assignRole.jsp时别忘了添加我们编写的公共的左侧菜单栏user_menu.jsp和设置展开与选中并高亮的样式呦!

当然在assignRole.jsp中取得角色信息的时候会用到JSTL的东西<c:forEach>,我们也是在user_menu.jsp中引用的,所以只要引用user_menu.jsp就可以了,不需要再重新引用JSTL库啦。

角色分配页面assignRole.jsp我们也已经修改了。可是我们的数据库表中还没有数据,我需要造一些数据用于显示。

为角色表创建8个角色。

为用户与角色的关联表,添加用户id为12的两个角色信息,用户12同时拥有5号与7号角色。

ok,我们去页面看看效果。

哈哈,很好,是我们想要的效果。

接下来呢,我们看到角色分配页面中有左、右两个按钮。他们他们分别代表分配角色、与撤回角色功能。某一用户所拥有的真实角色信息显示在了列表框中。下面我们就来实现一下角色的分配与撤回功能吧!

其实这两个功能还是很好实现的,不过就是数据库的添加与 删除操作嘛!

角色分配页面有两个列表,左边是未分配角色列表,右边是已分配角色列表。那么分配角色与撤销角色功能都是相对于用户而言的,也就是相对于右边的已分配角色列表而做的操作。分配功能:就是讲左边未分配角色列表中医选中的角色移动到右边的已分配角色列表中。撤销功能就是将右边已分配角色列表中选中的角色移动到左边的未分配角色列表中。同时还要对数据库的用户与角色关联表进行添加月删除操作,以实现真实数据的分配与撤销。

在角色分配页面assignRole.jsp中添加JavaScript脚本,为分配与撤销按钮绑定单击事件,实现点击时将未分配列表中选择了的角色数据移动到已分配列表中,或者将已分配列表中选择了的角色数据移动到未分配列表中,并已用户id与需要移动的角色id作为参数发送添加或者删除角色信息的请求。

找角色分配页面中到分配与撤销的按钮,和两个角色列表,并为他们添加可以定位的标识。

为分配角色和撤销角色按钮绑定点击事件,并发送ajax请求。

这里有个需要地方需要注意一下。var uid = "${param.uid}";是不是很奇怪,这个param.uid是哪来的?我们什么时候设置的域对象?其实我们并没有在域对象中添加过这个参数,而是本来就有这个param。这句话的意思是取出当前页面的请求地址中的参数uid的值。param代表当前页面请求地址中的所有参数。

我们继续。接下来是controller,还记得我们在页面中发送的事ajax请求嘛,也不需要返回什么数据,但是我们希望ajax中的回调函数会被执行,用以提示所做的操作成功了,所以需要用到@ResponseBody这个注解。@ResponseBody的作用请参考:https://www.cnblogs.com/daimajun/p/7152970.html。

好,代码写完了。我们试一下。

再看看数据库。

妥了,角色分配功能完成。

好了,接下来我们来实现角色维护这个功能。

 

                                                             角色维护

角色维护这个功能主要就是对角色的增删改查功能,打开原型页面看看。

大家有没有觉得这个角色维护的角色列表界面也用户维护的用户列表页面很像呢!事实也确实如此,除了显示的数据列表中的数据不同外,他们基本相同。

所以这里就不详细的说具体实现啦!直接上图吧。

添加角色页面,修改依赖库路径。

添加左侧公共菜单栏并设置选中高亮

为查询条件form添加请求连接,回显查询条件。为批量删除添加id,用于绑定点击事件。显示角色信息时,在域对象中取出所有角色数据并循环显示。

修改原有的分页菜单,每一个分页按钮都要添加请求地址并绑定相应页面参数。

添加JavaScript脚本,为批量删除绑定点击事件,携带删除参数并发送批量删除请求。

点分页按钮发送相关页面查询请求时,为每个按钮绑定项目的查询信息。

设置全选框与单选框的联动效果。

修改左侧菜单栏中角色维护的请求地址。让它访问RoleController中的/permission/role/list请求。

在RoleController中处理页面的角色列表查询请求和批量删除请求。

在RoleServiceImpl中添加按条件查询角色和批量删除两个功能代码。

完成了 。我们感受一下吧!

呵呵,有了前边用户维护功能的铺垫,这个功能完全就是照着重写了一下,很简单。所以很快就完成啦。

那么重点来了,接下来呢,我们要实现的功能是为角色分配权限(也是分配维护)。之前实现用户角色分配功能的做法是,点击用户的分配角色按钮,跳转到角色分配页面进行分配角色。我们已经拿到了角色列表,也可以像之前为用户分配角色那样去跳转页面,然后进行分配权限。不过,那种方式我们已经实现过了,照着之前的功能完全重写一下显然不是我们在这写文章浪费时间的目的。这里我们使用一种新方法,bootstrap的模态框以弹出框的形式显示页面,可以使页面更炫酷,不用像之前那样需要编写controller的页面跳转,也更有逼格。嘻嘻。。下面我们来一起实现一下吧。

 

                                           角色分配权限并采用模态框显示

我们先来试着显示一个模态框吧!打开bootstrap的中文说明文档查看一下。

经过查看文档我们发现模态框是有静态与动态之分的,我使用动态模态框就好了。使用方法也很简单,只需要向下面一样为模态框的<div id=“myModal”>绑定事件,添加相应的显示div,并且为按钮添加data-toggle="modal" 和data-target="#myModal"两个属性就可以了。

 

在角色维护页面添加模态框的相关代码。

为角色的权限分配按钮添加data-toggle="modal" 和data-target="#myModal"两个属性。

添加模态框中将要显示的div,并且id与权限分配按钮中相关属性一致。添加JavaScript脚本绑定事件监听。

还有就是,如果按钮之前有定义点击事件的话,需要禁用。

运行一下。

哈哈,成了。

这里我们要做一个小修改,因为这个模态框默认有一个关闭行为,就是点击模态框外边的背景页就会自动关闭。这个行为对我们来说不是很友好。所以我们需要禁用这个点击模态框外边的背景就自动关闭的行为。

怎么禁用呢?呵呵,当然是查看说明文档啦!

照着这个方法,我们在权限分配按钮上添加data-backdrop="static"。

接下来我们来修改这个模态框的显示,让它变成我们需要的权限分配页面的显示。

首先我们的权限列表是一个树形结构,还记得前一篇的文章中介绍过的zTree插件吗?我们正是使用zTree来显示一个树的。

那我们先来显示一个简单的树,然后再在树中显示真实的权限数据吧!

添加zTree需要的js与css,还有zTree依赖jQuery,所以需要添加jQuery的js。修改模态框中显示权限树的位置并设置id="permissionTree" class="ztree"。

使用简单数据模式创建一棵树,树的节点与父节点对应的字段分别是id和pid。

ok,显示一下。

好的,假数据可以显示了,那下一步就是显示我们需要的真实数据啦。

不过呢,这里有一个地方需要做一下修改,那就是模态框的显示方式需要修改。现在的做法是让按钮直接触发模态框的同时并且为模态框绑定监听器,模态框显示后向其中添加树结构,这样做对于我们获取分配权限按钮中r_id属性的值很不方便。因为我们在模态框中显示的权限树结构是根据角色id进行获取的,所以我们采用另一种方式,直接为按钮绑定点击事件,在JavaScript脚本事件中初始化树结构并且以js的方式显示模态框。

先将权限分配按钮中之前添加的属性删除。

在为按钮绑定点击事件。在事件中初始化权限树,并主动显示模态框。初始化权限树时应该以当前按钮所在角色的id做为参数,获取不同角色的权限树。

运行看看,获取的角色id正不正确?

ok,可以正确的获取到权限分配按钮所在角色的相关id啦。现在要在模态框中显示真实的权限树,并且显示不同角色已经拥有的权限信息。

初始化权限树时发生ajax请求获取全部权限的JSON数据,并且指定zTree的配置信息idKey和pidKey的值,要与我们真实的权限数据中的id与pid对应起来,这样才能正确的显示出一棵权限树(我们的已经在写假数据时就指定并对应好了)。取得全部权限JSON数据后,我们还要在每个父节点中添加open:true属性,使权限树显示时父节点自动展开。

获取全部权限数据并返回JSON。

成功。

现在我们在模态框中显示了全部的权限信息,那么怎么才能在这个全部信息的树中看出某个角色拥有那些权限呢?我们可以为整个权限树的每个权限节点前面添加一个单选框,让已拥有的权限前边的单选框为选中状态,未拥有的为未选中状态,不就行啦!这样为某一角色分配未拥有的权限或者撤销已拥有的权限时,只需要点击单选框就可以啦。而这个整颗的每个节点前面都添加单选框的功能zTree已经帮我们实现啦,只需要在配置信息中设置一下就好啦。是不是很方便!!!所以,需要就去查文档吧。

而且不光是在所有节点前添加了单选框,zTree还帮我们吗做了子父节点单选框的关联功能,默认是开启的。

接下来我们将一号角色所拥有的权限显示在这个权限树中。

我们需要将初始化后的整颗权限树保存起来,用以为已拥有的权限做选中操作。选中操作zTree已经为我们提供了,需要先根据树中某个节点的信息取得这个节点,然后再对这个节点执行选中操作。注意这里用来操作的树!必须是我们之前初始化的对象,否则不行!

发送取得某个角色所拥有权限的请求,并根据返回的权限数据设置权限树中那些是已拥有的,已拥有的为勾选状态。

处理根据角色rid取得权限JSON的请求。这里为了方便,自定义了一个多表联查的dao层的数据库查询方法。

service层定义

dao层定义

编写sql语句。

为id为1的角色创建权限信息。

运行。

好了,已经可以显示某一角色已拥有的权限啦。接下来我们来实现为这个角色分配权限的功能。权限树我们可以操作,并且根据zTree的说明文档可以获取我们勾选后的所有权限节点,那么我们如何分配权限呢?最简单的方法就是,先删除某一角色的所有权限,然后再将新分配的所有权限设置进去就行了,这样做的优点就是:不需要考虑当前的权限分配操作对于已拥有的是新增还是删除。

我们需要在模态框中点击分配权限按钮时获取当前操作角色的id,以方便更新操作。角色列表的权限分配按钮时由角色id数据的,我们要将这个数据传递给模态框中的分配权限按钮。这样在点击模态框中分配权限按钮时就可以轻易的拿到角色id啦。

先为模态框中的分配权限按钮绑定点击事件。以权限树中选中的所有权限id和角色id作为参数,发送更新请求。在ajax的成功回调中隐藏模态框。

controller层处理更新请求。

service层处理更新的逻辑,应该先删除,再添加。最好加上事务控制,这样即使哪一步操作数据库失败了,也可以回滚,不会让数据丢失啦。

运行试试。。

修改id为1的角色的权限并点击分配权限按钮。

成功。。。

角色的权限分配功能我们实现了,可是我们打开权限分配的模态框会发现两个小问题。一,点击权限树中的某个节点时,会发生页面跳转。二,权限树中每个节点前面虽然有图标,但并不是我们的图标。那我们就来解决这两个小问题吧 。

一,点击权限树中的某个节点时,发生页面跳转其实是发送了对某个页面的请求,还记得我们数据库中权限表是存在url属性列的嘛!url列中保存的正是对某个页面的请求地址,我们在取得权限信息时将某一权限的所有属性都放到了某一个权限节点中,那么这个节点也就拥有了以对某个页面请求为值的url属性。而zTree在我们点击某个树的节点时,恰恰会访问当前节点中的url属性的地址。这个行为是默认的,但是我们可以自行指定点击树节点时访问url的key名称。如果我们想点击时不发生页面跳转,只需要将url的key名称指定为一个不存在的属性名即可。

将 treeNode 的 haha属性当做节点链接的目标 URL(haha属性不存在),所以不会发送这个URL请求,也不会发生页面跳转。

二,树中节点的图标并不是我们自己定义并且想显示的图标。zTree默认会开启图标的显示,并且也已经显示了图标,只是显示的图标是zTree默认定义的图标,并不是我们需要的。如果我想显示成我们自己定义的图标的话,需要自定义显示效果,添加JavaScript方法,并且在方法中可以随意的修改节点的样式,想怎么改就怎么改。

zTree的初始化设置中开启自定义显示效果,并指定自定义效果显示函数名称为showIcon。在showIcon方法中我们根据当前节点所有属性信息的命名规律确定图标的id,然后为当前节点的图标属性设置样式(样式信息我们是从数据库中拿过来,并已经保存到了当前节点中的)。

我们的数据库中只保存了前四个权限的icon信息。所以现在的模态框中其他的权限是没有icon信息的。

好了,到这里为止,我们的角色维护功能就全部都完成啦。

至于下面的许可维护功能呢?我们已经实现了用户维护和角色维护,不管是页面跳转还是使用模态框的形式,显示数据列表或者显示树结构,我们都实现过了。无非就是权限数据表的crud。这里就不再实现啦!只是有一个功能没有实现,那就是带按钮的树节点,这里可以参考https://www.cnblogs.com/my-freedom/p/6627204.html。和zTree的说明文档。

 

最后再附上例子程序,以供需要时查看:https://download.csdn.net/download/qq_25106373/11192181

 

 

 

 

 

 

                                                         

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章